@@ -19,10 +19,13 @@ import {
1919 routePointLayer ,
2020 routePointSymbolLayer ,
2121 routeLineLayer ,
22+ routableTilesLayer ,
2223} from "./map-style" ;
2324import PinMarker from "./components/PinMarker" ;
2425import calculatePlan , { geometryToGeoJSON } from "./planner" ;
2526import { queryEntrances , ElementWithCoordinates } from "./overpass" ;
27+ import routableTilesToGeoJSON from "./RoutableTilesToGeoJSON" ;
28+ import { getVisibleTiles } from "./minimal-xyz-viewer" ;
2629import "./App.css" ;
2730
2831interface State {
@@ -31,6 +34,7 @@ interface State {
3134 destination : ElementWithCoordinates ;
3235 entrances : Array < ElementWithCoordinates > ;
3336 route : FeatureCollection ;
37+ routableTiles : Map < string , FeatureCollection | null > ;
3438}
3539
3640const latLngToDestination = (
@@ -59,6 +63,7 @@ const initialState: State = {
5963 bearing : 0 ,
6064 pitch : 0 ,
6165 } ,
66+ routableTiles : new Map ( ) ,
6267} ;
6368
6469const transformRequest = ( originalURL ?: string ) : MapRequest => {
@@ -115,6 +120,69 @@ const App: React.FC = () => {
115120
116121 const [ state , setState ] = useState ( initialState ) ;
117122
123+ useEffect ( ( ) => {
124+ if (
125+ ! state . viewport . zoom ||
126+ ! state . viewport . width ||
127+ ! state . viewport . height
128+ ) {
129+ return ; // Nothing to do yet
130+ }
131+ if ( state . viewport . zoom < 12 ) return ; // minzoom
132+
133+ const zoomOffset = 1 ;
134+ const zoomMultiplier = 2 ** ( 14 - zoomOffset ) - state . viewport . zoom ;
135+ const visibleTiles = getVisibleTiles (
136+ zoomMultiplier * state . viewport . width ,
137+ zoomMultiplier * state . viewport . height ,
138+ [ state . viewport . longitude , state . viewport . latitude ] ,
139+ 14
140+ ) ;
141+
142+ // Initialise the new Map with nulls and available tiles from previous
143+ const routableTiles = new Map ( ) ;
144+ visibleTiles . forEach ( ( { x, y } ) => {
145+ const key = `${ x } -${ y } ` ;
146+ routableTiles . set ( key , state . routableTiles . get ( key ) || null ) ;
147+ } ) ;
148+
149+ setState (
150+ ( prevState : State ) : State => {
151+ return {
152+ ...prevState ,
153+ routableTiles,
154+ } ;
155+ }
156+ ) ;
157+
158+ visibleTiles . map ( async ( { x, y } ) => {
159+ const key = `${ x } -${ y } ` ;
160+ if ( routableTiles . get ( key ) !== null ) return ; // We already have the tile
161+ // fetch tile
162+ const response = await fetch (
163+ `https://tile.olmap.org/routable-tiles/14/${ x } /${ y } `
164+ ) ;
165+ const body = await response . json ( ) ;
166+ // convert to geojson
167+ const geoJSON = routableTilesToGeoJSON ( body ) as FeatureCollection ;
168+ // add to tiles if still needed based on latest state
169+ setState (
170+ ( prevState : State ) : State => {
171+ if ( prevState . routableTiles . get ( key ) !== null ) {
172+ return prevState ; // This tile is not needed anymore
173+ }
174+ const newRoutableTiles = new Map ( prevState . routableTiles ) ;
175+ newRoutableTiles . set ( key , geoJSON ) ;
176+ return {
177+ ...prevState ,
178+ routableTiles : newRoutableTiles ,
179+ } ;
180+ }
181+ ) ;
182+ } ) ;
183+ } , [ state . viewport ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
184+ // XXX: state.routableTiles is missing above as we only use it as a cache here
185+
118186 useEffect ( ( ) => {
119187 if ( urlMatch ) {
120188 const origin = parseLatLng ( urlMatch . params . from ) ;
@@ -313,6 +381,24 @@ const App: React.FC = () => {
313381 }
314382 } }
315383 />
384+ { Array . from (
385+ state . routableTiles . entries ( ) ,
386+ ( [ coords , tile ] ) =>
387+ tile && (
388+ < Source
389+ key = { coords }
390+ id = { `source-${ coords } ` }
391+ type = "geojson"
392+ data = { tile }
393+ >
394+ < Layer
395+ // eslint-disable-next-line react/jsx-props-no-spreading
396+ { ...routableTilesLayer }
397+ id = { coords }
398+ />
399+ </ Source >
400+ )
401+ ) }
316402 < Source type = "geojson" data = { state . route } >
317403 < Layer
318404 // eslint-disable-next-line react/jsx-props-no-spreading
@@ -327,6 +413,7 @@ const App: React.FC = () => {
327413 { ...routePointSymbolLayer }
328414 />
329415 </ Source >
416+
330417 < PinMarker
331418 marker = { {
332419 draggable : true ,
0 commit comments