Based on E.J. Marey’s graphical train schedule this position-time-diagram shows the stations on the x-axis and the time on the y-axis.
Last active
August 29, 2015 14:03
-
-
Save Stefku/935862470f7ae6babdf4 to your computer and use it in GitHub Desktop.
Marey’s Trains III
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
svg { | |
font: 10px sans-serif; | |
} | |
.axis path { | |
display: none; | |
} | |
.axis line { | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.station line { | |
stroke: #ddd; | |
stroke-dasharray: 1, 1; | |
shape-rendering: crispEdges; | |
} | |
.station text { | |
text-anchor: end; | |
} | |
.train path { | |
fill: none; | |
stroke-width: 1.5px; | |
} | |
.train path:hover{ | |
fill: none; | |
stroke-width: 5px; | |
} | |
.train circle { | |
stroke: #fff; | |
} | |
.train .S path { | |
stroke: rgb(183, 116, 9); | |
} | |
.train .S circle { | |
fill: rgb(183, 116, 9); | |
} | |
.train .RE path { | |
stroke: rgb(49, 77, 183); | |
} | |
.train .RE circle { | |
fill: rgb(49, 77, 183); | |
} | |
.train .EC path { | |
stroke: rgb(183, 19, 15); | |
} | |
.train .EC circle { | |
fill: rgb(183, 19, 15); | |
} | |
.train .IC path { | |
stroke: rgb(183, 19, 15); | |
} | |
.train .IC circle { | |
fill: rgb(183, 19, 15); | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script type="text/javascript"> | |
var stations = [ | |
{'name': 'Thun', 'distance': 0}, | |
{'name': 'Uttigen', 'distance': 6}, | |
{'name': 'Kiesen', 'distance': 8.8}, | |
{'name': 'Wichtrach', 'distance': 11.4}, | |
{'name': 'Münsingen', 'distance': 14.9}, | |
{'name': 'Rubigen', 'distance': 18.1}, | |
{'name': 'Gümligen', 'distance': 23.2}, | |
{'name': 'Ostermundigen', 'distance': 26.4}, | |
{'name': 'Bern Wankdorf', 'distance': 28.7}, | |
{'name': 'Bern', 'distance': 31.4} | |
]; | |
var getDistance = function(station) { | |
for (i = 0; i < stations.length; i++) { | |
if (station === stations[i].name) { | |
return stations[i].distance; | |
} | |
} | |
}; | |
var trains = [ | |
{ | |
'name': 'EuroCity 52', | |
'type': 'EC', | |
'stops': [ | |
{'station': 'Thun', 'time': '14:04'}, | |
{'station': 'Bern', 'time': '14:23'} | |
] | |
}, | |
{ | |
'name': 'InterCity 978', | |
'type': 'IC', | |
'stops': [ | |
{'station': 'Thun', 'time': '14:32'}, | |
{'station': 'Bern', 'time': '14:52'} | |
] | |
}, | |
{ | |
'name': 'InterCity 829', | |
'type': 'IC', | |
'stops': [ | |
{'station': 'Thun', 'time': '14:36'}, | |
{'station': 'Bern', 'time': '14:54'} | |
] | |
}, | |
{ | |
'name': 'InterCity 1078', | |
'type': 'IC', | |
'stops': [ | |
{'station': 'Thun', 'time': '15:04'}, | |
{'station': 'Bern', 'time': '15:23'} | |
] | |
}, | |
{ | |
'name': 'RegioExpress 3168 LÖTSCHBERGER', | |
'type': 'RE', | |
'stops': [ | |
{'station': 'Thun', 'time': '13:59'}, | |
{'station': 'Münsingen', 'time': '14:08'}, | |
{'station': 'Bern', 'time': '14:20'} | |
] | |
}, | |
{ | |
'name': 'RegioExpress 3168 LÖTSCHBERGER', | |
'type': 'RE', | |
'stops': [ | |
{'station': 'Thun', 'time': '14:59'}, | |
{'station': 'Münsingen', 'time': '15:08'}, | |
{'station': 'Bern', 'time': '15:20'} | |
] | |
}, | |
{ | |
'name': 'S1', | |
'type': 'S', | |
'stops': [ | |
{'station': 'Thun', 'time': '14:13'}, | |
{'station': 'Uttigen', 'time': '14:17'}, | |
{'station': 'Kiesen', 'time': '14:19'}, | |
{'station': 'Wichtrach', 'time': '14:22'}, | |
{'station': 'Münsingen', 'time': '14:26'}, | |
{'station': 'Rubigen', 'time': '14:28'}, | |
{'station': 'Gümligen', 'time': '14:33'}, | |
{'station': 'Ostermundigen', 'time': '14:35'}, | |
{'station': 'Bern Wankdorf', 'time': '14:37'}, | |
{'station': 'Bern', 'time': '14:43'} | |
] | |
}, | |
{ | |
'name': 'S1', | |
'type': 'S', | |
'stops': [ | |
{'station': 'Thun', 'time': '14:43'}, | |
{'station': 'Uttigen', 'time': '14:47'}, | |
{'station': 'Kiesen', 'time': '14:49'}, | |
{'station': 'Wichtrach', 'time': '14:52'}, | |
{'station': 'Münsingen', 'time': '14:56'}, | |
{'station': 'Rubigen', 'time': '14:58'}, | |
{'station': 'Gümligen', 'time': '15:03'}, | |
{'station': 'Ostermundigen', 'time': '15:05'}, | |
{'station': 'Bern Wankdorf', 'time': '15:07'}, | |
{'station': 'Bern', 'time': '15:13'} | |
] | |
}, | |
{ | |
'name': 'S1', | |
'type': 'S', | |
'stops': [ | |
{'station': 'Thun', 'time': '15:13'}, | |
{'station': 'Uttigen', 'time': '15:17'}, | |
{'station': 'Kiesen', 'time': '15:19'}, | |
{'station': 'Wichtrach', 'time': '15:22'}, | |
{'station': 'Münsingen', 'time': '15:26'}, | |
{'station': 'Rubigen', 'time': '15:28'}, | |
{'station': 'Gümligen', 'time': '15:33'}, | |
{'station': 'Ostermundigen', 'time': '15:35'}, | |
{'station': 'Bern Wankdorf', 'time': '15:37'}, | |
{'station': 'Bern', 'time': '15:43'} | |
] | |
}, | |
// Rückfahrt | |
{ | |
'name': 'InterCity 973', | |
'type': 'IC', | |
'stops': [ | |
{'station': 'Bern', 'time': '14:04'}, | |
{'station': 'Thun', 'time': '14:21'} | |
] | |
}, | |
{ | |
'name': 'InterCity 824', | |
'type': 'IC', | |
'stops': [ | |
{'station': 'Bern', 'time': '14:07'}, | |
{'station': 'Thun', 'time': '14:24'} | |
] | |
}, | |
{ | |
'name': 'InterCity', | |
'type': 'IC', | |
'stops': [ | |
{'station': 'Bern', 'time': '14:34'}, | |
{'station': 'Thun', 'time': '14:52'} | |
] | |
}, | |
{ | |
'name': 'RegioExpress 3168 LÖTSCHBERGER', | |
'type': 'RE', | |
'stops': [ | |
{'station': 'Bern', 'time': '14:39'}, | |
{'station': 'Münsingen', 'time': '14:49'}, | |
{'station': 'Thun', 'time': '15:01'} | |
] | |
}, | |
{ | |
'name': 'S1', | |
'type': 'S', | |
'stops': [ | |
{'station': 'Bern', 'time': '14:16'}, | |
{'station': 'Bern Wankdorf', 'time': '14:19'}, | |
{'station': 'Ostermundigen', 'time': '14:20'}, | |
{'station': 'Gümligen', 'time': '14:24'}, | |
{'station': 'Rubigen', 'time': '14:27'}, | |
{'station': 'Münsingen', 'time': '14:31'}, | |
{'station': 'Wichtrach', 'time': '14:34'}, | |
{'station': 'Kiesen', 'time': '14:36'}, | |
{'station': 'Uttigen', 'time': '14:39'}, | |
{'station': 'Thun', 'time': '14:46'} | |
] | |
}, | |
{ | |
'name': 'S1', | |
'type': 'S', | |
'stops': [ | |
{'station': 'Bern', 'time': '14:46'}, | |
{'station': 'Bern Wankdorf', 'time': '14:49'}, | |
{'station': 'Ostermundigen', 'time': '14:50'}, | |
{'station': 'Gümligen', 'time': '14:54'}, | |
{'station': 'Rubigen', 'time': '14:57'}, | |
{'station': 'Münsingen', 'time': '15:01'}, | |
{'station': 'Wichtrach', 'time': '15:04'}, | |
{'station': 'Kiesen', 'time': '15:06'}, | |
{'station': 'Uttigen', 'time': '15:09'}, | |
{'station': 'Thun', 'time': '15:16'} | |
] | |
}, | |
{ | |
'name': 'S1', | |
'type': 'S', | |
'stops': [ | |
{'station': 'Bern', 'time': '15:16'}, | |
{'station': 'Bern Wankdorf', 'time': '15:19'}, | |
{'station': 'Ostermundigen', 'time': '15:20'}, | |
{'station': 'Gümligen', 'time': '15:24'}, | |
{'station': 'Rubigen', 'time': '15:27'}, | |
{'station': 'Münsingen', 'time': '15:31'}, | |
{'station': 'Wichtrach', 'time': '15:34'}, | |
{'station': 'Kiesen', 'time': '15:36'}, | |
{'station': 'Uttigen', 'time': '15:39'}, | |
{'station': 'Thun', 'time': '15:46'} | |
] | |
} | |
]; | |
var formatTime = d3.time.format("%H:%M"); | |
var margin = {top: 70, right: 40, bottom: 20, left: 100}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom; | |
var x = d3.scale.linear() | |
.range([0, width]); | |
var y = d3.time.scale() | |
.domain([formatTime.parse("14:00"), formatTime.parse("16:00")]) | |
.range([0, height]); | |
var yAxis = d3.svg.axis() | |
.scale(y) | |
.ticks(8) | |
.tickFormat(formatTime); | |
var line = d3.svg.line() | |
.x(function (d) { | |
return x(getDistance(d.station)); | |
}) | |
.y(function (d) { | |
return y(formatTime.parse(d.time)); | |
}); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
svg.append("defs").append("clipPath") | |
.attr("id", "clip") | |
.append("rect") | |
.attr("y", -margin.top) | |
.attr("width", width) | |
.attr("height", height + margin.top + margin.bottom); | |
// Stations | |
x.domain(d3.extent(stations, function (d) { | |
return d.distance; | |
})); | |
var station = svg.append("g") | |
.attr("class", "station") | |
.selectAll("g") | |
.data(stations) | |
.enter().append("g") | |
.attr("transform", function (d) { | |
return "translate(" + x(d.distance) + ", 0)"; | |
}); | |
station.append("text") | |
.attr("x", -15) | |
.attr("dy", ".35em") | |
.attr("transform", "rotate(30 20,40)") | |
.text(function (d) { | |
return d.name; | |
}); | |
station.append("line") | |
.attr("y2", height); | |
// Time | |
svg.append("g") | |
.attr("class", "y left axis") | |
.call(yAxis.orient("left")); | |
svg.append("g") | |
.attr("class", "y rigth axis") | |
.attr("transform", "translate(" + width + ", 0)") | |
.call(yAxis.orient("right")); | |
// Trains | |
var train = svg.append("g") | |
.attr("class", "train") | |
.attr("clip-path", "url(#clip)") | |
.selectAll("g") | |
.data(trains) | |
.enter().append("g") | |
.attr("class", function (d) { | |
return d.type; | |
}); | |
train.append("path") | |
.attr("d", function (d) { | |
return line(d.stops); | |
}) | |
.on("click", function() { | |
alert(d.name); | |
}); | |
train.selectAll("circle") | |
.data(function(d) { return d.stops; }) | |
.enter().append("circle") | |
.attr("transform", function(d) { return "translate(" + x(getDistance(d.station)) + "," + y(formatTime.parse(d.time)) + ")"; }) | |
.attr("r", 2); | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment