Create SVG circle with several points

Viewed 93

I need to create an SVG circle with 30 points and display the current hours in the center.

I already have half circle but I don't know how to finish it.

The code:

 <svg version="1.1" width="140px" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 49.35 23.93" style="enable-background:new 0 0 49.35 23.93;" xml:space="preserve">
    <style type="text/css">
        .st0{fill:#000;}
        .st1{font-family:'ArboriaBook';}
        .st2{font-size:12px;}
    </style>
    <g>
        <path class="st0" d="M1.96,23.43c-0.44-0.06-0.71-0.39-0.66-0.81c0.05-0.42,0.4-0.66,0.84-0.61c0.43,0.05,0.72,0.37,0.66,0.81
            C2.74,23.24,2.39,23.48,1.96,23.43z"></path>
        <path class="st0" d="M2.9,18.83c-0.42-0.15-0.62-0.53-0.48-0.93c0.14-0.4,0.53-0.57,0.95-0.42c0.41,0.14,0.62,0.51,0.48,0.93
            C3.71,18.8,3.31,18.97,2.9,18.83z"></path>
        <path class="st0" d="M4.77,14.52c-0.38-0.23-0.5-0.65-0.28-1.01c0.21-0.36,0.63-0.45,1.01-0.22c0.37,0.22,0.51,0.62,0.28,1.01
            C5.57,14.66,5.14,14.74,4.77,14.52z"></path>
        <path class="st0" d="M7.47,10.69c-0.33-0.3-0.35-0.73-0.07-1.04c0.28-0.31,0.71-0.31,1.04-0.01c0.32,0.29,0.37,0.71,0.07,1.04
            C8.22,10.99,7.79,10.98,7.47,10.69z"></path>
        <path class="st0" d="M10.9,7.48c-0.26-0.36-0.2-0.79,0.14-1.03c0.34-0.24,0.76-0.16,1.02,0.2c0.25,0.35,0.22,0.77-0.14,1.03
            C11.58,7.92,11.15,7.83,10.9,7.48z"></path>
        <path class="st0" d="M14.92,5.02c-0.18-0.41-0.03-0.81,0.35-0.98c0.38-0.17,0.77,0,0.95,0.4c0.18,0.39,0.05,0.8-0.35,0.98
            C15.49,5.6,15.09,5.42,14.92,5.02z"></path>
        <path class="st0" d="M19.32,3.46c-0.09-0.43,0.13-0.8,0.54-0.89s0.76,0.16,0.85,0.59c0.09,0.42-0.11,0.8-0.54,0.89
            C19.76,4.13,19.41,3.88,19.32,3.46z"></path>
        <path class="st0" d="M23.94,2.82c0-0.44,0.29-0.76,0.71-0.76c0.42,0,0.71,0.3,0.72,0.75c0,0.43-0.27,0.76-0.71,0.76
            C24.24,3.57,23.95,3.25,23.94,2.82z"></path>
        <path class="st0" d="M28.66,3.13c0.09-0.44,0.44-0.68,0.85-0.6s0.63,0.44,0.55,0.88c-0.08,0.42-0.42,0.69-0.85,0.6
            C28.8,3.93,28.58,3.55,28.66,3.13z"></path>
        <path class="st0" d="M33.18,4.39c0.17-0.41,0.57-0.58,0.96-0.42c0.39,0.17,0.53,0.56,0.36,0.97c-0.17,0.4-0.55,0.59-0.96,0.42
            C33.15,5.2,33.01,4.79,33.18,4.39z"></path>
        <path class="st0" d="M37.33,6.54c0.25-0.37,0.68-0.45,1.02-0.21c0.35,0.24,0.4,0.66,0.15,1.02c-0.25,0.35-0.66,0.46-1.02,0.21
            C37.14,7.32,37.08,6.89,37.33,6.54z"></path>
        <path class="st0" d="M40.98,9.51c0.32-0.31,0.75-0.3,1.04,0s0.26,0.73-0.06,1.03c-0.31,0.3-0.74,0.32-1.04,0
            C40.63,10.24,40.67,9.8,40.98,9.51z"></path>
        <path class="st0" d="M43.94,13.13c0.38-0.23,0.8-0.14,1.02,0.21c0.22,0.36,0.11,0.77-0.27,1c-0.37,0.23-0.79,0.16-1.02-0.21
            C43.45,13.77,43.57,13.36,43.94,13.13z"></path>
        <path class="st0" d="M46.11,17.28c0.42-0.15,0.81,0.02,0.96,0.42s-0.05,0.77-0.47,0.92c-0.41,0.15-0.81,0-0.96-0.42
            C45.5,17.81,45.7,17.43,46.11,17.28z"></path>
        <path class="st0" d="M47.38,21.82c0.44-0.06,0.79,0.19,0.85,0.61c0.06,0.42-0.21,0.75-0.65,0.81c-0.43,0.06-0.79-0.17-0.85-0.61
            C46.68,22.22,46.96,21.88,47.38,21.82z"></path>
    </g>
    <text id="current_time" transform="matrix(1 0 0 1 11.2994 20.3894)" class="st0 st1 st2">09:54</text>
    </svg>

enter image description here

2 Answers

You could create just one dot, reuse it multiple times with <use> and give them the right coordinates by using basic trigonometry

Then add the text in the center (0,0) using both text-anchor="middle" and alignment-baseline="middle"

svg {
  width: 160px;
}
<svg viewBox="-52 -52 104 104" xmlns="http://www.w3.org/2000/svg">
    
   <!-- radius (r) of outer circle is 50, center is (0,0) -->
   <style>
      circle, text { fill: #9bc }

      text { font-family: system-ui; }
   </style>
   
   <!-- basic shape -->
   <defs>
      <circle r="2" id="dot"/>
   </defs>
   
   <!-- x = r * sin(-90),  y = r * cos(-90)  -->
   <use xlink:href="#dot"  x="-50" y="0" />
   
   <!-- x = r * sin(-78),  y = r * cos(-78)  -->
   <use xlink:href="#dot"  x="-48.907" y="-10.39" />
   
   <!-- x = r * sin(-66),  y = r * cos(-66)  -->
   <use xlink:href="#dot"  x="-45.677" y="-20.33" />
   
   
   <!-- continue by increasing the angle of 12° for
        the remaining 27 points, up to 270°
     -->

   <use xlink:href="#dot" x="-40.451" y="-29.389" />
   <use xlink:href="#dot" x="-33.457" y="-37.157" />
   <use xlink:href="#dot" x="-25.000" y="-43.301" />
   <use xlink:href="#dot" x="-15.451" y="-47.553" />
   <use xlink:href="#dot" x="-5.226" y="-49.726" />
   <use xlink:href="#dot" x="5.226" y="-49.726" />
   <use xlink:href="#dot" x="15.451" y="-47.553" />
   <use xlink:href="#dot" x="25.000" y="-43.301" />
   <use xlink:href="#dot" x="33.457" y="-37.157" />
   <use xlink:href="#dot" x="40.451" y="-29.389" />
   <use xlink:href="#dot" x="45.677" y="-20.337" />
   <use xlink:href="#dot" x="48.907" y="-10.396" />
   <use xlink:href="#dot" x="50.000" y="0" />
   <use xlink:href="#dot" x="48.907" y="10.396" />
   <use xlink:href="#dot" x="45.677" y="20.337" />
   <use xlink:href="#dot" x="40.451" y="29.389" />
   <use xlink:href="#dot" x="33.457" y="37.157" />
   <use xlink:href="#dot" x="25.000" y="43.301" />
   <use xlink:href="#dot" x="15.451" y="47.553" />
   <use xlink:href="#dot" x="5.226" y="49.726" />
   <use xlink:href="#dot" x="-5.226" y="49.726" />
   <use xlink:href="#dot" x="-15.451" y="47.553" />
   <use xlink:href="#dot" x="-25.000" y="43.301" />
   <use xlink:href="#dot" x="-33.457" y="37.157" />
   <use xlink:href="#dot" x="-40.451" y="29.389" />
   <use xlink:href="#dot" x="-45.677" y="20.337" />
   <use xlink:href="#dot" x="-48.907" y="10.396" />


   <text text-anchor="middle" alignment-baseline="middle" 
         x="0" y="0">12:34</text>

</svg>

I've generated automatically the list of coordinates with a simple script

var useNodes ="";
for (i = -90; i < 270; i = i + 12) {
   var angle = Math.abs(i) * (Math.PI / 180);
   var x = (Math.sin(angle) * 50).toFixed(3);
   var y = (Math.cos(angle) * 50).toFixed(3);
   useNodes +='<use xlink:href="#dot" x="'+ x + '" y="'+ y +'" />\n'
}

console.log(useNodes);

An easy way to cheat the system is, instead of drawing 30 dots, you can simply use the stroke of a <circle> element and set the dash-array such that the dashes are as short as possible. This doesn't guarantee the dots to be perfectly circular but might be close enough to what you need.

It is advisable to use JS to set the correct dash-array values though. However you can of course use an approximation in CSS.

See proof-of-concept below:

const circumference = 2 * Math.PI * 20;
const dots = 30;

document.querySelector('svg circle').setAttribute('stroke-dasharray', `0.1 ${circumference / dots - 0.1}`);
<svg version="1.1" width="300" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50 50" xml:space="preserve">
    <style type="text/css">
        .st0{fill:#000;}
        .st1{font-family:'ArboriaBook';}
        .st2{font-size:12px;}
        circle {
          stroke: black;
          stroke-width: 2;
          stroke-linecap: round;
          fill: none;
        }
        text {
          text-anchor: middle;
        }
    </style>
    <circle cx="25" cy="25" r="20"></circle>
    <text id="current_time" class="st0 st1 st2" x="25" y="25" dy="0.25em">09:54</text>
</svg>

Related