diff --git a/site/src/components/Explore.svelte b/site/src/components/Explore.svelte index 805aa1a..f270b86 100644 --- a/site/src/components/Explore.svelte +++ b/site/src/components/Explore.svelte @@ -133,31 +133,15 @@ }))}; } - function _heatGeoJSON(ts: Track[]) { - const features: any[] = []; - for (const t of ts) - for (const [lng, lat] of t.coords) - if (_inBbox(lng, lat)) - features.push({ type: 'Feature', geometry: { type: 'Point', coordinates: [lng, lat] }, properties: { type: t.type } }); - return { type: 'FeatureCollection', features }; - } - function _empty() { return { type: 'FeatureCollection', features: [] }; } - function _hexRgb(hex: string): [number,number,number] { - const m = hex.match(/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i); - return m ? [parseInt(m[1],16), parseInt(m[2],16), parseInt(m[3],16)] : [160,160,160]; - } - function _updateMap(filtered: Track[], view: string, heatMode: string) { const linesSrc = map.getSource('explore-lines'); - const heatSrc = map.getSource('explore-heat'); - if (!linesSrc || !heatSrc) return; + if (!linesSrc) return; - linesSrc.setData(view === 'lines' ? _linesGeoJSON(filtered) : _empty()); - heatSrc.setData(view === 'heatmap' ? _heatGeoJSON(filtered) : _empty()); + linesSrc.setData(_linesGeoJSON(filtered)); - map.setLayoutProperty('explore-lines', 'visibility', view === 'lines' ? 'visible' : 'none'); + map.setLayoutProperty('explore-lines', 'visibility', view === 'lines' ? 'visible' : 'none'); map.setLayoutProperty('explore-heat-global', 'visibility', view === 'heatmap' && heatMode === 'global' ? 'visible' : 'none'); for (const t of HEAT_TYPES) map.setLayoutProperty(`explore-heat-${t}`, 'visibility', view === 'heatmap' && heatMode === 'bytype' ? 'visible' : 'none'); @@ -195,9 +179,8 @@ map.on('load', () => { map.addSource('explore-lines', { type: 'geojson', data: _empty() }); - map.addSource('explore-heat', { type: 'geojson', data: _empty() }); - // Lines layer — color by type + // Normal lines — color by type, readable opacity map.addLayer({ id: 'explore-lines', type: 'line', source: 'explore-lines', layout: { visibility: 'none' }, paint: { 'line-width': 2, 'line-opacity': 0.5, 'line-color': ['match', ['get', 'type'], @@ -207,23 +190,16 @@ }, }); - // Global heatmap - map.addLayer({ id: 'explore-heat-global', type: 'heatmap', source: 'explore-heat', layout: { visibility: 'none' }, - paint: { 'heatmap-radius': 14, 'heatmap-opacity': 0.85, - 'heatmap-color': ['interpolate', ['linear'], ['heatmap-density'], - 0, 'rgba(0,0,0,0)', 0.2, '#4ade80', 0.5, '#facc15', 0.8, '#f97316', 1, '#ef4444'], - }, + // Global heatmap — all lines in warm amber, very low opacity so overlapping routes stack up + map.addLayer({ id: 'explore-heat-global', type: 'line', source: 'explore-lines', layout: { visibility: 'none' }, + paint: { 'line-width': 2, 'line-opacity': 0.08, 'line-blur': 0.5, 'line-color': '#f97316' }, }); - // Per-type heatmap layers + // Per-type heatmap layers — same accumulation trick, type-specific colour for (const [type, hex] of Object.entries(TYPE_COLORS)) { - const [r,g,b] = _hexRgb(hex); - map.addLayer({ id: `explore-heat-${type}`, type: 'heatmap', source: 'explore-heat', + map.addLayer({ id: `explore-heat-${type}`, type: 'line', source: 'explore-lines', filter: ['==', ['get', 'type'], type], layout: { visibility: 'none' }, - paint: { 'heatmap-radius': 14, 'heatmap-opacity': 0.85, - 'heatmap-color': ['interpolate', ['linear'], ['heatmap-density'], - 0, `rgba(${r},${g},${b},0)`, 0.3, `rgba(${r},${g},${b},0.4)`, 1, `rgba(${r},${g},${b},1)`], - }, + paint: { 'line-width': 2, 'line-opacity': 0.1, 'line-blur': 0.5, 'line-color': hex }, }); }