diff --git a/app/index.html b/app/index.html index 38f3861..b0fddd7 100644 --- a/app/index.html +++ b/app/index.html @@ -2,9 +2,9 @@ - + - Vite App + PMTiles Viewer
diff --git a/app/src/App.tsx b/app/src/App.tsx index 87f6fc3..fee4008 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -2,15 +2,13 @@ import { useState, useEffect } from "react"; import { styled, globalStyles } from "./stitches.config"; import Start from "./Start"; -import Inspector from "./Inspector"; -import LeafletMap from "./LeafletMap"; -import MaplibreMap from "./MaplibreMap"; +import Loader from "./Loader"; const Header = styled("div", { height: "$4", }); -const GIT_SHA = import.meta.env.VITE_GIT_SHA.substr(0,8) +const GIT_SHA = (import.meta.env.VITE_GIT_SHA || "").substr(0,8) function App() { globalStyles(); @@ -30,7 +28,7 @@ function App() { return (
pmtiles viewer | github | toggle | {GIT_SHA}
- {file ? : } + {file ? : }
); } diff --git a/app/src/Inspector.tsx b/app/src/Inspector.tsx index ed8d352..3623dff 100644 --- a/app/src/Inspector.tsx +++ b/app/src/Inspector.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { PMTiles } from "../../js"; import { styled } from "./stitches.config"; -function Inspector() { +function Inspector(props:{file:string}) { return ( <> foo diff --git a/app/src/LeafletMap.tsx b/app/src/LeafletMap.tsx index c5dc9b8..3b25692 100644 --- a/app/src/LeafletMap.tsx +++ b/app/src/LeafletMap.tsx @@ -8,7 +8,7 @@ const MapContainer = styled("div", { height: "calc(100vh - $4)", }); -function LeafletMap(props:{file:string}) { +function LeafletMap(props:{file:string, tileType: string | null}) { const p = new PMTiles( "https://protomaps-static.sfo3.digitaloceanspaces.com/osm_carto.pmtiles" ); diff --git a/app/src/Loader.tsx b/app/src/Loader.tsx new file mode 100644 index 0000000..7b772e8 --- /dev/null +++ b/app/src/Loader.tsx @@ -0,0 +1,55 @@ +import { useState, useEffect } from "react"; +import { PMTiles } from "../../js"; +import { styled } from "./stitches.config"; + +import Inspector from "./Inspector"; +import LeafletMap from "./LeafletMap"; +import MaplibreMap from "./MaplibreMap"; + +function Loader(props: { file: string }) { + let [tab, setTab] = useState("maplibre"); + let [tileType, setTileType] = useState(null); + + let view; + if (tab === "leaflet") { + view = ; + } else if (tab === "maplibre") { + view = ; + } else { + view = ; + } + + useEffect(() => { + let pmtiles = new PMTiles(props.file); + const fetchData = async () => { + let metadata = await pmtiles.metadata(); + + let resp = await fetch(props.file, { + headers: { Range: "bytes=512000-512003" }, + }); + let magic = new DataView(await resp.arrayBuffer()); + let b0 = magic.getUint8(0); + let b1 = magic.getUint8(1); + let b2 = magic.getUint8(2); + let b3 = magic.getUint8(3); + + if (b0 == 0x89 && b1 == 0x50 && b2 == 0x4e && b3 == 0x47) { + setTileType("png"); + } else if (b0 == 0xff && b1 == 0xd8 && b2 == 0xff && b3 == 0xe0) { + setTileType("jpg") + } else if (b0 == 0x1f && b1 == 0x8b) { + setTileType("mvt.gz"); + } else { + setTileType("mvt"); + } + }; + fetchData(); + }, [props.file]); + + return <> +
{props.file} | {tileType}
+ {view} + ; +} + +export default Loader; diff --git a/app/src/MaplibreMap.tsx b/app/src/MaplibreMap.tsx index bc80511..2e66853 100644 --- a/app/src/MaplibreMap.tsx +++ b/app/src/MaplibreMap.tsx @@ -1,58 +1,87 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useRef } from "react"; import { PMTiles, ProtocolCache } from "../../js"; import { styled } from "./stitches.config"; import maplibregl from "maplibre-gl"; -import "maplibre-gl/dist/maplibre-gl.css" +import "maplibre-gl/dist/maplibre-gl.css"; const MapContainer = styled("div", { height: "calc(100vh - $4)", }); -function MaplibreMap(props:{file:string}) { - let cache = new ProtocolCache(); - maplibregl.addProtocol("pmtiles",cache.protocol); - - var style = { - "version": 8, - "sources": { - "zcta": { - "type": "vector", - "tiles": ["pmtiles://" + props.file + "/{z}/{x}/{y}"], - "maxzoom":7 - } +const rasterStyle = (file:string) => { + return { + version: 8, + sources: { + source: { + type: "raster", + tiles: ["pmtiles://" + file + "/{z}/{x}/{y}"], + maxzoom:4 }, - "layers": [ - { - "id": "zcta_fill", - "type": "fill", - "source":"zcta", - "source-layer":"zcta", - "paint": { - "fill-color":"white" - } - }, - { - "id": "zcta_stroke", - "type": "line", - "source":"zcta", - "source-layer":"zcta", - "paint": { - "line-color":"steelblue", - "line-width":0.5 - } - } - ] - } + }, + layers: [ + { + id: "raster", + type: "raster", + source: "source" + }, + ], + }; +}; +const vectorStyle = (file:string) => { + return { + version: 8, + sources: { + source: { + type: "vector", + tiles: ["pmtiles://" + file + "/{z}/{x}/{y}"], + maxzoom: 7, + }, + }, + layers: [ + { + id: "zcta_fill", + type: "fill", + source: "source", + "source-layer": "zcta", + paint: { + "fill-color": "white", + }, + }, + { + id: "zcta_stroke", + type: "line", + source: "source", + "source-layer": "zcta", + paint: { + "line-color": "steelblue", + "line-width": 0.5, + }, + }, + ], + }; +}; + +function MaplibreMap(props: { file: string, tileType: string | null }) { + let mapRef = useRef(null); useEffect(() => { - const map = new maplibregl.Map({container:"map",zoom:3,center:[-101.43,44.34],style:style as any}); // TODO maplibre types + let cache = new ProtocolCache(); + maplibregl.addProtocol("pmtiles", cache.protocol); + + const map = new maplibregl.Map({ + container: "map", + zoom: 0, + center: [0, 0], + style: rasterStyle(props.file) as any, + }); // TODO maplibre types (not any) + map.on("load", map.resize); return () => { map.remove(); }; }, []); - return ; + return ; } export default MaplibreMap;