fix: share GPX+journey rendering via MapUtils.renderGpxJourney
The home map was drawing an initial addJourneyLine, then trying to remove layer 'home-journey' in the Promise.all callback — but addJourneyLine names the layer 'home-journey-line', so removeLayer was a no-op and removeSource failed (layer still referencing the source), leaving a ghost line on top of the GPX tracks. Extract the Promise.all → GPX tracks → buildJourneySegments → addJourneySegments pattern into MapUtils.renderGpxJourney() and replace both map.html.twig and home.html.twig with the shared call. No upfront journey line is drawn — the function handles the no-GPX case correctly via Promise.all([]). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
This commit is contained in:
@@ -283,6 +283,42 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetch GPX files, render their raw tracks, then draw journey connector lines
|
||||||
|
* only between entries not covered by any GPX file (connector suppression).
|
||||||
|
*
|
||||||
|
* gpxUrls: array of GPX file URLs to fetch
|
||||||
|
* entries: [{lat, lng, force_connect?}, ...] in chronological order
|
||||||
|
* gpxSourcePrefix: source/layer ID prefix for raw GPX tracks (e.g. 'gpx', 'home-gpx')
|
||||||
|
* journeySourceId: base source ID for connector segments (e.g. 'journey', 'home-journey')
|
||||||
|
*
|
||||||
|
* When gpxUrls is empty, Promise.all resolves immediately → no GPX layers,
|
||||||
|
* buildJourneySegments draws a full connector line between all entries.
|
||||||
|
*/
|
||||||
|
function renderGpxJourney(map, gpxUrls, entries, gpxSourcePrefix, journeySourceId) {
|
||||||
|
Promise.all(gpxUrls.map(function (url, idx) {
|
||||||
|
return fetch(url)
|
||||||
|
.then(function (r) { return r.text(); })
|
||||||
|
.then(function (text) {
|
||||||
|
var xml = new DOMParser().parseFromString(text, 'text/xml');
|
||||||
|
var geojson = toGeoJSON.gpx(xml);
|
||||||
|
var sid = gpxSourcePrefix + '-' + idx;
|
||||||
|
map.addSource(sid, { type: 'geojson', data: geojson });
|
||||||
|
map.addLayer({
|
||||||
|
id: sid + '-line', type: 'line', source: sid,
|
||||||
|
layout: { 'line-join': 'round', 'line-cap': 'round' },
|
||||||
|
paint: { 'line-color': ACCENT, 'line-width': 2, 'line-opacity': 0.7 }
|
||||||
|
});
|
||||||
|
return extractTrackpoints(geojson);
|
||||||
|
})
|
||||||
|
.catch(function (err) { console.warn('GPX load failed:', url, err); return []; });
|
||||||
|
})).then(function (allTrackpoints) {
|
||||||
|
var valid = allTrackpoints.filter(function (tp) { return tp.length > 0; });
|
||||||
|
var segments = buildJourneySegments(entries, valid, 10);
|
||||||
|
addJourneySegments(map, segments, journeySourceId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
global.MapUtils = {
|
global.MapUtils = {
|
||||||
MAP_STYLE: MAP_STYLE,
|
MAP_STYLE: MAP_STYLE,
|
||||||
ACCENT: ACCENT,
|
ACCENT: ACCENT,
|
||||||
@@ -290,6 +326,7 @@
|
|||||||
addJourneySegments: addJourneySegments,
|
addJourneySegments: addJourneySegments,
|
||||||
buildJourneySegments: buildJourneySegments,
|
buildJourneySegments: buildJourneySegments,
|
||||||
extractTrackpoints: extractTrackpoints,
|
extractTrackpoints: extractTrackpoints,
|
||||||
|
renderGpxJourney: renderGpxJourney,
|
||||||
createDotMarker: createDotMarker,
|
createDotMarker: createDotMarker,
|
||||||
createStoryMarker: createStoryMarker
|
createStoryMarker: createStoryMarker
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -184,9 +184,6 @@ homeMap.on('load', function () {
|
|||||||
new maplibregl.Marker({ element: el }).setLngLat(lngLat).addTo(homeMap);
|
new maplibregl.Marker({ element: el }).setLngLat(lngLat).addTo(homeMap);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Draw simple journey line immediately; replaced below if GPX is present */
|
|
||||||
MapUtils.addJourneyLine(homeMap, coords, 'home-journey');
|
|
||||||
|
|
||||||
if (HOME_ENTRIES.length === 1) {
|
if (HOME_ENTRIES.length === 1) {
|
||||||
homeMap.jumpTo({ center: coords[0], zoom: 10 });
|
homeMap.jumpTo({ center: coords[0], zoom: 10 });
|
||||||
} else {
|
} else {
|
||||||
@@ -195,31 +192,7 @@ homeMap.on('load', function () {
|
|||||||
|
|
||||||
setTimeout(function () { homeMap.resize(); }, 100);
|
setTimeout(function () { homeMap.resize(); }, 100);
|
||||||
|
|
||||||
if (HOME_GPX_URLS.length > 0) {
|
MapUtils.renderGpxJourney(homeMap, HOME_GPX_URLS, HOME_ENTRIES, 'home-gpx', 'home-journey');
|
||||||
Promise.all(HOME_GPX_URLS.map(function (url, idx) {
|
|
||||||
return fetch(url)
|
|
||||||
.then(function (r) { return r.text(); })
|
|
||||||
.then(function (text) {
|
|
||||||
var xml = new DOMParser().parseFromString(text, 'text/xml');
|
|
||||||
var geojson = toGeoJSON.gpx(xml);
|
|
||||||
var sid = 'home-gpx-' + idx;
|
|
||||||
homeMap.addSource(sid, { type: 'geojson', data: geojson });
|
|
||||||
homeMap.addLayer({
|
|
||||||
id: sid + '-line', type: 'line', source: sid,
|
|
||||||
layout: { 'line-join': 'round', 'line-cap': 'round' },
|
|
||||||
paint: { 'line-color': MapUtils.ACCENT, 'line-width': 2, 'line-opacity': 0.7 }
|
|
||||||
});
|
|
||||||
return MapUtils.extractTrackpoints(geojson);
|
|
||||||
})
|
|
||||||
.catch(function (err) { console.warn('GPX load failed:', url, err); return []; });
|
|
||||||
})).then(function (allTrackpoints) {
|
|
||||||
if (homeMap.getLayer('home-journey')) homeMap.removeLayer('home-journey');
|
|
||||||
if (homeMap.getSource('home-journey')) homeMap.removeSource('home-journey');
|
|
||||||
var valid = allTrackpoints.filter(function (tp) { return tp.length > 0; });
|
|
||||||
var segments = MapUtils.buildJourneySegments(HOME_ENTRIES, valid, 10);
|
|
||||||
MapUtils.addJourneySegments(homeMap, segments, 'home-journey');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -92,30 +92,7 @@ map.on('load', function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ── GPX tracks + journey segments ─────────────────────────── */
|
/* ── GPX tracks + journey segments ─────────────────────────── */
|
||||||
Promise.all(GPX_URLS.map(function (url, idx) {
|
MapUtils.renderGpxJourney(map, GPX_URLS, ENTRIES, 'gpx', 'journey');
|
||||||
return fetch(url)
|
|
||||||
.then(function (r) { return r.text(); })
|
|
||||||
.then(function (text) {
|
|
||||||
var xml = new DOMParser().parseFromString(text, 'text/xml');
|
|
||||||
var geojson = toGeoJSON.gpx(xml);
|
|
||||||
var sid = 'gpx-' + idx;
|
|
||||||
map.addSource(sid, { type: 'geojson', data: geojson });
|
|
||||||
map.addLayer({
|
|
||||||
id: sid + '-line', type: 'line', source: sid,
|
|
||||||
layout: { 'line-join': 'round', 'line-cap': 'round' },
|
|
||||||
paint: { 'line-color': MapUtils.ACCENT, 'line-width': 2, 'line-opacity': 0.7 }
|
|
||||||
});
|
|
||||||
return MapUtils.extractTrackpoints(geojson);
|
|
||||||
})
|
|
||||||
.catch(function (err) {
|
|
||||||
console.warn('GPX load failed:', url, err);
|
|
||||||
return [];
|
|
||||||
});
|
|
||||||
})).then(function (allTrackpoints) {
|
|
||||||
var validTrackpoints = allTrackpoints.filter(function (tp) { return tp.length > 0; });
|
|
||||||
var segments = MapUtils.buildJourneySegments(ENTRIES, validTrackpoints, 10);
|
|
||||||
MapUtils.addJourneySegments(map, segments, 'journey');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user