【问题标题】:How to transition along a path partially or by percentage only如何沿路径部分过渡或仅按百分比过渡
【发布时间】:2017-09-26 09:11:07
【问题描述】:

我是 d3 的初学者,目前无法使用最新版本,但我使用的是 3.x 版本。

我想要实现的应该很简单,但遗憾的是我没有找到有关如何做到这一点的资源:

目标是在我的 svg 中显示路径。然后我想显示例如一个圆圈并沿着路径过渡/移动/跟踪圆圈。如果我想遵循完整的路径,这很好用。

但我们的目标只是部分地走这条路。

如果我希望圆圈从路径的位置 0 开始并跟随它直到例如路径的 25%?

再一次,如果圆圈在 25%,我怎样才能从那里跟随路径的 50% 而不从路径的位置 0 开始?

我将非常感谢您在此处提供的任何意见。非常感谢。

【问题讨论】:

    标签: javascript d3.js svg transition


    【解决方案1】:

    我使用 Mike Bostock 的这段代码(根据需要使用 D3 v3.x)构建了我的答案:https://bl.ocks.org/mbostock/1705868

    首先,我创建了一个数据数组,指定每个圆圈应沿路径行进多少

    var data = [0.9, 1, 0.8, 0.75, 1.2];
    

    这里的值是百分比。所以,我们有 5 个圆圈:第一个(下面演示中的蓝色)将在路径的 90% 处停止,第二个(橙色)在 100% 处,第三个(绿色)在 80% 处,第四个(红色)在 75% 处,第五个(演示中的紫色)将行进 120% 的路径,也就是说,它将行进路径的所有长度,多行 20%。

    然后,我将 Bostock 的函数translateAlong 改为获取每个圈子的datum

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

    这里的重要部分是:

    var l = path.getTotalLength() * d;
    

    这将决定每个圆圈的最终位置。三元运算符很重要,因为我们的最后一个圆圈会超过路径的 100%。

    最后,我们必须调用转换,传递数据和路径本身:

    circle.transition()
        .duration(10000)
        .attrTween("transform", function(d) {
            return translateAlong(d, path.node())()
        });
    

    这里是演示:

    var points = [
         [240, 100],
         [290, 200],
         [340, 50],
         [390, 150],
         [90, 150],
         [140, 50],
         [190, 200]
     ];
    
     var svg = d3.select("body").append("svg")
         .attr("width", 500)
         .attr("height", 300);
    
     var path = svg.append("path")
         .data([points])
         .attr("d", d3.svg.line()
             .tension(0) // Catmull–Rom
             .interpolate("cardinal-closed"));
    
     var color = d3.scale.category10();
    
     var data = [0.9, 1, 0.8, 0.75, 1.2];
    
     svg.selectAll(".point")
         .data(points)
         .enter().append("circle")
         .attr("r", 4)
         .attr("transform", function(d) {
             return "translate(" + d + ")";
         });
    
     var circle = svg.selectAll("foo")
         .data(data)
         .enter()
         .append("circle")
         .attr("r", 13)
         .attr("fill", function(d, i) {
             return color(i)
         })
         .attr("transform", "translate(" + points[0] + ")");
    
    
     circle.transition()
         .duration(10000)
         .attrTween("transform", function(d) {
             return translateAlong(d, path.node())()
         });
    
     // Returns an attrTween for translating along the specified path element.
     function translateAlong(d, path) {
         var l = path.getTotalLength() * d;
         return function(d, i, a) {
             return function(t) {
                 var p = (t * l) < path.getTotalLength() ?
                     path.getPointAtLength(t * l) : path.getPointAtLength(t * l - path.getTotalLength());
                 return "translate(" + p.x + "," + p.y + ")";
             };
         };
     }
    path {
      fill: none;
      stroke: #000;
      stroke-width: 3px;
    }
        
    circle {
      stroke: #fff;
      stroke-width: 3px;
    }
    &lt;script src="//d3js.org/d3.v3.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 巧合的是,我刚刚做了一个带有这种过渡的数据可视化:gf.neocities.org/hmm/hmm.html 如果 SO 的某个人也是 F1 粉丝(不太可能!),他/她可能会觉得这很有趣。跨度>
    • 非常感谢您的详细解答。这很棒,让我能够满足我的需求。尽管如此,我仍然不确定,我现在如何能够以某个百分比值“继续”从它们的停止位置移动圆圈,而不是每次从位置 0 重新开始它们的路径移动。
    • 对于那个新问题,我相信你应该发布一个new问题。由于这个问题很老,发布一个新问题(准确指定新问题并链接此问题以进行澄清)将吸引更多关注!
    • 感谢您的评论。这个问题实际上是在我原来的问题中提到的,但我认为它可能会丢失,因为它不是粗体。那么我将提出一个新问题。顺便说一句,只需浏览您的 d3 页面,它看起来就很棒。
    • 谢谢。是的,我看到了提及,从 “然后再次...”.. 开始。问题是,每个问题保留 一个 问题总是一个好主意。这很容易回答,毕竟发布问题是免费的!
    猜你喜欢
    • 2017-12-27
    • 2021-06-13
    • 2012-02-15
    • 1970-01-01
    • 2012-11-04
    • 1970-01-01
    相关资源
    最近更新 更多