PageSourceSearch

https://www.ea2cw.eus/locator/js/ruler-dist.js

js ea2cw.eus collected 2026-10-06 13:15:05 UTC 5,590 bytes, 178 lines download raw bytes

1/*
2* Distance ruler for Leaflet
3* by TK5EP 2026/01
4* each click creates a poitn on the map
5* between each point, a box gives distance and azimut
6*/
7
8class RulerDist {
9    constructor(map, button) {
10        this.map = map;
11        this.button = button;
12        this.isActive = false;
13
14        this.points = [];
15        this.markers = [];
16        this.lines = [];
17        this.tempLine = null;
18
19        this.floatingInfo = document.getElementById("floating-info");
20        this._defaultCursor = map.getContainer().style.cursor;
21
22        // Bind
23        this.toggle = this.toggle.bind(this);
24        this._onClick = this._onClick.bind(this);
25        this._onMouseMove = this._onMouseMove.bind(this);
26        this._onKeyDown = this._onKeyDown.bind(this);
27    }
28
29    // ---------------- Toggle ----------------
30    toggle() {
31        if (!this.isActive) {
32            // ON → reset complet
33            this._reset();
34            this._activate();
35        } else {
36            // OFF → reset complet
37            this._reset();
38            this._deactivate();
39        }
40    }
41
42    _activate() {
43        this.isActive = true;
44        this.map.getContainer().style.cursor = "crosshair";
45        this.map.on('click', this._onClick);
46        this.map.on('mousemove', this._onMouseMove);
47        window.addEventListener('keydown', this._onKeyDown);
48    }
49
50    _deactivate() {
51        this.isActive = false;
52        this.map.getContainer().style.cursor = this._defaultCursor;
53        this.map.off('click', this._onClick);
54        this.map.off('mousemove', this._onMouseMove);
55        window.removeEventListener('keydown', this._onKeyDown);
56    }
57
58    // ---------------- Reset complet ----------------
59    _reset() {
60        this.points = [];
61        this.markers.forEach(m => this.map.removeLayer(m));
62        this.lines.forEach(l => this.map.removeLayer(l));
63        this.markers = [];
64        this.lines = [];
65
66        if (this.tempLine) this.map.removeLayer(this.tempLine);
67        this.tempLine = null;
68
69        this.floatingInfo.style.display = "none";
70    }
71
72    // ---------------- Azimut ----------------
73    _azimuth(p1, p2) {
74        const d2r = Math.PI / 180;
75        const y = Math.sin((p2.lng - p1.lng) * d2r) * Math.cos(p2.lat * d2r);
76        const x = Math.cos(p1.lat * d2r) * Math.sin(p2.lat * d2r) -
77                  Math.sin(p1.lat * d2r) * Math.cos(p2.lat * d2r) *
78                  Math.cos((p2.lng - p1.lng) * d2r);
79        return (Math.atan2(y, x) * 180 / Math.PI + 360) % 360;
80    }
81
82    // ---------------- Click ----------------
83    _onClick(e) {
84        const latlng = e.latlng;
85        this.points.push(latlng);
86
87        const marker = L.circleMarker(latlng, {
88            radius: 5,
89            fillColor: '#2ecc71',
90            color: '#fff',
91            weight: 1,
92            fillOpacity: 1,
93            interactive: false
94        }).addTo(this.map);
95
96        this.markers.push(marker);
97
98        if (this.points.length > 1) {
99            const prev = this.points[this.points.length - 2];
100
101            const line = L.polyline([prev, latlng], {
102                color: '#e74c3c',
103                weight: 1,
104                dashArray: '5,5',
105                interactive: false
106            }).addTo(this.map);
107
108            this.lines.push(line);
109
110            const dist = this.map.distance(prev, latlng) / 1000;
111            const az = this._azimuth(prev, latlng);
112
113            const tooltip = L.tooltip({
114                permanent: true,
115                direction: 'right',
116                offset: [10, 0],
117                className: 'measure-tooltip'
118            })
119            .setLatLng(latlng)
120            .setContent(`
121                <div class="measure-line">
122                    Distance : ${dist.toFixed(2)} km<br>
123                    Azimut : ${az.toFixed(1)}°
124                </div>
125            `)
126            .addTo(this.map);
127
128            this.markers.push(tooltip);
129        }
130    }
131
132    // ---------------- MouseMove ----------------
133    _onMouseMove(e) {
134        if (!this.isActive || this.points.length === 0) {
135            this.floatingInfo.style.display = "none";
136            return;
137        }
138
139        this.floatingInfo.style.display = "block";
140        this.floatingInfo.style.left = (e.originalEvent.clientX + 15) + "px";
141        this.floatingInfo.style.top  = (e.originalEvent.clientY + 15) + "px";
142
143        if (this.tempLine) this.map.removeLayer(this.tempLine);
144
145        const last = this.points[this.points.length - 1];
146        this.tempLine = L.polyline([last, e.latlng], {
147            color: '#2ecc71',
148            weight: 1,
149            dashArray: '4,4',
150            interactive: false
151        }).addTo(this.map);
152
153        const dist = this.map.distance(last, e.latlng) / 1000;
154        const az = this._azimuth(last, e.latlng);
155
156        this.floatingInfo.innerHTML = `
157            <div class="measure-line">
158                Distance : ${dist.toFixed(2)} km<br>
159                Azimut : ${az.toFixed(1)}°
160            </div>
161        `;
162    }
163
164    // ---------------- ESC ----------------
165    _onKeyDown(e) {
166        if (e.key === "Escape" && this.isActive) {
167            if (this.tempLine) this.map.removeLayer(this.tempLine);
168            this.tempLine = null;
169            this.floatingInfo.style.display = "none";
170
171            this._deactivate();
172
173            // 🔥 synchronisation bouton
174            if (this.button) this.button.state('off');
175        }
176    }
177
178}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.