简体   繁体   English

d3 按弧动画路径

[英]d3 animate path by arc

I started to work with d3.我开始使用 d3。 And have a question, how can I animate properly triangle along the filling path?有一个问题,我怎样才能沿着填充路径正确地设置三角形的动画? I created a base for the gauge chart and animated it.我为仪表图创建了一个基础并对其进行了动画处理。

 var chart = d3.select("#speedometer"); const arc = d3 .arc() .outerRadius(120) .innerRadius(90) .startAngle(-Math.PI / 2); chart .append("path") .datum({ endAngle: Math.PI / 2 }) .attr("transform", "translate(160, 180)") .attr("class", "background") .style("fill", "#495270") .attr("d", arc); const triangle = chart .append('g') .attr('transform', 'translate(30, 180) rotate(90)') .style('width', '100%') .append("path").attr("d", "M3.937,0,7.873,14H0Z"); const newAngle = (70 / 100) * Math.PI - Math.PI / 2; const foreground = chart .append("path") .datum({ endAngle: -Math.PI / 2 }) .style("fill", "rgb(50, 188, 228)") .attr("transform", "translate(160, 180)") .attr("d", arc); foreground .transition() .duration(3000) .attrTween("d", function (d) { const interpolate = d3.interpolate(d.endAngle, newAngle); return function (t) { d.endAngle = interpolate(t); return arc(d); }; }); triangle .transition() .duration(3000) function pathTween(path) { const length = path.node().getTotalLength(); // Get the length of the path const r = d3.interpolate(0, length); // Set up interpolation from 0 to the path length return function (t) { const point = path.node().getPointAtLength(r(t)); // Get the next point along the path d3 .select(this) // Select the circle .attr("transform", `translate(${point.x}, ${point.y})`); }; }
 .main-wrapper{ max-width: 80%; margin: 20px auto; } .element{ display: flex; flex-flow: column nowrap; margin-bottom: 20px; border: 1px solid rgba(0,0,0,.4); padding: 20px; border-radius: 6px; } .title{ margin-bottom: 4px; font-weight: 500; } .description{ margin-bottom: 10px; color: rgba(0,0,0,.4); } #speedometer { width: 300px; height: 300px; } canvas{ width: 100%; height: 100%; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script> <div class="main-wrapper"> <section class="ui-section"> <div class="element"> <div class="title"> Speedometr </div> <div class="content"> <svg id="speedometer" viewbox="0 0 300 300"></svg> </div> </div> </section> </div>

The question is, how can I link the triangle to the edge of the animating arc like in the picture?问题是,如何将三角形链接到图片中的动画弧的边缘?

I know I should use我知道我应该使用

tween('path'....)

but not sure但不确定

在此处输入图片说明

I'd use SVG transform: rotate , because it allows you to specify relative to what you should rotate, and because you can chain transformations.我会使用 SVG transform: rotate ,因为它允许您指定相对于您应该旋转的内容,并且因为您可以链接转换。 In this case, I transform the angle to the centre of the arc, then rotate it into the right direction, and then move it up a little bit more than the outer radius so it follows the line smoothly.在这种情况下,我将角度转换为圆弧的中心,然后将其旋转到正确的方向,然后将其向上移动到比外半径大一点的位置,以便平滑地沿着线移动。

It's not pixel perfect, which I think is because the triangle is not a whole number of pixels wide.它不是像素完美的,我认为这是因为三角形不是整数像素宽。

 var chart = d3.select("#speedometer"); const arc = d3 .arc() .outerRadius(120) .innerRadius(90) .startAngle(-Math.PI / 2); chart .append("path") .datum({ endAngle: Math.PI / 2 }) .attr("transform", "translate(160, 180)") .attr("class", "background") .style("fill", "#495270") .attr("d", arc); const triangle = chart .append('g') .datum({ endAngle: -Math.PI / 2 }) .style('width', '100%') .append("path").attr("d", "M3.937,0,7.873,14H0Z"); const newAngle = (70 / 100) * Math.PI - Math.PI / 2; const foreground = chart .append("path") .datum({ endAngle: -Math.PI / 2 }) .style("fill", "rgb(50, 188, 228)") .attr("transform", "translate(160, 180)") .attr("d", arc); foreground .transition() .duration(3000) .attrTween("d", function (d) { const interpolate = d3.interpolate(d.endAngle, newAngle); return function (t) { d.endAngle = interpolate(t); return arc(d); }; }); triangle .transition() .duration(3000) .attrTween("transform", function (d) { const interpolate = d3.interpolate(d.endAngle, newAngle); return function (t) { const angleRadians = interpolate(t); const angleDegrees = 360 * angleRadians / (2 * Math.PI); return ` translate(158 176) rotate(${angleDegrees + 180} 3.5 7) translate(0 132) `; }; }); function pathTween(path) { const length = path.node().getTotalLength(); // Get the length of the path const r = d3.interpolate(0, length); // Set up interpolation from 0 to the path length return function (t) { const point = path.node().getPointAtLength(r(t)); // Get the next point along the path d3 .select(this) // Select the circle .attr("transform", `translate(${point.x}, ${point.y})`); }; }
 .main-wrapper{ max-width: 80%; margin: 20px auto; } .element{ display: flex; flex-flow: column nowrap; margin-bottom: 20px; border: 1px solid rgba(0,0,0,.4); padding: 20px; border-radius: 6px; } .title{ margin-bottom: 4px; font-weight: 500; } .description{ margin-bottom: 10px; color: rgba(0,0,0,.4); } #speedometer { width: 300px; height: 300px; } canvas{ width: 100%; height: 100%; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script> <div class="main-wrapper"> <section class="ui-section"> <div class="element"> <div class="title"> Speedometr </div> <div class="content"> <svg id="speedometer" viewbox="0 0 300 300"></svg> </div> </div> </section> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM