From 6c57848277fa131eaf2ae6d3f38fc0a77a6a342c Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Sat, 27 Jun 2026 17:07:05 +0200 Subject: [PATCH] Add autoPan-ing for draggin markers on the diary adding page --- app/assets/javascripts/diary_entry.js | 2 +- app/assets/javascripts/maplibre/dom_util.js | 42 ++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/diary_entry.js b/app/assets/javascripts/diary_entry.js index 668a90cd5..9f3005e23 100644 --- a/app/assets/javascripts/diary_entry.js +++ b/app/assets/javascripts/diary_entry.js @@ -14,7 +14,7 @@ $(function () { if (marker) { marker.setLngLat(coords); } else { - marker = new OSM.MapLibre.Marker({ draggable: true }) + marker = new OSM.MapLibre.Marker({ draggable: true, autoPan: true }) .setLngLat(coords) .setPopup(new OSM.MapLibre.Popup().setHTML(OSM.i18n.t("diary_entries.edit.marker_text"))) .addTo(map); diff --git a/app/assets/javascripts/maplibre/dom_util.js b/app/assets/javascripts/maplibre/dom_util.js index 0a3c913f8..64692f27f 100644 --- a/app/assets/javascripts/maplibre/dom_util.js +++ b/app/assets/javascripts/maplibre/dom_util.js @@ -1,5 +1,5 @@ OSM.MapLibre.Marker = class extends maplibregl.Marker { - constructor({ icon = "dot", color = "var(--marker-red)", ...options } = {}) { + constructor({ icon = "dot", color = "var(--marker-red)", autoPan = false, ...options } = {}) { const element = document.createElement("div"); element.className = "maplibre-gl-marker"; element.style.width = "25px"; @@ -31,6 +31,46 @@ OSM.MapLibre.Marker = class extends maplibregl.Marker { offset: [0, 0], ...options }); + + if (autoPan && options.draggable) this._enableAutoPan(); + } + + _enableAutoPan() { + const edgeDistance = 50, + maxPanStep = 10; + + let frame = null; + + const step = () => { + frame = requestAnimationFrame(step); + + const map = this._map; + if (!map) return; + + const point = map.project(this.getLngLat()), + { clientWidth, clientHeight } = map.getContainer(); + + let dx = 0, + dy = 0; + if (point.x < edgeDistance) dx = point.x - edgeDistance; + else if (point.x > clientWidth - edgeDistance) dx = point.x - (clientWidth - edgeDistance); + if (point.y < edgeDistance) dy = point.y - edgeDistance; + else if (point.y > clientHeight - edgeDistance) dy = point.y - (clientHeight - edgeDistance); + if (!dx && !dy) return; + + const clamp = (v) => Math.max(-maxPanStep, Math.min(maxPanStep, v)); + map.panBy([clamp(dx), clamp(dy)], { duration: 0 }); + this.setLngLat(map.unproject(point)); + this.fire("drag"); + }; + + this.on("dragstart", () => { + if (frame === null) frame = requestAnimationFrame(step); + }); + this.on("dragend", () => { + if (frame !== null) cancelAnimationFrame(frame); + frame = null; + }); } }; -- 2.47.3