app improvements (#258)

* viewer app: improve type safety and visibility of overlay features.

* correct basemap attribution.

* prettier
This commit is contained in:
Brandon Liu
2023-09-27 13:49:40 +08:00
committed by GitHub
parent f378bb97a8
commit 96eb357362
3 changed files with 39 additions and 28 deletions

1
app/package-lock.json generated
View File

@@ -28,6 +28,7 @@
"react-use": "^17.4.0" "react-use": "^17.4.0"
}, },
"devDependencies": { "devDependencies": {
"@maplibre/maplibre-gl-style-spec": "^19.3.1",
"@types/d3-path": "^3.0.0", "@types/d3-path": "^3.0.0",
"@types/d3-scale-chromatic": "^3.0.0", "@types/d3-scale-chromatic": "^3.0.0",
"@types/leaflet": "^1.7.9", "@types/leaflet": "^1.7.9",

View File

@@ -30,6 +30,7 @@
"react-use": "^17.4.0" "react-use": "^17.4.0"
}, },
"devDependencies": { "devDependencies": {
"@maplibre/maplibre-gl-style-spec": "^19.3.1",
"@types/d3-path": "^3.0.0", "@types/d3-path": "^3.0.0",
"@types/d3-scale-chromatic": "^3.0.0", "@types/d3-scale-chromatic": "^3.0.0",
"@types/leaflet": "^1.7.9", "@types/leaflet": "^1.7.9",

View File

@@ -8,10 +8,18 @@ import { MapGeoJSONFeature } from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css"; import "maplibre-gl/dist/maplibre-gl.css";
import { schemeSet3 } from "d3-scale-chromatic"; import { schemeSet3 } from "d3-scale-chromatic";
import base_theme from "protomaps-themes-base"; import base_theme from "protomaps-themes-base";
import {
StyleSpecification,
LayerSpecification,
} from "@maplibre/maplibre-gl-style-spec";
const INITIAL_ZOOM = 0; const INITIAL_ZOOM = 0;
const INITIAL_LNG = 0; const INITIAL_LNG = 0;
const INITIAL_LAT = 0; const INITIAL_LAT = 0;
const BASEMAP_URL =
"https://api.protomaps.com/tiles/v3/{z}/{x}/{y}.mvt?key=1003762824b9687f";
const BASEMAP_ATTRIBUTION =
'Basemap <a href="https://github.com/protomaps/basemaps">Protomaps</a> © <a href="https://openstreetmap.org">OpenStreetMap</a>';
maplibregl.setRTLTextPlugin( maplibregl.setRTLTextPlugin(
"https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js", "https://unpkg.com/@mapbox/mapbox-gl-rtl-text@0.2.3/mapbox-gl-rtl-text.min.js",
@@ -169,14 +177,13 @@ const LayersVisibilityController = (props: {
); );
}; };
const rasterStyle = async (file: PMTiles): Promise<any> => { const rasterStyle = async (file: PMTiles): Promise<StyleSpecification> => {
let header = await file.getHeader(); let header = await file.getHeader();
let metadata = await file.getMetadata(); let metadata = await file.getMetadata();
let layers: any[] = []; let layers: LayerSpecification[] = [];
if (metadata.type !== "baselayer") { if (metadata.type !== "baselayer") {
layers = base_theme("basemap", "black"); layers = base_theme("basemap", "black");
layers[0].paint["background-color"] = "black";
} }
layers.push({ layers.push({
@@ -196,10 +203,9 @@ const rasterStyle = async (file: PMTiles): Promise<any> => {
}, },
basemap: { basemap: {
type: "vector", type: "vector",
tiles: [ tiles: [BASEMAP_URL],
"https://api.protomaps.com/tiles/v3/{z}/{x}/{y}.mvt?key=1003762824b9687f", maxzoom: 15,
], attribution: BASEMAP_ATTRIBUTION,
maxzoom: 14,
}, },
}, },
glyphs: "https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf", glyphs: "https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf",
@@ -207,18 +213,24 @@ const rasterStyle = async (file: PMTiles): Promise<any> => {
}; };
}; };
const vectorStyle = async (file: PMTiles): Promise<any> => { const vectorStyle = async (
file: PMTiles
): Promise<{
style: StyleSpecification;
layersVisibility: LayerVisibility[];
}> => {
let header = await file.getHeader(); let header = await file.getHeader();
let metadata = await file.getMetadata(); let metadata = await file.getMetadata();
let layers: any[] = []; let layers: LayerSpecification[] = [];
let baseOpacity = 0.35;
if (metadata.type !== "baselayer") { if (metadata.type !== "baselayer") {
layers = base_theme("basemap", "black"); layers = base_theme("basemap", "black");
layers[0].paint["background-color"] = "black"; baseOpacity = 0.9;
} }
var tilestats: any; var tilestats: any;
var vector_layers: any; var vector_layers: LayerSpecification[];
if (metadata.json) { if (metadata.json) {
let j = JSON.parse(metadata.json); let j = JSON.parse(metadata.json);
tilestats = j.tilestats; tilestats = j.tilestats;
@@ -240,14 +252,14 @@ const vectorStyle = async (file: PMTiles): Promise<any> => {
"fill-opacity": [ "fill-opacity": [
"case", "case",
["boolean", ["feature-state", "hover"], false], ["boolean", ["feature-state", "hover"], false],
0.35, baseOpacity,
0.2, baseOpacity - 0.15,
], ],
"fill-outline-color": [ "fill-outline-color": [
"case", "case",
["boolean", ["feature-state", "hover"], false], ["boolean", ["feature-state", "hover"], false],
"hsl(0,100%,90%)", "hsl(0,100%,90%)",
"rgba(0,0,0,0)", "rgba(0,0,0,0.2)",
], ],
}, },
filter: ["==", ["geometry-type"], "Polygon"], filter: ["==", ["geometry-type"], "Polygon"],
@@ -287,14 +299,12 @@ const vectorStyle = async (file: PMTiles): Promise<any> => {
} }
} }
for (let layer of layers) { const bounds: [number, number, number, number] = [
if (layer["source-layer"] === "mask" && layer["type"] === "fill") { header.minLon,
layer.paint["fill-color"] = "black"; header.minLat,
layer.paint["fill-opacity"] = 0.8; header.maxLon,
} header.maxLat,
} ];
const bounds = [header.minLon, header.minLat, header.maxLon, header.maxLat];
return { return {
style: { style: {
@@ -309,17 +319,16 @@ const vectorStyle = async (file: PMTiles): Promise<any> => {
}, },
basemap: { basemap: {
type: "vector", type: "vector",
tiles: [ tiles: [BASEMAP_URL],
"https://api.protomaps.com/tiles/v3/{z}/{x}/{y}.mvt?key=1003762824b9687f", maxzoom: 15,
],
maxzoom: 14,
bounds: bounds, bounds: bounds,
attribution: BASEMAP_ATTRIBUTION,
}, },
}, },
glyphs: "https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf", glyphs: "https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf",
layers: layers, layers: layers,
}, },
layersVisibility: vector_layers.map((l: any) => ({ layersVisibility: vector_layers.map((l: LayerSpecification) => ({
id: l.id, id: l.id,
visible: true, visible: true,
})), })),
@@ -455,7 +464,7 @@ function MaplibreMap(props: { file: PMTiles; mapHashPassed: boolean }) {
); );
} }
let style: any; // TODO maplibre types (not any) let style: StyleSpecification;
if ( if (
header.tileType === TileType.Png || header.tileType === TileType.Png ||
header.tileType === TileType.Webp || header.tileType === TileType.Webp ||