【问题标题】:d3js - Transition between 2 pathsd3js - 2 条路径之间的转换
【发布时间】:2014-08-27 23:39:46
【问题描述】:

我正在尝试对具有相同段数的 2 条路径进行补间。我在这里使用 Mike Bostock 描述的方法:https://gist.github.com/mbostock/3916621

svg.append("path")
    .attr("transform", "translate(180,150)scale(2,2)")
    .attr("d", d0)
    .call(transition, d0, d1);

function transition(path, d0, d1) {
  path.transition()
      .duration(2000)
      .attrTween("d", pathTween(d1, 4))
      .each("end", function() { d3.select(this).call(transition, d1, d0); });
}

function pathTween(d1, precision) {
  return function() {
    var path0 = this,
        path1 = path0.cloneNode(),
        n0 = path0.getTotalLength(),
        n1 = (path1.setAttribute("d", d1), path1).getTotalLength();

    // Uniform sampling of distance based on specified precision.
    var distances = [0], i = 0, dt = precision / Math.max(n0, n1);
    while ((i += dt) < 1) distances.push(i);
    distances.push(1);

    // Compute point-interpolators at each distance.
    var points = distances.map(function(t) {
      var p0 = path0.getPointAtLength(t * n0),
          p1 = path1.getPointAtLength(t * n1);
      return d3.interpolate([p0.x, p0.y], [p1.x, p1.y]);
    });

    return function(t) {
      return t < 1 ? "M" + points.map(function(p) { return p(t); }).join("L") : d1;
    };
  };
}

它给出了非常好的结果,但是我面临一个愚蠢的问题。 我想找到一种方法将我的第一个路径中的一个片段关联到第二个路径中的另一个片段以获得更好的补间。

例如,这里:http://jsfiddle.net/2brqoo5p/1/ 2 路径具有相似的形状,但补间比它可能的复杂得多。有没有办法解决这个问题?

非常感谢

【问题讨论】:

  • 也许你可以弄清楚如何用与d1相同的术语绘制第一条路径d0。 IE。指定d0 使用一系列曲线和直线,其顺序与它们在d1 中出现的顺序完全相同,但点的数值不同。因为d0 是一个圆,所以每条线都将在它之前的曲线结束的同一点结束(即,线的长度为 0)。这样 d3 可能“知道”如何正确插入它。

标签: svg d3.js tween


【解决方案1】:

恕我直言...

您可能找不到任何可以为您执行此操作的实用程序/库/等。你会 必须自己写。或者等别人帮你做。或者付钱给别人。

对于这个问题,我能想象的唯一解决方案相当乏味。如果我 找时间,我可能会写一个演示并更新这个答案。没有保证, 尽管。事实上,这段代码似乎只对演示中的闭环有用 你链接了。

这是伪代码中的想法。不过,这是相当蛮力的。

# convert both SVG path `d` attributes from strings to arrays of points
list_1  = convert('#path1')
list_2  = convert('#path2')

min_dist   = 9999
min_pt_set = {}

for each point in list_1 -> (p1)
    for each point in list_2 -> (p2)
        # find the pair of points with the least distance between them
        if (min_dist > dist(p1, p2))
            min_dist = dist(p1, p2)
            min_pt_set = {p1, p2}

# reorder list_1 so that p1 is the first element.
# reorder list_2 so that p2 is the first element.

# convert both lists back into svg path strings

# write the path strings back to the svg `d` attributes.

重新排序后,您可能需要对方向进行某种检查。如果路径 被定义在相反的方向,您可能需要反转操作 一条路。

我不知道任何适用于所有情况的算法。你选择了什么 可能取决于您正在编码的情况。你可以试试“最少 平方和,或者只是检查与 p1 和 p2 相邻的点并求解 最短距离。

我希望有人有比我更好的解决方案。这很有趣 问题。

另请参阅:

  1. http://www.w3.org/TR/SVG/paths.html
  2. Scripting <path> data in SVG (reading and modifying) -- 提到解析 svg 路径的方法。

【讨论】:

  • 此解决方案假定一个点数组与线链接(使用路径 l 指令),而链接示例还包含曲线(c 指令)。考虑到这一点会使解决方案更加复杂。
  • 我在回答中考虑了曲线。根据 SVG 规范,曲线指定端点。该解决方案既不插入直线也不插入曲线;它只检查端点。如果需要更准确的东西,那么自适应采样可能是要走的路。
猜你喜欢
  • 1970-01-01
  • 2018-02-11
  • 2014-12-23
  • 1970-01-01
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多