Published
Edited
Apr 22, 2018
7 stars
Insert cell
Insert cell
Insert cell
async function fetchXML(params) {
const REVERSE_PROXY = 'https://cors-anywhere.herokuapp.com/'
const API_BASE = 'http://webservices.nextbus.com/service/publicXMLFeed?'
const API_HEADERS = new Headers({'Accept-Encoding':'gzip, deflate'})
try {
let response = await fetch(`${REVERSE_PROXY}${API_BASE}${params}`, {headers: API_HEADERS})
let text = await response.text()
let xml = await (new window.DOMParser()).parseFromString(text, 'text/xml')
return xml
}
catch(e) {
console.error(e)
}
}
Insert cell
Insert cell
(await fetchXML(`command=vehicleLocations&a=sf-muni&r=N&t=0`))
.getElementsByTagName('vehicle')
Insert cell
Insert cell
function fetchInParallel(routeArray) {
return Promise.all(
routeArray.map(route =>
fetchXML(`command=vehicleLocations&a=sf-muni&r=${route}&t=0`)))
}
Insert cell
Insert cell
fetchInParallel(['M', 'N'])
Insert cell
Insert cell
function makeMarkers(routesAndVehiclesXML) {
return routesAndVehiclesXML
.filter(xml => xml.getElementsByTagName('vehicle').length) // filter out any empty routes
.map(route => route.getElementsByTagName('vehicle')) // map each route to vehicles
.map(vehicles => Array.from(vehicles).map(vehicle => ({ // map each vehicle to a map pin object
label: vehicle.getAttribute('routeTag'),
position: {
lat: parseFloat(vehicle.getAttribute('lat')),
lng: parseFloat(vehicle.getAttribute('lon')),
}
})))
}
Insert cell
Insert cell
makeMarkers(await fetchInParallel(['N','M','KT']))
Insert cell
Insert cell
Insert cell
function makeMap() {
return html`
<div style="height: 480px; width: 100%;">
loading... check for red in step three, may need to hit play
</div>
`
}
Insert cell
Insert cell
Insert cell
Insert cell
function makeGoogleMap($map) {
return new GoogleMaps.Map($map, {
zoom: 13,
center: {
lat: 37.7680445,
lng: -122.439697,
},
})
}
Insert cell
Insert cell
SanFrancisco_Map = {
let $map = makeMap()
let mapInstance = makeGoogleMap($map)
return $map
}
Insert cell
Insert cell
Insert cell
async function showRoutesOnMap(routes) {
const $map = makeMap()
const mapInstance = makeGoogleMap($map) // show a map while we're loading data
const xmls = await fetchInParallel(routes) // fetch data as efficiently as possible
const markers = makeMarkers(xmls) // maps our xml to markers for GoogleMaps
// added zest, stagger animate them dropping in
markers.forEach(markers =>
markers.forEach((marker, i) => // map objects to markers
window.setTimeout(() => { // offset creation to create animation
new GoogleMaps.Marker(Object.assign(marker, { // decorate marker with map and animation
map: mapInstance,
animation: GoogleMaps.Animation.DROP
}))
}, i * (500 / markers.length)) // stagger evenly across 500ms
))
return $map
}
Insert cell
Insert cell
Insert cell
showRoutesOnMap(UserInput)
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more