如何制作动画的SVG饼图

时间:2019-07-12 14:57:07

标签: javascript html css svg charts

我需要制作一个带有三个值的动画的svg饼图,并且找不到代码中的错误。当我删除setTimeout(function(){   circle.setAttribute(“ stroke-dasharray”,p +“ 100”);   },10);从JavaScript来看,饼形图看起来不错,但没有动画效果。当我添加那段代码时,它是有动画效果的,但是不会加载所有值,而是逆时针而非顺时针加载。我不知道任何JavaScript,但需要向现有的饼形图中添加两个额外的值,并使用给定的javascript创建了两个额外的圆。在只有一个圆圈的情况下,动画效果很好。我注意到最终结果(动画结束后仍留有粉红色的饼图)来自.pie div 35中的值,但如果我将div留为空白,整个饼图就会消失。

HTML
 <div class="widgets">
  <div class="left box stats">
  <div class="content">
  <div class="widget-row">
     <div class="stat stat--pie stat--productivity">
       <div class="pie">35</div>
                              </div>
                            </div>
                        </div>
                    </div>
                </div>

CSS
.box.stats .stat.stat--pie {
  width: 170px;
  display: -webkit-box;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
  -webkit-box-align: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
  align-items: center;
}


.box.stats  .stat.stat--pie .pie {
  position: relative;
  height: 170px;
  width: 170px;
}

.box.stats  .stat.stat--pie .pie > svg {
  -webkit-transform: rotate(-90deg);
  -ms-transform: rotate(-90deg);
  transform: rotate(-90deg);
  width: 170px;
  height: 170px;
}

.box.stats  .stat.stat--pie .pie > svg circle {
  -webkit-transition: all 1.2s ease-out;
  -o-transition: all 1.2s ease-out;
  transition: all 1.2s ease-out;
}

.box.stats .content .stat.stat--productivity .pie svg  {
  border-radius: 50%;
}

.box.stats .content .stat.stat--productivity .pie svg circle {
  fill: none;
  stroke: #283250;
  stroke-width: 32;
}

.box.stats .content .stat.stat--productivity .pie svg .circle2 {
  fill: none;
  stroke: #E8E05A;
  stroke-width: 32;
}

.box.stats .content .stat.stat--productivity .pie svg .circle3 {
  fill: none;
  stroke: #E24264;
  stroke-width: 32;
}

JavaScript 
function $$(selector, context) {
context = context || document;
var elements = context.querySelectorAll(selector);
return Array.prototype.slice.call(elements);
}

$$('.stat--productivity .pie').forEach(function(pie) {
  var p = parseFloat(pie.textContent);
  var NS = "http://www.w3.org/2000/svg";
  var svg = document.createElementNS(NS, "svg");
  var circle = document.createElementNS(NS, "circle");
  var circle2 = document.createElementNS(NS, "circle");
  var circle3 = document.createElementNS(NS, "circle");
  var digit = document.createElement("H1");
  var percent = document.createElement("span");


  circle.setAttribute("r", 16);
  circle.setAttribute("cx", 16);
  circle.setAttribute("cy", 16);
  circle.setAttribute("stroke-dasharray", "100 100");
  setTimeout(function(){
  circle.setAttribute("stroke-dasharray", p + " 100");
  }, 10);


  circle2.classList.add('circle2');
  circle2.setAttribute("r", 16);
  circle2.setAttribute("cx", 16);
  circle2.setAttribute("cy", 16);
  circle2.setAttribute("stroke-dasharray", "90 100");
  setTimeout(function(){
    circle2.setAttribute("stroke-dasharray", p + " 100");
  }, 10);

  circle3.classList.add('circle3');
  circle3.setAttribute("r", 16);
  circle3.setAttribute("cx", 16);
  circle3.setAttribute("cy", 16);
  circle3.setAttribute("stroke-dasharray", "50 100");
  setTimeout(function(){
    circle3.setAttribute("stroke-dasharray", p + " 100");
  }, 10);


  svg.setAttribute("viewBox", "0 0 32 32");
  digit.textContent = pie.textContent;
  percent.textContent = '%';
  pie.textContent = '';

  pie.appendChild(svg);
  svg.appendChild(circle);
  svg.appendChild(circle2);
  svg.appendChild(circle3);
  pie.appendChild(digit);
  pie.appendChild(percent);

});

Link to codepen: https://codepen.io/anon/pen/jjRYwR

2 个答案:

答案 0 :(得分:0)

以下是顺时针展开的多值图表的工作示例:https://jsfiddle.net/bowkugsq/

原始代码有多个更改,但是我尝试保留尽可能多的内容,以使OP理解更改并将其应用于自己的解决方案。

CSS已使用索引后缀为每个circle枚举类。还为label(传说)提供了一组类,以反映饼图的颜色并进行进一步的自定义。如果要添加下一个图表,则需要再添加一个circlelabel类。

大多数复杂的重构都是针对饼图生成的(如下所述):

$$('.stat--productivity .pie').forEach(function(pie) {
  var percents = pie.textContent.split(",");
  percents = percents.map(function(pct, idx) {
    return {
      value: parseFloat(pct),
      sum: 0,
      idx: idx + 1
    }
  });
  for (var i = 0; i < percents.length; i++) {
    var prevSum = (i > 0) ? percents[i - 1].sum : 1;
    percents[i].sum = prevSum + percents[i].value;
  };
  percents.reverse();
  var NS = "http://www.w3.org/2000/svg";
  var svg = document.createElementNS(NS, "svg");
  pie.textContent = ''; //clear div
  svg.setAttribute("viewBox", "0 0 32 32");
  pie.appendChild(svg);
  percents.forEach(function(pct, idx) {
    var circle = document.createElementNS(NS, "circle");
    circle.classList.add("circle" + pct.idx);
    circle.setAttribute("r", 16);
    circle.setAttribute("cx", 16);
    circle.setAttribute("cy", 16);
    circle.setAttribute("stroke-dasharray", "0 100");
    setTimeout(function() {
      circle.setAttribute("stroke-dasharray", pct.sum + " 100");
    });
    svg.appendChild(circle);
  });
  percents.forEach(function(pct, idx) {
    var digit = document.createElement("span");
    digit.textContent = pct.value + " %";
    digit.classList.add("label" + (idx + 1));
    pie.appendChild(digit);
  });
});

首先,主Pie div现在包含逗号分隔的百分比列表,如下所示:<div class="pie">25,15,60</div>。它们的总和必须为100%,否则圆圈将无法关闭。最初,文本内容通过逗号分隔为percents数组,随后转换为具有额外索引和部分和的对象数组;对于给定的样本,它将产生[{value:25,sum:25,idx:1}, {value:15,sum:40,idx:2}, {value:60,sum:100,idx:3}]。实际上,sum上调了1%,因为“笔划数组”的范围“ 100 100”导致微小的插槽未闭合整个圆。反转这样的对象阵列以使动画片段彼此不重叠。接下来的circle元素将按照原始OP代码中的每个百分比创建。最后,处理percent数组以添加带有原始值标签的span

免责声明:代码的结构可以更好,但是与原始方法的相似之处是主要驱动力。

答案 1 :(得分:-1)

如果您想学习新知识并提高编码技能,可以自己尝试编码,但是如果出于任何其他原因需要此编码,我建议您不要尝试重新设计Weeel,而是使用“准备就绪”的方法。 -使用'

看看这个:PieGraph