120 lines
4.4 KiB
HTML
120 lines
4.4 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>The Dark Elite - Maps</title>
|
|
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
|
|
https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.css
|
|
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
|
|
<script src="https://unpkg.com/pmtiles@3.2.1/dist/pmtiles.js"></script>
|
|
<script src="https://unpkg.com/protomaps-themes-base@4.3.0/dist/protomaps-themes-base.js"></script>
|
|
<style>
|
|
body { margin: 0; padding: 0; background: #060708; font-family: system-ui, sans-serif; }
|
|
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
|
|
#header {
|
|
position: absolute; top: 0; left: 0; right: 0; z-index: 10;
|
|
background: rgba(6,7,8,0.85); color: #e5e7eb;
|
|
padding: 10px 16px; border-bottom: 1px solid rgba(34,211,238,0.25);
|
|
display: flex; justify-content: space-between; align-items: center;
|
|
backdrop-filter: blur(8px);
|
|
}
|
|
#header .left { display: flex; gap: 1rem; align-items: center; }
|
|
#header a { color: #9ca3af; text-decoration: none; font-size: 0.85rem; }
|
|
#header a:hover { color: #22d3ee; }
|
|
#header strong { color: #22d3ee; letter-spacing: 0.2em; text-transform: uppercase; font-size: 0.9rem; text-shadow: 0 0 8px rgba(34,211,238,0.4); }
|
|
#layers {
|
|
display: flex; gap: 0.4rem;
|
|
}
|
|
#layers button {
|
|
background: rgba(18,20,24,0.9); color: #e5e7eb;
|
|
border: 1px solid rgba(80,90,100,0.3); border-radius: 4px;
|
|
padding: 0.35rem 0.8rem; font-size: 0.75rem; cursor: pointer;
|
|
letter-spacing: 0.1em; text-transform: uppercase;
|
|
font-family: ui-monospace, monospace;
|
|
}
|
|
#layers button.active {
|
|
border-color: #22d3ee; color: #22d3ee;
|
|
box-shadow: 0 0 12px rgba(34,211,238,0.25);
|
|
}
|
|
#layers button:hover:not(.active) { border-color: rgba(34,211,238,0.5); }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="header">
|
|
<div class="left"><strong>Maps</strong></div>
|
|
<div style="display:flex;gap:0.75rem;align-items:center"><div id="layers">
|
|
<button data-mode="base" class="active">Street</button>
|
|
<button data-mode="terrain">Topo</button>
|
|
</div><a href="/" style="color:#9ca3af;text-decoration:none;font-size:0.85rem">← Hub</a></div>
|
|
</div>
|
|
<div id="map"></div>
|
|
<script>
|
|
const protocol = new pmtiles.Protocol();
|
|
maplibregl.addProtocol("pmtiles", protocol.tile);
|
|
|
|
const map = new maplibregl.Map({
|
|
container: 'map',
|
|
style: {
|
|
version: 8,
|
|
glyphs: 'https://protomaps.github.io/basemaps-assets/fonts/{fontstack}/{range}.pbf',
|
|
sprite: 'https://protomaps.github.io/basemaps-assets/sprites/v4/dark',
|
|
sources: {
|
|
protomaps: { type: 'vector', url: 'pmtiles:///maps/base.pmtiles' },
|
|
terrain: { type: 'raster-dem', url: 'pmtiles:///maps/terrain.pmtiles', tileSize: 512, encoding: 'terrarium', maxzoom: 12 }
|
|
},
|
|
layers: protomaps_themes_base.default('protomaps', 'dark')
|
|
},
|
|
center: [-97.0, 39.0],
|
|
zoom: 4
|
|
});
|
|
|
|
map.addControl(new maplibregl.NavigationControl());
|
|
map.addControl(new maplibregl.ScaleControl());
|
|
|
|
map.on('load', () => {
|
|
// Add hillshade layer (initially hidden)
|
|
map.addLayer({
|
|
id: 'hillshade',
|
|
type: 'hillshade',
|
|
source: 'terrain',
|
|
layout: { visibility: 'none' },
|
|
paint: {
|
|
'hillshade-exaggeration': 0.6,
|
|
'hillshade-shadow-color': '#000000',
|
|
'hillshade-highlight-color': '#ffffff',
|
|
'hillshade-accent-color': '#22d3ee'
|
|
}
|
|
}, map.getStyle().layers[1].id);
|
|
|
|
setMode('base');
|
|
});
|
|
|
|
function setMode(mode) {
|
|
document.querySelectorAll('#layers button').forEach(b => {
|
|
b.classList.toggle('active', b.dataset.mode === mode);
|
|
});
|
|
|
|
const vectorLayers = map.getStyle().layers.filter(l => l.source === 'protomaps').map(l => l.id);
|
|
|
|
if (mode === 'base') {
|
|
map.setLayoutProperty('hillshade', 'visibility', 'none');
|
|
vectorLayers.forEach(id => map.setLayoutProperty(id, 'visibility', 'visible'));
|
|
if (map.getTerrain()) map.setTerrain(null);
|
|
} else if (mode === 'terrain') {
|
|
map.setLayoutProperty('hillshade', 'visibility', 'visible');
|
|
vectorLayers.forEach(id => {
|
|
// Keep only labels and roads visible for context
|
|
const layer = map.getStyle().layers.find(l => l.id === id);
|
|
const keep = layer && (layer.type === 'symbol' || id.includes('roads') || id.includes('water'));
|
|
map.setLayoutProperty(id, 'visibility', keep ? 'visible' : 'none');
|
|
});
|
|
if (map.getTerrain()) map.setTerrain(null);
|
|
}
|
|
}
|
|
|
|
document.querySelectorAll('#layers button').forEach(btn => {
|
|
btn.addEventListener('click', () => setMode(btn.dataset.mode));
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |