【问题标题】:D3 transition along segments of path and pause at coordinate valuesD3 沿路径段过渡并在坐标值处暂停
【发布时间】:2017-11-23 06:14:11
【问题描述】:

我希望能够点击一个圆(坐标点);将标记带到圆圈的位置并在圆圈的位置暂停,然后沿着路径再次恢复。

此外,我想在标记暂停时激活一个圆圈-单击它们(或单击它们的 Voronoi 单元格)。我的意图是最终为圆坐标提供一个点击功能。

我想我需要将路径坐标的索引而不是时间变量传递给 translateAlong 函数,但我不知道该怎么做。

我不确定 Voronoi 细胞是否是必要的 - 我试图添加这个想法,我可以暂停我的过渡并用 Voronoi 细胞激活我的圈子。在任何情况下,我都无法使用 Voronoi 单元激活圆圈。

我最近在 Stackoverflow d3 on click on circle pause and resume transition of marker along line 上得到了很大帮助 我希望再次得到帮助

<!DOCTYPE html>
<html lang="en">
    <head>
<meta charset="utf-8">
<title>basic_animateBetweenCircles</title>

<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
path {
  stroke: #848484;
    fill: none;
}
circle {
    fill: steelblue;
    stroke: steelblue;
    stroke-width: 3px;
}

.line {
    fill: none;
    stroke: #FE642E;
    stroke-width: 4;
    stroke-dasharray: 4px, 8px;
}
.point{
    fill:#DF013A;
}
</style>
</head>
<body>

<script>

var width = 960,
    height = 500;

var data = [
        [480, 200],
        [580, 400],
        [680, 100],
        [780, 300],
        [180, 300],
        [280, 100],
        [380, 400]
    ];

    //check index of path data
      for (var i = 0; i < data.length; i++) {
            var coordindex = i + " " + data[i];
            console.log("Coordindex: " + coordindex);
            //return coordindex;
      };

var duration = 20000;

var line = d3.line()
    .x(function(d) {return (d)[0];})
    .y(function(d) {return (d)[1];});

var voronoi = d3.voronoi()
  .extent([[0, 0], [width, height]]);

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

//path to animate - marker transitions along this path
var path = svg.append("path")
    .data([data])
    .attr("d", line)
    .attr('class', 'line')
    .attr("d", function(d) {
        return line(d)
    });

//voronoi
var voronoiPath = svg.append("g")
    .selectAll("path")
    .data(voronoi.polygons(data))
    .enter().append("path")
    .attr("d", polygon)
    .on("touchmove mousemove", function() {
        d3.select(this)
         .style("fill", "purple");
 });

//Want to activate circles when marker paused on them / in voronoi cell - intention is to have on click to href
 svg.selectAll("circle")
        .data(data)
    .enter()
        .append("circle")
        .attr("class", "point")
        .attr("r", 10)
    .attr("transform", function(d) { return "translate(" + d + ")"; })
        .on('click', function(d, i) {
        d3.select(this)
            .style("fill", "green");
        if (d3.active(this)) {
            marker.transition();
            setTimeout(function() {
                pauseValues.lastTime = pauseValues.currentTime;
                //console.log(pauseValues);
            }, 100);
        } else {
            transition();
        }
    });

var pauseValues = {
    lastTime: 0,
    currentTime: 0
};

//marker to transition along path
var marker = svg.append("circle")
    .attr("r", 19)
    .attr("transform", "translate(" + (data[0]) + ")")
    .on('click', function(d, i) {
        if (d3.active(this)) {
            marker.transition();
            setTimeout(function() {
                pauseValues.lastTime = pauseValues.currentTime;
                //console.log(pauseValues);
            }, 100);
        } else {
            transition();
        }
    });

function transition() {
    marker.transition()
        .duration(duration - (duration * pauseValues.lastTime))
        .attrTween("transform", translateAlong(path.node()))
        .on("end", function() {
            pauseValues = {
                lastTime: 0,
                currentTime: 0
            };
            transition()
        });
}

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

function polygon(d) {
  return "M" + d.join("L") + "Z";
}

</script>
</body>

【问题讨论】:

    标签: d3.js path jquery-animate geojson voronoi


    【解决方案1】:

    如果您想在某些点暂停,我不会在整个路径上运行一个过渡。相反,我会将其分解为 N 个转换,从一个点移动到另一个点。在下一回合开始循环之前,您可以暂停一段时间。为此,我只需用一点代数沿着每个线段过渡:

    // copy our data
    transData = data.slice();
    
    function transition() {
      marker.transition()
        .ease(d3.easeLinear)
        .duration(duration)
        .attrTween("transform", function(){
    
          // get our two points
          // slope between them
          // and intercetp
          var p0 = transData.shift(),
              p1 = transData[0];
              m = (p0[1] - p1[1]) / (p0[0] - p1[0]),
              b = p0[1] - (m * p0[0]),
              i = d3.interpolateNumber(p0[0], p1[0]);
    
            // move the point along the line
            return function(t){
              var x = i(t),
                  y = m*x + b;
              return "translate(" + x + "," + y + ")";
            }
        })
        // one line segment is complete
        .on("end", function(){
          // if no more movements, stop
          if (transData.length <= 1) return;
          iter++;  
          // determine if this is a "pause"        
          setTimeout(transition, pausePoints.indexOf(iter) !== -1 ? pauseTime : 0);
        });
    

    运行代码,点击一个点开始可以多点暂停:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8">
      <title>basic_animateBetweenCircles</title>
    
      <script src="https://d3js.org/d3.v4.min.js"></script>
      <style>
        path {
          stroke: #848484;
          fill: none;
        }
        
        circle {
          fill: steelblue;
          stroke: steelblue;
          stroke-width: 3px;
        }
        
        .line {
          fill: none;
          stroke: #FE642E;
          stroke-width: 4;
          stroke-dasharray: 4px, 8px;
        }
        
        .point {
          fill: #DF013A;
        }
      </style>
    </head>
    
    <body>
    
      <script>
        var width = 960,
          height = 500;
    
        var data = [
          [480, 200],
          [580, 400],
          [680, 100],
          [780, 300],
          [180, 300],
          [280, 100],
          [380, 400]
        ];
    
    
        var duration = 20000/data.length,
            pauseTime = 2000;
    
        var line = d3.line()
          .x(function(d) {
            return (d)[0];
          })
          .y(function(d) {
            return (d)[1];
          });
    
        var voronoi = d3.voronoi()
          .extent([
            [0, 0],
            [width, height]
          ]);
    
        var svg = d3.select("body")
          .append("svg")
          .attr("width", width)
          .attr("height", height);
    
        //path to animate - marker transitions along this path
        var path = svg.append("path")
          .data([data])
          .attr("d", line)
          .attr('class', 'line')
          .attr("d", function(d) {
            return line(d)
          });
    
        //voronoi
        var voronoiPath = svg.append("g")
          .selectAll("path")
          .data(voronoi.polygons(data))
          .enter().append("path")
          .attr("d", polygon);
    
        //Want to activate circles when marker paused on them / in voronoi cell - intention is to have on click to href
        svg.selectAll("circle")
          .data(data)
          .enter()
          .append("circle")
          .attr("class", "point")
          .attr("r", 10)
          .attr("transform", function(d) {
            return "translate(" + d + ")";
          })
          .on('click', function(d, i) {
            d3.select(this)
              .style("fill", "green");
            pausePoints.push(i);
            if (pausePoints.length === 1)
              transition();    
          });
    
        //marker to transition along path
        var marker = svg.append("circle")
          .attr("r", 19)
          .attr("transform", "translate(" + (data[0]) + ")");
    
        var pausePoints = [],
            iter = 0,
            transData = data.slice();
        
        function transition() {
          marker.transition()
            .ease(d3.easeLinear)
            .duration(duration)
            .attrTween("transform", function(){
              var p0 = transData.shift(),
                  p1 = transData[0];
                  m = (p0[1] - p1[1]) / (p0[0] - p1[0]),
                  b = p0[1] - (m * p0[0]),
                  i = d3.interpolateNumber(p0[0], p1[0]);
                  
                return function(t){
                  var x = i(t),
                      y = m*x + b;
                  return "translate(" + x + "," + y + ")";
                }
            })
            .on("end", function(){
              if (transData.length <= 1) return;
              iter++;          
              setTimeout(transition, pausePoints.indexOf(iter) !== -1 ? pauseTime : 0);
            });
        }
    
        function polygon(d) {
          return "M" + d.join("L") + "Z";
        }
      </script>
    </body>

    【讨论】:

    • 非常感谢 - 你太棒了!我知道我需要做这样的事情,但不知道如何实现它。感谢这个社区,我学到了很多东西。
    猜你喜欢
    • 2018-05-15
    • 2018-05-01
    • 1970-01-01
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-14
    • 1970-01-01
    相关资源
    最近更新 更多