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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more