animation - 使用 D3.js 沿连续路径进行插值

标签 animation d3.js

我正在改编 Mike Bostock 的 point along path interpolation模型接受n条单独路径的数组并沿每个连续进行插值。对于 D3 来说,下面的代码相对较新,据我所知,它是同时运行两条路径的点插值。现在,我对如何重组这一过程以使该过程连续(只有一个移动对象)感到有点困惑。实际上,我需要能够在路径之间停下来监听鼠标点击,但是一旦结构存在,我就可以找出该代码。非常感谢您的帮助。

这是jsfiddle .

后代代码:

  <!DOCTYPE html>
  <meta charset="utf-8">
  <body>
  <style>

  path {
    fill: none;
    stroke: #000;
    stroke-width: 3px;
  }

  circle {
    stroke: #fff;
    stroke-width: 3px;
  }

  </style>
  <script type="text/javascript" src="http://d3js.org/d3.v3.js"></script><script>

var pathdata = [
   [[240, 100],
    [290, 200],
    [340, 50]],
   [[340, 50],
    [90, 150],
    [140, 50],
    [190, 200]]
];

  var svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 500);

  var paths = svg.selectAll("path")
      .data(pathdata)
      .enter()
      .append("path")
      .attr("d", d3.svg.line())
      .attr("id",function(d, i) { return "path" + i });

  // plot path vertices
  svg.selectAll(".point")
      .data([].concat.apply([], pathdata))
      .enter().append("circle")
      .attr("r", 5)
      .attr("fill", "red")
      .attr("transform", function(d) { return "translate(" + d + ")"; });

  // interpolate along path0
  var circle = svg.append("circle")
      .attr("r", 10)
      .attr("fill", "steelblue")
      .attr("transform", "translate(" + pathdata[0][1] + ")")
      .transition()
      .duration(4000)
      .attrTween("transform", translateAlong(d3.select("#path0")[0][0]));

  // interpolate along path1
  var circle = svg.append("circle")
      .attr("r", 10)
      .attr("fill", "steelblue")
      .attr("transform", "translate(" + pathdata[1][1] + ")")
      .transition()
      .duration(4000)
      .attrTween("transform", translateAlong(d3.select("#path1")[0][0]));

  function translateAlong(path) {
    console.log(path);
    var l = path.getTotalLength();
    return function(d, i, a) {
      return function(t) {
        var p = path.getPointAtLength(t * l);
        return "translate(" + p.x + "," + p.y + ")";
      };
    };
  }

  </script>

  </body>
  </html>

我还想知道按照以下行之一格式化输入数据是否会更好?

// 3rd field for path id
var points_alt1 = [
  [240, 100, 0],
  [290, 200, 0],
  [340, 50,  0],
  [340, 50,  1],
  [90, 150,  1],
  [140, 50,  1],
  [190, 200, 1]
]    

或者..

// 3rd field for interpolation end-points
var points_alt2 = [
  [240, 100, 0],
  [290, 200, 0],
  [340, 50,  1],
  [340, 50,  0],
  [90, 150,  0],
  [140, 50,  0],
  [190, 200, 1]
]

最佳答案

创建一个函数,将 d3 个路径选择和要设置动画的路径(在选择内)的整数索引作为参数。此函数在该选择中找到适当的路径,沿着它启动圆的过渡,并订阅 'end'转换事件,此时它会触发下一个动画。

Here's the working fiddle

function animateSinglePath(selection, indexOfAnimated) {
    indexOfAnimated = indexOfAnimated || 0;

    // Create circle if doesn't already exist
    // (achived by binding to single element array)
    circle = svg.selectAll('.animated-circle').data([null])
    circle.enter()
        .append("circle")
        .attr("class", "animated-circle")
        .attr("r", 10)
        .attr("fill", "steelblue")    

    selection.each(function(d, i) {
        // find the path we want to animate
        if(i == indexOfAnimated) {
            // In this context, the "this" object is the DOM
            // element of the path whose index, i equals the
            // desired indexOfAnimated
            path = d3.select(this)
            // For style, make it dashed
            path.attr('stroke-dasharray', '5, 5')

            // Move circle to start pos and begin animation
            console.log('Start animation', i)
            circle
                .attr("transform", "translate(" + d[0] + ")")
                .transition()
                .duration(2000)
                .attrTween("transform", translateAlong(path.node()))
                .each('end', function() {
                    console.log('End animation', i);

                    // For style, revert stroke to non-dashed
                    path.attr('stroke-dasharray', '')

                    // trigger the next animation by calling this
                    // function again
                    animateSinglePath(selection, indexOfAnimated + 1);
                });
        }
    });
}

附注

我不会按照您的建议重组数据,因为您需要有不同的 SVG <path>元素 – 序列中的每个“章节”一个。为每个路径拥有一个不同的数组(就像您现在所做的那样),使您能够创建这些 <path>通过data()绑定(bind)。

根据您想要实现的目标,您甚至可能想要进一步嵌套每个路径数组,用对象 {} 包装它。 ,保存有关路径的元数据:

var pathData = [
  {
    name: "Crossing the Niemen",
    points: [ [240, 100], [290, 200], [340, 50] ]
  },
  {
    name: "March on Vilnius",
    points: [ [340, 50], [90, 150], [140, 50], [190, 200] ]
  },
  {
    name: "March on Moscow",
    points: [ [190, 200], [70, 180], [30, 30], [350, 160] ]
  }
];

关于animation - 使用 D3.js 沿连续路径进行插值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19849484/

相关文章:

javascript - 如何通过半径大小将节点定位在中心?

javascript - d3.js 液体填充计剪辑路径不工作

javascript - 从数据对象数组创建折线图

android - 如何在 Android Canvas 上为路径设置动画

ios - SwiftUI 动画不会在绑定(bind)更新时发生

ios - 可以在导航栏中从左向右移动uilabel吗?

jquery - 如何获取 jQuery 动画中的 X 和 Y 位置

c++ - 如何在 SFML 中为 Sprite 制作动画

javascript - 带有播放/暂停循环的 HTML 范围 slider

javascript - 在多行图表 d3js 中悬停时获取所有 y 值的更好方法