Skip to content

Instantly share code, notes, and snippets.

@rveciana
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rveciana/f536039e5b5d41f82c8c to your computer and use it in GitHub Desktop.
Save rveciana/f536039e5b5d41f82c8c to your computer and use it in GitHub Desktop.
D3 Trail Layout example

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="http://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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment