|
<!DOCTYPE html> |
|
<meta charset='utf-8'> |
|
<style> |
|
|
|
text { |
|
fill: #999; |
|
font-size: 9px; |
|
font-family: sans-serif; |
|
font-weight: bold; |
|
text-anchor: middle; |
|
} |
|
|
|
.road { |
|
fill: none; |
|
stroke: #eee; |
|
} |
|
.water { |
|
fill: #88f; |
|
opacity: 0.5; |
|
} |
|
|
|
</style> |
|
<body></body> |
|
<script src='https://d3js.org/d3.v4.min.js'></script> |
|
<script src='https://d3js.org/d3-scale-chromatic.v1.min.js'></script> |
|
<script src='https://d3js.org/d3-queue.v2.min.js'></script> |
|
<script src='https://d3js.org/topojson.v1.min.js'></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js"></script> |
|
|
|
<script> |
|
var minuteFormat = d3.timeFormat("g%H%M"); |
|
|
|
var margin = {top: 10, right: 10, bottom: 10, left: 10}, |
|
width = 545 - margin.left - margin.right, |
|
height = 900 - margin.top - margin.bottom; |
|
|
|
var projection = d3.geoMercator() |
|
.center([19.05, 47.525]) // Budapest |
|
.translate([width / 2, height / 2]) |
|
.scale(width * 750); |
|
|
|
var path = d3.geoPath() |
|
.projection(projection); |
|
|
|
var svg = d3.select('body').append('svg') |
|
.attr('width', width + margin.left + margin.right) |
|
.attr('height', height + margin.top + margin.bottom) |
|
.append('g') |
|
.attr('class', 'g-map') |
|
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); |
|
|
|
var colorScale = d3.scaleLinear() |
|
.range([0, 1]); |
|
|
|
var timeScale = d3.scaleTime() |
|
.rangeRound([0, width]); |
|
|
|
var wptColors = d3.scaleOrdinal() |
|
.domain(['Start', 'Finish', 'Challenge']) |
|
.range(['green', 'red', 'grey']); |
|
|
|
d3.queue() |
|
.defer(d3.json, 'budapest.json') |
|
.defer(d3.xml, 'trabi.gpx') |
|
.await(ready); |
|
|
|
function startClock() { |
|
var currTime = moment(timeScale.domain()[0]);; |
|
setInterval(function() { |
|
if(currTime.isBefore(moment(timeScale.domain()[1]))) { |
|
currTime = currTime.add(1, 'm'); |
|
|
|
d3.select('.g-map').selectAll('circle.' + minuteFormat(currTime)) |
|
.transition() |
|
.duration(100) |
|
.style('opacity', 1.0) |
|
.transition() |
|
.duration(1000) |
|
.style('opacity', 0.3); |
|
} else { |
|
currTime = moment(timeScale.domain()[0]); |
|
d3.select('.g-map').selectAll('circle.' + minuteFormat(currTime)) |
|
.style('opacity', 0); |
|
} |
|
}, 200); |
|
} |
|
|
|
function ready(error, map, gpx) { |
|
if (error) return console.error(error); |
|
|
|
svg.append('path') |
|
.datum(topojson.feature(map, map.objects.water)) |
|
.attr('class', 'water') |
|
.attr('d', path); |
|
|
|
svg.append('path') |
|
.datum(topojson.feature(map, map.objects.roads)) |
|
.attr('class', 'road') |
|
.attr('d', path); |
|
|
|
var points = gpx.getElementsByTagName('trkpt'), |
|
wpts = gpx.getElementsByTagName('wpt'), |
|
data = [], |
|
waypoints = []; |
|
|
|
// extract gpx data |
|
for (i = 0; i < points.length; i++) { |
|
var point = points[i], |
|
ele = parseInt(point.getElementsByTagName('ele')[0].firstChild.nodeValue), |
|
lat = parseFloat(point.getAttribute('lat')), |
|
lng = parseFloat(point.getAttribute('lon')), |
|
ts = d3.isoParse(point.getElementsByTagName('time')[0].firstChild.nodeValue); |
|
|
|
data.push({ 'lat': lat, 'lon': lng, 'ele': ele, 'ts': ts }); |
|
} |
|
|
|
for (i = 0; i < wpts.length; i++) { |
|
var wpt = wpts[i], |
|
lat = parseFloat(wpt.getAttribute('lat')), |
|
lng = parseFloat(wpt.getAttribute('lon')), |
|
name = wpt.getElementsByTagName('name')[0].firstChild.nodeValue, |
|
desc = wpt.getElementsByTagName('desc')[0].firstChild.nodeValue, |
|
type = wpt.getElementsByTagName('type')[0].firstChild.nodeValue, |
|
ts = d3.isoParse(wpt.getElementsByTagName('time')[0].firstChild.nodeValue); |
|
|
|
waypoints.push({ 'lat |