[Vuejs]-Recreating the dynamic donut chart with SVG and Vue

0👍

I would do this in a different way. Instead of using strokes I would use paths. I would make the paths touching one with another and next I would apply the same path (stroke:#000; stroke-width:3; fill: #ffffff) as a mask. You can change the stroke width for a different gap.

This would be the resulting svg:

svg{border:1px solid}

mask use{stroke:#000; stroke-width:3; fill: #ffffff}
<svg width="320" viewBox="-80 -80 160 160" class="donut-chart">
<defs id="theDefs">
<path d="M5.475206276408082,-34.56909192082982 L10.16824022761501,-64.19974213868396 A65,65 0 0 1 10.16824022761501,64.19974213868396 L5.475206276408082,34.56909192082982 A35,35 0 0 0 5.475206276408082,-34.56909192082982" id="elmt45" style="mask: url(#mask45)"></path>
<mask id="mask45">
<use xlink:href="#elmt45"></use>
</mask>
<path d="M18.75393782426488,-29.55147739257053 L34.828741673634774,-54.88131515763098 A65,65 0 0 1 34.828741673634774,54.88131515763098 L18.75393782426488,29.55147739257053 A35,35 0 0 0 18.75393782426488,-29.55147739257053" id="elmt32" style="mask: url(#mask32)"></path>
<mask id="mask32">
<use xlink:href="#elmt32"></use>
</mask>
<path d="M26.253887437066084,-23.145915286327813 L48.75721952597986,-42.98527124603737 A65,65 0 0 1 48.75721952597986,42.98527124603737 L26.253887437066084,23.145915286327813 A35,35 0 0 0 26.253887437066084,-23.145915286327813" id="elmt23" style="mask: url(#mask23)"></path>
<mask id="mask23">
<use xlink:href="#elmt23"></use>
</mask>
</defs>
<g id="theG">
<use xlink:href="#elmt45" fill="rgb(182, 130, 7)" transform="rotate(-9)"></use><use xlink:href="#elmt32" fill="rgb(120, 98, 89)" transform="rotate(129.6)"></use>
<use xlink:href="#elmt23" fill="rgb(195, 180, 166)" transform="rotate(228.6)"></use>
</g>
</svg>

As for the Javascript to produce this, I’m using plain javascript. I hope you’ll be able to translate it to Vue.

const SVG_NS = "http://www.w3.org/2000/svg";
const SVG_XLINK = "http://www.w3.org/1999/xlink";
let colors = ["rgb(182, 130, 7)", "rgb(120, 98, 89)", "rgb(195, 180, 166)"];

class Sector {
  constructor(color, prev, a) {
    this.color = color;
    this.R = 65; //external radius
    this.r = 35; //inner radius
    this.a = a * 360 / 100; //360degs = 100%
    this.A = this.a * Math.PI / 180; // angle in radians

    this.prev = prev;
    this.color = color;

    this.elmt = document.createElementNS(SVG_NS, "path");
    document.querySelector("#theDefs").appendChild(this.elmt);

    this.p1 = {};
    this.p2 = {};
    this.p3 = {};
    this.p4 = {};
    this.p1.x = this.r * Math.cos(-this.A / 2);
    this.p1.y = this.r * Math.sin(-this.A / 2);
    this.p2.x = this.R * Math.cos(-this.A / 2);
    this.p2.y = this.R * Math.sin(-this.A / 2);
    this.p3.x = this.R * Math.cos(this.A / 2);
    this.p3.y = this.R * Math.sin(this.A / 2);
    this.p4.x = this.r * Math.cos(this.A / 2);
    this.p4.y = this.r * Math.sin(this.A / 2);

    this.d = `M${this.p1.x},${this.p1.y} L${this.p2.x},${this.p2.y} A${
      this.R
    },${this.R} 0 0 1 ${this.p3.x},${this.p3.y} L${this.p4.x},${this.p4.y} A${
      this.r
    },${this.r} 0 0 0 ${this.p1.x},${this.p1.y}`;

    this.elmt.setAttributeNS(null, "d", this.d);

    this.elmt.setAttribute("id", `elmt${a}`);

    this.mask = document.createElementNS(SVG_NS, "mask");
    this.use = document.createElementNS(SVG_NS, "use");
    this.use.setAttributeNS(SVG_XLINK, "xlink:href", `#elmt${a}`);
    this.mask.appendChild(this.use);
    this.mask.setAttribute("id", `mask${a}`);
    document.querySelector("#theDefs").appendChild(this.mask);

    this.use1 = document.createElementNS(SVG_NS, "use");
    this.use1.setAttributeNS(SVG_XLINK, "xlink:href", `#elmt${a}`);
    this.use1.setAttributeNS(null, "fill", this.color);

    theG.appendChild(this.use1);

    this.elmt.setAttribute("style", `mask: url(#mask${a})`);
    this.use1.setAttributeNS(
      null,
      "transform",
      `rotate(${-90 + this.a / 2 + this.prev})`
    );
  }
}

let s1 = new Sector(colors[0], 0, 45);
let s2 = new Sector(colors[1], s1.a, 32);
let s3 = new Sector(colors[2], s1.a + s2.a, 23);
svg{border:1px solid}

mask use{stroke:#000; stroke-width:3; fill: #ffffff}
<svg height="250" width="320" viewBox="-80 -80 160 160" class="donut-chart">
  <defs id="theDefs"></defs>
  <g id="theG">

  </g>
</svg>

Leave a comment