-
Notifications
You must be signed in to change notification settings - Fork 0
/
script.js
108 lines (98 loc) · 3.14 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
(function init() {
let svg;
let projection;
renderSFMap()
.then(() => {
renderRoutes();
renderVehicles();
updateLocations();
});
}());
function renderSFMap() {
return new Promise((resolve, reject) => {
const width = 720;
const height = 700;
const offset = [width / 2, height / 2];
// DISCLAIMER: scale and translate calculations referenced from 3rd party
projection = d3.geoMercator()
.scale(160000)
.translate(offset)
.center([-122.43, 37.75]);
svg = d3.select('body')
.append('svg')
.attr('height', height)
.attr('width', width)
.attr('viewBox', '0 140 650 450');
const path = d3.geoPath().projection(projection);
d3.selectAll('path').attr('d', path);
d3.json('sfmaps/neighborhoods.json', (neighborhoods) => {
svg.append('g')
.attr('id', 'neighborhoods')
.selectAll('path')
.data(neighborhoods.features)
.enter()
.append('path')
.attr('id', data => data.properties.neighborho)
.attr('d', path);
// return promise as SVG
resolve(svg);
});
});
}
function renderVehicles() {
//TODO: remove hardcoded route and t.
const VEHICLESURL = 'http://webservices.nextbus.com/service/publicJSONFeed?command=vehicleLocations&a=sf-muni&r=N&t=1144953500233';
const xhr = new XMLHttpRequest();
const url = VEHICLESURL;
xhr.open('GET', url);
xhr.send();
xhr.onload = function () {
if ((xhr.readyState === xhr.DONE) && (xhr.status === 200)) {
const vehicles = JSON.parse(xhr.response).vehicle;
const g = svg.insert('g', '#neighborhoods + *')
.attr('id', 'vehicles');
//TODO: remove vehicle's previous position. In the absence of an animating marker,
// I am appending to svg as opposed to overwriting markers. This is to show that the
// data does update.
const circles = g.selectAll('circle')
.data(vehicles)
.enter()
.append('circle');
const circleAttributes = circles
.attr('cx', data => projection([data.lon, data.lat])[0])
.attr('cy', data => projection([data.lon, data.lat])[1])
.attr('r', 4)
.style('fill', 'yellow');
}
};
}
function renderRoutes() {
const ROUTESURL = 'http://webservices.nextbus.com/service/publicJSONFeed?command=routeConfig&a=sf-muni&r=N';
const xhr = new XMLHttpRequest();
const url = ROUTESURL;
xhr.open('GET', url);
xhr.send();
xhr.onload = function () {
if ((xhr.readyState === xhr.DONE) && (xhr.status === 200)) {
const stops = JSON.parse(xhr.response).route.stop;
const g = svg.insert('g', '#neighborhoods + *')
.attr('id', 'stops');
const circles = g.selectAll('circle')
.data(stops)
.enter()
.append('circle');
const circleAttributes = circles
.attr('cx', data => projection([data.lon, data.lat])[0])
.attr('cy', data => projection([data.lon, data.lat])[1])
.attr('r', 2)
.style('fill', 'black');
}
};
}
function updateLocations() {
const INTERVAL = 15000;
// update location every 15 seconds
setInterval(() => {
renderVehicles();
}, INTERVAL);
}