@theseam/ui-common 2.0.1-beta.99 → 2.1.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/ai/index.d.ts +1 -363
- package/carousel/index.d.ts +1 -21
- package/data-filters/index.d.ts +30 -6
- package/datatable/index.d.ts +3 -299
- package/datatable-alterations-display/index.d.ts +1 -61
- package/fesm2022/theseam-ui-common-ai.mjs +1 -1368
- package/fesm2022/theseam-ui-common-ai.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-carousel.mjs +1 -48
- package/fesm2022/theseam-ui-common-carousel.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-data-filters.mjs +61 -18
- package/fesm2022/theseam-ui-common-data-filters.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-datatable-alterations-display.mjs +1 -197
- package/fesm2022/theseam-ui-common-datatable-alterations-display.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-datatable.mjs +4 -668
- package/fesm2022/theseam-ui-common-datatable.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-file-input.mjs +1 -156
- package/fesm2022/theseam-ui-common-file-input.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-google-maps.mjs +299 -218
- package/fesm2022/theseam-ui-common-google-maps.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-icon.mjs +1 -72
- package/fesm2022/theseam-ui-common-icon.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-table-cell-types.mjs +0 -4
- package/fesm2022/theseam-ui-common-table-cell-types.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-toggle-group.mjs +81 -112
- package/fesm2022/theseam-ui-common-toggle-group.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-tooltip.mjs +1 -110
- package/fesm2022/theseam-ui-common-tooltip.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-utils.mjs +112 -21
- package/fesm2022/theseam-ui-common-utils.mjs.map +1 -1
- package/fesm2022/theseam-ui-common-widget.mjs +1 -23
- package/fesm2022/theseam-ui-common-widget.mjs.map +1 -1
- package/file-input/index.d.ts +1 -78
- package/google-maps/index.d.ts +35 -23
- package/icon/index.d.ts +3 -33
- package/package.json +5 -2
- package/toggle-group/index.d.ts +42 -18
- package/tooltip/index.d.ts +2 -40
- package/utils/index.d.ts +38 -6
- package/widget/index.d.ts +2 -17
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { __decorate } from 'tslib';
|
|
2
2
|
import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { InjectionToken, Injectable, Injector,
|
|
4
|
+
import { InjectionToken, Injectable, Injector, inject, ChangeDetectionStrategy, Component, HostListener, Input, Optional, Inject, ChangeDetectorRef, EventEmitter, forwardRef, ViewChild, Output, HostBinding, Directive, NgModule, LOCALE_ID } from '@angular/core';
|
|
5
5
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
6
6
|
import { Observable, Subject, fromEvent, BehaviorSubject, from, of, interval, defer, throwError } from 'rxjs';
|
|
7
7
|
import { takeUntil, switchMap, tap, map, catchError, startWith, filter, take, mapTo } from 'rxjs/operators';
|
|
8
|
-
import { faFileImport, faCrosshairs, faSearchLocation } from '@fortawesome/free-solid-svg-icons';
|
|
8
|
+
import { faDrawPolygon, faFileImport, faCrosshairs, faSearchLocation } from '@fortawesome/free-solid-svg-icons';
|
|
9
9
|
import { mixinDisabled, InputBoolean, InputNumber } from '@theseam/ui-common/core';
|
|
10
10
|
import * as i6 from '@theseam/ui-common/menu';
|
|
11
11
|
import { MenuComponent, TheSeamMenuModule } from '@theseam/ui-common/menu';
|
|
12
|
-
import {
|
|
12
|
+
import { TerraDraw, TerraDrawPolyLineMode } from 'terra-draw';
|
|
13
|
+
import { TerraDrawGoogleMapsAdapter } from 'terra-draw-google-maps-adapter';
|
|
14
|
+
import { notNullOrUndefined, closePolygons, polygonHasMinDistinctVertices, addHoleToPolygon, polygonContains, readGeoFile } from '@theseam/ui-common/utils';
|
|
13
15
|
import { ESCAPE } from '@angular/cdk/keycodes';
|
|
14
|
-
import
|
|
15
|
-
import { polygon, multiPolygon } from '@turf/helpers';
|
|
16
|
+
import { toSignal } from '@angular/core/rxjs-interop';
|
|
16
17
|
import * as i2 from '@theseam/ui-common/icon';
|
|
17
18
|
import { TheSeamIconModule } from '@theseam/ui-common/icon';
|
|
18
19
|
import * as i1 from '@angular/cdk/a11y';
|
|
@@ -71,64 +72,6 @@ function stripAppFeaturePropertiesFromJson(json) {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
|
-
/**
|
|
75
|
-
* Searches for a Feature in Data that contains the provided Feature and can use
|
|
76
|
-
* it as a cutout area.
|
|
77
|
-
*/
|
|
78
|
-
function getPossibleExteriorFeature(data, feature) {
|
|
79
|
-
let exteriorPolygonFeature;
|
|
80
|
-
data.forEach((f) => {
|
|
81
|
-
if (f === feature) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const geometry = f.getGeometry();
|
|
85
|
-
if (geometry === null) {
|
|
86
|
-
throw Error(`Geometry not found.`);
|
|
87
|
-
}
|
|
88
|
-
if (geometry.getType() === 'Polygon' && featureContains(f, feature)) {
|
|
89
|
-
exteriorPolygonFeature = f;
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
return exteriorPolygonFeature;
|
|
93
|
-
}
|
|
94
|
-
function addInnerFeatureCutoutToExteriorFeature(exteriorFeature, innerFeature) {
|
|
95
|
-
const exteriorGeometry = exteriorFeature.getGeometry();
|
|
96
|
-
if (exteriorGeometry === null) {
|
|
97
|
-
throw Error(`Geometry not found.`);
|
|
98
|
-
}
|
|
99
|
-
const innerGeometry = innerFeature.getGeometry();
|
|
100
|
-
if (innerGeometry === null) {
|
|
101
|
-
throw Error(`Geometry not found.`);
|
|
102
|
-
}
|
|
103
|
-
// NOTE: Other geometries may support cutouts, but our map shapes editor only
|
|
104
|
-
// supports polygons currently, so we will need to handle other geometry types
|
|
105
|
-
// here if we start allowing users to draw shapes other than polygon.
|
|
106
|
-
if (exteriorGeometry.getType() !== 'Polygon' ||
|
|
107
|
-
innerGeometry.getType() !== 'Polygon') {
|
|
108
|
-
throw Error(`Inner cutout is only supported by Polygon gemoetry.`);
|
|
109
|
-
}
|
|
110
|
-
const featurePolygon = innerGeometry;
|
|
111
|
-
const exteriorPolygon = exteriorGeometry;
|
|
112
|
-
exteriorFeature.setGeometry(new google.maps.Data.Polygon([
|
|
113
|
-
...exteriorPolygon.getArray(),
|
|
114
|
-
featurePolygon.getAt(0).getArray().reverse(),
|
|
115
|
-
]));
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Google maps paths don't always start and stop at the exact same position, so
|
|
119
|
-
* this will fix that for turfjs.
|
|
120
|
-
*/
|
|
121
|
-
function fixPathDifferentStartingAndEndingPoint(coordinates) {
|
|
122
|
-
if (coordinates.length <= 1) {
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
const start = coordinates[0];
|
|
126
|
-
const end = coordinates[coordinates.length - 1];
|
|
127
|
-
if (start[0] === end[0] && start[1] === end[1]) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
coordinates.push(coordinates[0]);
|
|
131
|
-
}
|
|
132
75
|
function polygonHasValidPathsLengths(polygon, minPointsInValidPath = 3) {
|
|
133
76
|
const paths = polygon.getPaths().getArray();
|
|
134
77
|
for (const path of paths) {
|
|
@@ -139,47 +82,50 @@ function polygonHasValidPathsLengths(polygon, minPointsInValidPath = 3) {
|
|
|
139
82
|
return true;
|
|
140
83
|
}
|
|
141
84
|
function polygonCoordinates(polygon) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return
|
|
85
|
+
const polygonGeoJson = {
|
|
86
|
+
type: 'Polygon',
|
|
87
|
+
coordinates: polygon
|
|
88
|
+
.getArray()
|
|
89
|
+
.map((linRing) => linRing.getArray().map((x) => [x.lng(), x.lat()])),
|
|
90
|
+
};
|
|
91
|
+
closePolygons(polygonGeoJson);
|
|
92
|
+
return polygonGeoJson.coordinates;
|
|
150
93
|
}
|
|
151
|
-
|
|
152
|
-
|
|
94
|
+
/** Build a google.maps.Data.Polygon from a GeoJSON Polygon (lng/lat order). */
|
|
95
|
+
function dataPolygonFromGeoJson(polygon) {
|
|
96
|
+
const rings = polygon.coordinates.map((ring) =>
|
|
97
|
+
// GeoJSON rings are explicitly closed (first coordinate repeated at the
|
|
98
|
+
// end), but google.maps.Data.Polygon paths are implicitly closed and must
|
|
99
|
+
// NOT include the repeated point — otherwise it becomes a duplicate vertex
|
|
100
|
+
// coincident with the first (two points that edit independently, and a
|
|
101
|
+
// double closing point when serialized back to GeoJSON).
|
|
102
|
+
openRing(ring).map(([lng, lat]) => ({ lat, lng })));
|
|
103
|
+
return new google.maps.Data.Polygon(rings);
|
|
153
104
|
}
|
|
154
|
-
|
|
155
|
-
|
|
105
|
+
/** Drop a ring's explicit closing point (a trailing copy of the first). */
|
|
106
|
+
function openRing(ring) {
|
|
107
|
+
if (ring.length < 2) {
|
|
108
|
+
return ring;
|
|
109
|
+
}
|
|
110
|
+
const first = ring[0];
|
|
111
|
+
const last = ring[ring.length - 1];
|
|
112
|
+
return first[0] === last[0] && first[1] === last[1] ? ring.slice(0, -1) : ring;
|
|
156
113
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
else if (geometry.getType() === 'MultiPolygon') {
|
|
166
|
-
return toTurfJsMultiPolygon(geometry);
|
|
114
|
+
/**
|
|
115
|
+
* Read an existing feature's Polygon geometry as a closed GeoJSON Polygon.
|
|
116
|
+
* Returns undefined for non-Polygon geometries. Does not mutate the feature.
|
|
117
|
+
*/
|
|
118
|
+
function geoJsonPolygonFromDataFeature(feature) {
|
|
119
|
+
const geometry = feature.getGeometry();
|
|
120
|
+
if (geometry === null || geometry.getType() !== 'Polygon') {
|
|
121
|
+
return undefined;
|
|
167
122
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return
|
|
174
|
-
}
|
|
175
|
-
function createDataFeatureFromPolygon(polygon) {
|
|
176
|
-
const arr = polygon
|
|
177
|
-
.getPaths()
|
|
178
|
-
.getArray()
|
|
179
|
-
.map((x) => x.getArray());
|
|
180
|
-
return new google.maps.Data.Feature({
|
|
181
|
-
geometry: new google.maps.Data.Polygon(arr),
|
|
182
|
-
});
|
|
123
|
+
const polygon = {
|
|
124
|
+
type: 'Polygon',
|
|
125
|
+
coordinates: polygonCoordinates(geometry),
|
|
126
|
+
};
|
|
127
|
+
closePolygons(polygon);
|
|
128
|
+
return polygon;
|
|
183
129
|
}
|
|
184
130
|
function getBoundsWithAllFeatures(data) {
|
|
185
131
|
const bounds = new google.maps.LatLngBounds();
|
|
@@ -440,19 +386,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
440
386
|
type: Injectable
|
|
441
387
|
}], ctorParameters: () => [] });
|
|
442
388
|
|
|
443
|
-
const DEFAULT_POLYGON_OPTIONS = (editingEnabled) => ({
|
|
444
|
-
clickable: editingEnabled,
|
|
445
|
-
draggable: editingEnabled,
|
|
446
|
-
editable: editingEnabled,
|
|
447
|
-
});
|
|
448
|
-
const DEFAULT_DRAWING_MANAGER_OPTIONS = (editingEnabled) => ({
|
|
449
|
-
drawingControl: editingEnabled,
|
|
450
|
-
drawingControlOptions: {
|
|
451
|
-
drawingModes: [google.maps.drawing.OverlayType.POLYGON],
|
|
452
|
-
},
|
|
453
|
-
polygonOptions: DEFAULT_POLYGON_OPTIONS(editingEnabled),
|
|
454
|
-
drawingMode: null,
|
|
455
|
-
});
|
|
456
389
|
const FEATURE_STYLE_OPTIONS_DEFAULT = (editingEnabled) => ({
|
|
457
390
|
clickable: true,
|
|
458
391
|
// clickable: editingEnabled,
|
|
@@ -501,7 +434,10 @@ class GoogleMapsService {
|
|
|
501
434
|
_ngUnsubscribe = new Subject();
|
|
502
435
|
_mapReadySubject = new BehaviorSubject(false);
|
|
503
436
|
_editingEnabledSubject = new BehaviorSubject(true);
|
|
504
|
-
|
|
437
|
+
_terraDraw;
|
|
438
|
+
_terraDrawReady = false;
|
|
439
|
+
_drawingSubject = new BehaviorSubject(false);
|
|
440
|
+
drawing$ = this._drawingSubject.asObservable();
|
|
505
441
|
_featureContextMenu = null;
|
|
506
442
|
_activeContextMenu = null;
|
|
507
443
|
_baseLatLng;
|
|
@@ -523,13 +459,23 @@ class GoogleMapsService {
|
|
|
523
459
|
this.mapReady$ = this._mapReadySubject.asObservable();
|
|
524
460
|
}
|
|
525
461
|
ngOnDestroy() {
|
|
462
|
+
if (this._terraDraw?.enabled) {
|
|
463
|
+
this._terraDraw.stop();
|
|
464
|
+
}
|
|
465
|
+
this._terraDraw = undefined;
|
|
466
|
+
this._drawingSubject.complete();
|
|
526
467
|
this._ngUnsubscribe.next();
|
|
527
468
|
this._ngUnsubscribe.complete();
|
|
528
469
|
}
|
|
529
470
|
setMap(map) {
|
|
530
471
|
this.googleMap = map;
|
|
531
472
|
this._mapReadySubject.next(true);
|
|
532
|
-
|
|
473
|
+
// Terra Draw's Google Maps adapter binds its event listeners to the map's
|
|
474
|
+
// rendered '.gm-style' DOM subtree (located via querySelector). That subtree
|
|
475
|
+
// does not exist yet when 'mapInitialized' fires, so initializing Terra Draw
|
|
476
|
+
// synchronously here makes the adapter register listeners on a null element
|
|
477
|
+
// and throw. Defer init until the map has rendered (first 'idle').
|
|
478
|
+
google.maps.event.addListenerOnce(map, 'idle', () => this._initTerraDraw());
|
|
533
479
|
this._initFeatureStyling();
|
|
534
480
|
this._initFeatureChangeListeners();
|
|
535
481
|
}
|
|
@@ -551,20 +497,12 @@ class GoogleMapsService {
|
|
|
551
497
|
this.googleMap.data.revertStyle();
|
|
552
498
|
if (!enabled) {
|
|
553
499
|
this.stopDrawing();
|
|
554
|
-
const options = DEFAULT_DRAWING_MANAGER_OPTIONS(this.isEditingEnabled());
|
|
555
|
-
this._drawingManager?.setOptions(options);
|
|
556
|
-
this._drawingManager?.setMap(null);
|
|
557
500
|
this.googleMap.data.forEach((f) => {
|
|
558
501
|
if (isFeatureSelected(f)) {
|
|
559
502
|
setFeatureSelected(f, false);
|
|
560
503
|
}
|
|
561
504
|
});
|
|
562
505
|
}
|
|
563
|
-
else {
|
|
564
|
-
const options = DEFAULT_DRAWING_MANAGER_OPTIONS(this.isEditingEnabled());
|
|
565
|
-
this._drawingManager?.setOptions(options);
|
|
566
|
-
this._drawingManager?.setMap(this.googleMap);
|
|
567
|
-
}
|
|
568
506
|
}
|
|
569
507
|
}
|
|
570
508
|
isEditingEnabled() {
|
|
@@ -590,58 +528,138 @@ class GoogleMapsService {
|
|
|
590
528
|
}
|
|
591
529
|
});
|
|
592
530
|
}
|
|
531
|
+
/** Whether polygon drawing mode is currently active. */
|
|
532
|
+
isDrawing() {
|
|
533
|
+
return this._terraDraw?.getMode() === 'polyline';
|
|
534
|
+
}
|
|
535
|
+
/** Enter polygon drawing mode. */
|
|
536
|
+
startDrawing() {
|
|
537
|
+
if (!this._terraDraw || !this._terraDrawReady || !this.isEditingEnabled()) {
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
// Clear any selection when entering drawing mode. Otherwise a selected
|
|
541
|
+
// feature and the shape being drawn both appear selected, reading as one
|
|
542
|
+
// shape even though they are unrelated.
|
|
543
|
+
this._assertInitialized();
|
|
544
|
+
this.googleMap.data.forEach((f) => {
|
|
545
|
+
if (isFeatureSelected(f)) {
|
|
546
|
+
setFeatureSelected(f, false);
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
this._terraDraw.setMode('polyline');
|
|
550
|
+
this._drawingSubject.next(true);
|
|
551
|
+
}
|
|
593
552
|
/**
|
|
594
|
-
*
|
|
553
|
+
* Cancel any in-progress drawing and leave drawing mode. Switching to the
|
|
554
|
+
* `static` mode clears an unfinished line.
|
|
595
555
|
*/
|
|
596
556
|
stopDrawing() {
|
|
597
|
-
this.
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
// Listening for the completion event of the overlay currently being drawn
|
|
603
|
-
// and removing it. I haven't found a way to cancel the current drawing,
|
|
604
|
-
// without this hack that assumes our listeners will not run into a race
|
|
605
|
-
// condition.
|
|
606
|
-
const listener = google.maps.event.addListener(this._drawingManager, 'overlaycomplete', (event) => {
|
|
607
|
-
event.overlay?.setMap(null);
|
|
608
|
-
listener.remove();
|
|
609
|
-
});
|
|
610
|
-
// To fake canceling the current drawing, without disabling the drawing
|
|
611
|
-
// mode, the drawing mode is being unset then immediately set back. When
|
|
612
|
-
// the mode is unset the 'overlaycomplete' event will fire, which will
|
|
613
|
-
// give a reference to the current overlay to remove, then it is set back
|
|
614
|
-
// to the mode the user was using. To the user is should just seem like
|
|
615
|
-
// the current drawing was canceled and they can start drawing again.
|
|
616
|
-
const mode = this._drawingManager.getDrawingMode();
|
|
617
|
-
this._drawingManager.setDrawingMode(null);
|
|
618
|
-
this._drawingManager.setDrawingMode(mode);
|
|
619
|
-
// 'overlaycomplete' should fire immediately, unless an overlay hadn't
|
|
620
|
-
// started drawing. This timeout will make sure the listener gets removed.
|
|
621
|
-
setTimeout(() => {
|
|
622
|
-
listener.remove();
|
|
623
|
-
});
|
|
624
|
-
});
|
|
557
|
+
if (!this._terraDraw || !this._terraDrawReady) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
this._terraDraw.setMode('static');
|
|
561
|
+
this._drawingSubject.next(false);
|
|
625
562
|
}
|
|
626
|
-
|
|
627
|
-
if (notNullOrUndefined(this.
|
|
628
|
-
throw Error(`
|
|
563
|
+
_initTerraDraw() {
|
|
564
|
+
if (notNullOrUndefined(this._terraDraw)) {
|
|
565
|
+
throw Error(`Terra Draw is already initialized.`);
|
|
629
566
|
}
|
|
630
567
|
this._assertInitialized();
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
568
|
+
// The Google Maps adapter creates an OverlayView on the map; ensure the map
|
|
569
|
+
// element has an id (harmless if one is already present).
|
|
570
|
+
const div = this.googleMap.getDiv();
|
|
571
|
+
if (!div.id) {
|
|
572
|
+
div.id = `seam-google-map-${Math.floor(performance.now())}`;
|
|
573
|
+
}
|
|
574
|
+
const pointerDistance = 10;
|
|
575
|
+
// KNOWN ISSUE (upstream, unresolved): after repeated draws, Terra Draw can
|
|
576
|
+
// intermittently lose pointer control of the Google Maps adapter, so input
|
|
577
|
+
// pans the map instead of drawing until the page is reloaded. This is a race
|
|
578
|
+
// between Terra Draw and the Google Maps adapter, tracked at
|
|
579
|
+
// https://github.com/JamesLMilner/terra-draw/issues/710 (open as of
|
|
580
|
+
// terra-draw 1.32.0 / adapter 1.6.1). It is not fixable in this wrapper;
|
|
581
|
+
// revisit when the upstream issue is resolved.
|
|
582
|
+
const draw = new TerraDraw({
|
|
583
|
+
adapter: new TerraDrawGoogleMapsAdapter({
|
|
584
|
+
lib: google.maps,
|
|
585
|
+
map: this.googleMap,
|
|
586
|
+
// Render Terra Draw's in-progress/finished geometry on its OWN Data
|
|
587
|
+
// layer instead of the map's shared `map.data`. Without this, Terra
|
|
588
|
+
// Draw's features land in the same layer this service manages, so the
|
|
589
|
+
// exterior-feature search would match a just-drawn polygon against its
|
|
590
|
+
// own rendered copy (cutting a hole equal to itself) and getGeoJson
|
|
591
|
+
// would serialize Terra Draw's transient features.
|
|
592
|
+
isolatedData: true,
|
|
593
|
+
}),
|
|
594
|
+
modes: [
|
|
595
|
+
new TerraDrawPolyLineMode({
|
|
596
|
+
// Tighten how close a click must be to the first point to close the
|
|
597
|
+
// polygon (Terra Draw's default ~40px felt too far / closed too
|
|
598
|
+
// easily).
|
|
599
|
+
pointerDistance,
|
|
600
|
+
// Snap the moving vertex onto the line's OWN first point when the
|
|
601
|
+
// cursor is within a few pixels of it, so it's clear the ends are
|
|
602
|
+
// about to meet just before the click that closes the polygon.
|
|
603
|
+
// (Terra Draw's built-in `toCoordinate` only snaps to OTHER features'
|
|
604
|
+
// points — excluding the line being drawn — so it does nothing here.)
|
|
605
|
+
snapping: {
|
|
606
|
+
toCustom: (event, ctx) => {
|
|
607
|
+
const geometry = ctx.getCurrentGeometrySnapshot();
|
|
608
|
+
if (!geometry) {
|
|
609
|
+
return undefined;
|
|
610
|
+
}
|
|
611
|
+
const ring = geometry.type === 'LineString'
|
|
612
|
+
? geometry.coordinates
|
|
613
|
+
: geometry.coordinates[0];
|
|
614
|
+
// Only offer the closing snap once enough points exist to form a
|
|
615
|
+
// polygon (placed points plus the live cursor point).
|
|
616
|
+
if (!ring || ring.length < 4) {
|
|
617
|
+
return undefined;
|
|
618
|
+
}
|
|
619
|
+
const first = ring[0];
|
|
620
|
+
const firstPixel = ctx.project(first[0], first[1]);
|
|
621
|
+
const distance = Math.hypot(firstPixel.x - event.containerX, firstPixel.y - event.containerY);
|
|
622
|
+
const SNAP_DISTANCE_PX = pointerDistance;
|
|
623
|
+
return distance <= SNAP_DISTANCE_PX ? first : undefined;
|
|
624
|
+
},
|
|
625
|
+
},
|
|
626
|
+
// Draw as an open line that closes into a polygon when the start point
|
|
627
|
+
// is clicked (the old Drawing manager's feel): while drawing you see a
|
|
628
|
+
// line, and the shape only "fills in" once committed to the map's Data
|
|
629
|
+
// layer, which is the clear "done" signal. Black line, small white
|
|
630
|
+
// closing/snapping dots (like the edit anchors), no fill on Terra
|
|
631
|
+
// Draw's transient polygon. Terra Draw requires hex colors.
|
|
632
|
+
styles: {
|
|
633
|
+
lineStringColor: '#000000',
|
|
634
|
+
lineStringWidth: 2,
|
|
635
|
+
polygonFillOpacity: 0,
|
|
636
|
+
polygonOutlineColor: '#000000',
|
|
637
|
+
polygonOutlineWidth: 2,
|
|
638
|
+
closingPointColor: '#ffffff',
|
|
639
|
+
closingPointWidth: 4,
|
|
640
|
+
closingPointOutlineColor: '#000000',
|
|
641
|
+
closingPointOutlineWidth: 1,
|
|
642
|
+
snappingPointColor: '#ffffff',
|
|
643
|
+
snappingPointWidth: 4,
|
|
644
|
+
snappingPointOutlineColor: '#000000',
|
|
645
|
+
snappingPointOutlineWidth: 1,
|
|
646
|
+
},
|
|
647
|
+
}),
|
|
648
|
+
],
|
|
649
|
+
});
|
|
650
|
+
draw.on('ready', () => {
|
|
651
|
+
this._terraDrawReady = true;
|
|
652
|
+
// Start in the resting (non-drawing) mode.
|
|
653
|
+
draw.setMode('static');
|
|
654
|
+
});
|
|
655
|
+
draw.on('finish', (id, context) => {
|
|
656
|
+
if (context.action !== 'draw') {
|
|
657
|
+
return;
|
|
643
658
|
}
|
|
659
|
+
this._ngZone.run(() => this._onDrawFinished(id));
|
|
644
660
|
});
|
|
661
|
+
draw.start();
|
|
662
|
+
this._terraDraw = draw;
|
|
645
663
|
}
|
|
646
664
|
addControl(element, position) {
|
|
647
665
|
this._assertInitialized();
|
|
@@ -703,6 +721,12 @@ class GoogleMapsService {
|
|
|
703
721
|
// Select a feature when clicked.
|
|
704
722
|
this.googleMap.data.addListener('click', (event) => {
|
|
705
723
|
this._assertInitialized();
|
|
724
|
+
// While drawing, a click on an existing polygon is placing a vertex,
|
|
725
|
+
// not selecting a feature. Selecting here would both steal the click
|
|
726
|
+
// and leave a misleading selection (see startDrawing's deselect).
|
|
727
|
+
if (this.isDrawing()) {
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
706
730
|
setFeatureSelected(event.feature, true);
|
|
707
731
|
this.googleMap.data.forEach((f) => {
|
|
708
732
|
if (f !== event.feature && isFeatureSelected(f)) {
|
|
@@ -752,54 +776,6 @@ class GoogleMapsService {
|
|
|
752
776
|
}
|
|
753
777
|
this._openContextMenuForFeature(event.feature, event.latLng ?? undefined);
|
|
754
778
|
});
|
|
755
|
-
if (notNullOrUndefined(this._drawingManager)) {
|
|
756
|
-
google.maps.event.addListener(this._drawingManager, 'polygoncomplete', (polygon) => {
|
|
757
|
-
// The DrawingManager doesn't seem to have a way to access the overlays,
|
|
758
|
-
// so if the map is not set then it shouldn'y be considered a successful
|
|
759
|
-
// completion. I am canceling the active drawing by disabling drawing
|
|
760
|
-
// mode and setting the map null in the 'overlaycomplete' event, which
|
|
761
|
-
// fires before the 'polygoncomplete' event.
|
|
762
|
-
if (isNullOrUndefined(polygon.getMap())) {
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
this._assertInitialized();
|
|
766
|
-
// TODO: See if there is a way to prevent the polygon from completing
|
|
767
|
-
// without enough points. This is very low priority, because starting
|
|
768
|
-
// over after adding a single point isn't a major inconvenience.
|
|
769
|
-
if (!polygonHasValidPathsLengths(polygon)) {
|
|
770
|
-
// Remove the drawn polygon.
|
|
771
|
-
polygon.setMap(null);
|
|
772
|
-
// Stop drawing.
|
|
773
|
-
this._drawingManager?.setDrawingMode(null);
|
|
774
|
-
return;
|
|
775
|
-
}
|
|
776
|
-
// Create a map feature of the drawn polygon.
|
|
777
|
-
const feature = createDataFeatureFromPolygon(polygon);
|
|
778
|
-
// Remove the drawn polygon.
|
|
779
|
-
polygon.setMap(null);
|
|
780
|
-
// Stop drawing.
|
|
781
|
-
this._drawingManager?.setDrawingMode(null);
|
|
782
|
-
// Check if the feature should be used as a cutout to an existing
|
|
783
|
-
// feature or added as it's own feature.
|
|
784
|
-
const exteriorPolygonFeature = this._allowDrawingHoleInPolygon
|
|
785
|
-
? getPossibleExteriorFeature(this.googleMap.data, feature)
|
|
786
|
-
: undefined;
|
|
787
|
-
if (exteriorPolygonFeature) {
|
|
788
|
-
addInnerFeatureCutoutToExteriorFeature(exteriorPolygonFeature, feature);
|
|
789
|
-
setFeatureSelected(exteriorPolygonFeature, true);
|
|
790
|
-
}
|
|
791
|
-
else {
|
|
792
|
-
this.googleMap.data.add(feature);
|
|
793
|
-
setFeatureSelected(feature, true);
|
|
794
|
-
}
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
isDrawing() {
|
|
799
|
-
if (isNullOrUndefined(this._drawingManager)) {
|
|
800
|
-
return true;
|
|
801
|
-
}
|
|
802
|
-
return this._drawingManager.getDrawingMode() !== null;
|
|
803
779
|
}
|
|
804
780
|
// TODO: Refactor out of the service meant to just wrap the google maps api.
|
|
805
781
|
hasSelectedFeature() {
|
|
@@ -867,6 +843,74 @@ class GoogleMapsService {
|
|
|
867
843
|
'Please wait for the API to load before trying to interact with it.');
|
|
868
844
|
}
|
|
869
845
|
}
|
|
846
|
+
_onDrawFinished(id) {
|
|
847
|
+
const feature = this._terraDraw?.getSnapshotFeature(id);
|
|
848
|
+
this._terraDraw?.removeFeatures([id]);
|
|
849
|
+
this.stopDrawing();
|
|
850
|
+
const drawn = feature ? this._toDrawnPolygon(feature.geometry) : undefined;
|
|
851
|
+
if (!drawn || !polygonHasMinDistinctVertices(drawn, 3)) {
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
this._assertInitialized();
|
|
855
|
+
const exteriorFeature = this._allowDrawingHoleInPolygon
|
|
856
|
+
? this._getPossibleExteriorFeature(drawn)
|
|
857
|
+
: undefined;
|
|
858
|
+
if (exteriorFeature) {
|
|
859
|
+
const exteriorPolygon = geoJsonPolygonFromDataFeature(exteriorFeature);
|
|
860
|
+
if (exteriorPolygon) {
|
|
861
|
+
const merged = addHoleToPolygon(exteriorPolygon, drawn);
|
|
862
|
+
// Mutate the EXISTING feature instance to preserve its identity and
|
|
863
|
+
// properties (see design constraints).
|
|
864
|
+
exteriorFeature.setGeometry(dataPolygonFromGeoJson(merged));
|
|
865
|
+
setFeatureSelected(exteriorFeature, true);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
const newFeature = new google.maps.Data.Feature({
|
|
870
|
+
geometry: dataPolygonFromGeoJson(drawn),
|
|
871
|
+
});
|
|
872
|
+
this.googleMap.data.add(newFeature);
|
|
873
|
+
setFeatureSelected(newFeature, true);
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Normalize a finished Terra Draw geometry into a Polygon. A Polygon (the
|
|
877
|
+
* user closed the line on its start point) passes through; an open LineString
|
|
878
|
+
* (the user finished without closing) is closed into a polygon so nothing
|
|
879
|
+
* they drew is discarded. Any other geometry type yields undefined.
|
|
880
|
+
*/
|
|
881
|
+
_toDrawnPolygon(geometry) {
|
|
882
|
+
if (geometry.type === 'Polygon') {
|
|
883
|
+
return geometry;
|
|
884
|
+
}
|
|
885
|
+
if (geometry.type === 'LineString') {
|
|
886
|
+
const polygon = {
|
|
887
|
+
type: 'Polygon',
|
|
888
|
+
coordinates: [[...geometry.coordinates]],
|
|
889
|
+
};
|
|
890
|
+
closePolygons(polygon);
|
|
891
|
+
return polygon;
|
|
892
|
+
}
|
|
893
|
+
return undefined;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Find an existing Polygon feature that fully contains the drawn polygon, so
|
|
897
|
+
* the drawing can be applied as a cutout. Returns the existing feature
|
|
898
|
+
* instance (never a copy).
|
|
899
|
+
*/
|
|
900
|
+
_getPossibleExteriorFeature(drawn) {
|
|
901
|
+
this._assertInitialized();
|
|
902
|
+
let match;
|
|
903
|
+
this.googleMap.data.forEach((f) => {
|
|
904
|
+
if (match) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
const candidate = geoJsonPolygonFromDataFeature(f);
|
|
908
|
+
if (candidate && polygonContains(candidate, drawn)) {
|
|
909
|
+
match = f;
|
|
910
|
+
}
|
|
911
|
+
});
|
|
912
|
+
return match;
|
|
913
|
+
}
|
|
870
914
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GoogleMapsService, deps: [{ token: MapValueManagerService }, { token: i0.NgZone }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
871
915
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GoogleMapsService });
|
|
872
916
|
}
|
|
@@ -950,6 +994,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
950
994
|
type: Injectable
|
|
951
995
|
}], ctorParameters: () => [{ type: GoogleMapsService }, { type: i0.Injector }, { type: i0.ViewContainerRef }] });
|
|
952
996
|
|
|
997
|
+
class TheSeamGoogleMapsDrawButtonControlComponent {
|
|
998
|
+
_googleMaps = inject(GoogleMapsService);
|
|
999
|
+
_data = inject(MAP_CONTROL_DATA, { optional: true });
|
|
1000
|
+
_active = toSignal(this._googleMaps.drawing$, {
|
|
1001
|
+
initialValue: false,
|
|
1002
|
+
});
|
|
1003
|
+
label = this._data?.label ?? 'Draw Field';
|
|
1004
|
+
icon = this._data?.icon ?? faDrawPolygon;
|
|
1005
|
+
_onClick() {
|
|
1006
|
+
if (this._googleMaps.isDrawing()) {
|
|
1007
|
+
this._googleMaps.stopDrawing();
|
|
1008
|
+
}
|
|
1009
|
+
else {
|
|
1010
|
+
this._googleMaps.startDrawing();
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamGoogleMapsDrawButtonControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1014
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TheSeamGoogleMapsDrawButtonControlComponent, isStandalone: true, selector: "button[seam-google-maps-draw-button-control]", host: { attributes: { "type": "button" }, listeners: { "click": "_onClick()" }, properties: { "attr.draggable": "false", "attr.aria-label": "label", "attr.title": "label", "attr.aria-pressed": "_active()", "class.active": "_active()" }, classAttribute: "gmnoprint gm-control-active" }, ngImport: i0, template: "<seam-icon [icon]=\"icon\" iconType=\"image-fill\"></seam-icon>\n", styles: [":host{box-sizing:border-box;position:absolute;height:40px;width:40px;margin:10px;padding:8px;border:0px;border-radius:2px;background:none #fff;box-shadow:#0000004d 0 1px 4px -1px;color:#666;text-transform:none;appearance:none;cursor:pointer;-webkit-user-select:none;user-select:none;overflow:hidden}:host.active{color:#000;box-shadow:#0000004d 0 1px 4px -1px,inset 0 0 0 2px #000}\n"], dependencies: [{ kind: "ngmodule", type: TheSeamIconModule }, { kind: "component", type: i2.IconComponent, selector: "seam-icon", inputs: ["grayscaleOnDisable", "disabled", "iconClass", "icon", "size", "showDefaultOnError", "defaultIcon", "iconType"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1015
|
+
}
|
|
1016
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TheSeamGoogleMapsDrawButtonControlComponent, decorators: [{
|
|
1017
|
+
type: Component,
|
|
1018
|
+
args: [{ selector: 'button[seam-google-maps-draw-button-control]', imports: [TheSeamIconModule], host: {
|
|
1019
|
+
'(click)': '_onClick()',
|
|
1020
|
+
'[attr.draggable]': 'false',
|
|
1021
|
+
'[attr.aria-label]': 'label',
|
|
1022
|
+
'[attr.title]': 'label',
|
|
1023
|
+
'[attr.aria-pressed]': '_active()',
|
|
1024
|
+
'[class.active]': '_active()',
|
|
1025
|
+
type: 'button',
|
|
1026
|
+
class: 'gmnoprint gm-control-active',
|
|
1027
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, template: "<seam-icon [icon]=\"icon\" iconType=\"image-fill\"></seam-icon>\n", styles: [":host{box-sizing:border-box;position:absolute;height:40px;width:40px;margin:10px;padding:8px;border:0px;border-radius:2px;background:none #fff;box-shadow:#0000004d 0 1px 4px -1px;color:#666;text-transform:none;appearance:none;cursor:pointer;-webkit-user-select:none;user-select:none;overflow:hidden}:host.active{color:#000;box-shadow:#0000004d 0 1px 4px -1px,inset 0 0 0 2px #000}\n"] }]
|
|
1028
|
+
}] });
|
|
1029
|
+
|
|
953
1030
|
/**
|
|
954
1031
|
*
|
|
955
1032
|
*/
|
|
@@ -1359,6 +1436,10 @@ class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase {
|
|
|
1359
1436
|
data: { label: 'Center on Field', icon: faCrosshairs },
|
|
1360
1437
|
position: 9 /* google.maps.ControlPosition.RIGHT_BOTTOM */,
|
|
1361
1438
|
};
|
|
1439
|
+
_drawControlDef = {
|
|
1440
|
+
component: TheSeamGoogleMapsDrawButtonControlComponent,
|
|
1441
|
+
position: 1 /* google.maps.ControlPosition.TOP_LEFT */,
|
|
1442
|
+
};
|
|
1362
1443
|
_focusOrigin = null;
|
|
1363
1444
|
set value(value) {
|
|
1364
1445
|
this._mapValueManager.setValue(value, MapValueSource.Input);
|
|
@@ -1579,7 +1660,7 @@ class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase {
|
|
|
1579
1660
|
useExisting: forwardRef(() => TheSeamGoogleMapsComponent),
|
|
1580
1661
|
multi: true,
|
|
1581
1662
|
},
|
|
1582
|
-
], viewQueries: [{ propertyName: "featureContextMenu", first: true, predicate: ["featureContextMenu"], descendants: true, read: MenuComponent, static: true }], exportAs: ["seamGoogleMaps"], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"_gmApiLoaded | async\">\n <google-map\n height=\"100%\"\n width=\"100%\"\n [center]=\"{ lat: latitude, lng: longitude }\"\n [zoom]=\"zoom\"\n [options]=\"_options\"\n (mapInitialized)=\"_onMapReady($any($event))\"\n >\n </google-map>\n</ng-container>\n<seam-menu #featureContextMenu>\n <button\n seamMenuItem\n *ngFor=\"let item of _contextMenuItems$ | async\"\n (click)=\"item.action(item)\"\n >\n {{ item.label }}\n </button>\n</seam-menu>\n<seam-map-file-drop *ngIf=\"fileDropEnabled\"></seam-map-file-drop>\n\n<seam-map-control\n *ngIf=\"fileUploadControlEnabled\"\n [def]=\"_fileUploadControlDef\"\n></seam-map-control>\n<seam-map-control\n *ngIf=\"reCenterControlEnabled\"\n [def]=\"_reCenterControlDef\"\n></seam-map-control>\n", styles: [":host{display:block;position:relative;height:400px;width:100%}:host.show-focus-border.cdk-focused{outline:0;box-shadow:0 0 0 .2rem #357ebd40}:host.show-focus-border[disabled]{opacity:.65}\n"], dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i6.MenuComponent, selector: "seam-menu", inputs: ["menuClass", "baseWidth", "animationType"], outputs: ["closed"], exportAs: ["seamMenu"] }, { kind: "component", type: i6.MenuItemComponent, selector: "[seamMenuItem]", inputs: ["disabled", "role", "icon", "iconClass", "sublevelIcon", "subLevelIconClass", "badgeText", "badgeTheme"], exportAs: ["seamMenuItem"] }, { kind: "component", type: i7.GoogleMap, selector: "google-map", inputs: ["height", "width", "mapId", "mapTypeId", "center", "zoom", "options"], outputs: ["mapInitialized", "authFailure", "boundsChanged", "centerChanged", "mapClick", "mapDblclick", "mapDrag", "mapDragend", "mapDragstart", "headingChanged", "idle", "maptypeidChanged", "mapMousemove", "mapMouseout", "mapMouseover", "projectionChanged", "mapRightclick", "tilesloaded", "tiltChanged", "zoomChanged"], exportAs: ["googleMap"] }, { kind: "component", type: TheSeamMapFileDropComponent, selector: "seam-map-file-drop" }, { kind: "component", type: TheSeamMapsControlComponent, selector: "seam-map-control", inputs: ["def"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1663
|
+
], viewQueries: [{ propertyName: "featureContextMenu", first: true, predicate: ["featureContextMenu"], descendants: true, read: MenuComponent, static: true }], exportAs: ["seamGoogleMaps"], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"_gmApiLoaded | async\">\n <google-map\n height=\"100%\"\n width=\"100%\"\n [center]=\"{ lat: latitude, lng: longitude }\"\n [zoom]=\"zoom\"\n [options]=\"_options\"\n (mapInitialized)=\"_onMapReady($any($event))\"\n >\n </google-map>\n</ng-container>\n<seam-menu #featureContextMenu>\n <button\n seamMenuItem\n *ngFor=\"let item of _contextMenuItems$ | async\"\n (click)=\"item.action(item)\"\n >\n {{ item.label }}\n </button>\n</seam-menu>\n<seam-map-file-drop *ngIf=\"fileDropEnabled\"></seam-map-file-drop>\n\n<seam-map-control\n *ngIf=\"fileUploadControlEnabled\"\n [def]=\"_fileUploadControlDef\"\n></seam-map-control>\n<seam-map-control\n *ngIf=\"reCenterControlEnabled\"\n [def]=\"_reCenterControlDef\"\n></seam-map-control>\n<seam-map-control\n *ngIf=\"editingEnabled\"\n [def]=\"_drawControlDef\"\n></seam-map-control>\n", styles: [":host{display:block;position:relative;height:400px;width:100%}:host.show-focus-border.cdk-focused{outline:0;box-shadow:0 0 0 .2rem #357ebd40}:host.show-focus-border[disabled]{opacity:.65}\n"], dependencies: [{ kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i6.MenuComponent, selector: "seam-menu", inputs: ["menuClass", "baseWidth", "animationType"], outputs: ["closed"], exportAs: ["seamMenu"] }, { kind: "component", type: i6.MenuItemComponent, selector: "[seamMenuItem]", inputs: ["disabled", "role", "icon", "iconClass", "sublevelIcon", "subLevelIconClass", "badgeText", "badgeTheme"], exportAs: ["seamMenuItem"] }, { kind: "component", type: i7.GoogleMap, selector: "google-map", inputs: ["height", "width", "mapId", "mapTypeId", "center", "zoom", "options"], outputs: ["mapInitialized", "authFailure", "boundsChanged", "centerChanged", "mapClick", "mapDblclick", "mapDrag", "mapDragend", "mapDragstart", "headingChanged", "idle", "maptypeidChanged", "mapMousemove", "mapMouseout", "mapMouseover", "projectionChanged", "mapRightclick", "tilesloaded", "tiltChanged", "zoomChanged"], exportAs: ["googleMap"] }, { kind: "component", type: TheSeamMapFileDropComponent, selector: "seam-map-file-drop" }, { kind: "component", type: TheSeamMapsControlComponent, selector: "seam-map-control", inputs: ["def"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1583
1664
|
}
|
|
1584
1665
|
__decorate([
|
|
1585
1666
|
InputBoolean()
|
|
@@ -1625,7 +1706,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
1625
1706
|
useExisting: forwardRef(() => TheSeamGoogleMapsComponent),
|
|
1626
1707
|
multi: true,
|
|
1627
1708
|
},
|
|
1628
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, exportAs: 'seamGoogleMaps', standalone: false, template: "<ng-container *ngIf=\"_gmApiLoaded | async\">\n <google-map\n height=\"100%\"\n width=\"100%\"\n [center]=\"{ lat: latitude, lng: longitude }\"\n [zoom]=\"zoom\"\n [options]=\"_options\"\n (mapInitialized)=\"_onMapReady($any($event))\"\n >\n </google-map>\n</ng-container>\n<seam-menu #featureContextMenu>\n <button\n seamMenuItem\n *ngFor=\"let item of _contextMenuItems$ | async\"\n (click)=\"item.action(item)\"\n >\n {{ item.label }}\n </button>\n</seam-menu>\n<seam-map-file-drop *ngIf=\"fileDropEnabled\"></seam-map-file-drop>\n\n<seam-map-control\n *ngIf=\"fileUploadControlEnabled\"\n [def]=\"_fileUploadControlDef\"\n></seam-map-control>\n<seam-map-control\n *ngIf=\"reCenterControlEnabled\"\n [def]=\"_reCenterControlDef\"\n></seam-map-control>\n", styles: [":host{display:block;position:relative;height:400px;width:100%}:host.show-focus-border.cdk-focused{outline:0;box-shadow:0 0 0 .2rem #357ebd40}:host.show-focus-border[disabled]{opacity:.65}\n"] }]
|
|
1709
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, exportAs: 'seamGoogleMaps', standalone: false, template: "<ng-container *ngIf=\"_gmApiLoaded | async\">\n <google-map\n height=\"100%\"\n width=\"100%\"\n [center]=\"{ lat: latitude, lng: longitude }\"\n [zoom]=\"zoom\"\n [options]=\"_options\"\n (mapInitialized)=\"_onMapReady($any($event))\"\n >\n </google-map>\n</ng-container>\n<seam-menu #featureContextMenu>\n <button\n seamMenuItem\n *ngFor=\"let item of _contextMenuItems$ | async\"\n (click)=\"item.action(item)\"\n >\n {{ item.label }}\n </button>\n</seam-menu>\n<seam-map-file-drop *ngIf=\"fileDropEnabled\"></seam-map-file-drop>\n\n<seam-map-control\n *ngIf=\"fileUploadControlEnabled\"\n [def]=\"_fileUploadControlDef\"\n></seam-map-control>\n<seam-map-control\n *ngIf=\"reCenterControlEnabled\"\n [def]=\"_reCenterControlDef\"\n></seam-map-control>\n<seam-map-control\n *ngIf=\"editingEnabled\"\n [def]=\"_drawControlDef\"\n></seam-map-control>\n", styles: [":host{display:block;position:relative;height:400px;width:100%}:host.show-focus-border.cdk-focused{outline:0;box-shadow:0 0 0 .2rem #357ebd40}:host.show-focus-border[disabled]{opacity:.65}\n"] }]
|
|
1629
1710
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.FocusMonitor }, { type: GoogleMapsService }, { type: MapValueManagerService }, { type: TheSeamGoogleMapsApiLoader }], propDecorators: { value: [{
|
|
1630
1711
|
type: Input
|
|
1631
1712
|
}], tabIndex: [{
|
|
@@ -2244,5 +2325,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
2244
2325
|
* Generated bundle index. Do not edit.
|
|
2245
2326
|
*/
|
|
2246
2327
|
|
|
2247
|
-
export { AppFeaturePropertyName, GoogleMapsContextMenu, GoogleMapsControlsService, GoogleMapsService, MAP_CONTROLS_SERVICE, MAP_CONTROL_DATA, MapControlRef, MapValueManagerService, MapValueSource, SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS, THESEAM_LAZY_MAPS_API_CONFIG, TheSeamGoogleMapsApiLoader, TheSeamGoogleMapsComponent, TheSeamGoogleMapsModule, TheSeamGoogleMapsPlacesAutoCompleteComponent, TheSeamGoogleMapsPlacesAutocompleteDirective, TheSeamGoogleMapsRecenterButtonControlComponent, TheSeamGoogleMapsUploadButtonControlComponent, TheSeamLazyMapsApiLoader, TheSeamMapFileDropComponent, TheSeamMapsControlComponent, TheSeamNoopGoogleMapsAPILoader,
|
|
2328
|
+
export { AppFeaturePropertyName, GoogleMapsContextMenu, GoogleMapsControlsService, GoogleMapsService, MAP_CONTROLS_SERVICE, MAP_CONTROL_DATA, MapControlRef, MapValueManagerService, MapValueSource, SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS, THESEAM_LAZY_MAPS_API_CONFIG, TheSeamGoogleMapsApiLoader, TheSeamGoogleMapsComponent, TheSeamGoogleMapsModule, TheSeamGoogleMapsPlacesAutoCompleteComponent, TheSeamGoogleMapsPlacesAutocompleteDirective, TheSeamGoogleMapsRecenterButtonControlComponent, TheSeamGoogleMapsUploadButtonControlComponent, TheSeamLazyMapsApiLoader, TheSeamMapFileDropComponent, TheSeamMapsControlComponent, TheSeamNoopGoogleMapsAPILoader, createFeatureChangeObservable, dataPolygonFromGeoJson, geoJsonPolygonFromDataFeature, getBoundsWithAllFeatures, getFeatureBounds, getFeatureCenter, getFeaturesCount, getHoveredStyleOptionsDefinedByFeature, getSelectedStyleOptionsDefinedByFeature, getStyleOptionsDefinedByFeature, isAppFeatureProperty, isFeatureSelected, polygonCoordinates, polygonHasValidPathsLengths, removeAllFeatures, setFeatureSelected, stripAppFeaturePropertiesFromJson };
|
|
2248
2329
|
//# sourceMappingURL=theseam-ui-common-google-maps.mjs.map
|