d3 通过弧线制作动画路径

我开始使用 d3。还有一个问题,如何沿着填充路径正确设置三角形动画?我为仪表图创建了一个基础并对其进行了动画处理。


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%;

}

问题是,如何将三角形链接到动画弧的边缘,如图所示?

我知道我应该使用

tween('path'....)


红糖糍粑
浏览 193回答 0
0回答

慕无忌1623718

我会使用 SVG transform:rotate,因为它允许您指定相对于应该旋转的内容,并且因为您可以链接转换。在本例中,我将角度变换到圆弧的中心,然后将其旋转到正确的方向,然后将其向上移动到比外半径稍多一点,以便它顺利地沿着线移动。它不是像素完美的,我认为这是因为三角形不是整数像素宽。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>
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript