d3弧形动画路径 [英] d3 animate path by arc

查看:65
本文介绍了d3弧形动画路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I started to work with 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?

我知道我应该使用

tween('path'....)

但不确定

推荐答案

我将使用SVG

I'd use SVG transform: rotate, because it allows you to specify relative to what you should rotate, and because you can chain transformations. 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>

这篇关于d3弧形动画路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆