diff options
| author | Dennis Fink | 2026-07-23 00:18:21 +0200 |
|---|---|---|
| committer | Dennis Fink | 2026-07-23 00:18:21 +0200 |
| commit | 1fe1d13c600b7dfe421b3b99b833b7d5d1232724 (patch) | |
| tree | 2e8636160cc1719c907be56f5ef8cbc7e0f10a53 /assets/static/vendor/leaflet-elevation/src/handlers/runner.js | |
| parent | ca77de06be474dfd712402c327dc436864d233a3 (diff) | |
| download | dennisfink.me-1fe1d13c600b7dfe421b3b99b833b7d5d1232724.tar.gz dennisfink.me-1fe1d13c600b7dfe421b3b99b833b7d5d1232724.zip | |
Add GPX trail maps to blog posts
This adds a trail flow block so posts can include attached GPX files as
interactive maps with route display, elevation charts, activity
summaries, and start/finish markers.
The trail assets are loaded only when needed, keeping the shared
templates clean while vendoring the Leaflet dependencies required for
offline, self-hosted map rendering.
Diffstat (limited to '')
| -rw-r--r-- | assets/static/vendor/leaflet-elevation/src/handlers/runner.js | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/assets/static/vendor/leaflet-elevation/src/handlers/runner.js b/assets/static/vendor/leaflet-elevation/src/handlers/runner.js new file mode 100644 index 0000000..30dd80a --- /dev/null +++ b/assets/static/vendor/leaflet-elevation/src/handlers/runner.js @@ -0,0 +1,109 @@ +/** + * @see https://github.com/Igor-Vladyka/leaflet.motion + * + * @example + * ```js + * L.control.Elevation({ handlers: [ 'Runner' ], runnerOptions: { polyline: {..}, motion: {..}, marker {..} } }) + * ``` + */ +export async function Runner() { + + await this.import(this.__LMOTION || 'https://unpkg.com/leaflet.motion@0.3.2/dist/leaflet.motion.min.js', typeof L.Motion !== 'object') + + let { runnerOptions } = this.options; + + runnerOptions = L.extend( + { polyline: {}, motion: {}, marker: undefined }, + 'object' === typeof runnerOptions ? runnerOptions : {} + ); + + // Custom tooltips + this._registerTooltip({ + name: 'here', + marker: (item) => L._("You are here: "), + order: 1, + }); + + this._registerTooltip({ + name: 'distance', + marker: (item) => Math.round(item.dist) + " " + this.options.xLabel, + order: 2, + }); + + this.addCheckpoint = function (checkpoint) { + return this._registerCheckPoint({ // <-- NB these are private functions use them at your own risk! + latlng: this._findItemForX(this._x(checkpoint.dist)).latlng, + label: checkpoint.label || '' + }); + } + + this.addRunner = function (runner) { + let x = this._x(runner.dist); + let y = this._y(this._findItemForX(x).z) + let g = d3.select(this._container) + .select('svg > g') + .append("svg:circle") + .attr("class", "runner " + this.options.theme + " height-focus circle-lower") + .attr("r", 6) + .attr("cx", x) + .attr("cy", y); + return g; + } + + this.setPositionFromLatLng = function (latlng) { + this._onMouseMoveLayer({ latlng: latlng }); // Update map and chart "markers" from latlng + }; + + this.tick = function (runner, dist = 0, inc = 0.1) { + dist = (dist <= this.track_info.distance - inc) ? dist + inc : 0; + this.updateRunnerPos(runner, dist); + setTimeout(() => this.tick(runner, dist), 150); + }; + + this.updateRunnerPos = function (runner, pos) { + let curr, x; + + if (pos instanceof L.LatLng) { + curr = this._findItemForLatLng(pos); + x = this._x(curr.dist); + } else { + x = this._x(pos); + curr = this._findItemForX(x); + } + + runner + .attr("cx", x) + .attr("cy", this._y(curr.z)); + this.setPositionFromLatLng(curr.latlng); + }; + + this.animate = function (layer, speed = 1500) { + + if (this._runner) { + this._runner.remove(); + } + + layer.setStyle({ opacity: 0.5 }); + + const geo = L.geoJson(layer.toGeoJSON(), { coordsToLatLng: (coords) => L.latLng(coords[0], coords[1], coords[2] * (this.options.altitudeFactor || 1)) }); + this._runner = L.motion.polyline( + geo.toGeoJSON().features[0].geometry.coordinates, + L.extend({}, { color: 'red', pane: 'elevationPane', attribution: '' }, runnerOptions.polyline), + L.extend({}, { auto: true, speed: speed, }, runnerOptions.motion), + runnerOptions.marker || undefined + ); + + // Override default function behavior: `L.Motion.Polyline::_drawMarker()` + this._runner._drawMarker = new Proxy(this._runner._drawMarker, { + apply: (target, thisArg, argArray) => { + thisArg._runner = thisArg._runner || this.addRunner({ dist: 0 }); + this.updateRunnerPos(thisArg._runner, argArray[0]); + return target.apply(thisArg, argArray); + } + }); + + this._runner.addTo(this._map); + }; + + return {}; +} |
