Skip to content

Instantly share code, notes, and snippets.

@Rub21
Created October 12, 2026 21:13
Show Gist options
  • Select an option

  • Save Rub21/14112ddb97e26d74ebff8570dc84fdb9 to your computer and use it in GitHub Desktop.

Select an option

Save Rub21/14112ddb97e26d74ebff8570dc84fdb9 to your computer and use it in GitHub Desktop.
ohm non-admin-lines
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OHM non-admin boundary lines</title>
<link rel="stylesheet" href="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>
<style>
html, body, #map { margin: 0; height: 100%; }
body { font: 13px/1.4 system-ui, sans-serif; }
#panel {
position: absolute; top: 10px; left: 10px; z-index: 1;
background: #fff; padding: 10px 12px; border-radius: 6px;
box-shadow: 0 1px 6px rgba(0,0,0,.3); max-height: calc(100% - 40px); overflow: auto;
}
#panel h1 { font-size: 14px; margin: 0 0 6px; }
#panel label { display: flex; align-items: center; gap: 6px; cursor: pointer; }
#types { margin-top: 8px; }
.swatch { width: 18px; height: 4px; border-radius: 2px; flex: none; }
#year { width: 190px; }
.maplibregl-popup-content { font: 12px/1.4 system-ui, sans-serif; }
.maplibregl-popup-content td:first-child { color: #666; padding-right: 8px; }
</style>
</head>
<body>
<div id="map"></div>
<div id="panel">
<h1>Non-admin boundary lines (production)</h1>
<label><input type="checkbox" id="useYear" checked> Filter by year: <b id="yearLabel"></b></label>
<input type="range" id="year" min="1000" max="2026" value="2000">
<div id="types"></div>
</div>
<script>
const TILES = 'https://vtiles.openhistoricalmap.org/maps/ohm/{z}/{x}/{y}';
const TYPES = {
timezone: '#1f78b4',
disputed: '#e31a1c',
religious_administration: '#6a3d9a',
judicial: '#b15928',
postal_code: '#ff7f00',
census: '#33a02c',
political: '#fb9a99',
ceremonial: '#cab2d6',
place: '#a6761d',
statistical: '#66a61e',
protected_area: '#1b9e77',
national_park: '#006d2c',
indigenous_administration: '#e7298a',
aboriginal_lands: '#d95f02',
maritime: '#17becf',
historic: '#7570b3'
};
const OTHER = '#555555';
const map = new maplibregl.Map({
container: 'map',
hash: true,
center: [-100, 45],
zoom: 4,
style: {
version: 8,
sources: {
osm: {
type: 'raster',
tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
maxzoom: 19,
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
},
ohm: {
type: 'vector',
tiles: [TILES],
maxzoom: 16,
attribution: '<a href="https://www.openhistoricalmap.org/copyright">OpenHistoricalMap</a>'
}
},
layers: [
{ id: 'osm', type: 'raster', source: 'osm', paint: { 'raster-opacity': 0.6 } },
{
id: 'non-admin-lines',
type: 'line',
source: 'ohm',
'source-layer': 'land_ohm_lines',
layout: { 'line-cap': 'round', 'line-join': 'round' },
paint: {
'line-width': ['interpolate', ['linear'], ['zoom'], 2, 1, 10, 2.5],
'line-color': ['match', ['get', 'type'], ...Object.entries(TYPES).flat(), OTHER]
}
}
]
}
});
map.addControl(new maplibregl.NavigationControl(), 'top-right');
const hidden = new Set();
const useYear = document.getElementById('useYear');
const year = document.getElementById('year');
const yearLabel = document.getElementById('yearLabel');
function applyFilter() {
yearLabel.textContent = useYear.checked ? year.value : 'all';
year.disabled = !useYear.checked;
if (!map.getLayer('non-admin-lines')) return;
const filter = ['all',
['!=', ['get', 'type'], 'administrative'],
['!', ['in', ['get', 'type'], ['literal', [...hidden]]]]
];
if (useYear.checked) {
const y = Number(year.value);
// Features with no start or end date have no property in the tile.
filter.push(['<', ['coalesce', ['get', 'start_decdate'], -99999], y + 1]);
filter.push(['>=', ['coalesce', ['get', 'end_decdate'], 99999], y]);
}
map.setFilter('non-admin-lines', filter);
}
const typesEl = document.getElementById('types');
for (const [type, color] of [...Object.entries(TYPES), ['other', OTHER]]) {
const label = document.createElement('label');
label.innerHTML = `<input type="checkbox" checked><span class="swatch" style="background:${color}"></span>${type}`;
const input = label.querySelector('input');
if (type === 'other') {
input.disabled = true;
} else {
input.addEventListener('change', () => {
input.checked ? hidden.delete(type) : hidden.add(type);
applyFilter();
});
}
typesEl.appendChild(label);
}
useYear.addEventListener('change', applyFilter);
year.addEventListener('input', applyFilter);
map.on('load', applyFilter);
applyFilter();
map.on('click', 'non-admin-lines', (e) => {
const p = e.features[0].properties;
const rows = ['type', 'admin_level', 'start_date', 'end_date', 'osm_id']
.filter((k) => p[k] !== undefined && p[k] !== '')
.map((k) => `<tr><td>${k}</td><td>${p[k]}</td></tr>`).join('');
const link = `https://www.openhistoricalmap.org/way/${Math.abs(p.osm_id)}`;
new maplibregl.Popup()
.setLngLat(e.lngLat)
.setHTML(`<table>${rows}</table><a href="${link}" target="_blank" rel="noopener">Open way in OHM</a>`)
.addTo(map);
});
map.on('mouseenter', 'non-admin-lines', () => { map.getCanvas().style.cursor = 'pointer'; });
map.on('mouseleave', 'non-admin-lines', () => { map.getCanvas().style.cursor = ''; });
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment