summaryrefslogtreecommitdiff
path: root/assets/static/vendor/leaflet-elevation/src/handlers/runner.js
diff options
context:
space:
mode:
authorDennis Fink2026-07-23 00:18:21 +0200
committerDennis Fink2026-07-23 00:18:21 +0200
commit1fe1d13c600b7dfe421b3b99b833b7d5d1232724 (patch)
tree2e8636160cc1719c907be56f5ef8cbc7e0f10a53 /assets/static/vendor/leaflet-elevation/src/handlers/runner.js
parentca77de06be474dfd712402c327dc436864d233a3 (diff)
downloaddennisfink.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 'assets/static/vendor/leaflet-elevation/src/handlers/runner.js')
-rw-r--r--assets/static/vendor/leaflet-elevation/src/handlers/runner.js109
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 {};
+}