// MapLibre-GL-Style für die zentrale Karte — gerendert aus unseren DACH-PMTiles // (OpenMapTiles-Schema). GPU + Worker → performant auf dem Handy (Ziel der Migration). // GEOMETRIE-ONLY (keine Symbol/Text-Layer) → KEINE Glyphs/Fonts nötig für den ersten // Perf-Test. Labels (mit Glyph-Hosting) kommen in M3, wenn die Performance steht. (function () { 'use strict'; var TILES_FILE = 'dach.pmtiles'; function tilesUrl() { return window.location.origin + '/tiles/' + TILES_FILE; } var THEMES = { light: { bg: '#f4f1ec', land: '#dce8c8', park: '#c8e6b0', water: '#a0c8f0', road: '#ffffff', roadCasing: '#d9cfc2', building: '#e6ddcf', buildingLine: '#d4cabb', boundary: '#b08ac0', path: '#c19a86', label: '#33312e', roadLabel: '#6b6357', waterLabel: '#4a78a8', poiLabel: '#5c5346', labelHalo: 'rgba(255,255,255,0.9)', }, dark: { bg: '#1a1d21', land: '#222820', park: '#27331f', water: '#16242e', road: '#3a4046', roadCasing: '#23282d', building: '#262b30', buildingLine: '#31373d', boundary: '#7d5a8c', path: '#5a4f47', label: '#d6d9dd', roadLabel: '#9aa0a6', waterLabel: '#6fa0cc', poiLabel: '#b7ad9e', labelHalo: 'rgba(0,0,0,0.8)', }, }; var FONT = ['Open Sans Regular']; // Liefert ein MapLibre-Style-JSON (Version 8) ohne glyphs/sprite. function build(opts) { opts = opts || {}; var t = THEMES[opts.dark ? 'dark' : 'light']; return { version: 8, glyphs: window.location.origin + '/fonts/{fontstack}/{range}.pbf', sources: { by: { type: 'vector', url: 'pmtiles://' + tilesUrl() }, }, layers: [ { id: 'bg', type: 'background', paint: { 'background-color': t.bg } }, { id: 'landcover', type: 'fill', source: 'by', 'source-layer': 'landcover', paint: { 'fill-color': t.land, 'fill-opacity': 0.55 } }, { id: 'park', type: 'fill', source: 'by', 'source-layer': 'park', paint: { 'fill-color': t.park, 'fill-opacity': 0.5 } }, { id: 'water', type: 'fill', source: 'by', 'source-layer': 'water', paint: { 'fill-color': t.water } }, { id: 'waterway', type: 'line', source: 'by', 'source-layer': 'waterway', paint: { 'line-color': t.water, 'line-width': 1 } }, // Pfade/Wege/Tracks: dünn + gestrichelt (NICHT wie Straßen). { id: 'paths', type: 'line', source: 'by', 'source-layer': 'transportation', minzoom: 13, filter: ['in', ['get', 'class'], ['literal', ['path', 'track']]], paint: { 'line-color': t.path, 'line-dasharray': [1.8, 1.8], 'line-width': ['interpolate', ['linear'], ['zoom'], 13, 0.6, 16, 1.2, 19, 2] } }, // Straßen-Casing (nur echte Straßen, Breite nach Klasse). { id: 'road-casing', type: 'line', source: 'by', 'source-layer': 'transportation', minzoom: 11, filter: ['!', ['in', ['get', 'class'], ['literal', ['path', 'track', 'ferry', 'rail', 'transit', 'aerialway']]]], paint: { 'line-color': t.roadCasing, 'line-width': ['interpolate', ['linear'], ['zoom'], 11, ['match', ['get', 'class'], ['motorway', 'trunk'], 3, ['primary', 'secondary'], 2.2, 1.6], 16, ['match', ['get', 'class'], ['motorway', 'trunk'], 8, ['primary', 'secondary'], 6, 4.5]] } }, // Straßen-Füllung. { id: 'roads', type: 'line', source: 'by', 'source-layer': 'transportation', filter: ['!', ['in', ['get', 'class'], ['literal', ['path', 'track', 'ferry', 'rail', 'transit', 'aerialway']]]], paint: { 'line-color': t.road, 'line-width': ['interpolate', ['linear'], ['zoom'], 6, ['match', ['get', 'class'], ['motorway', 'trunk'], 1.4, 0.4], 12, ['match', ['get', 'class'], ['motorway', 'trunk', 'primary'], 2.4, 1.1], 16, ['match', ['get', 'class'], ['motorway', 'trunk'], 6, ['primary', 'secondary'], 4.5, 3]] } }, { id: 'buildings', type: 'fill', source: 'by', 'source-layer': 'building', minzoom: 13, paint: { 'fill-color': t.building, 'fill-outline-color': t.buildingLine } }, { id: 'boundary', type: 'line', source: 'by', 'source-layer': 'boundary', paint: { 'line-color': t.boundary, 'line-dasharray': [2, 2], 'line-width': 1 } }, // ---- Labels (brauchen glyphs). Reihenfolge = Kollisions-Priorität (zuerst = wichtiger). ---- // Ortsnamen (Städte/Dörfer) zuerst — höchste Priorität, auch bei kleinem Zoom. { id: 'place-labels', type: 'symbol', source: 'by', 'source-layer': 'place', filter: ['in', ['get', 'class'], ['literal', ['city', 'town', 'village', 'suburb', 'hamlet', 'neighbourhood']]], layout: { 'text-field': ['coalesce', ['get', 'name:de'], ['get', 'name']], 'text-font': FONT, 'text-max-width': 8, 'text-anchor': 'center', 'text-size': ['interpolate', ['linear'], ['zoom'], 4, 10, 8, 12, 12, 14, 16, 17], }, paint: { 'text-color': t.label, 'text-halo-color': t.labelHalo, 'text-halo-width': 1.6 } }, { id: 'water-labels', type: 'symbol', source: 'by', 'source-layer': 'water_name', layout: { 'text-field': ['coalesce', ['get', 'name:de'], ['get', 'name']], 'text-font': FONT, 'text-size': 12, 'text-max-width': 6 }, paint: { 'text-color': t.waterLabel, 'text-halo-color': t.labelHalo, 'text-halo-width': 1.2 } }, { id: 'street-labels', type: 'symbol', source: 'by', 'source-layer': 'transportation_name', minzoom: 14, layout: { 'text-field': ['coalesce', ['get', 'name:de'], ['get', 'name']], 'text-font': FONT, 'symbol-placement': 'line', 'text-size': 11 }, paint: { 'text-color': t.roadLabel, 'text-halo-color': t.labelHalo, 'text-halo-width': 1.2 } }, // POI-Namen (Kinderspielplatz, Schule, …) ab Z15 — Kollisionserkennung verhindert Überladung. { id: 'poi-labels', type: 'symbol', source: 'by', 'source-layer': 'poi', minzoom: 15, layout: { 'text-field': ['coalesce', ['get', 'name:de'], ['get', 'name']], 'text-font': FONT, 'text-size': 11, 'text-max-width': 8, 'text-anchor': 'top', 'text-offset': [0, 0.4], 'symbol-sort-key': ['get', 'rank'], }, paint: { 'text-color': t.poiLabel, 'text-halo-color': t.labelHalo, 'text-halo-width': 1.2 } }, // Hausnummern ab Z17 (niedrigste Priorität). { id: 'housenumbers', type: 'symbol', source: 'by', 'source-layer': 'housenumber', minzoom: 17, layout: { 'text-field': ['get', 'housenumber'], 'text-font': FONT, 'text-size': 9.5 }, paint: { 'text-color': t.roadLabel, 'text-halo-color': t.labelHalo, 'text-halo-width': 1 } }, ], }; } window.MapGLStyle = { build: build, tilesUrl: tilesUrl, tilesFile: TILES_FILE }; })();