Add map-frontend (nginx + MapLibre GL), make pmtiles internal-only
- map-frontend: nginx serves MapLibre GL static app, proxies /tiles/ to pmtiles internally - pmtiles: remove host port binding (internal to npm-network only), update public-url - 5 themes: light, dark, grayscale, white, black
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
services:
|
||||
map-frontend:
|
||||
image: nginx:alpine
|
||||
container_name: map-frontend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8087:80"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
- ./html:/usr/share/nginx/html:ro
|
||||
networks:
|
||||
- npm-network
|
||||
|
||||
networks:
|
||||
npm-network:
|
||||
external: true
|
||||
@@ -0,0 +1,112 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Maps</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.css">
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
html, body { height: 100%; }
|
||||
#map { width: 100%; height: 100vh; }
|
||||
|
||||
#theme-control {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#theme-control select {
|
||||
appearance: none;
|
||||
background: #fff;
|
||||
border: 1px solid rgba(0,0,0,0.2);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.15);
|
||||
cursor: pointer;
|
||||
font-family: system-ui, sans-serif;
|
||||
font-size: 13px;
|
||||
padding: 6px 28px 6px 10px;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23666'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px center;
|
||||
}
|
||||
|
||||
#theme-control select.dark {
|
||||
background-color: #1a1a1a;
|
||||
color: #eee;
|
||||
border-color: rgba(255,255,255,0.2);
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23aaa'/%3E%3C/svg%3E");
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<div id="theme-control">
|
||||
<select id="theme">
|
||||
<option value="light">Light</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="grayscale">Grayscale</option>
|
||||
<option value="white">White</option>
|
||||
<option value="black">Black</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/maplibre-gl@4/dist/maplibre-gl.js"></script>
|
||||
<script type="module">
|
||||
import { layers, namedFlavor } from 'https://esm.sh/@protomaps/basemaps@4';
|
||||
|
||||
const TILESET = 'north-america';
|
||||
|
||||
function buildStyle(theme) {
|
||||
return {
|
||||
version: 8,
|
||||
glyphs: 'https://protomaps.github.io/basemaps-assets/fonts/{fontstack}/{range}.pbf',
|
||||
sprite: `https://protomaps.github.io/basemaps-assets/sprites/v4/${theme}`,
|
||||
sources: {
|
||||
protomaps: {
|
||||
type: 'vector',
|
||||
tiles: [`${window.location.origin}/tiles/${TILESET}/{z}/{x}/{y}.mvt`],
|
||||
minzoom: 0,
|
||||
maxzoom: 15,
|
||||
attribution: '© <a href="https://openstreetmap.org">OpenStreetMap</a>'
|
||||
}
|
||||
},
|
||||
layers: layers('protomaps', namedFlavor(theme), { lang: 'en' })
|
||||
};
|
||||
}
|
||||
|
||||
const map = new maplibregl.Map({
|
||||
container: 'map',
|
||||
style: buildStyle('light'),
|
||||
center: [-98, 39],
|
||||
zoom: 4
|
||||
});
|
||||
|
||||
map.addControl(new maplibregl.NavigationControl(), 'top-right');
|
||||
map.addControl(new maplibregl.ScaleControl(), 'bottom-left');
|
||||
map.addControl(new maplibregl.FullscreenControl(), 'top-right');
|
||||
map.addControl(new maplibregl.GeolocateControl({
|
||||
positionOptions: { enableHighAccuracy: true },
|
||||
trackUserLocation: true
|
||||
}), 'top-right');
|
||||
|
||||
const themeSelect = document.getElementById('theme');
|
||||
|
||||
themeSelect.addEventListener('change', e => {
|
||||
const theme = e.target.value;
|
||||
const { lng, lat } = map.getCenter();
|
||||
const zoom = map.getZoom();
|
||||
const bearing = map.getBearing();
|
||||
const pitch = map.getPitch();
|
||||
|
||||
themeSelect.className = (theme === 'dark' || theme === 'black') ? 'dark' : '';
|
||||
|
||||
map.setStyle(buildStyle(theme));
|
||||
map.once('styledata', () => {
|
||||
map.jumpTo({ center: [lng, lat], zoom, bearing, pitch });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,18 @@
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
# Proxy tile requests to the internal pmtiles server
|
||||
location /tiles/ {
|
||||
proxy_pass http://pmtiles:8080/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Serve the static frontend
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@ services:
|
||||
image: protomaps/go-pmtiles:latest
|
||||
container_name: pmtiles
|
||||
restart: unless-stopped
|
||||
command: serve /data --port=8080 --cors=* --public-url=https://maps.kolpacksoftware.com/
|
||||
ports:
|
||||
- "8086:8080"
|
||||
command: serve /data --port=8080 --cors=* --public-url=https://maps.kolpacksoftware.com/tiles/
|
||||
volumes:
|
||||
- /mnt/nas_library/pmtiles/data:/data
|
||||
networks:
|
||||
|
||||
Reference in New Issue
Block a user