D3沿路径线段过渡并在坐标值处暂停 [英] D3 transition along segments of path and pause at coordinate values

查看:112
本文介绍了D3沿路径线段过渡并在坐标值处暂停的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to be able to click on a circle (coordinate points); bring the marker to the position of the circle and pause at the position of the circle and then resume again along the path.

此外,当我在其上暂停标记时,我想激活一个圆圈-单击它们(或单击其Voronoi单元格).我的目的是最终为圆坐标的href提供一个on click功能.

In addition I would like to activate a circle when marker is paused on them - they are clicked (or their Voronoi cell is clicked). My intention is to have an on click function to an href for the circle coordinates eventually.

我认为我需要将路径坐标的索引传递给translateAlong函数而不是时间变量,但无法解决该问题.

I think I need to pass the index of the path coordinates into the translateAlong function instead of the time variables but can't work out how to do this.

我不确定是否需要Voronoi细胞-我想补充一下这一想法,我可以暂停过渡并使用Voronoi细胞激活我的圈子.无论如何,我无法使用Voronoi单元格激​​活圈子.

I’m not sure if the Voronoi cells are necessary - I tried to add this thinking I could pause my transition and activate my circles with the Voronoi cells. In any case I can’t activate the circle with the Voronoi cell.

最近我在Stackoverflow

I was helped considerably recently on Stackoverflow d3 on click on circle pause and resume transition of marker along line and I am hoping for assistance again

<!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>

推荐答案

如果要在点处暂停,我不会在整个路径上进行一次过渡.相反,我会将其分解为N个过渡,从一个点到另一个点.在下一圈开始圈之前,您可以暂停一下.为此,我只需沿每个线段过渡,并添加一些代数:

If you want to pause at points, I would not run one transition across the entire path. Instead, I would break it up into N transitions, moving from point to point. Before starting the circle on it's next leg, you can pause it for a time. To do this, I would just transition along each line segment with a little algebra:

// 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);
    });

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

Running code, click a dot to start you can pause a multiple points:

<!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>

这篇关于D3沿路径线段过渡并在坐标值处暂停的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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