Skip to content
Advertisement

Control the order of visibility of the multiple paths of SVG element

i was searching a way to show an image in html with rounded dashed border like example below

enter image description here

such that number of dashes and their individual colors can be controlled, the similar example can be observed in WhatsApp application status tab where number of dashes changes according to the number of statuses uploaded by user.

Now to address the problem I applied following steps to produce the desired output obviously code is not written by me but I made changes

  1. Generate a Simple Pi chart in SVG using equal values for equal length
  2. Color individual slices according to needs
  3. Display image on top of SVG element actual output or almost near to output results produce

Now in following code I am facing a strange issue which I am not able resolve, the order of the dashed bars are not same e.g. as in the image above the purple color should comes first and then orange and then rest of the gray bars to the end of the circle, but actual output differs.

function pie(data){
  // set size of <svg> element
  $('#'+data.$id).attr("width", 2*data.radius);
  $('#'+data.$id).attr("height", 2*data.radius);
  // calculate sum of values
  var sum=0;
  var radius=data.radius;
  for(var e=0; e<data.segments.length; e++){
    sum+=data.segments[e].value;
  }
  // generate proportional pie for all segments
  var startAngle=0, endAngle=0;
  for(var i=0; i<data.segments.length; i++){
    var element=data.segments[i];
    var angle=element.value * 2 * Math.PI / sum;
    endAngle+=angle;
    var svgLine=makeSVG('line',{x1: radius, y1: radius, x2: (Math.cos(endAngle)*radius+radius), y2: (Math.sin(endAngle)*radius+radius), stroke: element.color});    
    $('#'+data.$id).append(svgLine);
    var pathStr=
        "M "+(radius)+","+(radius)+" "+
        "L "+(Math.cos(startAngle)*radius+radius)+","+
             (Math.sin(startAngle)*radius+radius)+" "+
        "A "+(radius)+","+(radius)+
             " 0 "+(angle<Math.PI?"0":"1")+" 1 "+
             (Math.cos(endAngle)*radius+radius)+","+
             (Math.sin(endAngle)*radius+radius)+" "+
        "Z";
    var svgPath=makeSVG('path',{"d": pathStr, "fill": element.color, stroke:"white", "stroke-width": "4" });
    $('#'+data.$id).append(svgPath);
    startAngle+=angle;
  }
};

function makeSVG(tag, attrs) {
  var el= document.createElementNS('http://www.w3.org/2000/svg', tag);
  for (var k in attrs)
    el.setAttribute(k, attrs[k]);
  return el;
} //SVG Maker

var example={ //set parameters for pie chart
  $id: "pie1", //set id of <svg> containning pie
  radius: 56, //set radius of pie
  segments: [
    {value: 1, color: "#7E57F9"},
    {value: 1, color: "#7E57F9"},
    {value: 1, color: "#7E57F9"},
    {value: 1, color: "#7E57F9"},
    {value: 1, color: "#F9A657"},
    {value: 1, color: "#D3D3D3"},
    {value: 1, color: "#D3D3D3"}
  ]
  };
  pie(example);
svg {
  margin-top: -10px;
  margin-left: -10px;
}

img {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  position: absolute;
  top: 4px;
  left: 4px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg id="pie1"></svg>
<img src="https://5.imimg.com/data5/SELLER/Default/2020/8/ND/OY/KF/111699996/country-hen-500x500.jpg" width="100">

Advertisement

Answer

Finally i found the solution from the @Michael’s comment, the order was right but the rendering start point was not from the top of the circle so initializing startAngle and endAngle to Math.PI * 1.5 solves the problem e.g. replacing the line

var startAngle=0, endAngle=0;

with

var startAngle=Math.PI * 1.5, endAngle=Math.PI * 1.5;
Advertisement