From c0b1257b7e19c9204df0edbe1e065e4f37b4b729 Mon Sep 17 00:00:00 2001 From: Brandon Liu Date: Mon, 20 Jan 2025 17:24:23 +0800 Subject: [PATCH] Support tilejson (#364) * refactor to support basemaps TileJSON in addition to PMTiles. * Support TileJSON in addition to PMTiles for basemaps. --- app/src/MapView.tsx | 104 +++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/app/src/MapView.tsx b/app/src/MapView.tsx index c3eb5ab7..513dccf6 100644 --- a/app/src/MapView.tsx +++ b/app/src/MapView.tsx @@ -16,6 +16,7 @@ import { setRTLTextPlugin, } from "maplibre-gl"; import type { + LngLatBoundsLike, MapGeoJSONFeature, MapTouchEvent, StyleSpecification, @@ -299,19 +300,17 @@ function MapLibreView(props: { map.on("idle", () => { setZoom(map.getZoom()); setError(undefined); - memoizedArchive() - ?.getMetadata() - .then((metadata) => { - if (metadata) { - const m = metadata as { - version?: string; - "planetiler:osm:osmosisreplicationtime"?: string; - }; - setTimelinessInfo( - `tiles@${m.version} ${m["planetiler:osm:osmosisreplicationtime"]?.substr(0, 10)}`, - ); - } - }); + archiveInfo().then((i) => { + if (i?.metadata) { + const m = i.metadata as { + version?: string; + "planetiler:osm:osmosisreplicationtime"?: string; + }; + setTimelinessInfo( + `tiles@${m.version} ${m["planetiler:osm:osmosisreplicationtime"]?.substr(0, 10)}`, + ); + } + }); }); const showContextMenu = (e: MapTouchEvent) => { @@ -365,34 +364,51 @@ function MapLibreView(props: { }); // ensure the dropped archive is first added to the protocol - const memoizedArchive = () => { + const archiveInfo = async (): Promise< + { metadata: unknown; bounds: LngLatBoundsLike } | undefined + > => { + if (!props.droppedArchive && props.tiles?.endsWith(".json")) { + const resp = await fetch(props.tiles); + const tileJson = await resp.json(); + return { + metadata: tileJson, + bounds: [ + [tileJson.bounds[0], tileJson.bounds[1]], + [tileJson.bounds[2], tileJson.bounds[3]], + ], + }; + } + const p = protocolRef(); if (p) { - if (props.droppedArchive) { - p.add(props.droppedArchive); - return props.droppedArchive; - } - if (props.tiles) { - let archive = p.tiles.get(props.tiles); + let archive = props.droppedArchive; + if (archive) { + p.add(archive); + } else if (props.tiles) { + archive = p.tiles.get(props.tiles); if (!archive) { archive = new PMTiles(props.tiles); p.add(archive); } - return archive; + } + if (archive) { + const metadata = await archive.getMetadata(); + const header = await archive.getHeader(); + return { + metadata: metadata, + bounds: [ + [header.minLon, header.minLat], + [header.maxLon, header.maxLat], + ], + }; } } }; const fit = async () => { - const header = await memoizedArchive()?.getHeader(); - if (header) { - mapRef?.fitBounds( - [ - [header.minLon, header.minLat], - [header.maxLon, header.maxLat], - ], - { animate: false }, - ); + const bounds = (await archiveInfo())?.bounds; + if (bounds) { + mapRef?.fitBounds(bounds, { animate: false }); } }; @@ -411,22 +427,20 @@ function MapLibreView(props: { const styleMajorVersion = props.npmVersion ? +props.npmVersion.split(".")[0] : STYLE_MAJOR_VERSION; - memoizedArchive() - ?.getMetadata() - .then((m) => { - if (m instanceof Object && "version" in m) { - const tilesetVersion = +(m.version as string).split(".")[0]; - if ( - VERSION_COMPATIBILITY[tilesetVersion].indexOf(styleMajorVersion) < 0 - ) { - setMismatch( - `style v${styleMajorVersion} may not be compatible with tileset v${tilesetVersion}. `, - ); - } else { - setMismatch(""); - } + archiveInfo().then((i) => { + if (i && i.metadata instanceof Object && "version" in i.metadata) { + const tilesetVersion = +(i.metadata.version as string).split(".")[0]; + if ( + VERSION_COMPATIBILITY[tilesetVersion].indexOf(styleMajorVersion) < 0 + ) { + setMismatch( + `style v${styleMajorVersion} may not be compatible with tileset v${tilesetVersion}. `, + ); + } else { + setMismatch(""); } - }); + } + }); }); createEffect(() => {