|
var agency = 'ncsu'; |
|
var width = 960; |
|
var height = 500; |
|
var graph = {nodes: [], links: []}; |
|
|
|
var force = d3.layout.force() |
|
.charge(-20) |
|
.gravity(0.02) |
|
.friction(0.8) |
|
.linkDistance(function (d) { return d.value / 1000 / 10; }) |
|
.size([width, height]); |
|
|
|
var fetchAgencies = function (agency) { |
|
return $.getJSON('http://tlapi.dhaz.in/agencies.jsonp?callback=?&agencies=' + agency); |
|
}; |
|
|
|
var fetchArrivals = function (agency) { |
|
return $.getJSON('http://tlapi.dhaz.in/arrival-estimates.jsonp?callback=?&agencies=' + agency); |
|
}; |
|
|
|
var fetchRoutes = function (agency) { |
|
return $.getJSON('http://tlapi.dhaz.in/routes.jsonp?callback=?&agencies=' + agency); |
|
}; |
|
|
|
var fetchStops = function (agency) { |
|
return $.getJSON('http://tlapi.dhaz.in/stops.jsonp?callback=?&agencies=' + agency); |
|
}; |
|
|
|
var cleanArrivals = function (arrivals) { |
|
var cleaned = []; |
|
var now = new Date(); |
|
|
|
_.each(arrivals, function(arrival) { |
|
var tmp = {}; |
|
|
|
_.each(arrival.arrivals, function(a) { |
|
|
|
if (tmp[a.route_id] === undefined) { |
|
return tmp[a.route_id] = new Date(a.arrival_at) - now; |
|
} |
|
|
|
if (tmp[a.route_id] > new Date(a.arrival_at) - now) { |
|
tmp[a.route_id] = new Date(a.arrival_at) - now; |
|
} |
|
|
|
}); |
|
|
|
arrival.arrivals = []; |
|
|
|
_.each(_.keys(tmp), function (key) { |
|
arrival.arrivals.push({ |
|
route_id: key, |
|
delta: tmp[key] |
|
}); |
|
}); |
|
|
|
cleaned.push(arrival); |
|
|
|
}); |
|
|
|
return cleaned; |
|
}; |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
var linkGroup = svg.append('g'); |
|
var stopNodeGroup = svg.append('g'); |
|
var routeNodeGroup = svg.append('g'); |
|
|
|
$.when(fetchAgencies(agency), fetchRoutes(agency), fetchStops(agency)).done(function (agenciesRes, routesRes, stopsRes) { |
|
|
|
var agencyId = agenciesRes[0].data[0].agency_id; |
|
var routes = routesRes[0].data[agencyId]; |
|
var stops = stopsRes[0].data; |
|
|
|
routeNodes = _.map(routes, function(route) { |
|
return { |
|
id: route.route_id, |
|
name: route.short_name + ': ' + route.long_name, |
|
color: '#' + route.color, |
|
//fixed: true, |
|
type: 'route' |
|
}; |
|
}); |
|
|
|
stopNodes = _.map(stops, function(stop) { |
|
return { |
|
id: stop.stop_id, |
|
name: stop.code + ': ' + stop.name, |
|
code: stop.code, |
|
type: 'stop' |
|
}; |
|
}); |
|
|
|
var routeMap = {}; |
|
var stopMap = {}; |
|
|
|
_.each(stopNodes, function(node) { |
|
stopMap[node.id] = node; |
|
}); |
|
|
|
_.each(routeNodes, function(node) { |
|
routeMap[node.id] = node; |
|
}); |
|
|
|
var loopArrivals = function () { |
|
$.when(fetchArrivals(agency)).done(function (arrivalsRes) { |
|
var arrivals = arrivalsRes.data; |
|
var routeIds = {}; |
|
var stopIds = {}; |
|
var now = new Date(); |
|
|
|
arrivals = cleanArrivals(arrivals); |
|
|
|
graph.nodes.length = 0; |
|
graph.links.length = 0; |
|
|
|
_.each(arrivals, function(arrival) { |
|
|
|
_.each(arrival.arrivals, function(a) { |
|
|
|
graph.links.push({ |
|
source: stopMap[arrival.stop_id], |
|
target: routeMap[a.route_id], |
|
value: a.delta |
|
}); |
|
stopIds[arrival.stop_id] = 1; |
|
routeIds[a.route_id] = 1; |
|
|
|
}); |
|
|
|
}); |
|
|
|
_.each(_.keys(routeIds), function(id) { |
|
graph.nodes.push(routeMap[id]); |
|
}); |
|
|
|
_.each(_.keys(stopIds), function(id) { |
|
graph.nodes.push(stopMap[id]); |
|
}); |
|
|
|
start(); |
|
setTimeout(loopArrivals, 5000); |
|
}); |
|
}; |
|
|
|
run(); |
|
loopArrivals(); |
|
|
|
}); |
|
|
|
var start = function() { |
|
|
|
var link = linkGroup.selectAll(".link") |
|
.data(graph.links); |
|
|
|
link.enter().append("line") |
|
.attr("class", "link") |
|
.style("stroke-width", 1); |
|
|
|
link.exit().remove(); |
|
|
|
var stopNode = stopNodeGroup.selectAll(".node") |
|
.data(_.filter(graph.nodes, function(n) {return n.type === 'stop';}), function(d) { return d.id; }); |
|
|
|
stopNode.enter().append("circle") |
|
.attr("class", function(d) { return 'node ' + d.type; }) |
|
.attr("r", function(d) { return d.type === 'route' ? 10 : 5; }) |
|
.style("fill", function(d) { return d.type === 'route' ? d.color : '#555'; }) |
|
.call(force.drag); |
|
|
|
stopNode.exit().remove(); |
|
|
|
stopNode.append("title") |
|
.text(function(d) { return d.name; }); |
|
|
|
var routeNode = routeNodeGroup.selectAll(".node") |
|
.data(_.filter(graph.nodes, function(n) {return n.type === 'route';}), function(d) { return d.id; }); |
|
|
|
routeNode.enter().append("circle") |
|
.attr("class", function(d) { return 'node ' + d.type; }) |
|
.attr("r", function(d) { return d.type === 'route' ? 10 : 5; }) |
|
.style("fill", function(d) { return d.type === 'route' ? d.color : '#555'; }) |
|
.call(force.drag); |
|
|
|
routeNode.exit().remove(); |
|
|
|
routeNode.append("title") |
|
.text(function(d) { return d.name; }); |
|
|
|
force.start(); |
|
|
|
}; |
|
|
|
var run = function() { |
|
|
|
force |
|
.nodes(graph.nodes) |
|
.links(graph.links); |
|
|
|
start(); |
|
|
|
force.on("tick", function() { |
|
var link = linkGroup.selectAll(".link"); |
|
var route = routeNodeGroup.selectAll(".node"); |
|
var stop = stopNodeGroup.selectAll(".node"); |
|
|
|
link.attr("x1", function(d) { return d.source.x; }) |
|
.attr("y1", function(d) { return d.source.y; }) |
|
.attr("x2", function(d) { return d.target.x; }) |
|
.attr("y2", function(d) { return d.target.y; }); |
|
|
|
route.attr("cx", function(d) { return d.x; }) |
|
.attr("cy", function(d) { return d.y; }); |
|
|
|
stop.attr("cx", function(d) { return d.x; }) |
|
.attr("cy", function(d) { return d.y; }); |
|
}); |
|
}; |