@angular-helpers/openlayers 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -6
- package/fesm2022/angular-helpers-openlayers-controls.mjs +289 -36
- package/fesm2022/angular-helpers-openlayers-core.mjs +215 -16
- package/fesm2022/angular-helpers-openlayers-interactions.mjs +426 -23
- package/fesm2022/angular-helpers-openlayers-layers.mjs +717 -38
- package/fesm2022/angular-helpers-openlayers-military.mjs +329 -12
- package/fesm2022/angular-helpers-openlayers-overlays.mjs +11 -10
- package/package.json +6 -2
- package/types/angular-helpers-openlayers-controls.d.ts +24 -4
- package/types/angular-helpers-openlayers-core.d.ts +143 -4
- package/types/angular-helpers-openlayers-interactions.d.ts +127 -23
- package/types/angular-helpers-openlayers-layers.d.ts +194 -35
- package/types/angular-helpers-openlayers-military.d.ts +160 -16
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, computed, Injectable, inject } from '@angular/core';
|
|
2
|
+
import { signal, computed, Injectable, inject, DestroyRef, input, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { OlMapService, OlZoneHelper } from '@angular-helpers/openlayers/core';
|
|
4
4
|
import { Subject } from 'rxjs';
|
|
5
5
|
import Select from 'ol/interaction/Select';
|
|
6
|
+
import { pointerMove, click } from 'ol/events/condition';
|
|
6
7
|
import Draw from 'ol/interaction/Draw';
|
|
7
8
|
import Snap from 'ol/interaction/Snap';
|
|
8
9
|
import VectorSource from 'ol/source/Vector';
|
|
10
|
+
import { Polygon, LineString } from 'ol/geom';
|
|
9
11
|
import { OlLayerService } from '@angular-helpers/openlayers/layers';
|
|
10
12
|
import Modify from 'ol/interaction/Modify';
|
|
13
|
+
import VectorLayer from 'ol/layer/Vector';
|
|
14
|
+
import Overlay from 'ol/Overlay';
|
|
15
|
+
import { getLength, getArea } from 'ol/sphere';
|
|
16
|
+
import { unByKey } from 'ol/Observable';
|
|
17
|
+
import { Style, Circle, Fill, Stroke } from 'ol/style';
|
|
18
|
+
import { outputFromObservable } from '@angular/core/rxjs-interop';
|
|
19
|
+
import { filter } from 'rxjs/operators';
|
|
11
20
|
|
|
12
21
|
// Interaction state management service
|
|
13
22
|
/**
|
|
@@ -22,6 +31,7 @@ class InteractionStateService {
|
|
|
22
31
|
drawStartSubject = new Subject();
|
|
23
32
|
drawEndSubject = new Subject();
|
|
24
33
|
modifySubject = new Subject();
|
|
34
|
+
selectSubject = new Subject();
|
|
25
35
|
// Public readonly signals
|
|
26
36
|
selectedFeatures = computed(() => this.selectedFeaturesInternal(), ...(ngDevMode ? [{ debugName: "selectedFeatures" }] : /* istanbul ignore next */ []));
|
|
27
37
|
selectionCount = computed(() => this.selectedFeaturesInternal().length, ...(ngDevMode ? [{ debugName: "selectionCount" }] : /* istanbul ignore next */ []));
|
|
@@ -31,11 +41,23 @@ class InteractionStateService {
|
|
|
31
41
|
drawStart$ = this.drawStartSubject.asObservable();
|
|
32
42
|
drawEnd$ = this.drawEndSubject.asObservable();
|
|
33
43
|
modify$ = this.modifySubject.asObservable();
|
|
44
|
+
select$ = this.selectSubject.asObservable();
|
|
34
45
|
/**
|
|
35
46
|
* Adds a managed interaction to the state.
|
|
47
|
+
* If the interaction is marked as exclusive, it disables other exclusive interactions.
|
|
36
48
|
* @param interaction - The interaction to add
|
|
37
49
|
*/
|
|
38
50
|
addInteraction(interaction) {
|
|
51
|
+
if (interaction.config.exclusive !== false) {
|
|
52
|
+
// Disable other exclusive interactions to maintain mutual exclusivity
|
|
53
|
+
const currentInteractions = this.interactions();
|
|
54
|
+
for (const existing of currentInteractions) {
|
|
55
|
+
if (existing.id !== interaction.id && existing.config.exclusive !== false) {
|
|
56
|
+
existing.cleanup();
|
|
57
|
+
this.removeInteraction(existing.id);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
39
61
|
this.interactions.update((list) => [...list, interaction]);
|
|
40
62
|
}
|
|
41
63
|
/**
|
|
@@ -94,6 +116,13 @@ class InteractionStateService {
|
|
|
94
116
|
emitModify(event) {
|
|
95
117
|
this.modifySubject.next(event);
|
|
96
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Emits a select event.
|
|
121
|
+
* @param event - The select event data
|
|
122
|
+
*/
|
|
123
|
+
emitSelect(event) {
|
|
124
|
+
this.selectSubject.next(event);
|
|
125
|
+
}
|
|
97
126
|
/**
|
|
98
127
|
* Gets the current interaction state summary.
|
|
99
128
|
* @returns Array of interaction state objects
|
|
@@ -122,10 +151,10 @@ class InteractionStateService {
|
|
|
122
151
|
this.interactions.set([]);
|
|
123
152
|
this.selectedFeaturesInternal.set([]);
|
|
124
153
|
}
|
|
125
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
126
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
154
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: InteractionStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
155
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: InteractionStateService });
|
|
127
156
|
}
|
|
128
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
157
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: InteractionStateService, decorators: [{
|
|
129
158
|
type: Injectable
|
|
130
159
|
}] });
|
|
131
160
|
|
|
@@ -195,16 +224,22 @@ class SelectInteractionService {
|
|
|
195
224
|
: undefined,
|
|
196
225
|
multi: config.multi ?? false,
|
|
197
226
|
hitTolerance: config.hitTolerance ?? 0,
|
|
227
|
+
condition: config.condition === 'pointerMove' ? pointerMove : click,
|
|
198
228
|
});
|
|
199
229
|
// Listen to selection changes — use getFeatures().getArray() for the full
|
|
200
230
|
// accumulated collection, not e.selected which only contains newly added ones
|
|
201
|
-
select.on('select', (
|
|
231
|
+
select.on('select', (e) => {
|
|
202
232
|
this.zoneHelper.runInsideAngular(() => {
|
|
203
233
|
const allSelected = select
|
|
204
234
|
.getFeatures()
|
|
205
235
|
.getArray()
|
|
206
236
|
.map((f) => olFeatureToFeature(f));
|
|
207
237
|
this.stateService.setSelectedFeatures(allSelected);
|
|
238
|
+
this.stateService.emitSelect({
|
|
239
|
+
interactionId: id,
|
|
240
|
+
selected: e.selected.map((f) => olFeatureToFeature(f)),
|
|
241
|
+
deselected: e.deselected.map((f) => olFeatureToFeature(f)),
|
|
242
|
+
});
|
|
208
243
|
});
|
|
209
244
|
});
|
|
210
245
|
map.addInteraction(select);
|
|
@@ -221,10 +256,10 @@ class SelectInteractionService {
|
|
|
221
256
|
this.stateService.addInteraction(managed);
|
|
222
257
|
});
|
|
223
258
|
}
|
|
224
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
225
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
259
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SelectInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
260
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SelectInteractionService });
|
|
226
261
|
}
|
|
227
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
262
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: SelectInteractionService, decorators: [{
|
|
228
263
|
type: Injectable
|
|
229
264
|
}] });
|
|
230
265
|
|
|
@@ -256,9 +291,69 @@ class DrawInteractionService {
|
|
|
256
291
|
source = new VectorSource();
|
|
257
292
|
}
|
|
258
293
|
this.zoneHelper.runOutsideAngular(() => {
|
|
294
|
+
let drawType = config.type;
|
|
295
|
+
let geometryFunction;
|
|
296
|
+
if (config.type === 'Ellipse') {
|
|
297
|
+
drawType = 'Circle';
|
|
298
|
+
geometryFunction = (coords, geom) => {
|
|
299
|
+
if (!geom) {
|
|
300
|
+
geom = new Polygon([]);
|
|
301
|
+
}
|
|
302
|
+
const center = coords[0];
|
|
303
|
+
const last = coords[1];
|
|
304
|
+
const dx = last[0] - center[0];
|
|
305
|
+
const dy = last[1] - center[1];
|
|
306
|
+
const semiMajor = Math.sqrt(dx * dx + dy * dy);
|
|
307
|
+
const semiMinor = semiMajor * 0.7; // Default ratio
|
|
308
|
+
const rotation = Math.atan2(dy, dx);
|
|
309
|
+
const ring = [];
|
|
310
|
+
const segments = 64;
|
|
311
|
+
for (let i = 0; i < segments; i++) {
|
|
312
|
+
const theta = (i / segments) * Math.PI * 2;
|
|
313
|
+
const ax = Math.cos(theta) * semiMajor;
|
|
314
|
+
const ay = Math.sin(theta) * semiMinor;
|
|
315
|
+
const rx = ax * Math.cos(rotation) - ay * Math.sin(rotation);
|
|
316
|
+
const ry = ax * Math.sin(rotation) + ay * Math.cos(rotation);
|
|
317
|
+
ring.push([center[0] + rx, center[1] + ry]);
|
|
318
|
+
}
|
|
319
|
+
ring.push(ring[0]);
|
|
320
|
+
geom.setCoordinates([ring]);
|
|
321
|
+
return geom;
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
else if (config.type === 'Donut') {
|
|
325
|
+
drawType = 'Circle';
|
|
326
|
+
geometryFunction = (coords, geom) => {
|
|
327
|
+
if (!geom) {
|
|
328
|
+
geom = new Polygon([]);
|
|
329
|
+
}
|
|
330
|
+
const center = coords[0];
|
|
331
|
+
const last = coords[1];
|
|
332
|
+
const dx = last[0] - center[0];
|
|
333
|
+
const dy = last[1] - center[1];
|
|
334
|
+
const outerRadius = Math.sqrt(dx * dx + dy * dy);
|
|
335
|
+
const innerRadius = outerRadius * 0.6; // Default ratio
|
|
336
|
+
const outer = [];
|
|
337
|
+
const inner = [];
|
|
338
|
+
const segments = 64;
|
|
339
|
+
for (let i = 0; i < segments; i++) {
|
|
340
|
+
const theta = (i / segments) * Math.PI * 2;
|
|
341
|
+
const cosT = Math.cos(theta);
|
|
342
|
+
const sinT = Math.sin(theta);
|
|
343
|
+
outer.push([center[0] + cosT * outerRadius, center[1] + sinT * outerRadius]);
|
|
344
|
+
inner.push([center[0] + cosT * innerRadius, center[1] + sinT * innerRadius]);
|
|
345
|
+
}
|
|
346
|
+
inner.reverse();
|
|
347
|
+
outer.push(outer[0]);
|
|
348
|
+
inner.push(inner[0]);
|
|
349
|
+
geom.setCoordinates([outer, inner]);
|
|
350
|
+
return geom;
|
|
351
|
+
};
|
|
352
|
+
}
|
|
259
353
|
const draw = new Draw({
|
|
260
354
|
source,
|
|
261
|
-
type:
|
|
355
|
+
type: drawType,
|
|
356
|
+
geometryFunction,
|
|
262
357
|
freehand: config.freehand ?? false,
|
|
263
358
|
snapTolerance: config.snapTolerance ?? 12,
|
|
264
359
|
});
|
|
@@ -267,14 +362,14 @@ class DrawInteractionService {
|
|
|
267
362
|
draw.on('drawstart', (e) => {
|
|
268
363
|
this.zoneHelper.runInsideAngular(() => {
|
|
269
364
|
const feature = olFeatureToFeature(e.feature);
|
|
270
|
-
this.stateService.emitDrawStart({ feature });
|
|
365
|
+
this.stateService.emitDrawStart({ interactionId: id, feature });
|
|
271
366
|
});
|
|
272
367
|
});
|
|
273
368
|
// Handle draw end event
|
|
274
369
|
draw.on('drawend', (e) => {
|
|
275
370
|
this.zoneHelper.runInsideAngular(() => {
|
|
276
371
|
const feature = olFeatureToFeature(e.feature);
|
|
277
|
-
const event = { feature, type: config.type };
|
|
372
|
+
const event = { interactionId: id, feature, type: config.type };
|
|
278
373
|
this.stateService.emitDrawEnd(event);
|
|
279
374
|
});
|
|
280
375
|
});
|
|
@@ -296,10 +391,10 @@ class DrawInteractionService {
|
|
|
296
391
|
});
|
|
297
392
|
return true;
|
|
298
393
|
}
|
|
299
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
300
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
394
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DrawInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
395
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DrawInteractionService });
|
|
301
396
|
}
|
|
302
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
397
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: DrawInteractionService, decorators: [{
|
|
303
398
|
type: Injectable
|
|
304
399
|
}] });
|
|
305
400
|
|
|
@@ -337,7 +432,7 @@ class ModifyInteractionService {
|
|
|
337
432
|
modify.on('modifystart', (e) => {
|
|
338
433
|
this.zoneHelper.runInsideAngular(() => {
|
|
339
434
|
const features = e.features.getArray().map((f) => olFeatureToFeature(f));
|
|
340
|
-
const event = { features, type: 'modifystart' };
|
|
435
|
+
const event = { interactionId: id, features, type: 'modifystart' };
|
|
341
436
|
this.stateService.emitModify(event);
|
|
342
437
|
});
|
|
343
438
|
});
|
|
@@ -345,7 +440,7 @@ class ModifyInteractionService {
|
|
|
345
440
|
modify.on('modifyend', (e) => {
|
|
346
441
|
this.zoneHelper.runInsideAngular(() => {
|
|
347
442
|
const features = e.features.getArray().map((f) => olFeatureToFeature(f));
|
|
348
|
-
const event = { features, type: 'modifyend' };
|
|
443
|
+
const event = { interactionId: id, features, type: 'modifyend' };
|
|
349
444
|
this.stateService.emitModify(event);
|
|
350
445
|
});
|
|
351
446
|
});
|
|
@@ -366,10 +461,10 @@ class ModifyInteractionService {
|
|
|
366
461
|
this.stateService.addInteraction(managed);
|
|
367
462
|
});
|
|
368
463
|
}
|
|
369
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
370
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
464
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ModifyInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
465
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ModifyInteractionService });
|
|
371
466
|
}
|
|
372
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
467
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: ModifyInteractionService, decorators: [{
|
|
373
468
|
type: Injectable
|
|
374
469
|
}] });
|
|
375
470
|
|
|
@@ -408,6 +503,7 @@ class OlInteractionService {
|
|
|
408
503
|
drawStart$ = this.stateService.drawStart$;
|
|
409
504
|
drawEnd$ = this.stateService.drawEnd$;
|
|
410
505
|
modify$ = this.stateService.modify$;
|
|
506
|
+
select$ = this.stateService.select$;
|
|
411
507
|
/**
|
|
412
508
|
* Enable a select interaction on the map.
|
|
413
509
|
* @param id - Unique identifier for this interaction
|
|
@@ -517,13 +613,305 @@ class OlInteractionService {
|
|
|
517
613
|
getInteractionState() {
|
|
518
614
|
return this.stateService.getInteractionState();
|
|
519
615
|
}
|
|
520
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
521
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
616
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
617
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlInteractionService });
|
|
522
618
|
}
|
|
523
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
619
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlInteractionService, decorators: [{
|
|
524
620
|
type: Injectable
|
|
525
621
|
}] });
|
|
526
622
|
|
|
623
|
+
class MeasurementInteractionService {
|
|
624
|
+
mapService = inject(OlMapService);
|
|
625
|
+
zoneHelper = inject(OlZoneHelper);
|
|
626
|
+
draw;
|
|
627
|
+
source = new VectorSource();
|
|
628
|
+
vectorLayer;
|
|
629
|
+
map;
|
|
630
|
+
sketch = null;
|
|
631
|
+
measureTooltipElement = null;
|
|
632
|
+
measureTooltip = null;
|
|
633
|
+
listener = null;
|
|
634
|
+
isMeasuring = false;
|
|
635
|
+
startMeasuring(type) {
|
|
636
|
+
if (this.isMeasuring)
|
|
637
|
+
this.stopMeasuring();
|
|
638
|
+
this.map = this.mapService.getMap() ?? undefined;
|
|
639
|
+
if (!this.map)
|
|
640
|
+
return;
|
|
641
|
+
this.zoneHelper.runOutsideAngular(() => {
|
|
642
|
+
this.vectorLayer = new VectorLayer({
|
|
643
|
+
source: this.source,
|
|
644
|
+
style: new Style({
|
|
645
|
+
fill: new Fill({ color: 'rgba(255, 255, 255, 0.2)' }),
|
|
646
|
+
stroke: new Stroke({ color: '#ffcc33', width: 2 }),
|
|
647
|
+
image: new Circle({ radius: 7, fill: new Fill({ color: '#ffcc33' }) }),
|
|
648
|
+
}),
|
|
649
|
+
zIndex: 9999,
|
|
650
|
+
});
|
|
651
|
+
this.map.addLayer(this.vectorLayer);
|
|
652
|
+
this.draw = new Draw({
|
|
653
|
+
source: this.source,
|
|
654
|
+
type,
|
|
655
|
+
style: new Style({
|
|
656
|
+
fill: new Fill({ color: 'rgba(255, 255, 255, 0.2)' }),
|
|
657
|
+
stroke: new Stroke({ color: 'rgba(0, 0, 0, 0.5)', lineDash: [10, 10], width: 2 }),
|
|
658
|
+
image: new Circle({
|
|
659
|
+
radius: 5,
|
|
660
|
+
stroke: new Stroke({ color: 'rgba(0, 0, 0, 0.7)' }),
|
|
661
|
+
fill: new Fill({ color: 'rgba(255, 255, 255, 0.2)' }),
|
|
662
|
+
}),
|
|
663
|
+
}),
|
|
664
|
+
});
|
|
665
|
+
this.map.addInteraction(this.draw);
|
|
666
|
+
this.createMeasureTooltip();
|
|
667
|
+
this.draw.on('drawstart', (evt) => {
|
|
668
|
+
this.sketch = evt.feature;
|
|
669
|
+
let tooltipCoord = evt.coordinate;
|
|
670
|
+
const geometry = this.sketch?.getGeometry();
|
|
671
|
+
if (geometry) {
|
|
672
|
+
this.listener = geometry.on('change', (e) => {
|
|
673
|
+
const geom = e.target;
|
|
674
|
+
let output;
|
|
675
|
+
if (geom instanceof Polygon) {
|
|
676
|
+
output = this.formatArea(geom);
|
|
677
|
+
tooltipCoord = geom.getInteriorPoint().getCoordinates();
|
|
678
|
+
}
|
|
679
|
+
else if (geom instanceof LineString) {
|
|
680
|
+
output = this.formatLength(geom);
|
|
681
|
+
tooltipCoord = geom.getLastCoordinate();
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
output = '';
|
|
685
|
+
}
|
|
686
|
+
if (this.measureTooltipElement) {
|
|
687
|
+
this.measureTooltipElement.innerHTML = output;
|
|
688
|
+
this.measureTooltip?.setPosition(tooltipCoord);
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
this.draw.on('drawend', () => {
|
|
694
|
+
if (this.measureTooltipElement) {
|
|
695
|
+
this.measureTooltipElement.className = 'ol-tooltip ol-tooltip-static';
|
|
696
|
+
this.measureTooltip?.setOffset([0, -7]);
|
|
697
|
+
this.sketch = null;
|
|
698
|
+
this.measureTooltipElement = null;
|
|
699
|
+
this.createMeasureTooltip();
|
|
700
|
+
}
|
|
701
|
+
if (this.listener)
|
|
702
|
+
unByKey(this.listener);
|
|
703
|
+
});
|
|
704
|
+
this.isMeasuring = true;
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
stopMeasuring() {
|
|
708
|
+
if (!this.isMeasuring)
|
|
709
|
+
return;
|
|
710
|
+
this.zoneHelper.runOutsideAngular(() => {
|
|
711
|
+
if (this.draw && this.map)
|
|
712
|
+
this.map.removeInteraction(this.draw);
|
|
713
|
+
if (this.vectorLayer && this.map)
|
|
714
|
+
this.map.removeLayer(this.vectorLayer);
|
|
715
|
+
this.source.clear();
|
|
716
|
+
// Remove all tooltips
|
|
717
|
+
const overlays = this.map
|
|
718
|
+
?.getOverlays()
|
|
719
|
+
.getArray()
|
|
720
|
+
.filter((o) => o.getElement()?.classList.contains('ol-tooltip'));
|
|
721
|
+
overlays?.forEach((o) => this.map?.removeOverlay(o));
|
|
722
|
+
this.isMeasuring = false;
|
|
723
|
+
this.measureTooltipElement = null;
|
|
724
|
+
this.measureTooltip = null;
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
isActive() {
|
|
728
|
+
return this.isMeasuring;
|
|
729
|
+
}
|
|
730
|
+
createMeasureTooltip() {
|
|
731
|
+
if (!this.map)
|
|
732
|
+
return;
|
|
733
|
+
if (this.measureTooltipElement) {
|
|
734
|
+
this.measureTooltipElement.parentNode?.removeChild(this.measureTooltipElement);
|
|
735
|
+
}
|
|
736
|
+
this.measureTooltipElement = document.createElement('div');
|
|
737
|
+
this.measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
|
|
738
|
+
this.measureTooltipElement.style.backgroundColor = 'rgba(0,0,0,0.7)';
|
|
739
|
+
this.measureTooltipElement.style.color = 'white';
|
|
740
|
+
this.measureTooltipElement.style.padding = '4px 8px';
|
|
741
|
+
this.measureTooltipElement.style.borderRadius = '4px';
|
|
742
|
+
this.measureTooltipElement.style.fontSize = '12px';
|
|
743
|
+
this.measureTooltipElement.style.whiteSpace = 'nowrap';
|
|
744
|
+
this.measureTooltipElement.style.pointerEvents = 'none';
|
|
745
|
+
this.measureTooltip = new Overlay({
|
|
746
|
+
element: this.measureTooltipElement,
|
|
747
|
+
offset: [0, -15],
|
|
748
|
+
positioning: 'bottom-center',
|
|
749
|
+
stopEvent: false,
|
|
750
|
+
});
|
|
751
|
+
this.map.addOverlay(this.measureTooltip);
|
|
752
|
+
}
|
|
753
|
+
formatLength(line) {
|
|
754
|
+
const length = getLength(line);
|
|
755
|
+
let output;
|
|
756
|
+
if (length > 100) {
|
|
757
|
+
output = Math.round((length / 1000) * 100) / 100 + ' km';
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
output = Math.round(length * 100) / 100 + ' m';
|
|
761
|
+
}
|
|
762
|
+
return output;
|
|
763
|
+
}
|
|
764
|
+
formatArea(polygon) {
|
|
765
|
+
const area = getArea(polygon);
|
|
766
|
+
let output;
|
|
767
|
+
if (area > 10000) {
|
|
768
|
+
output = Math.round((area / 1000000) * 100) / 100 + ' km<sup>2</sup>';
|
|
769
|
+
}
|
|
770
|
+
else {
|
|
771
|
+
output = Math.round(area * 100) / 100 + ' m<sup>2</sup>';
|
|
772
|
+
}
|
|
773
|
+
return output;
|
|
774
|
+
}
|
|
775
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: MeasurementInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
776
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: MeasurementInteractionService });
|
|
777
|
+
}
|
|
778
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: MeasurementInteractionService, decorators: [{
|
|
779
|
+
type: Injectable
|
|
780
|
+
}] });
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Declarative component to configure an OpenLayers Draw Interaction.
|
|
784
|
+
*/
|
|
785
|
+
class OlDrawInteractionComponent {
|
|
786
|
+
interactionService = inject(OlInteractionService);
|
|
787
|
+
destroyRef = inject(DestroyRef);
|
|
788
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
789
|
+
type = input.required(...(ngDevMode ? [{ debugName: "type" }] : /* istanbul ignore next */ []));
|
|
790
|
+
source = input(...(ngDevMode ? [undefined, { debugName: "source" }] : /* istanbul ignore next */ []));
|
|
791
|
+
freehand = input(...(ngDevMode ? [undefined, { debugName: "freehand" }] : /* istanbul ignore next */ []));
|
|
792
|
+
snapTolerance = input(...(ngDevMode ? [undefined, { debugName: "snapTolerance" }] : /* istanbul ignore next */ []));
|
|
793
|
+
active = input(true, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
794
|
+
drawStartFiltered$ = this.interactionService.drawStart$.pipe(filter((e) => e.interactionId === this.id()));
|
|
795
|
+
drawEndFiltered$ = this.interactionService.drawEnd$.pipe(filter((e) => e.interactionId === this.id()));
|
|
796
|
+
drawStart = outputFromObservable(this.drawStartFiltered$);
|
|
797
|
+
drawEnd = outputFromObservable(this.drawEndFiltered$);
|
|
798
|
+
constructor() {
|
|
799
|
+
effect(() => {
|
|
800
|
+
if (this.active()) {
|
|
801
|
+
this.interactionService.enableDraw(this.id(), {
|
|
802
|
+
type: this.type(),
|
|
803
|
+
source: this.source(),
|
|
804
|
+
freehand: this.freehand(),
|
|
805
|
+
snapTolerance: this.snapTolerance(),
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
this.interactionService.disableInteraction(this.id());
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
this.destroyRef.onDestroy(() => {
|
|
813
|
+
this.interactionService.disableInteraction(this.id());
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlDrawInteractionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
817
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlDrawInteractionComponent, isStandalone: true, selector: "ol-draw-interaction", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, freehand: { classPropertyName: "freehand", publicName: "freehand", isSignal: true, isRequired: false, transformFunction: null }, snapTolerance: { classPropertyName: "snapTolerance", publicName: "snapTolerance", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { drawStart: "drawStart", drawEnd: "drawEnd" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
818
|
+
}
|
|
819
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlDrawInteractionComponent, decorators: [{
|
|
820
|
+
type: Component,
|
|
821
|
+
args: [{
|
|
822
|
+
selector: 'ol-draw-interaction',
|
|
823
|
+
standalone: true,
|
|
824
|
+
template: '',
|
|
825
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
826
|
+
}]
|
|
827
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: true }] }], source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], freehand: [{ type: i0.Input, args: [{ isSignal: true, alias: "freehand", required: false }] }], snapTolerance: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapTolerance", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], drawStart: [{ type: i0.Output, args: ["drawStart"] }], drawEnd: [{ type: i0.Output, args: ["drawEnd"] }] } });
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Declarative component to configure an OpenLayers Modify Interaction.
|
|
831
|
+
*/
|
|
832
|
+
class OlModifyInteractionComponent {
|
|
833
|
+
interactionService = inject(OlInteractionService);
|
|
834
|
+
destroyRef = inject(DestroyRef);
|
|
835
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
836
|
+
source = input(...(ngDevMode ? [undefined, { debugName: "source" }] : /* istanbul ignore next */ []));
|
|
837
|
+
snapTolerance = input(...(ngDevMode ? [undefined, { debugName: "snapTolerance" }] : /* istanbul ignore next */ []));
|
|
838
|
+
active = input(true, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
839
|
+
modifyFiltered$ = this.interactionService.modify$.pipe(filter((e) => e.interactionId === this.id()));
|
|
840
|
+
modifyEvent = outputFromObservable(this.modifyFiltered$);
|
|
841
|
+
constructor() {
|
|
842
|
+
effect(() => {
|
|
843
|
+
if (this.active()) {
|
|
844
|
+
this.interactionService.enableModify(this.id(), {
|
|
845
|
+
source: this.source(),
|
|
846
|
+
snapTolerance: this.snapTolerance(),
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
else {
|
|
850
|
+
this.interactionService.disableInteraction(this.id());
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
this.destroyRef.onDestroy(() => {
|
|
854
|
+
this.interactionService.disableInteraction(this.id());
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlModifyInteractionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
858
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlModifyInteractionComponent, isStandalone: true, selector: "ol-modify-interaction", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, snapTolerance: { classPropertyName: "snapTolerance", publicName: "snapTolerance", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { modifyEvent: "modifyEvent" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
859
|
+
}
|
|
860
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlModifyInteractionComponent, decorators: [{
|
|
861
|
+
type: Component,
|
|
862
|
+
args: [{
|
|
863
|
+
selector: 'ol-modify-interaction',
|
|
864
|
+
standalone: true,
|
|
865
|
+
template: '',
|
|
866
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
867
|
+
}]
|
|
868
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], snapTolerance: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapTolerance", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], modifyEvent: [{ type: i0.Output, args: ["modifyEvent"] }] } });
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Declarative component to configure an OpenLayers Select Interaction.
|
|
872
|
+
*/
|
|
873
|
+
class OlSelectInteractionComponent {
|
|
874
|
+
interactionService = inject(OlInteractionService);
|
|
875
|
+
destroyRef = inject(DestroyRef);
|
|
876
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
877
|
+
layers = input(...(ngDevMode ? [undefined, { debugName: "layers" }] : /* istanbul ignore next */ []));
|
|
878
|
+
multi = input(...(ngDevMode ? [undefined, { debugName: "multi" }] : /* istanbul ignore next */ []));
|
|
879
|
+
hitTolerance = input(...(ngDevMode ? [undefined, { debugName: "hitTolerance" }] : /* istanbul ignore next */ []));
|
|
880
|
+
condition = input(...(ngDevMode ? [undefined, { debugName: "condition" }] : /* istanbul ignore next */ []));
|
|
881
|
+
active = input(true, ...(ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []));
|
|
882
|
+
selectFiltered$ = this.interactionService.select$.pipe(filter((e) => e.interactionId === this.id()));
|
|
883
|
+
selectEvent = outputFromObservable(this.selectFiltered$);
|
|
884
|
+
constructor() {
|
|
885
|
+
effect(() => {
|
|
886
|
+
if (this.active()) {
|
|
887
|
+
this.interactionService.enableSelect(this.id(), {
|
|
888
|
+
layers: this.layers(),
|
|
889
|
+
multi: this.multi(),
|
|
890
|
+
hitTolerance: this.hitTolerance(),
|
|
891
|
+
condition: this.condition(),
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
895
|
+
this.interactionService.disableInteraction(this.id());
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
this.destroyRef.onDestroy(() => {
|
|
899
|
+
this.interactionService.disableInteraction(this.id());
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlSelectInteractionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
903
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlSelectInteractionComponent, isStandalone: true, selector: "ol-select-interaction", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, layers: { classPropertyName: "layers", publicName: "layers", isSignal: true, isRequired: false, transformFunction: null }, multi: { classPropertyName: "multi", publicName: "multi", isSignal: true, isRequired: false, transformFunction: null }, hitTolerance: { classPropertyName: "hitTolerance", publicName: "hitTolerance", isSignal: true, isRequired: false, transformFunction: null }, condition: { classPropertyName: "condition", publicName: "condition", isSignal: true, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectEvent: "selectEvent" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
904
|
+
}
|
|
905
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlSelectInteractionComponent, decorators: [{
|
|
906
|
+
type: Component,
|
|
907
|
+
args: [{
|
|
908
|
+
selector: 'ol-select-interaction',
|
|
909
|
+
standalone: true,
|
|
910
|
+
template: '',
|
|
911
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
912
|
+
}]
|
|
913
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], layers: [{ type: i0.Input, args: [{ isSignal: true, alias: "layers", required: false }] }], multi: [{ type: i0.Input, args: [{ isSignal: true, alias: "multi", required: false }] }], hitTolerance: [{ type: i0.Input, args: [{ isSignal: true, alias: "hitTolerance", required: false }] }], condition: [{ type: i0.Input, args: [{ isSignal: true, alias: "condition", required: false }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], selectEvent: [{ type: i0.Output, args: ["selectEvent"] }] } });
|
|
914
|
+
|
|
527
915
|
/**
|
|
528
916
|
* Provide the interactions feature with OlInteractionService and all specialized services.
|
|
529
917
|
* Note: ZoneHelper is inherited from core's provideOpenLayers.
|
|
@@ -533,11 +921,13 @@ function withInteractions() {
|
|
|
533
921
|
return {
|
|
534
922
|
kind: 'interactions',
|
|
535
923
|
providers: [
|
|
924
|
+
OlLayerService, // DX: interactions often need layers
|
|
536
925
|
OlInteractionService,
|
|
537
926
|
InteractionStateService,
|
|
538
927
|
SelectInteractionService,
|
|
539
928
|
DrawInteractionService,
|
|
540
929
|
ModifyInteractionService,
|
|
930
|
+
MeasurementInteractionService,
|
|
541
931
|
],
|
|
542
932
|
};
|
|
543
933
|
}
|
|
@@ -596,6 +986,19 @@ function withModifyInteraction(id, config = {}) {
|
|
|
596
986
|
deps: [OlInteractionService],
|
|
597
987
|
};
|
|
598
988
|
}
|
|
989
|
+
/**
|
|
990
|
+
* Enable measurement interaction when providing the interactions feature.
|
|
991
|
+
* @returns Provider function that enables measurement interaction
|
|
992
|
+
*/
|
|
993
|
+
function withMeasurementInteraction() {
|
|
994
|
+
return {
|
|
995
|
+
provide: 'MEASUREMENT_INTERACTION_CONFIG',
|
|
996
|
+
useFactory: (service) => {
|
|
997
|
+
return service;
|
|
998
|
+
},
|
|
999
|
+
deps: [MeasurementInteractionService],
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
599
1002
|
|
|
600
1003
|
// @angular-helpers/openlayers/interactions
|
|
601
1004
|
// Main orchestrator service
|
|
@@ -604,4 +1007,4 @@ function withModifyInteraction(id, config = {}) {
|
|
|
604
1007
|
* Generated bundle index. Do not edit.
|
|
605
1008
|
*/
|
|
606
1009
|
|
|
607
|
-
export { DrawInteractionService, InteractionStateService, ModifyInteractionService, OlInteractionService, SelectInteractionService, olFeatureToFeature, provideInteractions, withDrawInteraction, withInteractions, withModifyInteraction, withSelectInteraction };
|
|
1010
|
+
export { DrawInteractionService, InteractionStateService, MeasurementInteractionService, ModifyInteractionService, OlDrawInteractionComponent, OlInteractionService, OlModifyInteractionComponent, OlSelectInteractionComponent, SelectInteractionService, olFeatureToFeature, provideInteractions, withDrawInteraction, withInteractions, withMeasurementInteraction, withModifyInteraction, withSelectInteraction };
|