How to navigate a path, but only between two specified waypoints

This question is about d3 version 3.x and path movements.

Imagine that there is a path and a circle element, and I want the circle to go that path in transition, but only up to a certain percentage. I've asked this before and got a great answer from Gerardo Furtado: My previous question

However, one question in this regard remains for me, and since I'm a beginner, I haven't found any working solution yet:

How can I track this path, say, from a point at 25% to a point at 50%, and then from a point at 50% to a point at 60%?

These numbers are just examples, any percentage should be possible.

I need to avoid the fact that the movement of the path always starts from position 0, but instead I want to start the movement along the path from the current position to which the circle has already reached.

I hope I could make my question clear enough.

Thank you for your understanding and help.

0


source to share


1 answer


Well, I have to agree with LeBeau and I see that you do that too. Since I answered your last question , I just needed to make some minor changes to the function. However, save his recommendations for next time: when asking a question, show us some code you tried, even if it doesn't work because it shows effort.

Let's get back to the question.

For this solution, I will wrap everything inside a named function move

that takes two arguments, a start position and an end position (both in percentages):

function move(initialPosition, finalPosition) {

      

Home position, as the name suggests, sets the starting position of the circle along the path. The math is this:

var start = path.node()
    .getPointAtLength(path.node().getTotalLength() * initialPosition);

      



Then I slightly modified the function from my last answer to accept the start and end positions:

function translateAlong(path) {
    var l = path.getTotalLength() * (finalPosition - initialPosition);
    return function() {
        return function(t) {
            var p = path.getPointAtLength(t * l + 
                (path.getTotalLength() * initialPosition));
            return "translate(" + p.x + "," + p.y + ")";
        };
    };
}

      

Here's a demo. Clicking the button invokes move

with 0.25

(start position) and 0.5

(end position) as arguments:

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 dataPositions = [{
  initial: 0.25,
  final: 0.5
}, {
  initial: 0.5,
  final: 0.6
}];


svg.selectAll(".point")
  .data(points)
  .enter().append("circle")
  .attr("r", 4)
  .attr("transform", function(d) {
    return "translate(" + d + ")";
  });

d3.select("button").on("click", function() {
  move(0.25, 0.5);
});

function move(initialPosition, finalPosition) {

  var start = path.node().getPointAtLength(path.node().getTotalLength() * initialPosition);

  var circle = svg.append("circle")
    .attr("r", 13)
    .attr("fill", function(d, i) {
      return color(i)
    })
    .attr("transform", "translate(" + start.x + "," + start.y + ")");

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

  function translateAlong(path) {
    var l = path.getTotalLength() * (finalPosition - initialPosition);
    return function() {
      return function(t) {
        var p = path.getPointAtLength(t * l + 
            (path.getTotalLength() * initialPosition));
        return "translate(" + p.x + "," + p.y + ")";
      };
    };
  }

}
      

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

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

<script src="//d3js.org/d3.v3.min.js"></script>
<button>Move</button>
<br>
      

Run codeHide result


PS: The function in this answer does not accept values โ€‹โ€‹greater than 1. But you can try changing it if you need to do more than "one circle" in the path.

+1


source







All Articles