block by rveciana f536039e5b5d41f82c8c

D3 Trail Layout example

Full Screen

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.

index.html

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

pathlayout.js

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;

}