@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.
@@ -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.4", ngImport: i0, type: InteractionStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
126
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: InteractionStateService });
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.4", ngImport: i0, type: InteractionStateService, decorators: [{
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', (_e) => {
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.4", ngImport: i0, type: SelectInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
225
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: SelectInteractionService });
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.4", ngImport: i0, type: SelectInteractionService, decorators: [{
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: config.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.4", ngImport: i0, type: DrawInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
300
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: DrawInteractionService });
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.4", ngImport: i0, type: DrawInteractionService, decorators: [{
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.4", ngImport: i0, type: ModifyInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
370
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ModifyInteractionService });
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.4", ngImport: i0, type: ModifyInteractionService, decorators: [{
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.4", ngImport: i0, type: OlInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
521
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlInteractionService });
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.4", ngImport: i0, type: OlInteractionService, decorators: [{
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 };