繁体   English   中英

d3 按路径设置动画组

[英]d3 animate group by path

这是我的下一个问题,以增强原始问题

所以我想要的是沿着填充路径动画三角形标记和文本工具提示。

 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 mainGroup = chart.append('g') .datum({ endAngle: -Math.PI / 2 }); const triangle = mainGroup .append('path') .attr("d", "M3.937,0,7.873,14H0Z") .datum({ endAngle: -Math.PI / 2 }) const text = mainGroup.append('text') .text('hello there') .attr('transform', 'rotate(180)') .datum({ endAngle: -Math.PI / 2 }) .transition() .duration(3000) .attrTween("transform", function(d) { const topVal = (300 / 2 - 16); const interpolate = d3.interpolate(d.endAngle, newAngle); return function(t) { const angleRadians = interpolate(t); const angleDegrees = 360 * angleRadians / (2 * Math.PI); return ` rotate(${angleDegrees}) `; }; }); 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); }; }); mainGroup .transition() .duration(3000) .attrTween("transform", function(d) { const topVal = (300 / 2 - 16); 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 ${topVal}) `; }; }); 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, 0.4); padding: 20px; border-radius: 6px; } .element .title { margin-bottom: 4px; font-weight: 500; } .element .description { margin-bottom: 10px; color: rgba(0, 0, 0, 0.4); } #speedometer { width: 300px; height: 300px; overflow: visible !important; } 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>

所以这里的主要问题是旋转文本。 它应该处于正常位置。 在这种情况下动画应该如何? 我如何为整个组设置动画并控制每个节点?

首先,可以抵消通过转动180 - angleDegrees而不是angleDegrees的文本。

其次,您可能希望文本始终与圆弧保持大致相同的距离,不要太近以至于重叠,也不要太远因为看起来很奇怪。 为此,一种解决方案是使节点text-anchor: middle ,然后在过渡期间将其定位。

 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 mainGroup = chart.append('g') .datum({ endAngle: -Math.PI / 2 }); const triangle = mainGroup .append('path') .attr("d", "M3.937,0,7.873,14H0Z") .datum({ endAngle: -Math.PI / 2 }) const text = mainGroup.append('text') .text('hello there') .datum({ endAngle: -Math.PI / 2 }) .attr("text-anchor", "middle") // to more easily position the text .transition() .duration(3000) .attrTween("transform", function(d) { const topVal = (300 / 2 - 16); const interpolateAngle = d3.interpolate(d.endAngle, newAngle); // We want to add some offset so the text is always easily visible // Think about what happens when the following functions are called with // angles -90, -45, 0, 45, 90 const textWidth = this.getBBox().width; const offsetX = function(angle) { return (angle / 90) * textWidth / 2; }; const offsetY = function(angle) { if (angle < 0) { return offsetY(-angle); } // The -4 and -3 are a little bit trial and error, and can be // tweaked further to return -4 + (1 - angle / 90) * -3; }; return function(t) { const angleRadians = interpolateAngle(t); const angleDegrees = 360 * angleRadians / (2 * Math.PI); return ` translate(0 15) rotate(${180 - angleDegrees}) translate(${offsetX(angleDegrees)} ${offsetY(angleDegrees)}) `; }; }); 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); }; }); mainGroup .transition() .duration(3000) .attrTween("transform", function(d) { const topVal = (300 / 2 - 16); 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 ${topVal}) `; }; }); 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, 0.4); padding: 20px; border-radius: 6px; } .element .title { margin-bottom: 4px; font-weight: 500; } .element .description { margin-bottom: 10px; color: rgba(0, 0, 0, 0.4); } #speedometer { width: 300px; height: 300px; overflow: visible !important; } 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