This is my first example using the D3 trail layout made by Benjamin Schmidt. There is no complete hellow world example yet in the official docs, so I created this one.
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="pathlayout.js"></script>
<script>
var width = 600,
height = 500;
var points = [{"x":0,"y":0}, {"x":200,"y":200}, {"x":0,"y":400}, {"x":200,"y":100}];
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var trail = d3.layout.trail().coordType('xy');
var trail_layout = trail.data(points).layout();
paths = svg.selectAll("line").data(trail_layout);
paths.enter()
.append('line')
.style("stroke-width",3)
.style("stroke","black")
.attr("x1",function(d) {return d.x1})
.attr("y1",function(d) {return d.y1})
.attr("y2",function(d) {return d.y2})
.attr("x2",function(d) {return d.x2})
</script>
d3.layout.trail = function() {
var that = {}; //output object
var time = function() {}, //how to access the time data (must be numeric--should but doesn't handle dates);
currentTime, //points of this time will be display with full opacity;
//later points are dropped;
decayRange, //points of this age will have opacity 0. If either currentTime or decayRange is not defined, opacity will be added as some undefined values.
data, // the data being arranged
positioner, // a function that returns the [x,y] for the point.
sort, // a function specifying the sort order
coordType = 'coordinates', //either "coordinates" or "xy"; if the first, returns a "coordinates" array; if the latter, returns x1,y1,x2,y2
grouping; // a function to split the data up into multiple segments;
grouping = function(d) {
return 1
}
positioner = function(datum) {
//given a datum, returns an [x,y] array.
//Might be a projection, for example, or a scale output.
return [datum.x,datum.y]
}
lineToSegments = function(values) {
//the returned array will be filtered to only include segments that fit the defined values.
if (currentTime != undefined & decayRange != undefined) {
values = values.filter(function(d) {
return (time(d) <= currentTime && time(d) >= (currentTime-decayRange))
})
}
values = d3
.nest()
.key(function(d) {return grouping(d)})
.entries(values);
tmp = values;
output = [];
var i = 0
values.forEach(function(element) {
i++;
if (sort!=undefined) {
element.values.sort(sort)
}
if (i==1) {
//console.log(element)
}
var values = element.values;
for (var i = 0; i < (values.length); i++) {
var current = values[i];
if (values[i+1] != undefined) {
current.next = values[i+1]
} else {
current.next = {}
}
if (values[i-1] != undefined) {
current.previous = values[i-1]
if (coordType=="coordinates") {
current.coordinates = [
positioner(values[i-1]),
positioner(values[i])
]
} else if (coordType=="xy") {
var a = positioner(values[i-1]),
b = positioner(values[i]);
current.x1=a[0]
current.y1=a[1]
current.x2=b[0]
current.y2=b[1]
}
current.type = "LineString";
//opacity will probably be this: the percentage of the decay range ago that it was.
//Early tests should guarantee a result between 0 and 1.
}
current.opacity = 1-(currentTime-time(current))/decayRange
}
output = output.concat(values);
})
return output;
}
that.layout = function() {
output = lineToSegments(data);
return output;
}
that.coordType = function(x) {
if (!arguments.length) return coordType;
coordType= x
return that
}
that.grouping = function(x) {
if (!arguments.length) return grouping;
grouping= x
return that
}
that.time = function(x) {
if (!arguments.length) return time;
time = x
return that
}
that.currentTime = function(x) {
if (!arguments.length) return currentTime;
currentTime= x
return that
}
that.decayRange = function(x) {
if (!arguments.length) return decayRange;
decayRange= x
return that
}
that.data = function(x,append) {
if (!arguments.length) return data;
if (append) {
data = data || [];
data = data.concat(x)
} else {
data = x
}
return that
}
that.positioner = function(x) {
if (!arguments.length) return positioner;
positioner = x
return that
}
that.sort = function(x) {
if (!arguments.length) return sort;
sort= x
return that
}
return that;
}