|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
html, |
|
body { |
|
margin: 0; |
|
overflow: hidden; |
|
} |
|
|
|
.lines path { |
|
fill: none; |
|
stroke-width:3px; |
|
} |
|
.lines .yellow { |
|
stroke: #ffd204; |
|
} |
|
.lines .yellow-rush-N, .lines .yellow-rush-S { |
|
stroke: #ffd204; |
|
stroke-dasharray: 2 2; |
|
} |
|
.lines .silver { |
|
stroke: #a1a3a1; |
|
} |
|
.lines .red { |
|
stroke: #e51937; |
|
} |
|
.lines .green { |
|
stroke: #00a950; |
|
} |
|
.lines .blue { |
|
stroke: #0077c0; |
|
} |
|
.lines .orange { |
|
stroke: #f7941d; |
|
} |
|
|
|
.stations circle { |
|
fill: white; |
|
stroke-width: 1; |
|
stroke: #000; |
|
} |
|
|
|
#state { |
|
position: fixed; |
|
top: 12px; |
|
left: 12px; |
|
} |
|
#autoplay { |
|
position: fixed; |
|
top: 12px; |
|
left: 43px; |
|
} |
|
.btn { |
|
border: 1px solid #ccc; |
|
border-radius: 2px; |
|
background-color: #fff; |
|
cursor: pointer; |
|
} |
|
.btn:hover { |
|
background-color: #e6e6e6; |
|
border-color: #adadad; |
|
} |
|
.sprite { |
|
background-image: url(sprite.png); |
|
} |
|
@media (min--moz-device-pixel-ratio: 1.5), (-o-min-device-pixel-ratio: 3/2), (-webkit-min-device-pixel-ratio: 1.5), (min-device-pixel-ratio: 1.5), (min-resolution: 1.5dppx) { |
|
.sprite { |
|
background-image: url(sprite@2x.png); |
|
background-size: 100px 25px; |
|
} |
|
} |
|
.map { |
|
width: 25px; |
|
height: 25px; |
|
background-position: 0 0; |
|
} |
|
.world { |
|
width: 25px; |
|
height: 25px; |
|
background-position: -25px 0px; |
|
} |
|
.play { |
|
width: 25px; |
|
height: 25px; |
|
background-position: -50px 0px; |
|
} |
|
.pause { |
|
width: 25px; |
|
height: 25px; |
|
background-position: -75px 0px; |
|
} |
|
|
|
</style> |
|
<body> |
|
|
|
<div id="state" class="btn sprite map"></div> |
|
<div id="autoplay" class="btn sprite pause"></div> |
|
|
|
<svg></svg> |
|
|
|
<script src="//d3js.org/d3.v4.min.js"></script> |
|
<script src="fitProjection.js"></script> |
|
<script> |
|
|
|
var mapLines, worldLines, mapStations, worldStations, |
|
playing = true; |
|
projection = d3.geoMercator(), |
|
path = d3.geoPath(), |
|
margin = {"top": 20, "right": 20, "bottom": 20, "left": 20 }, |
|
width = window.innerWidth - margin.left - margin.right, |
|
height = window.innerHeight - margin.top - margin.bottom; |
|
|
|
var svg = d3.select("svg") |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom ) |
|
.append("g") |
|
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
d3.queue() |
|
.defer(d3.json, "map-lines.json") |
|
.defer(d3.json, "world-lines.json") |
|
.defer(d3.json, "map-stations.json") |
|
.defer(d3.json, "world-stations.json") |
|
.await(ready); |
|
|
|
function ready(error, mapLinesJson, worldLinesJson, mapStationsJson, worldStationsJson){ |
|
mapLines = mapLinesJson; |
|
worldLines = worldLinesJson; |
|
mapStations = mapStationsJson; |
|
worldStations = worldStationsJson; |
|
fitProjection(projection, worldLines.features, [[0,0],[width, height]]); |
|
path.projection(projection); |
|
|
|
lines = svg.append("g") |
|
.attr("class", "lines") |
|
.selectAll("path") |
|
.data(mapLines.features, function(d) { return d.properties.name; }) |
|
.enter().append("path") |
|
.attr("d", path) |
|
.attr("class", function(d){ return d.properties.name; }); |
|
|
|
stations = svg.append("g") |
|
.attr("class", "stations") |
|
.selectAll("circle") |
|
.data(mapStations.features, function(d) { return d.properties.name; }) |
|
.enter().append("circle") |
|
.attr("cx", function (d) { return projection(d.geometry.coordinates)[0]; }) |
|
.attr("cy", function (d) { return projection(d.geometry.coordinates)[1]; }) |
|
.attr("r", function (d) { |
|
if(d.properties.type === "lg") return 2.5; |
|
if(d.properties.type === "sm") return 1; |
|
}) |
|
|
|
warp(); |
|
} |
|
|
|
function warp() { |
|
if(d3.select("#state").classed("world")){ |
|
lines.data(mapLines.features, function(d) { return d.properties.name; }) |
|
.transition().attr("d", path).duration(4000); |
|
stations.data(mapStations.features, function(d) { return d.properties.name; }) |
|
.transition() |
|
.attr("cx", function (d) { return projection(d.geometry.coordinates)[0]; }) |
|
.attr("cy", function (d) { return projection(d.geometry.coordinates)[1]; }) |
|
.duration(4000); |
|
d3.select("#state").classed("world", false).classed("map", true); |
|
} else { |
|
lines.data(worldLines.features, function(d) { return d.properties.name; }) |
|
.transition().attr("d", path).duration(4000); |
|
stations.data(worldStations.features, function(d) { return d.properties.name; }) |
|
.transition() |
|
.attr("cx", function (d) { return projection(d.geometry.coordinates)[0]; }) |
|
.attr("cy", function (d) { return projection(d.geometry.coordinates)[1]; }) |
|
.duration(4000); |
|
d3.select("#state").classed("world", true).classed("map", false); |
|
} |
|
setTimeout(function () { |
|
if(playing){ |
|
warp(); |
|
} |
|
}, 5000) |
|
} |
|
|
|
d3.select("#state").on("click", warp); |
|
|
|
d3.select("#autoplay").on("click", function(){ |
|
if(d3.select("#autoplay").classed("pause")){ |
|
d3.select("#autoplay").classed("pause", false) |
|
.classed("play", true); |
|
playing = false; |
|
} else { |
|
d3.select("#autoplay").classed("pause", true) |
|
.classed("play", false); |
|
playing = true; |
|
warp(); |
|
} |
|
}); |
|
|
|
d3.select(window).on("resize", throttle); |
|
function throttle() { |
|
window.setTimeout(function() { |
|
width = window.innerWidth - margin.left - margin.right; |
|
height = window.innerHeight - margin.top - margin.bottom; |
|
svg.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom ); |
|
fitProjection(projection, worldLines.features, [[0,0],[width, height]]); |
|
path.projection(projection); |
|
lines.attr("d", path); |
|
stations.attr("cx", function (d) { return projection(d.geometry.coordinates)[0]; }) |
|
.attr("cy", function (d) { return projection(d.geometry.coordinates)[1]; }); |
|
}, 600); |
|
} |
|
|
|
</script> |