]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/maplibre/marker.js
Merge remote-tracking branch 'upstream/pull/7252'
[rails.git] / app / assets / javascripts / maplibre / marker.js
1 OSM.MapLibre.Marker = class extends maplibregl.Marker {
2   constructor({ icon = "dot", color = "var(--marker-red)", autoPan = false, ...options } = {}) {
3     const element = document.createElement("div");
4     element.className = "maplibre-gl-marker";
5     element.style.width = "25px";
6     element.style.height = "40px";
7
8     const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
9     svg.setAttribute("viewBox", "0 0 25 40");
10     svg.setAttribute("width", "25");
11     svg.setAttribute("height", "40");
12     svg.classList.add("pe-none");
13     svg.style.overflow = "visible";
14
15     // Use the marker icons from NoteMarker.svg
16     const use1 = document.createElementNS("http://www.w3.org/2000/svg", "use");
17     use1.setAttribute("href", "#pin-shadow");
18
19     const use2 = document.createElementNS("http://www.w3.org/2000/svg", "use");
20     use2.setAttribute("href", `#pin-${icon}`);
21     use2.setAttribute("color", color);
22     use2.classList.add("pe-auto");
23
24     svg.appendChild(use1);
25     svg.appendChild(use2);
26     element.appendChild(svg);
27
28     super({
29       element,
30       anchor: "bottom",
31       offset: [0, 0],
32       ...options
33     });
34
35     if (autoPan && options.draggable) this._enableAutoPan();
36   }
37
38   _enableAutoPan() {
39     const edgeDistance = 50,
40           maxPanStep = 10;
41
42     let frame = null;
43
44     const step = () => {
45       frame = requestAnimationFrame(step);
46
47       const map = this._map;
48       if (!map) return;
49
50       const point = map.project(this.getLngLat()),
51             { clientWidth, clientHeight } = map.getContainer();
52
53       let dx = 0,
54           dy = 0;
55       if (point.x < edgeDistance) dx = point.x - edgeDistance;
56       else if (point.x > clientWidth - edgeDistance) dx = point.x - (clientWidth - edgeDistance);
57       if (point.y < edgeDistance) dy = point.y - edgeDistance;
58       else if (point.y > clientHeight - edgeDistance) dy = point.y - (clientHeight - edgeDistance);
59       if (!dx && !dy) return;
60
61       const clamp = (v) => Math.max(-maxPanStep, Math.min(maxPanStep, v));
62       map.panBy([clamp(dx), clamp(dy)], { duration: 0 });
63       this.setLngLat(map.unproject(point));
64       this.fire("drag");
65     };
66
67     this.on("dragstart", () => {
68       if (frame === null) frame = requestAnimationFrame(step);
69     });
70     this.on("dragend", () => {
71       if (frame !== null) cancelAnimationFrame(frame);
72       frame = null;
73     });
74   }
75 };