This example demonstrates how to use the getTotalLength and getPointAtLength methods on SVG path elements to interpolate a point along a Catmull–Rom spline.
A related technique is stroke dash interpolation.
forked from mbostock's block: Point-Along-Path Interpolation
forked from antonyross's block: Point-Along-Path Interpolation
forked from antonyross's block: Point-Along-Path Interpolation
forked from antonyross's block: Point-Along-Path Interpolation
forked from antonyross's block: Point-Along-Path Interpolation
forked from antonyross's block: Point-Along-Path Interpolation
forked from antonyross's block: Point-Along-Path Interpolation
xxxxxxxxxx
<meta charset="utf-8">
<body>
<style>
path {
fill: none;
stroke: #000;
stroke-width: 3px;
}
circle {
/*fill: steelblue; */
stroke: #fff;
stroke-width: 3px;
}
</style>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var points = [
[200, 200],
[500, 200],
[500, 400],
[200, 400],
];
var points2 = [
[100, 200],
[400, 200],
[400, 400],
[100, 400],
];
var w = 960;
var h = 500;
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
// Text to show "stopwatch"
svg.append("text").text("hey").attr("x", 700).attr("y", 50)
///////////// RUNNER ///////////////////////
Vector.prototype.add = function(v)
{
this.x += v.x;
this.y += v.y;
};
Vector.prototype.magnitude = function()
{
return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2));
}
Vector.prototype.multiply = function(n)
{
this.x *= n;
this.y *= n;
}
Vector.prototype.normalize = function()
{
magnitude = this.magnitude();
this.x/= magnitude;
this.y/= magnitude;
}
Vector.prototype.limit = function(max)
{
magnitude = this.magnitude();
if(magnitude > max)
{
this.normalize();
this.multiply(max);
}
};
function Vector(x,y)
{
this.x = x;
this.y = y;
}
Runner.prototype.get_random_color = function()
{
var colors = ["red", "green", "blue", "orange"]
random_color = Math.floor(Math.random()*colors.length);
return colors[random_color];
};
//Runner.prototype.r = 15;
Runner.prototype.checkEdges = function()
{
/*if((this.location.x > w) || (this.location.x < 0))
{
this.velocity.x = this.velocity.x * -1
}
if((this.location.y > h) || (this,location.y < 0))
{
this.velocity.x = this.velocity.y * -1
}*/
if(this.location.x > w)
{
this.location.x = 0;
}
else if(this.location.x < 0)
{
this.location.x = w;
}
if(this.location.y > h)
{
this.location.y = 0;
}
else if(this.location.y < 0)
{
this.location.y = h;
}
};
Runner.prototype.update = function()
{
this.velocity.add(this.acceleration);
this.velocity.limit(this.topspeed);
this.location.add(this.velocity);
};
function Runner(r,color,path, coordinates)
{
this.r = r;
this.color = color;
this.path = path;
this.location = new Vector(coordinates[0], coordinates[1]);
// velocity: the rate of change of location
this.velocity = new Vector(Math.random() * 5, 0);//Math.random() * 5;
// acceleration: the rate of change of velocity
this.acceleration = new Vector(-.001, .01);
this.topspeed = 10;
}
///////////////////////////////////////////////
var dataset = [];
var path = svg.append("path")
.data([points])
.attr("d", d3.svg.line()
.tension(0) // Catmull–Rom
.interpolate("cardinal-closed"));
var path2 = svg.append("path")
.data([points2])
.attr("d", d3.svg.line()
.tension(0) // Catmull–Rom
.interpolate("cardinal-closed"));
/*
// OPTIONAL
svg.selectAll(".point")
.data(points)
.enter()
.append("circle")
.attr("r", 4)
.attr("transform", function(d) { return "translate(" + d + ")"; });
// OPTIONAL
var circle = svg.append("circle")
.attr("r", 13)
.attr("transform", "translate(" + points[0] + ")");
*/
d3.select("svg").on("click", function()
{
// get the mouse position coordinates
var coordinates = [0, 0];
coordinates = d3.mouse(this);
dataset.push(new Runner(15, "blue", 1, coordinates));
var circles = svg.selectAll("circle") //Select all circles
.data(dataset);
circles.enter()
.append("circle")
.attr({cx:0, cy:0, fill: function(d){return d.get_random_color()}})
.attr("r", function(d){return d.r})
//.transition()
//.duration(2000)
//.attr("transform", translator()); //"translate(" + points[0] + ")")
//.each("end", transition);
transition();
function transition()
{
circles.transition()
.duration(10000)
//.attrTween("transform", translateAlong(path.node(),path2.node()))
.attrTween("transform", mover())
.each("end", transition);
}
// Returns an attrTween for translating along the specified path element.
function translateAlong(path1, path2)
{
var length_1 = path1.getTotalLength();
var length_2 = path2.getTotalLength();
return function(d, i, a)
{
return function(t)
{
var p1 = path1.getPointAtLength(t * length_1);
var p2 = path2.getPointAtLength(t * length_2);
svg.select("text").text(Math.floor(t * 100))
if (t < .3)
{
p = p2
}
else
{
p = p1
}
return "translate(" + p.x + "," + p.y + ")";
};
};
}
function mover()
{
return function(d, i, a)
{
return function(t)
{
svg.select("text").text(Math.floor(t * 100))
d.checkEdges(); // make sure objects remain on screen; bounce back
d.update(); // update the object's position
// return the updated translated position
return "translate(" + d.location.x + "," + d.location.y + ")";
};
};
}
});
</script>
https://d3js.org/d3.v3.min.js