raf18seb
raf18seb

Reputation: 2146

SVG: how to draw multiple semicircles (arcs) path

Using the answer from this thread I was able to draw a semicircle (arc):

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
  var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;

  return {
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  };
}

function describeArc(x, y, radius, startAngle, endAngle) {

  var start = polarToCartesian(x, y, radius, endAngle);
  var end = polarToCartesian(x, y, radius, startAngle);

  var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

  var d = [
    "M", start.x, start.y,
    "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
  ].join(" ");
  console.log(d)
  return d;
}

window.onload = function() {
  document.getElementById("arc1").setAttribute("d", describeArc(100, 100, 50, -90, 90));
};
<svg width="1000" height="1000">
  <path id="arc1" fill="red" stroke="#446688" stroke-width="2" />
</svg>

What I'm trying to achieve is to be able to draw an SVG as a path consistent with many arcs (semicircles) and be able to set fill on them.

Something like this: enter image description here

<svg xmlns="http://www.w3.org/2000/svg">
  <path d="M 50 100 A 10 10 0 0 1 100 100 M 100 100 A 10 10 0 0 1 150 100 M 150 100 A 10 10 0 0 1 200 100 M 200 100 A 10 10 0 0 1 250 100" fill="red" stroke="blue" stroke-width="3" />
</svg>

Is there a better way to achieve a simpler path? For now, it looks like this:

<svg xmlns="http://www.w3.org/2000/svg">
  <path d="M 50 100 A 10 10 0 0 1 100 100 M 100 100 A 10 10 0 0 1 150 100 M 150 100 A 10 10 0 0 1 200 100 M 200 100 A 10 10 0 0 1 250 100" fill="red" stroke="blue" stroke-width="3" />
</svg>

Or do I have to generate a longer and longer path when there are, let's say, 30 semicircles?

Edit: the IE9+ support is required. Also, those elements will be clickable, draggable and controllable. By controllable I mean that their number and size will change when mouse clicking/moving.

I choose my first approach with a dynamic very long path.

Thanks!

Upvotes: 1

Views: 2071

Answers (3)

enxaneta
enxaneta

Reputation: 33072

For this I would use lower case commands. For example this is drawing the arc you need: an arc with a radius of 25 and an ending point 50 units ( 2 * 25 ) away from the starting point of the arc.

<svg xmlns="http://www.w3.org/2000/svg">
  <path d="M 50 100 a 25 25 0 0 1 50 0" fill="red" stroke="blue" stroke-width="3" />
</svg>

In order to get a path of 4 arcs you need to repeat the arc (a 25 25 0 0 1 50 0) 4 times something like this:

<svg xmlns="http://www.w3.org/2000/svg">
  <path d="M 50 100 a 25 25 0 0 1 50 0 
                    a 25 25 0 0 1 50 0 
                    a 25 25 0 0 1 50 0 
                    a 25 25 0 0 1 50 0 " fill="red" stroke="blue" stroke-width="3" />
</svg>

It's easy to see how you can use javascript to generate the d attribute you need:

let d ="M 50 100";

for(let i=0; i<4;i++){d +="a 25 25 0 0 1 50 0 "}

document.querySelector("path").setAttribute("d",d);
<svg xmlns="http://www.w3.org/2000/svg">
  <path d="M 50 100" fill="red" stroke="blue" stroke-width="3" />
</svg>

Upvotes: 2

Michael Mullany
Michael Mullany

Reputation: 31805

You could use a pattern and size your patterned object appropriately. Here is one that accomodates 4 iterations.

Edit & Update: If you want those arcs to be independently clickable/draggable, then they need to be separately addressable in the DOM. The "use" element might be what you're looking for.

    svg {
    background: grey;
    }
    <svg width="800px" height="600px">
      <defs>
       <path id="arc-template" d="M1.5 50 a 10 10 0 0 1 97 0" fill="red" stroke="blue" stroke-width="3" />
      </defs>
      
     <use id="arc1" href="#arc-template" x="50" y="100"/>
     <use id="arc2" href="#arc-template" x="150" y="100"/>
     <use id="arc3" href="#arc-template" x="250" y="100"/>
     <use id="arc4" href="#arc-template" x="350" y="100"/>
         
    </svg>

Upvotes: 1

You can use a vanilla JavaScript Web Component (supported in all modern Browsers) to create the SVG

Your Custom Element <svg-arcs repeat="7"></svg-arcs> then creates:

<style>
  svg { background: pink }
  svg path { stroke-width: 3 }
</style>

<svg-arcs repeat="30"></svg-arcs>

<script>
  customElements.define("svg-arcs", class extends HTMLElement {
    connectedCallback() {
      let repeat = this.getAttribute("repeat") || 5;
      let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      for (let x = 0; x < repeat; x++) {
        let path = document.createElementNS("http://www.w3.org/2000/svg", "path");
        path.setAttribute("d", `M${3 + 50*x} 100 A 10 10 0 0 1 ${50+50*x} 100`);
        path.setAttribute("fill", "red");
        path.setAttribute("stroke", "blue");
        svg.append(path);
      }
      svg.setAttribute("viewBox", `0 0 ${50*repeat + 3} 150`);
      this.append(svg);
    }
  })
</script>

For more dynamic control over individual arcs see the Web Component in SO post: Firefox: shadow-DOM compatibility

Upvotes: 1

Related Questions