javascript - 使用 SVG 和 Vue 重新创建动态圆环图

标签 javascript vue.js svg donut-chart

我需要一个带有 SVG 和 Vue 的动态圆环图。

它必须与此页面上的 SVG 完全相同:

https://www.chipotle.co.uk/nutrition-calculator (要查看动态图表,首先您必须选择一道菜,然后单击一些成分)

也许这是一个糟糕的方向,但这是我能够找到并修改任务的

( https://codepen.io/fifuruho/pen/zYOBWLx )

All code in codeopen.io

我真的很不擅长复杂的 svg。

我需要您可以提供的任何解决方案或提示。
(但在代码示例中更好)

最佳答案

我会以不同的方式做到这一点。我会使用路径而不是使用笔画。我会让路径相互接触,接下来我会应用相同的路径 (stroke:#000;stroke-width:3;fill:#ffffff) 作为掩码。您可以更改不同间隙的笔划宽度。

这将是由此产生的 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>


至于产生这个的 Javascript,我使用的是普通的 javascript。我希望你能把它翻译成 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>

关于javascript - 使用 SVG 和 Vue 重新创建动态圆环图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57541393/

相关文章:

SVGPath LinkedList 上的 java.lang.NullPointerException

javascript - raphael svg 路径的一部分卡在原地

javascript - 无法使用 js/jquery 获取多个元素上的 Codemirror textarea 值

javascript - 在自动建议中使用上下键向上/向下切换

javascript - 使用 vue.js 绑定(bind)动态表单值

javascript - 无法从父级访问嵌套元素

html - 使用外部 CSS 样式表设置 SVG 行的样式

javascript - 如何将 UUID 从 Drupal 用户数据库导出到单个页面上的 javascript 中?

javascript - 如何以 reCAPTCHA 形式重写链接文本? (本地化问题)

javascript - Vue.js如何在更新前显示图像预览