Skip to content

Commit

Permalink
feat(taui): Drop Browsochrones, use new data format
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Does not work with old data formats
  • Loading branch information
trevorgerhardt committed Feb 5, 2018
1 parent cdd4cd5 commit f17f17c
Show file tree
Hide file tree
Showing 31 changed files with 970 additions and 974 deletions.
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,13 @@
},
"dependencies": {
"@conveyal/lonlat": "^1.1.1",
"@conveyal/woonerf": "^2.3.0",
"browsochrones": "^0.9.1",
"@conveyal/woonerf": "^3.0.0",
"color": "^1.0.3",
"date-fns": "^1.28.5",
"debug": "^2.6.8",
"font-awesome": "^4.6.3",
"isomorphic-fetch": "^2.2.1",
"isomorphic-mapzen-search": "^1.2.0",
"jsolines": "^1.0.2",
"leaflet": "^0.7.7",
"leaflet-transitivelayer": "^0.2.0",
"lodash": "^4.17.4",
Expand Down
136 changes: 0 additions & 136 deletions src/actions/browsochrones.js

This file was deleted.

183 changes: 183 additions & 0 deletions src/actions/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// @flow
import lonlat from '@conveyal/lonlat'
import fetch, {fetchMultiple} from '@conveyal/woonerf/fetch'
import Leaflet from 'leaflet'

import {ACCESSIBILITY_IS_EMPTY, ACCESSIBILITY_IS_LOADING} from '../constants'
import geocode from './geocode'
import {getAsObject as getHash} from '../utils/hash'

import {
setEnd,
setOrigin,
setStart,
updateMap
} from '../actions'
import {loadGrid} from './grid'

import type {LonLat} from '../types'

const setQuery = (query) => ({type: 'set query', payload: query})

export function initialize () {
return (dispatch: Dispatch, getState: any) => {
const state = getState()
const qs = getHash()
const origins = state.data.origins

const currentZoom = qs.zoom ? parseInt(qs.zoom, 10) : 11
dispatch(updateMap({zoom: currentZoom}))

origins.map((origin) => {
dispatch(
qs.start
? setOrigin({name: origin.name, accessibility: ACCESSIBILITY_IS_LOADING})
: setOrigin({name: origin.name, accessibility: ACCESSIBILITY_IS_EMPTY})
)
})

state.data.grids.map((grid) => {
dispatch(loadGrid(grid.name, state.data.gridsUrl))
})

if (qs.start) {
dispatch(setStart({label: qs.start}))
dispatch(geocode(qs.start, (feature) => {
const originLonlat = lonlat(feature.center)
dispatch(setStart({
label: qs.start,
position: originLonlat
}))

dispatch(loadOrigins(origins, originLonlat, currentZoom))
}))
} else {
dispatch(loadOrigins(origins))
if (qs.end) {
dispatch(setEnd({label: qs.end}))
dispatch(geocode(qs.end, (feature) => {
dispatch([
setEnd({
label: qs.end,
position: lonlat(feature.center)
}),
updateMap({centerCoordinates: lonlat.toLeaflet(feature.center)})
])
}))
}
}
}
}

const loadOrigins = (origins, originLonlat?: LonLat, currentZoom?: number) =>
origins.map(origin => loadOrigin(origin, originLonlat, currentZoom))

const loadOrigin = (origin, originLonlat?: LonLat, currentZoom?: number) =>
fetch({
url: `${origin.url}/query.json`,
next (response) {
const query = response.value

if (originLonlat && currentZoom) {
return [
setQuery(query),
fetchDataForOrigin({...origin, query}, originLonlat, currentZoom)
]
} else {
return [
setQuery(query),
setOrigin({
...origin,
query
})
]
}
}
})

export const fetchDataForLonLat = (originLonLat: LonLat) =>
(dispatch: Dispatch, getState: any) => {
const state = getState()
const currentZoom = state.map.zoom
dispatch(state.data.origins.map(origin =>
fetchDataForOrigin(origin, originLonLat, currentZoom)))
}

const fetchDataForOrigin = (origin, originLonlat, currentZoom) => {
const originPoint = getOriginPoint(originLonlat, currentZoom, origin.query)
const originIndex = originPoint.x + originPoint.y * origin.query.width
return fetchMultiple({
fetches: [{
url: `${origin.url}/${originIndex}_times.dat`
}, {
url: `${origin.url}/${originIndex}_paths.dat`
}],
next: ([timesResponse, pathsResponse]) =>
setOrigin({
...origin,
originPoint,
travelTimeSurface: parseTimes(timesResponse.value),
paths: parsePaths(pathsResponse.value)
})
})
}

function getOriginPoint (originLonlat, currentZoom: number, query) {
const pixel = Leaflet.CRS.EPSG3857.latLngToPoint(
lonlat.toLeaflet(originLonlat),
currentZoom
)
const scale = Math.pow(2, query.zoom - currentZoom)

let {x, y} = pixel
x = x * scale - query.west | 0
y = y * scale - query.north | 0

return {x, y}
}

const TIMES_GRID_TYPE = 'ACCESSGR'
const TIMES_HEADER_LENGTH = 9

function parseTimes (ab: ArrayBuffer) {
const data = new Int32Array(ab)
const headerData = new Int8Array(ab)
const header = {}
header.type = String.fromCharCode(...headerData.slice(0, TIMES_GRID_TYPE.length))

if (header.type !== TIMES_GRID_TYPE) {
throw new Error(`Retrieved grid header ${header.type} !== ${TIMES_GRID_TYPE}. Please check your data.`)
}

let offset = 2
const version = data[offset++]
const zoom = data[offset++]
const west = data[offset++]
const north = data[offset++]
const width = data[offset++]
const height = data[offset++]
const nSamples = data[offset++]

return {
version,
zoom,
west,
north,
width,
height,
nSamples,
data: data.slice(TIMES_HEADER_LENGTH)
}
}

const PATHS_GRID_TYPE = 'PATHGRID'
const PATHS_HEADER_LENGTH = 2

function parsePaths (ab: ArrayBuffer) {
const data = new Int32Array(ab)
const headerData = new Int8Array(ab)

return {
data:
}
}
34 changes: 34 additions & 0 deletions src/actions/geocode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// @flow
import lonlat from '@conveyal/lonlat'
import fetch from '@conveyal/woonerf/fetch'

import {MAPBOX_GEOCODING_URL} from '../constants'

import type {LonLat} from '../types'

/**
* Format URL for fetching with query parameters
*/
function formatURL (text: string, opts) {
opts.access_token = process.env.MAPBOX_ACCESS_TOKEN
const queryParams = Object.keys(opts).map(k => `${k}=${opts[k]}`).join('&')
return `${MAPBOX_GEOCODING_URL}/${text}.json?${queryParams}`
}

/**
* Create an action that dispatches the given action on success.
*/
export default function geocode (text: string, nextAction: any) {
return function (dispatch: Dispatch, getState: any) {
const state = getState()
const {geocoder} = state

dispatch(fetch({
url: formatURL(text, geocoder),
next: (response) => nextAction(JSON.parse(response.value).features[0]) // Content-Type is application/vnd.geo+json so woonerf/fetch parses as text
}))
}
}

export const reverse = (position: LonLat, nextAction: any) =>
geocode(lonlat.toString(position), nextAction)
Loading

0 comments on commit f17f17c

Please sign in to comment.