@theseam/ui-common 0.3.0 → 0.3.3

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.
Files changed (131) hide show
  1. package/breadcrumbs/_breadcrumbs-theme.scss +3 -0
  2. package/breadcrumbs/breadcrumbs/breadcrumbs.component.scss +10 -0
  3. package/breadcrumbs/styles/_utilities.scss +3 -0
  4. package/breadcrumbs/styles/_variables.scss +1 -0
  5. package/breadcrumbs/theseam-ui-common-breadcrumbs.metadata.json +1 -1
  6. package/bundles/theseam-ui-common-breadcrumbs.umd.js +2 -1
  7. package/bundles/theseam-ui-common-breadcrumbs.umd.js.map +1 -1
  8. package/bundles/theseam-ui-common-dynamic.umd.js +1 -0
  9. package/bundles/theseam-ui-common-dynamic.umd.js.map +1 -1
  10. package/bundles/theseam-ui-common-form-field.umd.js +1 -1
  11. package/bundles/theseam-ui-common-form-field.umd.js.map +1 -1
  12. package/bundles/theseam-ui-common-framework.umd.js +18 -15
  13. package/bundles/theseam-ui-common-framework.umd.js.map +1 -1
  14. package/bundles/theseam-ui-common-google-maps.umd.js +2202 -0
  15. package/bundles/theseam-ui-common-google-maps.umd.js.map +1 -0
  16. package/bundles/theseam-ui-common-menu.umd.js +1 -0
  17. package/bundles/theseam-ui-common-menu.umd.js.map +1 -1
  18. package/bundles/theseam-ui-common-modal.umd.js +21 -1
  19. package/bundles/theseam-ui-common-modal.umd.js.map +1 -1
  20. package/bundles/theseam-ui-common-utils.umd.js +610 -136
  21. package/bundles/theseam-ui-common-utils.umd.js.map +1 -1
  22. package/bundles/theseam-ui-common-widget.umd.js +4 -2
  23. package/bundles/theseam-ui-common-widget.umd.js.map +1 -1
  24. package/esm2015/breadcrumbs/breadcrumbs/breadcrumbs.component.js +4 -3
  25. package/esm2015/dynamic/evaluators/jexl-evaluator/jexl-evaluator.js +2 -1
  26. package/esm2015/form-field/input.directive.js +2 -2
  27. package/esm2015/framework/base-layout/base-layout.component.js +3 -3
  28. package/esm2015/framework/top-bar/top-bar-menu-button/top-bar-menu-button.component.js +5 -5
  29. package/esm2015/framework/top-bar/top-bar-title/top-bar-title.component.js +4 -3
  30. package/esm2015/framework/top-bar/top-bar.component.js +10 -8
  31. package/esm2015/google-maps/google-maps/google-maps.component.js +261 -0
  32. package/esm2015/google-maps/google-maps-contextmenu.js +113 -0
  33. package/esm2015/google-maps/google-maps-controls.service.js +70 -0
  34. package/esm2015/google-maps/google-maps-feature-helpers.js +177 -0
  35. package/esm2015/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.component.js +195 -0
  36. package/esm2015/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.directive.js +163 -0
  37. package/esm2015/google-maps/google-maps-recenter-button-control/google-maps-recenter-button-control.component.js +57 -0
  38. package/esm2015/google-maps/google-maps-upload-button-control/google-maps-upload-button-control.component.js +119 -0
  39. package/esm2015/google-maps/google-maps.module.js +45 -0
  40. package/esm2015/google-maps/google-maps.service.js +344 -0
  41. package/esm2015/google-maps/map-control.component.js +65 -0
  42. package/esm2015/google-maps/map-controls-service.js +4 -0
  43. package/esm2015/google-maps/map-file-drop/map-file-drop.component.js +135 -0
  44. package/esm2015/google-maps/map-value-manager.service.js +46 -0
  45. package/esm2015/google-maps/public-api.js +14 -0
  46. package/esm2015/google-maps/theseam-ui-common-google-maps.js +6 -0
  47. package/esm2015/menu/menu-toggle.directive.js +2 -1
  48. package/esm2015/modal/modal-ref.js +22 -2
  49. package/esm2015/utils/geo-json/coerce-feature-collection.js +44 -0
  50. package/esm2015/utils/geo-json/geo-json-to-area.js +11 -0
  51. package/esm2015/utils/geo-json/is-feature-collection.validator.js +21 -0
  52. package/esm2015/utils/geo-json/is-only-geometry-types.js +23 -0
  53. package/esm2015/utils/geo-json/is-only-geometry-types.validator.js +32 -0
  54. package/esm2015/utils/geo-json/merge-polygons.js +35 -0
  55. package/esm2015/utils/geo-json/no-inner-rings.validator.js +63 -0
  56. package/esm2015/utils/geo-json/no-kinks.validator.js +39 -0
  57. package/esm2015/utils/geo-json/read-geo-file.js +99 -0
  58. package/esm2015/utils/geo-json/split-multi-polygons.js +29 -0
  59. package/esm2015/utils/is-null-or-undefined.js +1 -1
  60. package/esm2015/utils/public-api.js +11 -1
  61. package/esm2015/widget/widget/widget.component.js +1 -1
  62. package/esm2015/widget/widget-content-components/widget-tile/widget-tile.component.js +4 -2
  63. package/fesm2015/theseam-ui-common-breadcrumbs.js +3 -2
  64. package/fesm2015/theseam-ui-common-breadcrumbs.js.map +1 -1
  65. package/fesm2015/theseam-ui-common-dynamic.js +1 -0
  66. package/fesm2015/theseam-ui-common-dynamic.js.map +1 -1
  67. package/fesm2015/theseam-ui-common-form-field.js +1 -1
  68. package/fesm2015/theseam-ui-common-form-field.js.map +1 -1
  69. package/fesm2015/theseam-ui-common-framework.js +15 -12
  70. package/fesm2015/theseam-ui-common-framework.js.map +1 -1
  71. package/fesm2015/theseam-ui-common-google-maps.js +1729 -0
  72. package/fesm2015/theseam-ui-common-google-maps.js.map +1 -0
  73. package/fesm2015/theseam-ui-common-menu.js +1 -0
  74. package/fesm2015/theseam-ui-common-menu.js.map +1 -1
  75. package/fesm2015/theseam-ui-common-modal.js +21 -1
  76. package/fesm2015/theseam-ui-common-modal.js.map +1 -1
  77. package/fesm2015/theseam-ui-common-utils.js +477 -94
  78. package/fesm2015/theseam-ui-common-utils.js.map +1 -1
  79. package/fesm2015/theseam-ui-common-widget.js +4 -2
  80. package/fesm2015/theseam-ui-common-widget.js.map +1 -1
  81. package/form-field/theseam-ui-common-form-field.metadata.json +1 -1
  82. package/framework/base-layout/base-layout.component.scss +14 -0
  83. package/framework/base-layout/styles/_variables.scss +14 -0
  84. package/framework/theseam-ui-common-framework.metadata.json +1 -1
  85. package/framework/top-bar/_top-bar-theme.scss +5 -0
  86. package/framework/top-bar/styles/_utilities.scss +3 -0
  87. package/framework/top-bar/styles/_variables.scss +18 -0
  88. package/framework/top-bar/top-bar-menu-button/top-bar-menu-button.component.d.ts +3 -1
  89. package/framework/top-bar/top-bar-menu-button/top-bar-menu-button.component.scss +15 -0
  90. package/framework/top-bar/top-bar-title/top-bar-title.component.scss +6 -0
  91. package/framework/top-bar/top-bar.component.d.ts +3 -0
  92. package/framework/top-bar/top-bar.component.scss +39 -0
  93. package/google-maps/google-maps/google-maps.component.d.ts +89 -0
  94. package/google-maps/google-maps-contextmenu.d.ts +15 -0
  95. package/google-maps/google-maps-controls.service.d.ts +23 -0
  96. package/google-maps/google-maps-feature-helpers.d.ts +37 -0
  97. package/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.component.d.ts +104 -0
  98. package/google-maps/google-maps-places-autocomplete/google-maps-places-autocomplete.directive.d.ts +80 -0
  99. package/google-maps/google-maps-recenter-button-control/google-maps-recenter-button-control.component.d.ts +21 -0
  100. package/google-maps/google-maps-upload-button-control/google-maps-upload-button-control.component.d.ts +34 -0
  101. package/google-maps/google-maps.module.d.ts +2 -0
  102. package/google-maps/google-maps.service.d.ts +53 -0
  103. package/google-maps/map-control.component.d.ts +20 -0
  104. package/google-maps/map-controls-service.d.ts +13 -0
  105. package/google-maps/map-file-drop/map-file-drop.component.d.ts +34 -0
  106. package/google-maps/map-value-manager.service.d.ts +18 -0
  107. package/google-maps/package.json +11 -0
  108. package/google-maps/public-api.d.ts +13 -0
  109. package/google-maps/theseam-ui-common-google-maps.d.ts +5 -0
  110. package/google-maps/theseam-ui-common-google-maps.metadata.json +1 -0
  111. package/modal/modal-ref.d.ts +1 -0
  112. package/modal/theseam-ui-common-modal.metadata.json +1 -1
  113. package/package.json +17 -10
  114. package/utils/geo-json/coerce-feature-collection.d.ts +2 -0
  115. package/utils/geo-json/geo-json-to-area.d.ts +6 -0
  116. package/utils/geo-json/is-feature-collection.validator.d.ts +3 -0
  117. package/utils/geo-json/is-only-geometry-types.d.ts +5 -0
  118. package/utils/geo-json/is-only-geometry-types.validator.d.ts +4 -0
  119. package/utils/geo-json/merge-polygons.d.ts +9 -0
  120. package/utils/geo-json/no-inner-rings.validator.d.ts +10 -0
  121. package/utils/geo-json/no-kinks.validator.d.ts +3 -0
  122. package/utils/geo-json/read-geo-file.d.ts +7 -0
  123. package/utils/geo-json/split-multi-polygons.d.ts +8 -0
  124. package/utils/is-null-or-undefined.d.ts +1 -1
  125. package/utils/public-api.d.ts +10 -0
  126. package/utils/theseam-ui-common-utils.metadata.json +1 -1
  127. package/widget/styles/_variables.scss +3 -0
  128. package/widget/theseam-ui-common-widget.metadata.json +1 -1
  129. package/widget/widget/widget.component.scss +2 -0
  130. package/widget/widget-content-components/widget-tile/widget-tile.component.d.ts +2 -0
  131. package/widget/widget-content-components/widget-tile/widget-tile.component.scss +1 -1
@@ -0,0 +1,1729 @@
1
+ import { __awaiter, __decorate } from 'tslib';
2
+ import { FocusMonitor } from '@angular/cdk/a11y';
3
+ import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
4
+ import { Injectable, NgZone, ViewContainerRef, InjectionToken, Injector, ComponentFactoryResolver, Component, ChangeDetectionStrategy, Optional, Inject, Input, HostListener, ElementRef, Renderer2, EventEmitter, forwardRef, HostBinding, Output, ViewChild, Directive, NgModule } from '@angular/core';
5
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
+ import { Observable, Subject, fromEvent, BehaviorSubject, from, interval } from 'rxjs';
7
+ import { takeUntil, switchMap, tap, startWith, filter, take, mapTo } from 'rxjs/operators';
8
+ import { AgmMap, AgmCoreModule } from '@agm/core';
9
+ import { faFileImport, faCrosshairs, faSearchLocation } from '@fortawesome/free-solid-svg-icons';
10
+ import { mixinDisabled, InputBoolean, InputNumber } from '@theseam/ui-common/core';
11
+ import { MenuComponent, TheSeamMenuModule } from '@theseam/ui-common/menu';
12
+ import { notNullOrUndefined, isNullOrUndefined, readGeoFile } from '@theseam/ui-common/utils';
13
+ import { ESCAPE } from '@angular/cdk/keycodes';
14
+ import booleanContains from '@turf/boolean-contains';
15
+ import { polygon, multiPolygon } from '@turf/helpers';
16
+ import { ObserversModule } from '@angular/cdk/observers';
17
+ import { CommonModule } from '@angular/common';
18
+ import { InputDirective, TheSeamFormFieldModule } from '@theseam/ui-common/form-field';
19
+ import { TheSeamIconModule } from '@theseam/ui-common/icon';
20
+ import { TheSeamSharedModule } from '@theseam/ui-common/shared';
21
+
22
+ var AppFeaturePropertyName;
23
+ (function (AppFeaturePropertyName) {
24
+ AppFeaturePropertyName["IsSelected"] = "__app__isSelected";
25
+ })(AppFeaturePropertyName || (AppFeaturePropertyName = {}));
26
+ function isAppFeatureProperty(propertyName) {
27
+ return Object.values(AppFeaturePropertyName)
28
+ .findIndex(value => value === propertyName) !== -1;
29
+ }
30
+ function isFeatureSelected(feature) {
31
+ const isSelected = feature.getProperty(AppFeaturePropertyName.IsSelected);
32
+ return coerceBooleanProperty(isSelected);
33
+ }
34
+ function setFeatureSelected(feature, isSelected) {
35
+ feature.setProperty(AppFeaturePropertyName.IsSelected, isSelected);
36
+ }
37
+ // TODO: Check performance of cloning a google.maps.Data instance, so the
38
+ // properties can be removed with the google maps api, instead of on the
39
+ // resulting json.
40
+ function stripAppFeaturePropertiesFromJson(json) {
41
+ if (notNullOrUndefined(json) && Array.isArray(json === null || json === void 0 ? void 0 : json.features)) {
42
+ for (const feature of json.features) {
43
+ if (notNullOrUndefined(feature === null || feature === void 0 ? void 0 : feature.properties)) {
44
+ for (const k of Object.keys(feature.properties)) {
45
+ if (isAppFeatureProperty(k)) {
46
+ feature.properties[k] = undefined;
47
+ delete feature.properties[k];
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ /**
55
+ * Searches for a Feature in Data that contains the provided Feature and can use
56
+ * it as a cutout area.
57
+ */
58
+ function getPossibleExteriorFeature(data, feature) {
59
+ let exteriorPolygonFeature;
60
+ data.forEach(f => {
61
+ if (f !== feature && (f.getGeometry().getType() === 'Polygon' && featureContains(f, feature))) {
62
+ exteriorPolygonFeature = f;
63
+ }
64
+ });
65
+ return exteriorPolygonFeature;
66
+ }
67
+ function addInnerFeatureCutoutToExteriorFeature(exteriorFeature, innerFeature) {
68
+ // NOTE: Other geometries may support cutouts, but our map shapes editor only
69
+ // supports polygons currently, so we will need to handle other geometry types
70
+ // here if we start allowing users to draw shapes other than polygon.
71
+ if (exteriorFeature.getGeometry().getType() !== 'Polygon' || innerFeature.getGeometry().getType() !== 'Polygon') {
72
+ throw Error(`Inner cutout is only supported by Polygon gemoetry.`);
73
+ }
74
+ const featurePolygon = innerFeature.getGeometry();
75
+ const exteriorPolygon = exteriorFeature.getGeometry();
76
+ exteriorFeature.setGeometry(new google.maps.Data.Polygon([
77
+ ...exteriorPolygon.getArray(),
78
+ featurePolygon.getAt(0).getArray().reverse()
79
+ ]));
80
+ }
81
+ /**
82
+ * Google maps paths don't always start and stop at the exact same position, so
83
+ * this will fix that for turfjs.
84
+ */
85
+ function fixPathDifferentStartingAndEndingPoint(coordinates) {
86
+ if (coordinates.length <= 1) {
87
+ return;
88
+ }
89
+ const start = coordinates[0];
90
+ const end = coordinates[coordinates.length - 1];
91
+ if (start[0] === end[0] && start[1] === end[1]) {
92
+ return;
93
+ }
94
+ coordinates.push(coordinates[0]);
95
+ }
96
+ function polygonCoordinates(polygon) {
97
+ return polygon.getArray().map(linRing => {
98
+ const coords = linRing.getArray().map(x => [x.lng(), x.lat()]);
99
+ fixPathDifferentStartingAndEndingPoint(coords);
100
+ return coords;
101
+ });
102
+ }
103
+ function multiPolygonCoordinates(multiPolygon) {
104
+ return multiPolygon.getArray().map(x => polygonCoordinates(x));
105
+ }
106
+ function toTurfJsPolygon(polygon$1) {
107
+ return polygon(polygonCoordinates(polygon$1));
108
+ }
109
+ function toTurfJsMultiPolygon(multiPolygon$1) {
110
+ return multiPolygon(multiPolygonCoordinates(multiPolygon$1));
111
+ }
112
+ function toTurfJsFeature(googleFeature) {
113
+ if (googleFeature.getGeometry().getType() === 'Polygon') {
114
+ return toTurfJsPolygon(googleFeature.getGeometry());
115
+ }
116
+ else if (googleFeature.getGeometry().getType() === 'MultiPolygon') {
117
+ return toTurfJsMultiPolygon(googleFeature.getGeometry());
118
+ }
119
+ throw Error(`Unexpected geometry.`);
120
+ }
121
+ function featureContains(featureA, featureB) {
122
+ const polygonA = toTurfJsFeature(featureA);
123
+ const polygonB = toTurfJsFeature(featureB);
124
+ return booleanContains(polygonA, polygonB);
125
+ }
126
+ function createDataFeatureFromPolygon(polygon) {
127
+ const arr = polygon.getPath().getArray();
128
+ return new google.maps.Data.Feature({
129
+ geometry: new google.maps.Data.Polygon([arr])
130
+ });
131
+ }
132
+ function getBoundsWithAllFeatures(data) {
133
+ const bounds = new google.maps.LatLngBounds();
134
+ data.forEach(feature => {
135
+ const geometry = feature.getGeometry();
136
+ geometry.forEachLatLng(latLng => {
137
+ bounds.extend(latLng);
138
+ });
139
+ });
140
+ return bounds;
141
+ }
142
+ function getFeatureBounds(feature) {
143
+ const bounds = new google.maps.LatLngBounds();
144
+ const geometry = feature.getGeometry();
145
+ geometry.forEachLatLng(latLng => {
146
+ bounds.extend(latLng);
147
+ });
148
+ return bounds;
149
+ }
150
+ function getFeatureCenter(feature) {
151
+ return getFeatureBounds(feature).getCenter();
152
+ }
153
+ function removeAllFeatures(data) {
154
+ data.forEach(f => data.remove(f));
155
+ }
156
+ function getFeaturesCount(data) {
157
+ let count = 0;
158
+ data.forEach(() => count++);
159
+ return count;
160
+ }
161
+ /**
162
+ * NOTE: Original events are not emitted, because filtering may omit events.
163
+ */
164
+ function createFeatureChangeObservable(data, ngZone) {
165
+ return new Observable(subscriber => {
166
+ const listeners = [];
167
+ ngZone.runOutsideAngular(() => {
168
+ listeners.push(data.addListener('setgeometry', (event) => {
169
+ ngZone.run(() => { subscriber.next(undefined); });
170
+ }));
171
+ listeners.push(data.addListener('addfeature', (event) => {
172
+ ngZone.run(() => { subscriber.next(undefined); });
173
+ }));
174
+ listeners.push(data.addListener('removefeature', (event) => {
175
+ ngZone.run(() => { subscriber.next(undefined); });
176
+ }));
177
+ listeners.push(data.addListener('setproperty', (event) => {
178
+ if (!isAppFeatureProperty(event.name)) {
179
+ ngZone.run(() => { subscriber.next(undefined); });
180
+ }
181
+ }));
182
+ listeners.push(data.addListener('removeproperty', (event) => {
183
+ if (!isAppFeatureProperty(event.name)) {
184
+ ngZone.run(() => { subscriber.next(undefined); });
185
+ }
186
+ }));
187
+ });
188
+ return () => {
189
+ listeners.forEach(google.maps.event.removeListener);
190
+ };
191
+ });
192
+ }
193
+
194
+ // TODO: Close on map losing focus.
195
+ class GoogleMapsContextMenu {
196
+ constructor(_map, _menu, _position, _vcr, _ngZone, _data, _feature) {
197
+ this._map = _map;
198
+ this._menu = _menu;
199
+ this._vcr = _vcr;
200
+ this._ngZone = _ngZone;
201
+ this._data = _data;
202
+ this._feature = _feature;
203
+ const tplRef = this._menu.templateRef;
204
+ if (tplRef === undefined || tplRef === null) {
205
+ throw Error(`Menu template is not defined.`);
206
+ }
207
+ const ref = this._vcr.createEmbeddedView(tplRef);
208
+ ref.detectChanges();
209
+ const listeners = [];
210
+ const ngUnsubscribe = new Subject();
211
+ // TODO: Fix the initial focus. setTimeout avoids the wrong contextmenu
212
+ // getting triggered, but the first item flashes and looks off this way.
213
+ setTimeout(() => {
214
+ this._menu.focusFirstItem('program');
215
+ });
216
+ this._menu.closed.pipe(takeUntil(ngUnsubscribe)).subscribe(v => {
217
+ this.close();
218
+ });
219
+ fromEvent(document, 'keydown').pipe(takeUntil(ngUnsubscribe)).subscribe((event) => {
220
+ if (event.keyCode === ESCAPE) {
221
+ this.close();
222
+ }
223
+ });
224
+ const __cleanup = () => this._cleanupFn();
225
+ class GoogleMapsContextMenuOverlayView extends google.maps.OverlayView {
226
+ constructor(position, content) {
227
+ super();
228
+ this.position = position;
229
+ this.position = position;
230
+ this.containerDiv = document.createElement('div');
231
+ this.containerDiv.style.cursor = 'auto';
232
+ this.containerDiv.style.height = '0',
233
+ this.containerDiv.style.position = 'absolute';
234
+ this.containerDiv.appendChild(content);
235
+ // Optionally stop clicks, etc., from bubbling up to the map.
236
+ GoogleMapsContextMenuOverlayView.preventMapHitsAndGesturesFrom(this.containerDiv);
237
+ }
238
+ /** Called when the view is added to the map. */
239
+ onAdd() {
240
+ // tslint:disable-next-line: no-non-null-assertion
241
+ this.getPanes().floatPane.appendChild(this.containerDiv);
242
+ }
243
+ /** Called when the view is removed from the map. */
244
+ onRemove() {
245
+ if (this.containerDiv.parentElement) {
246
+ this.containerDiv.parentElement.removeChild(this.containerDiv);
247
+ }
248
+ __cleanup();
249
+ }
250
+ /** Called each frame when the view needs to draw itself. */
251
+ draw() {
252
+ // tslint:disable-next-line: no-non-null-assertion
253
+ const divPosition = this.getProjection().fromLatLngToDivPixel(this.position);
254
+ // Hide the popup when it is far out of view.
255
+ const display = Math.abs(divPosition.x) < 4000 && Math.abs(divPosition.y) < 4000
256
+ ? 'block'
257
+ : 'none';
258
+ if (display === 'block') {
259
+ this.containerDiv.style.left = divPosition.x + 'px';
260
+ this.containerDiv.style.top = divPosition.y + 'px';
261
+ }
262
+ if (this.containerDiv.style.display !== display) {
263
+ this.containerDiv.style.display = display;
264
+ }
265
+ }
266
+ }
267
+ this._overlayView = new GoogleMapsContextMenuOverlayView(_position, ref.rootNodes[0]);
268
+ this._overlayView.setMap(this._map);
269
+ this._ngZone.runOutsideAngular(() => {
270
+ listeners.push(this._data.addListener('removefeature', (event) => {
271
+ if (event.feature === this._feature) {
272
+ this._ngZone.run(() => { this.close(); });
273
+ }
274
+ }));
275
+ listeners.push(this._data.addListener('setproperty', (event) => {
276
+ if (event.feature === this._feature && !isFeatureSelected(this._feature)) {
277
+ this._ngZone.run(() => { this.close(); });
278
+ }
279
+ }));
280
+ listeners.push(this._data.addListener('removeproperty', (event) => {
281
+ if (event.feature === this._feature && !isFeatureSelected(this._feature)) {
282
+ this._ngZone.run(() => { this.close(); });
283
+ }
284
+ }));
285
+ listeners.push(this._map.addListener('click', (event) => {
286
+ this._ngZone.run(() => { this.close(); });
287
+ }));
288
+ listeners.push(this._data.addListener('click', (event) => {
289
+ this._ngZone.run(() => { this.close(); });
290
+ }));
291
+ });
292
+ this._cleanupFn = () => {
293
+ ngUnsubscribe.next();
294
+ ngUnsubscribe.complete();
295
+ listeners.forEach(google.maps.event.removeListener);
296
+ };
297
+ }
298
+ close() {
299
+ this._overlayView.setMap(null);
300
+ }
301
+ }
302
+
303
+ var MapValueSource;
304
+ (function (MapValueSource) {
305
+ MapValueSource["Input"] = "input";
306
+ MapValueSource["FeatureChange"] = "featurechange";
307
+ })(MapValueSource || (MapValueSource = {}));
308
+ class MapValueManagerService {
309
+ constructor() {
310
+ this._valueChangedSubject = new Subject();
311
+ this.valueChanged = this._valueChangedSubject.asObservable();
312
+ }
313
+ setValue(value, source) {
314
+ if (value === this._value) {
315
+ return false;
316
+ }
317
+ if (value === null || value === undefined) {
318
+ this._value = value;
319
+ const _change = {
320
+ source,
321
+ value: this._value,
322
+ };
323
+ this._valueChangedSubject.next(_change);
324
+ return true;
325
+ }
326
+ if (JSON.stringify(value) === JSON.stringify(this._value)) {
327
+ return true;
328
+ }
329
+ // TODO: Validate object is valid geojson.
330
+ this._value = value;
331
+ const change = {
332
+ source,
333
+ value: this._value,
334
+ };
335
+ this._valueChangedSubject.next(change);
336
+ return true;
337
+ }
338
+ get value() {
339
+ return this._value;
340
+ }
341
+ }
342
+ MapValueManagerService.decorators = [
343
+ { type: Injectable }
344
+ ];
345
+ MapValueManagerService.ctorParameters = () => [];
346
+
347
+ const DEFAULT_POLYGON_OPTIONS = {
348
+ clickable: true,
349
+ draggable: true,
350
+ editable: true,
351
+ // fillColor: 'rgba(60,150,60,1)',
352
+ // strokeColor: 'rgba(155,255,0,1)'
353
+ };
354
+ const DEFAULT_DRAWING_MANAGER_OPTIONS = () => ({
355
+ drawingControl: true,
356
+ drawingControlOptions: {
357
+ drawingModes: [
358
+ google.maps.drawing.OverlayType.POLYGON
359
+ ]
360
+ },
361
+ polygonOptions: DEFAULT_POLYGON_OPTIONS,
362
+ drawingMode: null
363
+ });
364
+ const ɵ0 = DEFAULT_DRAWING_MANAGER_OPTIONS;
365
+ const FEATURE_STYLE_OPTIONS_DEFAULT = {
366
+ clickable: true,
367
+ visible: true,
368
+ // zIndex?: number;
369
+ // cursor?: string;
370
+ draggable: false,
371
+ editable: false,
372
+ fillColor: 'teal',
373
+ fillOpacity: 0.3,
374
+ strokeColor: 'blue',
375
+ strokeOpacity: 1,
376
+ strokeWeight: 2,
377
+ };
378
+ const FEATURE_STYLE_OPTIONS_SELECTED = Object.assign(Object.assign({}, FEATURE_STYLE_OPTIONS_DEFAULT), { draggable: true, editable: true, fillColor: 'green', fillOpacity: 0.7, strokeColor: 'limegreen', strokeOpacity: 1, strokeWeight: 2 });
379
+ class GoogleMapsService {
380
+ constructor(_mapValueManager, _ngZone, _vcr) {
381
+ this._mapValueManager = _mapValueManager;
382
+ this._ngZone = _ngZone;
383
+ this._vcr = _vcr;
384
+ this._ngUnsubscribe = new Subject();
385
+ this._mapReadySubject = new BehaviorSubject(false);
386
+ this._featureContextMenu = null;
387
+ this._activeContextMenu = null;
388
+ this._allowDrawingHoleInPolygon = false;
389
+ this.mapReady$ = this._mapReadySubject.asObservable();
390
+ }
391
+ get mapReady() { return this._mapReadySubject.value; }
392
+ ngOnDestroy() {
393
+ this._ngUnsubscribe.next();
394
+ this._ngUnsubscribe.complete();
395
+ }
396
+ setMap(map) {
397
+ this.googleMap = map;
398
+ this._mapReadySubject.next(true);
399
+ this._initDrawingManager();
400
+ this._initFeatureStyling();
401
+ this._initFeatureChangeListeners();
402
+ }
403
+ setBaseLatLng(lat, lng) {
404
+ this._baseLatLng = { lat, lng };
405
+ }
406
+ // TODO: Refactor out of the service meant to just wrap the google maps api.
407
+ setFeatureContextMenu(menu) {
408
+ this._featureContextMenu = menu;
409
+ }
410
+ getDiv() {
411
+ this._assertInitialized();
412
+ return this.googleMap.getDiv();
413
+ }
414
+ fitBounds(bounds, padding) {
415
+ this._assertInitialized();
416
+ this.googleMap.fitBounds(bounds, padding);
417
+ }
418
+ /**
419
+ * Iterates the map's features and removes any that are selected.
420
+ */
421
+ deleteSelection() {
422
+ this._assertInitialized();
423
+ const mapData = this.googleMap.data;
424
+ mapData.forEach(f => {
425
+ if (isFeatureSelected(f)) {
426
+ mapData.remove(f);
427
+ }
428
+ });
429
+ }
430
+ /**
431
+ * Stops the current drawing.
432
+ */
433
+ stopDrawing() {
434
+ this._ngZone.runOutsideAngular(() => {
435
+ if (isNullOrUndefined(this._drawingManager) || this._drawingManager.getDrawingMode() === null) {
436
+ return;
437
+ }
438
+ // Listening for the completion event of the overlay currently being drawn
439
+ // and removing it. I haven't found a way to cancel the current drawing,
440
+ // without this hack that assumes our listeners will not run into a race
441
+ // condition.
442
+ const listener = google.maps.event.addListener(this._drawingManager, 'overlaycomplete', (event) => {
443
+ event.overlay.setMap(null);
444
+ listener.remove();
445
+ });
446
+ // To fake canceling the current drawing, without disabling the drawing
447
+ // mode, the drawin mode is being unset then immediately set back. When
448
+ // the mode is unset the 'overlaycomplete' event will fire, which will
449
+ // give a reference to the current overlay to remove, then it is set back
450
+ // to the mode the user was using. To the user is should just seem like
451
+ // the current drawing was canceled and they can start drawing again.
452
+ const mode = this._drawingManager.getDrawingMode();
453
+ this._drawingManager.setDrawingMode(null);
454
+ this._drawingManager.setDrawingMode(mode);
455
+ // 'overlaycomplete' should fire immediately, unless an overlay hadn't
456
+ // started drawing. This timeout will make sure the listener gets removed.
457
+ setTimeout(() => {
458
+ listener.remove();
459
+ });
460
+ });
461
+ }
462
+ _initDrawingManager() {
463
+ if (notNullOrUndefined(this._drawingManager)) {
464
+ throw Error(`DrawingManager is already initialized.`);
465
+ }
466
+ this._assertInitialized();
467
+ const options = DEFAULT_DRAWING_MANAGER_OPTIONS();
468
+ const drawingManager = new google.maps.drawing.DrawingManager(options);
469
+ drawingManager.setMap(this.googleMap);
470
+ this._drawingManager = drawingManager;
471
+ this._drawingManager.addListener('drawingmode_changed', event => {
472
+ var _a;
473
+ if (((_a = this._drawingManager) === null || _a === void 0 ? void 0 : _a.getDrawingMode()) !== null) {
474
+ this._assertInitialized();
475
+ this.googleMap.data.forEach(f => {
476
+ if (isFeatureSelected(f)) {
477
+ setFeatureSelected(f, false);
478
+ }
479
+ });
480
+ }
481
+ });
482
+ }
483
+ addControl(element, position) {
484
+ this._assertInitialized();
485
+ this.googleMap.controls[position].push(element);
486
+ }
487
+ setData(data) {
488
+ return __awaiter(this, void 0, void 0, function* () {
489
+ this._assertInitialized();
490
+ removeAllFeatures(this.googleMap.data);
491
+ this.googleMap.data.addGeoJson(data);
492
+ this.googleMap.fitBounds(getBoundsWithAllFeatures(this.googleMap.data));
493
+ });
494
+ }
495
+ // TODO: Refactor out of the service meant to just wrap the google maps api.
496
+ reCenterOnFeatures() {
497
+ this._assertInitialized();
498
+ if (getFeaturesCount(this.googleMap.data) === 0) {
499
+ if (!this._baseLatLng) {
500
+ return;
501
+ }
502
+ this.googleMap.panTo(this._baseLatLng);
503
+ return;
504
+ }
505
+ this.googleMap.fitBounds(getBoundsWithAllFeatures(this.googleMap.data));
506
+ // TODO: Fix to pan to center. Currently fitBounds results in the expected
507
+ // result, but pantToBounds animates.
508
+ // this.googleMap.panToBounds(getBoundsWithAllFeatures(this.googleMap.data))
509
+ }
510
+ allowDrawingHoleInPolygon(allow) {
511
+ this._allowDrawingHoleInPolygon = allow;
512
+ }
513
+ setFileInputHandler(handler) {
514
+ this._fileInputHandler;
515
+ }
516
+ getFileInputHandler() {
517
+ return this._fileInputHandler;
518
+ }
519
+ _initFeatureStyling() {
520
+ this._assertInitialized();
521
+ // Disable any selection when clicking the map.
522
+ //
523
+ // TODO: There may be a better way to do this that would be more accurate or
524
+ // additional events that should be listened to, such as the disabling
525
+ // selection when the map looses focus.
526
+ this.googleMap.addListener('click', (even) => {
527
+ this._assertInitialized();
528
+ this.googleMap.data.forEach(f => setFeatureSelected(f, false));
529
+ });
530
+ // Determine what the style of the features are.
531
+ this.googleMap.data.setStyle((feature) => {
532
+ if (isFeatureSelected(feature)) {
533
+ return FEATURE_STYLE_OPTIONS_SELECTED;
534
+ }
535
+ return FEATURE_STYLE_OPTIONS_DEFAULT;
536
+ });
537
+ // Select a feature when clicked.
538
+ this.googleMap.data.addListener('click', (event) => {
539
+ this._assertInitialized();
540
+ setFeatureSelected(event.feature, true);
541
+ this.googleMap.data.forEach(f => {
542
+ if (f !== event.feature && isFeatureSelected(f)) {
543
+ setFeatureSelected(f, false);
544
+ }
545
+ });
546
+ });
547
+ // Set a style on hovered features that can be selected.
548
+ this.googleMap.data.addListener('mouseover', (event) => {
549
+ this._assertInitialized();
550
+ this.googleMap.data.revertStyle();
551
+ if (!this.isDrawing() && !isFeatureSelected(event.feature)) {
552
+ this.googleMap.data.overrideStyle(event.feature, { strokeWeight: 4 });
553
+ }
554
+ });
555
+ // Remove any hover styles when mouse moves away.
556
+ this.googleMap.data.addListener('mouseout', (event) => {
557
+ this._assertInitialized();
558
+ this.googleMap.data.revertStyle();
559
+ });
560
+ }
561
+ _initFeatureChangeListeners() {
562
+ this._assertInitialized();
563
+ createFeatureChangeObservable(this.googleMap.data, this._ngZone).pipe(switchMap(() => from(this.getGeoJson()).pipe(tap(geoJson => this._mapValueManager.setValue(geoJson, MapValueSource.FeatureChange)))), takeUntil(this._ngUnsubscribe)).subscribe();
564
+ this.googleMap.data.addListener('contextmenu', (event) => {
565
+ if (!isFeatureSelected(event.feature)) {
566
+ return;
567
+ }
568
+ this._openContextMenuForFeature(event.feature, event.latLng);
569
+ });
570
+ if (notNullOrUndefined(this._drawingManager)) {
571
+ google.maps.event.addListener(this._drawingManager, 'polygoncomplete', (polygon) => {
572
+ var _a;
573
+ // The DrawingManager doesn't seem to have a way to access the overlays,
574
+ // so if the map is not set then it shouldn'y be considered a successful
575
+ // completion. I am canceling the active drawing by disabling drawing
576
+ // mode and setting the map null in the 'overlaycomplete' event, which
577
+ // fires before the 'polygoncomplete' event.
578
+ if (isNullOrUndefined(polygon.getMap())) {
579
+ return;
580
+ }
581
+ this._assertInitialized();
582
+ // Create a map feature of the drawn polygon.
583
+ const feature = createDataFeatureFromPolygon(polygon);
584
+ // Remove the drawn polygon.
585
+ polygon.setMap(null);
586
+ // Stop drawing.
587
+ (_a = this._drawingManager) === null || _a === void 0 ? void 0 : _a.setDrawingMode(null);
588
+ // Check if the feature should be used as a cutout to an existing
589
+ // feature or added as it's own feature.
590
+ const exteriorPolygonFeature = this._allowDrawingHoleInPolygon
591
+ ? getPossibleExteriorFeature(this.googleMap.data, feature)
592
+ : undefined;
593
+ if (exteriorPolygonFeature) {
594
+ addInnerFeatureCutoutToExteriorFeature(exteriorPolygonFeature, feature);
595
+ setFeatureSelected(exteriorPolygonFeature, true);
596
+ }
597
+ else {
598
+ this.googleMap.data.add(feature);
599
+ setFeatureSelected(feature, true);
600
+ }
601
+ });
602
+ }
603
+ }
604
+ isDrawing() {
605
+ if (isNullOrUndefined(this._drawingManager)) {
606
+ return true;
607
+ }
608
+ return this._drawingManager.getDrawingMode() !== null;
609
+ }
610
+ // TODO: Refactor out of the service meant to just wrap the google maps api.
611
+ hasSelectedFeature() {
612
+ this._assertInitialized();
613
+ let isSelected = false;
614
+ this.googleMap.data.forEach(f => {
615
+ if (isFeatureSelected(f)) {
616
+ isSelected = true;
617
+ }
618
+ });
619
+ return isSelected;
620
+ }
621
+ // TODO: Refactor out of the service meant to just wrap the google maps api.
622
+ getSelectedFeature() {
623
+ this._assertInitialized();
624
+ let feature = null;
625
+ this.googleMap.data.forEach(f => {
626
+ if (isFeatureSelected(f)) {
627
+ feature = f;
628
+ }
629
+ });
630
+ return feature;
631
+ }
632
+ // TODO: Refactor out of the service meant to just wrap the google maps api.
633
+ openContextMenu() {
634
+ const feature = this.getSelectedFeature();
635
+ if (feature) {
636
+ this._openContextMenuForFeature(feature);
637
+ }
638
+ }
639
+ // TODO: Refactor out of the service meant to just wrap the google maps api.
640
+ _openContextMenuForFeature(feature, position) {
641
+ if (this._activeContextMenu) {
642
+ this._activeContextMenu.close();
643
+ this._activeContextMenu = null;
644
+ }
645
+ this._assertInitialized();
646
+ let _position = position;
647
+ if (!_position) {
648
+ _position = getFeatureCenter(feature);
649
+ }
650
+ if (this._featureContextMenu) {
651
+ this._activeContextMenu = new GoogleMapsContextMenu(this.googleMap, this._featureContextMenu, _position, this._vcr, this._ngZone, this.googleMap.data, feature);
652
+ }
653
+ }
654
+ getGeoJson(removeAppProperties = true) {
655
+ return new Promise((resolve, reject) => {
656
+ this._assertInitialized();
657
+ this.googleMap.data.toGeoJson(f => {
658
+ if (removeAppProperties) {
659
+ stripAppFeaturePropertiesFromJson(f);
660
+ }
661
+ resolve(f);
662
+ });
663
+ });
664
+ }
665
+ /** Asserts that the map has been initialized. */
666
+ _assertInitialized() {
667
+ if (!this.googleMap && (typeof ngDevMode === 'undefined' || ngDevMode)) {
668
+ throw Error('Cannot access Google Map information before the API has been initialized. ' +
669
+ 'Please wait for the API to load before trying to interact with it.');
670
+ }
671
+ }
672
+ }
673
+ GoogleMapsService.decorators = [
674
+ { type: Injectable }
675
+ ];
676
+ GoogleMapsService.ctorParameters = () => [
677
+ { type: MapValueManagerService },
678
+ { type: NgZone },
679
+ { type: ViewContainerRef }
680
+ ];
681
+
682
+ const MAP_CONTROLS_SERVICE = new InjectionToken('MAP_CONTROLS_SERVICE');
683
+ const MAP_CONTROL_DATA = new InjectionToken('MAP_CONTROL_DATA');
684
+
685
+ class MapControlRef {
686
+ constructor(_googleMaps, _componentFactoryResolver, _injector, _controlDef) {
687
+ var _a;
688
+ this._googleMaps = _googleMaps;
689
+ this._componentFactoryResolver = _componentFactoryResolver;
690
+ this._injector = _injector;
691
+ this._controlDef = _controlDef;
692
+ this._destroyedSubject = new Subject();
693
+ this.destroyed = this._destroyedSubject.asObservable();
694
+ const component = this._controlDef.component;
695
+ const factory = this._componentFactoryResolver.resolveComponentFactory(component);
696
+ const providers = [];
697
+ if (this._controlDef.data) {
698
+ providers.push({
699
+ provide: MAP_CONTROL_DATA,
700
+ useValue: this._controlDef.data
701
+ });
702
+ }
703
+ const injector = Injector.create({
704
+ providers,
705
+ parent: this._injector,
706
+ });
707
+ this._componentRef = factory.create(injector);
708
+ this._componentRef.changeDetectorRef.detectChanges();
709
+ const position = (_a = this._controlDef.position) !== null && _a !== void 0 ? _a : google.maps.ControlPosition.LEFT_BOTTOM;
710
+ this._googleMaps.addControl(this._componentRef.location.nativeElement, position);
711
+ this._addedAtPosition = position;
712
+ }
713
+ destroy() {
714
+ const googleMaps = this._googleMaps.googleMap;
715
+ if (googleMaps !== undefined) {
716
+ let idx = -1;
717
+ googleMaps.controls[this._addedAtPosition].forEach((elem, index) => {
718
+ if (elem === this._componentRef.location.nativeElement) {
719
+ idx = index;
720
+ }
721
+ });
722
+ if (idx === -1) {
723
+ throw Error(`Unable to destroy control. Control not found.`);
724
+ }
725
+ googleMaps.controls[this._addedAtPosition].removeAt(idx);
726
+ }
727
+ this._componentRef.destroy();
728
+ this._destroyedSubject.next();
729
+ this._destroyedSubject.complete();
730
+ }
731
+ }
732
+ class GoogleMapsControlsService {
733
+ constructor(_googleMaps, _componentFactoryResolver, _injector) {
734
+ this._googleMaps = _googleMaps;
735
+ this._componentFactoryResolver = _componentFactoryResolver;
736
+ this._injector = _injector;
737
+ }
738
+ add(control) {
739
+ return new MapControlRef(this._googleMaps, this._componentFactoryResolver, this._injector, control);
740
+ }
741
+ }
742
+ GoogleMapsControlsService.decorators = [
743
+ { type: Injectable }
744
+ ];
745
+ GoogleMapsControlsService.ctorParameters = () => [
746
+ { type: GoogleMapsService },
747
+ { type: ComponentFactoryResolver },
748
+ { type: Injector }
749
+ ];
750
+
751
+ /**
752
+ *
753
+ */
754
+ class TheSeamGoogleMapsRecenterButtonControlComponent {
755
+ constructor(_googleMaps, _data) {
756
+ this._googleMaps = _googleMaps;
757
+ this._ngUnsubscribe = new Subject();
758
+ this._listeners = [];
759
+ if (_data) {
760
+ if (_data.hasOwnProperty('label')) {
761
+ this.label = _data.label;
762
+ }
763
+ if (_data.hasOwnProperty('icon')) {
764
+ this.icon = _data.icon;
765
+ }
766
+ }
767
+ }
768
+ _onClick(event) {
769
+ this._googleMaps.reCenterOnFeatures();
770
+ }
771
+ /** @ignore */
772
+ ngOnDestroy() {
773
+ this._listeners.forEach(l => l());
774
+ this._ngUnsubscribe.next();
775
+ this._ngUnsubscribe.complete();
776
+ }
777
+ }
778
+ TheSeamGoogleMapsRecenterButtonControlComponent.decorators = [
779
+ { type: Component, args: [{
780
+ // tslint:disable-next-line: component-selector
781
+ selector: 'button[seam-google-maps-recenter-button-control]',
782
+ template: "<seam-icon [icon]=\"icon\" iconType=\"image-fill\"></seam-icon>\n",
783
+ host: {
784
+ '[attr.draggable]': 'false',
785
+ '[attr.aria-label]': 'label',
786
+ '[attr.title]': 'label',
787
+ 'type': 'button',
788
+ 'class': 'gmnoprint gm-control-active'
789
+ },
790
+ changeDetection: ChangeDetectionStrategy.OnPush,
791
+ styles: [":host{background:none white;border:0px;margin:10px;padding:11px;text-transform:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;position:absolute;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border-radius:2px;height:40px;width:40px;box-shadow:#0000004d 0 1px 4px -1px;overflow:hidden}\n"]
792
+ },] }
793
+ ];
794
+ TheSeamGoogleMapsRecenterButtonControlComponent.ctorParameters = () => [
795
+ { type: GoogleMapsService },
796
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [MAP_CONTROL_DATA,] }] }
797
+ ];
798
+ TheSeamGoogleMapsRecenterButtonControlComponent.propDecorators = {
799
+ label: [{ type: Input }],
800
+ icon: [{ type: Input }],
801
+ _onClick: [{ type: HostListener, args: ['click', ['event'],] }]
802
+ };
803
+
804
+ /**
805
+ *
806
+ */
807
+ class TheSeamGoogleMapsUploadButtonControlComponent {
808
+ constructor(_elementRef, _mapValueManager, _renderer, _googleMaps, _data) {
809
+ this._elementRef = _elementRef;
810
+ this._mapValueManager = _mapValueManager;
811
+ this._renderer = _renderer;
812
+ this._googleMaps = _googleMaps;
813
+ this._ngUnsubscribe = new Subject();
814
+ this._listeners = [];
815
+ if (_data) {
816
+ if (_data.hasOwnProperty('label')) {
817
+ this.label = _data.label;
818
+ }
819
+ if (_data.hasOwnProperty('icon')) {
820
+ this.icon = _data.icon;
821
+ }
822
+ }
823
+ this._fileInputElement = this._createHiddenInput();
824
+ this._renderer.appendChild(this._elementRef.nativeElement, this._fileInputElement);
825
+ }
826
+ _onClick(event) {
827
+ this._fileInputElement.click();
828
+ }
829
+ /** @ignore */
830
+ ngOnDestroy() {
831
+ this._listeners.forEach(l => l());
832
+ this._ngUnsubscribe.next();
833
+ this._ngUnsubscribe.complete();
834
+ }
835
+ _getFile(throwIfInvalidFiles = true) {
836
+ const files = this._fileInputElement.files;
837
+ if (files === null || files.length === 0) {
838
+ return null;
839
+ }
840
+ if (throwIfInvalidFiles) {
841
+ if (files.length > 1) {
842
+ throw Error(`Only one file can be imported at a time.`);
843
+ }
844
+ }
845
+ return files[0];
846
+ }
847
+ _importFile(file) {
848
+ return __awaiter(this, void 0, void 0, function* () {
849
+ const json = yield readGeoFile(file);
850
+ this._mapValueManager.setValue(json, MapValueSource.Input);
851
+ this._resetInput();
852
+ });
853
+ }
854
+ _createHiddenInput() {
855
+ const fileInputElement = this._renderer.createElement('input');
856
+ this._renderer.setAttribute(fileInputElement, 'type', 'file');
857
+ this._renderer.setAttribute(fileInputElement, 'hidden', '');
858
+ this._renderer.setAttribute(fileInputElement, 'accept', '.json,.geojson,.shp,.zip');
859
+ this._listeners.push(this._renderer.listen(fileInputElement, 'change', (event) => {
860
+ const file = this._getFile();
861
+ if (file === null) {
862
+ return;
863
+ }
864
+ const fileImportHandler = this._googleMaps.getFileInputHandler();
865
+ if (fileImportHandler) {
866
+ fileImportHandler(file);
867
+ }
868
+ else {
869
+ this._importFile(file);
870
+ }
871
+ }));
872
+ return fileInputElement;
873
+ }
874
+ _createTemporaryFormElement() {
875
+ return this._renderer.createElement('form');
876
+ }
877
+ /**
878
+ * Reset input element, so that the same file can be added again.
879
+ */
880
+ _resetInput() {
881
+ const formElement = this._createTemporaryFormElement();
882
+ this._renderer.appendChild(formElement, this._fileInputElement);
883
+ formElement.reset();
884
+ this._renderer.appendChild(this._elementRef.nativeElement, this._fileInputElement);
885
+ }
886
+ }
887
+ TheSeamGoogleMapsUploadButtonControlComponent.decorators = [
888
+ { type: Component, args: [{
889
+ // tslint:disable-next-line: component-selector
890
+ selector: 'button[seam-google-maps-upload-button-control]',
891
+ template: "<seam-icon [icon]=\"icon\" iconType=\"image-fill\"></seam-icon>\n",
892
+ host: {
893
+ '[attr.draggable]': 'false',
894
+ '[attr.aria-label]': 'label',
895
+ '[attr.title]': 'label',
896
+ 'type': 'button',
897
+ 'class': 'gmnoprint gm-control-active'
898
+ },
899
+ changeDetection: ChangeDetectionStrategy.OnPush,
900
+ styles: [":host{background:none white;border:0px;margin:10px;padding:11px;text-transform:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;position:absolute;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border-radius:2px;height:40px;width:40px;box-shadow:#0000004d 0 1px 4px -1px;overflow:hidden}\n"]
901
+ },] }
902
+ ];
903
+ TheSeamGoogleMapsUploadButtonControlComponent.ctorParameters = () => [
904
+ { type: ElementRef },
905
+ { type: MapValueManagerService },
906
+ { type: Renderer2 },
907
+ { type: GoogleMapsService },
908
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [MAP_CONTROL_DATA,] }] }
909
+ ];
910
+ TheSeamGoogleMapsUploadButtonControlComponent.propDecorators = {
911
+ label: [{ type: Input }],
912
+ icon: [{ type: Input }],
913
+ _onClick: [{ type: HostListener, args: ['click', ['event'],] }]
914
+ };
915
+
916
+ class TheSeamGoogleMapsComponentBase {
917
+ constructor(_elementRef) {
918
+ this._elementRef = _elementRef;
919
+ }
920
+ }
921
+ const _TheSeamGoogleMapsMixinBase = mixinDisabled(TheSeamGoogleMapsComponentBase);
922
+ /**
923
+ * A wrapper for googlemap.
924
+ */
925
+ class TheSeamGoogleMapsComponent extends _TheSeamGoogleMapsMixinBase {
926
+ constructor(elementRef, _focusMonitor, _googleMaps, _mapValueManager) {
927
+ super(elementRef);
928
+ this._focusMonitor = _focusMonitor;
929
+ this._googleMaps = _googleMaps;
930
+ this._mapValueManager = _mapValueManager;
931
+ this._ngUnsubscribe = new Subject();
932
+ this._fileUploadControlDef = {
933
+ component: TheSeamGoogleMapsUploadButtonControlComponent,
934
+ data: { label: 'Import Geo File', icon: faFileImport },
935
+ position: 6 /* google.maps.ControlPosition.LEFT_BOTTOM */,
936
+ };
937
+ this._reCenterControlDef = {
938
+ component: TheSeamGoogleMapsRecenterButtonControlComponent,
939
+ data: { label: 'Center on Field', icon: faCrosshairs },
940
+ position: 9 /* google.maps.ControlPosition.RIGHT_BOTTOM */,
941
+ };
942
+ this._focusOrigin = null;
943
+ /**
944
+ * Set the tab index to `-1` to allow the root element of the
945
+ * component to receive `focus` event from javascript, but not get focused by
946
+ * keyboard navigation.
947
+ */
948
+ this._tabIndex = -1;
949
+ this.fileDropEnabled = true;
950
+ this.fileUploadControlEnabled = false;
951
+ this.fullscreenControlEnabled = true;
952
+ this.reCenterControlEnabled = true;
953
+ this.mapTypeControlEnabled = true;
954
+ this.streetViewControlEnabled = false;
955
+ this.allowDrawingHoleInPolygon = false;
956
+ this.zoom = 14;
957
+ this.longitude = -98.570209;
958
+ this.latitude = 37.633814;
959
+ this.mapReady = new EventEmitter();
960
+ this._focusMonitor.monitor(this._elementRef, true).pipe(tap(origin => this._focusOrigin = origin), takeUntil(this._ngUnsubscribe)).subscribe();
961
+ this._mapValueManager.valueChanged.pipe(tap(change => {
962
+ if (this.onChange) {
963
+ this.onChange(change.value);
964
+ }
965
+ if (this.onTouched) {
966
+ this.onTouched();
967
+ }
968
+ }), tap(changed => {
969
+ if (this._googleMaps.mapReady && changed.source !== MapValueSource.FeatureChange) {
970
+ this._googleMaps.setData(changed.value);
971
+ }
972
+ }), takeUntil(this._ngUnsubscribe)).subscribe();
973
+ this._googleMaps.setBaseLatLng(this.latitude, this.longitude);
974
+ }
975
+ set value(value) {
976
+ this._mapValueManager.setValue(value, MapValueSource.Input);
977
+ }
978
+ get value() {
979
+ return this._mapValueManager.value;
980
+ }
981
+ set tabIndex(value) { this._tabIndex = coerceNumberProperty(value); }
982
+ get tabIndex() { return this._tabIndex; }
983
+ set fileImportHandler(value) {
984
+ this._googleMaps.setFileInputHandler(value);
985
+ }
986
+ get _attrDisabled() { return this.disabled || null; }
987
+ get _attrTabIndex() { return this.disabled ? -1 : (this.tabIndex || 0); }
988
+ /** @ignore */
989
+ ngOnInit() {
990
+ this._googleMaps.setFeatureContextMenu(this.featureContextMenu);
991
+ fromEvent(window, 'keydown').pipe(tap((event) => {
992
+ switch (event.code) {
993
+ case 'Delete':
994
+ this._googleMaps.deleteSelection();
995
+ event.preventDefault();
996
+ event.stopPropagation();
997
+ break;
998
+ case 'Escape':
999
+ this._googleMaps.stopDrawing();
1000
+ event.preventDefault();
1001
+ event.stopPropagation();
1002
+ break;
1003
+ case 'ContextMenu':
1004
+ this._googleMaps.openContextMenu();
1005
+ event.preventDefault();
1006
+ event.stopPropagation();
1007
+ break;
1008
+ }
1009
+ }), takeUntil(this._ngUnsubscribe)).subscribe();
1010
+ }
1011
+ /** @ignore */
1012
+ ngOnDestroy() {
1013
+ this._focusMonitor.stopMonitoring(this._elementRef);
1014
+ this._ngUnsubscribe.next();
1015
+ this._ngUnsubscribe.complete();
1016
+ }
1017
+ /** @ignore */
1018
+ ngAfterViewInit() { }
1019
+ ngOnChanges(changes) {
1020
+ let updateBase = false;
1021
+ if (changes.hasOwnProperty('latitude')) {
1022
+ this.latitude = changes['latitude'].currentValue;
1023
+ updateBase = true;
1024
+ }
1025
+ if (changes.hasOwnProperty('longitude')) {
1026
+ this.longitude = changes['longitude'].currentValue;
1027
+ updateBase = true;
1028
+ }
1029
+ if (updateBase) {
1030
+ this._googleMaps.setBaseLatLng(this.latitude, this.longitude);
1031
+ }
1032
+ if (changes.hasOwnProperty('allowDrawingHoleInPolygon')) {
1033
+ this._googleMaps.allowDrawingHoleInPolygon(this.allowDrawingHoleInPolygon);
1034
+ }
1035
+ }
1036
+ writeValue(value) {
1037
+ this.value = value;
1038
+ }
1039
+ registerOnChange(fn) {
1040
+ this.onChange = fn;
1041
+ }
1042
+ registerOnTouched(fn) {
1043
+ this.onTouched = fn;
1044
+ }
1045
+ setDisabledState(isDisabled) {
1046
+ this.disabled = isDisabled;
1047
+ }
1048
+ fitBounds(bounds, padding) {
1049
+ this._googleMaps.fitBounds(bounds, padding);
1050
+ }
1051
+ getGeoJson() {
1052
+ return this._googleMaps.getGeoJson();
1053
+ }
1054
+ hasFocus() {
1055
+ return this._focusOrigin !== null && this._focusOrigin !== undefined;
1056
+ }
1057
+ /** Focuses the button. */
1058
+ focus() {
1059
+ this._getHostElement().focus();
1060
+ }
1061
+ _getHostElement() {
1062
+ return this._elementRef.nativeElement;
1063
+ }
1064
+ _onMapReady(theMap) {
1065
+ var _a;
1066
+ this._googleMaps.setMap(theMap);
1067
+ this._googleMaps.setData(this._mapValueManager.value);
1068
+ // NOTE: AgmMap has a race condition problem that causes the input latitude,
1069
+ // longitude, and zoom to get ignored, before googlemaps emits
1070
+ // 'center_changed'. This should avoid the issue, until we stop using AgmMap
1071
+ // or upgrade to a more recent version that may not have the issue anymore.
1072
+ this._googleMaps.reCenterOnFeatures();
1073
+ (_a = this._googleMaps.googleMap) === null || _a === void 0 ? void 0 : _a.setZoom(this.zoom);
1074
+ }
1075
+ _onClickDeleteFeature() {
1076
+ this._googleMaps.deleteSelection();
1077
+ }
1078
+ }
1079
+ TheSeamGoogleMapsComponent.decorators = [
1080
+ { type: Component, args: [{
1081
+ selector: 'seam-google-maps',
1082
+ template: "<agm-map\n [latitude]=\"latitude\"\n [longitude]=\"longitude\"\n [zoom]=\"zoom\"\n [mapTypeControl]=\"true\"\n mapTypeId=\"hybrid\"\n [streetViewControl]=\"false\"\n (mapReady)=\"_onMapReady($event)\"\n [fullscreenControl]=\"$any(fullscreenControlEnabled)\">\n</agm-map>\n<seam-menu #featureContextMenu>\n <button seamMenuItem (click)=\"_onClickDeleteFeature()\">Delete</button>\n</seam-menu>\n<seam-map-file-drop *ngIf=\"fileDropEnabled\"></seam-map-file-drop>\n\n<seam-map-control *ngIf=\"fileUploadControlEnabled\" [def]=\"_fileUploadControlDef\"></seam-map-control>\n<seam-map-control *ngIf=\"reCenterControlEnabled\" [def]=\"_reCenterControlDef\"></seam-map-control>\n",
1083
+ inputs: [
1084
+ 'disabled'
1085
+ ],
1086
+ providers: [
1087
+ MapValueManagerService,
1088
+ GoogleMapsService,
1089
+ { provide: MAP_CONTROLS_SERVICE, useClass: GoogleMapsControlsService },
1090
+ {
1091
+ provide: NG_VALUE_ACCESSOR,
1092
+ // tslint:disable-next-line: no-use-before-declare
1093
+ useExisting: forwardRef(() => TheSeamGoogleMapsComponent),
1094
+ multi: true
1095
+ }
1096
+ ],
1097
+ changeDetection: ChangeDetectionStrategy.OnPush,
1098
+ exportAs: 'seamGoogleMaps',
1099
+ 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}agm-map{height:inherit;width:inherit}\n"]
1100
+ },] }
1101
+ ];
1102
+ TheSeamGoogleMapsComponent.ctorParameters = () => [
1103
+ { type: ElementRef },
1104
+ { type: FocusMonitor },
1105
+ { type: GoogleMapsService },
1106
+ { type: MapValueManagerService }
1107
+ ];
1108
+ TheSeamGoogleMapsComponent.propDecorators = {
1109
+ value: [{ type: Input }],
1110
+ tabIndex: [{ type: Input }],
1111
+ fileDropEnabled: [{ type: Input }],
1112
+ fileUploadControlEnabled: [{ type: Input }],
1113
+ fullscreenControlEnabled: [{ type: Input }],
1114
+ reCenterControlEnabled: [{ type: Input }],
1115
+ mapTypeControlEnabled: [{ type: Input }],
1116
+ streetViewControlEnabled: [{ type: Input }],
1117
+ allowDrawingHoleInPolygon: [{ type: Input }],
1118
+ fileImportHandler: [{ type: Input }],
1119
+ _attrDisabled: [{ type: HostBinding, args: ['attr.disabled',] }],
1120
+ _attrTabIndex: [{ type: HostBinding, args: ['attr.tabindex',] }],
1121
+ zoom: [{ type: Input }],
1122
+ longitude: [{ type: Input }],
1123
+ latitude: [{ type: Input }],
1124
+ mapReady: [{ type: Output }],
1125
+ agmMap: [{ type: ViewChild, args: [AgmMap, { static: true },] }],
1126
+ featureContextMenu: [{ type: ViewChild, args: ['featureContextMenu', { static: true, read: MenuComponent },] }],
1127
+ agmMapTpl: [{ type: ViewChild, args: [AgmMap, { static: true, read: ElementRef },] }]
1128
+ };
1129
+ __decorate([
1130
+ InputBoolean()
1131
+ ], TheSeamGoogleMapsComponent.prototype, "fileDropEnabled", void 0);
1132
+ __decorate([
1133
+ InputBoolean()
1134
+ ], TheSeamGoogleMapsComponent.prototype, "fileUploadControlEnabled", void 0);
1135
+ __decorate([
1136
+ InputBoolean()
1137
+ ], TheSeamGoogleMapsComponent.prototype, "fullscreenControlEnabled", void 0);
1138
+ __decorate([
1139
+ InputBoolean()
1140
+ ], TheSeamGoogleMapsComponent.prototype, "reCenterControlEnabled", void 0);
1141
+ __decorate([
1142
+ InputBoolean()
1143
+ ], TheSeamGoogleMapsComponent.prototype, "mapTypeControlEnabled", void 0);
1144
+ __decorate([
1145
+ InputBoolean()
1146
+ ], TheSeamGoogleMapsComponent.prototype, "streetViewControlEnabled", void 0);
1147
+ __decorate([
1148
+ InputBoolean()
1149
+ ], TheSeamGoogleMapsComponent.prototype, "allowDrawingHoleInPolygon", void 0);
1150
+ __decorate([
1151
+ InputNumber()
1152
+ ], TheSeamGoogleMapsComponent.prototype, "zoom", void 0);
1153
+ __decorate([
1154
+ InputNumber()
1155
+ ], TheSeamGoogleMapsComponent.prototype, "longitude", void 0);
1156
+ __decorate([
1157
+ InputNumber()
1158
+ ], TheSeamGoogleMapsComponent.prototype, "latitude", void 0);
1159
+
1160
+ const SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS = {
1161
+ componentRestrictions: { country: 'US' }
1162
+ };
1163
+ class TheSeamGoogleMapsPlacesAutocompleteDirective {
1164
+ constructor(_elementRef, _ngZone) {
1165
+ this._elementRef = _elementRef;
1166
+ this._ngZone = _ngZone;
1167
+ this._autoCompleteReadySubject = new Subject();
1168
+ this._ngUnsubscribe = new Subject();
1169
+ this._placeChangedPending = [];
1170
+ this._listeners = [];
1171
+ this._options = SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS;
1172
+ this._attrType = 'text';
1173
+ this.placeChanged = this._autoCompleteReadySubject.pipe(startWith(undefined), switchMap(() => this._createPlaceChangedObservable()));
1174
+ }
1175
+ set options(value) {
1176
+ this._options = value || SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS;
1177
+ }
1178
+ ngOnInit() {
1179
+ this._ngZone.runOutsideAngular(() => {
1180
+ this._untilGoogleMapsApiLoaded().pipe(takeUntil(this._ngUnsubscribe)).subscribe(() => {
1181
+ this.autoComplete = new google.maps.places.Autocomplete(this.getHostElement(), this._options);
1182
+ this._placeChangedPending.forEach(pending => pending.observable.subscribe(pending.subscriber));
1183
+ this._autoCompleteReadySubject.next();
1184
+ });
1185
+ });
1186
+ }
1187
+ ngOnDestroy() {
1188
+ this._listeners.forEach(l => l.remove());
1189
+ this._listeners = [];
1190
+ this._ngUnsubscribe.next();
1191
+ this._ngUnsubscribe.complete();
1192
+ }
1193
+ ngOnChanges(changes) {
1194
+ if (this.autoComplete && changes['options']) {
1195
+ this.autoComplete.setOptions(this._options);
1196
+ }
1197
+ }
1198
+ _untilGoogleMapsApiLoaded() {
1199
+ return interval(500).pipe(filter(() => !!(window.google && window.google.maps && window.google.maps.version)), take(1), mapTo(undefined));
1200
+ }
1201
+ /**
1202
+ * Returns the bounds to which predictions are biased.
1203
+ */
1204
+ getBounds() {
1205
+ this._assertInitialized();
1206
+ return this.autoComplete.getBounds();
1207
+ }
1208
+ /**
1209
+ * Returns the fields to be included for the Place in the details response
1210
+ * when the details are successfully retrieved. For a list of fields see
1211
+ * [PlaceResult](https://developers.google.com/maps/documentation/javascript/reference/places-service#PlaceResult).
1212
+ */
1213
+ getFields() {
1214
+ this._assertInitialized();
1215
+ return this.autoComplete.getFields();
1216
+ }
1217
+ /**
1218
+ * Returns the details of the Place selected by user if the details were
1219
+ * successfully retrieved. Otherwise returns a stub Place object, with the
1220
+ * name property set to the current value of the input field.
1221
+ */
1222
+ getPlace() {
1223
+ this._assertInitialized();
1224
+ return this.autoComplete.getPlace();
1225
+ }
1226
+ /**
1227
+ * Sets the preferred area within which to return Place results. Results are
1228
+ * biased towards, but not restricted to, this area.
1229
+ */
1230
+ setBounds(bounds) {
1231
+ this._assertInitialized();
1232
+ // tslint:disable-next-line: no-non-null-assertion
1233
+ return this.autoComplete.setBounds(bounds);
1234
+ }
1235
+ /**
1236
+ * Sets the component restrictions. Component restrictions are used to
1237
+ * restrict predictions to only those within the parent component. For
1238
+ * example, the country.
1239
+ */
1240
+ setComponentRestrictions(restrictions) {
1241
+ this._assertInitialized();
1242
+ // tslint:disable-next-line: no-non-null-assertion
1243
+ return this.autoComplete.setComponentRestrictions(restrictions);
1244
+ }
1245
+ /**
1246
+ * Sets the fields to be included for the Place in the details response when
1247
+ * the details are successfully retrieved. For a list of fields see
1248
+ * [PlaceResult](https://developers.google.com/maps/documentation/javascript/reference/places-service#PlaceResult).
1249
+ */
1250
+ setFields(fields) {
1251
+ this._assertInitialized();
1252
+ // tslint:disable-next-line: no-non-null-assertion
1253
+ return this.autoComplete.setFields(fields);
1254
+ }
1255
+ /** */
1256
+ setOptions(options) {
1257
+ this._assertInitialized();
1258
+ // tslint:disable-next-line: no-non-null-assertion
1259
+ return this.autoComplete.setOptions(options);
1260
+ }
1261
+ /**
1262
+ * Sets the types of predictions to be returned. For supported types, see the
1263
+ * [developer's guide](https://developers.google.com/maps/documentation/javascript/places-autocomplete#constrain-place-types).
1264
+ * If no types are specified, all types will be returned.
1265
+ */
1266
+ setTypes(types) {
1267
+ this._assertInitialized();
1268
+ // tslint:disable-next-line: no-non-null-assertion
1269
+ return this.autoComplete.setTypes(types);
1270
+ }
1271
+ /** Focuses the input. */
1272
+ focus() {
1273
+ this._elementRef.nativeElement.focus();
1274
+ }
1275
+ /** Unfocuses the input. */
1276
+ blur() {
1277
+ this._elementRef.nativeElement.blur();
1278
+ }
1279
+ getHostElement() {
1280
+ return this._elementRef.nativeElement;
1281
+ }
1282
+ _createPlaceChangedObservable() {
1283
+ const observable = new Observable(subscriber => {
1284
+ if (!this.autoComplete) {
1285
+ this._placeChangedPending.push({ observable, subscriber });
1286
+ return undefined;
1287
+ }
1288
+ const listener = this.autoComplete.addListener('place_changed', (event) => {
1289
+ this._ngZone.run(() => subscriber.next(event));
1290
+ });
1291
+ this._listeners.push(listener);
1292
+ return () => listener.remove();
1293
+ });
1294
+ return observable;
1295
+ }
1296
+ /** Asserts that the map has been initialized. */
1297
+ _assertInitialized() {
1298
+ if (!this.autoComplete && (typeof ngDevMode === 'undefined' || ngDevMode)) {
1299
+ throw Error('Cannot access Google Map Places information before the API has been initialized. ' +
1300
+ 'Please wait for the API to load before trying to interact with it.');
1301
+ }
1302
+ }
1303
+ }
1304
+ TheSeamGoogleMapsPlacesAutocompleteDirective.decorators = [
1305
+ { type: Directive, args: [{
1306
+ selector: 'input[seamGoogleMapsPlacesAutocomplete]',
1307
+ exportAs: 'seamGoogleMapsPlacesAutocomplete'
1308
+ },] }
1309
+ ];
1310
+ TheSeamGoogleMapsPlacesAutocompleteDirective.ctorParameters = () => [
1311
+ { type: ElementRef },
1312
+ { type: NgZone }
1313
+ ];
1314
+ TheSeamGoogleMapsPlacesAutocompleteDirective.propDecorators = {
1315
+ options: [{ type: Input }],
1316
+ placeChanged: [{ type: Output }],
1317
+ _attrType: [{ type: HostBinding, args: ['attr.type',] }]
1318
+ };
1319
+
1320
+ /**
1321
+ *
1322
+ */
1323
+ class TheSeamGoogleMapsPlacesAutoCompleteComponent {
1324
+ constructor(_elementRef) {
1325
+ this._elementRef = _elementRef;
1326
+ this._ngUnsubscribe = new Subject();
1327
+ this._autoCompleteReadySubject = new Subject();
1328
+ this._placeChangedPending = [];
1329
+ this.label = 'Search by address, place or name';
1330
+ this.icon = faSearchLocation;
1331
+ this.disabled = false;
1332
+ this.placeholder = 'Enter address, place or name';
1333
+ this.autocorrect = 'off';
1334
+ this.autocapitalize = 'off';
1335
+ this._tabIndex = -1;
1336
+ this._options = SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS;
1337
+ this.placeChanged = this._autoCompleteReadySubject.pipe(startWith(undefined), switchMap(() => this._createPlaceChangedObservable()));
1338
+ }
1339
+ /**
1340
+ * Set the tab index to `-1` to allow the root element of the
1341
+ * component to receive `focus` event from javascript, but not get focused by
1342
+ * keyboard navigation.
1343
+ */
1344
+ set tabIndex(value) { this._tabIndex = coerceNumberProperty(value); }
1345
+ get tabIndex() { return this._tabIndex; }
1346
+ set options(value) {
1347
+ this._options = value || SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS;
1348
+ }
1349
+ set __autocompleteDirective(value) {
1350
+ this._autoCompleteDirective = value;
1351
+ this._untilAutoCompleteReady().pipe(takeUntil(this._ngUnsubscribe)).subscribe(() => {
1352
+ this.autoComplete = this._autoCompleteDirective.autoComplete;
1353
+ this._placeChangedPending.forEach(pending => pending.observable.subscribe(pending.subscriber));
1354
+ this._placeChangedPending = [];
1355
+ });
1356
+ }
1357
+ get _attrTabIndex() { return this.disabled ? -1 : (this.tabIndex || 0); }
1358
+ _onClick(event) {
1359
+ this._inputDirective.focus();
1360
+ }
1361
+ _onFocus() {
1362
+ var _a;
1363
+ (_a = this._inputDirective) === null || _a === void 0 ? void 0 : _a.focus();
1364
+ }
1365
+ ngOnInit() { }
1366
+ /** @ignore */
1367
+ ngOnDestroy() {
1368
+ this._ngUnsubscribe.next();
1369
+ this._ngUnsubscribe.complete();
1370
+ }
1371
+ _untilAutoCompleteReady() {
1372
+ return interval(500).pipe(filter(() => !!this._autoCompleteDirective.autoComplete), take(1), mapTo(undefined));
1373
+ }
1374
+ /**
1375
+ * Returns the bounds to which predictions are biased.
1376
+ */
1377
+ getBounds() {
1378
+ this._assertInitialized();
1379
+ return this.autoComplete.getBounds();
1380
+ }
1381
+ /**
1382
+ * Returns the fields to be included for the Place in the details response
1383
+ * when the details are successfully retrieved. For a list of fields see
1384
+ * [PlaceResult](https://developers.google.com/maps/documentation/javascript/reference/places-service#PlaceResult).
1385
+ */
1386
+ getFields() {
1387
+ this._assertInitialized();
1388
+ return this.autoComplete.getFields();
1389
+ }
1390
+ /**
1391
+ * Returns the details of the Place selected by user if the details were
1392
+ * successfully retrieved. Otherwise returns a stub Place object, with the
1393
+ * name property set to the current value of the input field.
1394
+ */
1395
+ getPlace() {
1396
+ this._assertInitialized();
1397
+ return this.autoComplete.getPlace();
1398
+ }
1399
+ /**
1400
+ * Sets the preferred area within which to return Place results. Results are
1401
+ * biased towards, but not restricted to, this area.
1402
+ */
1403
+ setBounds(bounds) {
1404
+ this._assertInitialized();
1405
+ // tslint:disable-next-line: no-non-null-assertion
1406
+ return this.autoComplete.setBounds(bounds);
1407
+ }
1408
+ /**
1409
+ * Sets the component restrictions. Component restrictions are used to
1410
+ * restrict predictions to only those within the parent component. For
1411
+ * example, the country.
1412
+ */
1413
+ setComponentRestrictions(restrictions) {
1414
+ this._assertInitialized();
1415
+ // tslint:disable-next-line: no-non-null-assertion
1416
+ return this.autoComplete.setComponentRestrictions(restrictions);
1417
+ }
1418
+ /**
1419
+ * Sets the fields to be included for the Place in the details response when
1420
+ * the details are successfully retrieved. For a list of fields see
1421
+ * [PlaceResult](https://developers.google.com/maps/documentation/javascript/reference/places-service#PlaceResult).
1422
+ */
1423
+ setFields(fields) {
1424
+ this._assertInitialized();
1425
+ // tslint:disable-next-line: no-non-null-assertion
1426
+ return this.autoComplete.setFields(fields);
1427
+ }
1428
+ /** */
1429
+ setOptions(options) {
1430
+ this._assertInitialized();
1431
+ // tslint:disable-next-line: no-non-null-assertion
1432
+ return this.autoComplete.setOptions(options);
1433
+ }
1434
+ /**
1435
+ * Sets the types of predictions to be returned. For supported types, see the
1436
+ * [developer's guide](https://developers.google.com/maps/documentation/javascript/places-autocomplete#constrain-place-types).
1437
+ * If no types are specified, all types will be returned.
1438
+ */
1439
+ setTypes(types) {
1440
+ this._assertInitialized();
1441
+ // tslint:disable-next-line: no-non-null-assertion
1442
+ return this.autoComplete.setTypes(types);
1443
+ }
1444
+ /** Focuses the input. */
1445
+ focus() {
1446
+ this._elementRef.nativeElement.focus();
1447
+ }
1448
+ /** Unfocuses the input. */
1449
+ blur() {
1450
+ this._elementRef.nativeElement.blur();
1451
+ }
1452
+ getHostElement() {
1453
+ return this._elementRef.nativeElement;
1454
+ }
1455
+ _createPlaceChangedObservable() {
1456
+ const observable = new Observable(subscriber => {
1457
+ if (!this.autoComplete) {
1458
+ this._placeChangedPending.push({ observable, subscriber });
1459
+ return undefined;
1460
+ }
1461
+ const sub = this._autoCompleteDirective.placeChanged.subscribe(subscriber);
1462
+ return () => sub.unsubscribe();
1463
+ });
1464
+ return observable;
1465
+ }
1466
+ /** Asserts that the map has been initialized. */
1467
+ _assertInitialized() {
1468
+ if (!this.autoComplete && (typeof ngDevMode === 'undefined' || ngDevMode)) {
1469
+ throw Error('Cannot access Google Map Places information before the API has been initialized. ' +
1470
+ 'Please wait for the API to load before trying to interact with it.');
1471
+ }
1472
+ }
1473
+ }
1474
+ TheSeamGoogleMapsPlacesAutoCompleteComponent.decorators = [
1475
+ { type: Component, args: [{
1476
+ selector: 'seam-google-maps-places-autocomplete',
1477
+ template: "<div *ngIf=\"icon\" class=\"search-container--icon-wrapper\">\n <seam-icon [icon]=\"icon\" class=\"text-muted\" size=\"lg\"></seam-icon>\n</div>\n<label *ngIf=\"label || placeholder\" [attr.for]=\"inp.id\" class=\"sr-only\">{{ label || placeholder }}</label>\n<input #inp=\"seamInput\"\n seamInput\n seamGoogleMapsPlacesAutocomplete\n [disabled]=\"disabled\"\n [attr.placeholder]=\"placeholder\"\n [attr.autocorrect]=\"autocorrect\"\n [attr.autocapitalize]=\"autocapitalize\"\n [options]=\"_options\"\n/>\n",
1478
+ changeDetection: ChangeDetectionStrategy.OnPush,
1479
+ exportAs: 'seamGoogleMapsPlacesAutoComplete',
1480
+ styles: [":host{position:relative;width:100%}:host>input{padding-left:40px}:host .search-container--icon-wrapper{position:absolute;top:6px;left:10px;bottom:0px}:host .search-container--icon-wrapper ::ng-deep .svg-inline--fa{vertical-align:middle}\n"]
1481
+ },] }
1482
+ ];
1483
+ TheSeamGoogleMapsPlacesAutoCompleteComponent.ctorParameters = () => [
1484
+ { type: ElementRef }
1485
+ ];
1486
+ TheSeamGoogleMapsPlacesAutoCompleteComponent.propDecorators = {
1487
+ label: [{ type: Input }],
1488
+ icon: [{ type: Input }],
1489
+ disabled: [{ type: Input }],
1490
+ placeholder: [{ type: Input }],
1491
+ autocorrect: [{ type: Input }],
1492
+ autocapitalize: [{ type: Input }],
1493
+ tabIndex: [{ type: Input }],
1494
+ options: [{ type: Input }],
1495
+ placeChanged: [{ type: Output }],
1496
+ _inputDirective: [{ type: ViewChild, args: ['inp', { read: InputDirective, static: true },] }],
1497
+ __autocompleteDirective: [{ type: ViewChild, args: [TheSeamGoogleMapsPlacesAutocompleteDirective, { static: true },] }],
1498
+ _attrTabIndex: [{ type: HostBinding, args: ['attr.tabindex',] }],
1499
+ _onClick: [{ type: HostListener, args: ['click', ['event'],] }],
1500
+ _onFocus: [{ type: HostListener, args: ['focus', ['$event'],] }]
1501
+ };
1502
+ __decorate([
1503
+ InputBoolean()
1504
+ ], TheSeamGoogleMapsPlacesAutoCompleteComponent.prototype, "disabled", void 0);
1505
+
1506
+ class TheSeamMapsControlComponent {
1507
+ constructor(_googleMaps, _googleMapsControls) {
1508
+ this._googleMaps = _googleMaps;
1509
+ this._googleMapsControls = _googleMapsControls;
1510
+ this._ngUnsubscribe = new Subject();
1511
+ }
1512
+ set def(value) {
1513
+ if (value !== this._def) {
1514
+ this._remove();
1515
+ this._def = value;
1516
+ }
1517
+ }
1518
+ /** @ignore */
1519
+ ngOnInit() {
1520
+ this._googleMaps.mapReady$.pipe(tap(ready => {
1521
+ if (ready) {
1522
+ this._add();
1523
+ }
1524
+ else {
1525
+ this._remove();
1526
+ }
1527
+ }), takeUntil(this._ngUnsubscribe)).subscribe();
1528
+ }
1529
+ /** @ignore */
1530
+ ngOnDestroy() {
1531
+ this._remove();
1532
+ this._ngUnsubscribe.next();
1533
+ this._ngUnsubscribe.complete();
1534
+ }
1535
+ _add() {
1536
+ if (this._controlRef) {
1537
+ return;
1538
+ }
1539
+ if (this._def === null || this._def === undefined) {
1540
+ return;
1541
+ }
1542
+ this._controlRef = this._googleMapsControls.add(this._def);
1543
+ }
1544
+ _remove() {
1545
+ var _a;
1546
+ (_a = this._controlRef) === null || _a === void 0 ? void 0 : _a.destroy();
1547
+ this._controlRef = undefined;
1548
+ }
1549
+ }
1550
+ TheSeamMapsControlComponent.decorators = [
1551
+ { type: Component, args: [{
1552
+ selector: 'seam-map-control',
1553
+ template: '',
1554
+ changeDetection: ChangeDetectionStrategy.OnPush
1555
+ },] }
1556
+ ];
1557
+ TheSeamMapsControlComponent.ctorParameters = () => [
1558
+ { type: GoogleMapsService },
1559
+ { type: GoogleMapsControlsService, decorators: [{ type: Inject, args: [MAP_CONTROLS_SERVICE,] }] }
1560
+ ];
1561
+ TheSeamMapsControlComponent.propDecorators = {
1562
+ def: [{ type: Input }]
1563
+ };
1564
+
1565
+ /**
1566
+ *
1567
+ */
1568
+ class TheSeamMapFileDropComponent {
1569
+ constructor(_elementRef, _ngZone, _googleMaps, _mapValueManager, _renderer) {
1570
+ this._elementRef = _elementRef;
1571
+ this._ngZone = _ngZone;
1572
+ this._googleMaps = _googleMaps;
1573
+ this._mapValueManager = _mapValueManager;
1574
+ this._renderer = _renderer;
1575
+ this._ngUnsubscribe = new Subject();
1576
+ this._listeners = [];
1577
+ this._globalDragInProgress = false;
1578
+ this._handleDragOverEvent = (event) => {
1579
+ if (!this._dropAllowed()) {
1580
+ return;
1581
+ }
1582
+ if (!this._isSupportedDataTransferTypes(event.dataTransfer)) {
1583
+ return;
1584
+ }
1585
+ event.preventDefault();
1586
+ event.dataTransfer.dropEffect = 'copy';
1587
+ };
1588
+ this._handleDropEvent = (event) => {
1589
+ if (!this._dropAllowed()) {
1590
+ return;
1591
+ }
1592
+ event.preventDefault();
1593
+ event.stopPropagation();
1594
+ this._renderer.setStyle(this._elementRef.nativeElement, 'display', 'none');
1595
+ // TODO: Show error if multiple files?
1596
+ if (!this._isSupportedDataTransfer(event.dataTransfer)) {
1597
+ return;
1598
+ }
1599
+ const item = event.dataTransfer.items[0];
1600
+ const file = item.getAsFile();
1601
+ readGeoFile(file).then(json => {
1602
+ this._mapValueManager.setValue(json, MapValueSource.Input);
1603
+ });
1604
+ };
1605
+ this._handleDragEnterEvent = (event) => {
1606
+ if (!this._dropAllowed()) {
1607
+ return;
1608
+ }
1609
+ if (!this._isSupportedDataTransferTypes(event.dataTransfer)) {
1610
+ return;
1611
+ }
1612
+ this._renderer.setStyle(this._elementRef.nativeElement, 'display', 'block');
1613
+ };
1614
+ this._handleDragLeaveEvent = (event) => {
1615
+ if (!this._dropAllowed()) {
1616
+ return;
1617
+ }
1618
+ this._renderer.setStyle(this._elementRef.nativeElement, 'display', 'none');
1619
+ };
1620
+ }
1621
+ /** @ignore */
1622
+ ngOnInit() {
1623
+ this._googleMaps.mapReady$.pipe(tap(ready => {
1624
+ if (ready) {
1625
+ this._enableFileDrop();
1626
+ }
1627
+ else {
1628
+ this._disableFileDrop();
1629
+ }
1630
+ }), takeUntil(this._ngUnsubscribe)).subscribe();
1631
+ }
1632
+ /** @ignore */
1633
+ ngOnDestroy() {
1634
+ this._disableFileDrop();
1635
+ this._ngUnsubscribe.next();
1636
+ this._ngUnsubscribe.complete();
1637
+ }
1638
+ _enableFileDrop() {
1639
+ const divElement = this._googleMaps.getDiv();
1640
+ if (this._mapDiv === divElement) {
1641
+ return;
1642
+ }
1643
+ if (this._mapDiv !== undefined) {
1644
+ // Disable file drop on previous map div.
1645
+ this._disableFileDrop();
1646
+ }
1647
+ this._mapDiv = divElement;
1648
+ this._ngZone.runOutsideAngular(() => {
1649
+ this._listeners.push(this._renderer.listen('document', 'dragstart', (event) => {
1650
+ this._globalDragInProgress = true;
1651
+ }));
1652
+ this._listeners.push(this._renderer.listen('document', 'dragend', (event) => {
1653
+ this._globalDragInProgress = false;
1654
+ }));
1655
+ this._listeners.push(this._renderer.listen(divElement, 'dragover', this._handleDragOverEvent));
1656
+ this._listeners.push(this._renderer.listen(this._elementRef.nativeElement, 'dragover', this._handleDragOverEvent));
1657
+ this._listeners.push(this._renderer.listen(this._elementRef.nativeElement, 'drop', this._handleDropEvent));
1658
+ this._listeners.push(this._renderer.listen(divElement, 'dragenter', this._handleDragEnterEvent));
1659
+ this._listeners.push(this._renderer.listen(this._elementRef.nativeElement, 'dragleave', this._handleDragLeaveEvent));
1660
+ });
1661
+ }
1662
+ _disableFileDrop() {
1663
+ if (this._listeners.length > 0) {
1664
+ this._listeners.forEach(l => l());
1665
+ this._listeners = [];
1666
+ }
1667
+ }
1668
+ _dropAllowed() {
1669
+ return !this._globalDragInProgress;
1670
+ }
1671
+ _isSupportedDataTransfer(dataTransfer) {
1672
+ return dataTransfer.files.length === 1 && dataTransfer.types[0] === 'Files';
1673
+ }
1674
+ _isSupportedDataTransferTypes(dataTransfer) {
1675
+ return dataTransfer.types[0] === 'Files';
1676
+ }
1677
+ }
1678
+ TheSeamMapFileDropComponent.decorators = [
1679
+ { type: Component, args: [{
1680
+ selector: 'seam-map-file-drop',
1681
+ template: "",
1682
+ changeDetection: ChangeDetectionStrategy.OnPush,
1683
+ styles: [":host{display:none;position:absolute;top:0;left:0;width:100%;height:100%;z-index:9999!important;background-color:#1e1e1eb3}\n"]
1684
+ },] }
1685
+ ];
1686
+ TheSeamMapFileDropComponent.ctorParameters = () => [
1687
+ { type: ElementRef },
1688
+ { type: NgZone },
1689
+ { type: GoogleMapsService },
1690
+ { type: MapValueManagerService },
1691
+ { type: Renderer2 }
1692
+ ];
1693
+
1694
+ class TheSeamGoogleMapsModule {
1695
+ }
1696
+ TheSeamGoogleMapsModule.decorators = [
1697
+ { type: NgModule, args: [{
1698
+ declarations: [
1699
+ TheSeamGoogleMapsComponent,
1700
+ TheSeamMapFileDropComponent,
1701
+ TheSeamGoogleMapsUploadButtonControlComponent,
1702
+ TheSeamGoogleMapsRecenterButtonControlComponent,
1703
+ TheSeamMapsControlComponent,
1704
+ TheSeamGoogleMapsPlacesAutocompleteDirective,
1705
+ TheSeamGoogleMapsPlacesAutoCompleteComponent,
1706
+ ],
1707
+ imports: [
1708
+ CommonModule,
1709
+ ObserversModule,
1710
+ TheSeamSharedModule,
1711
+ TheSeamMenuModule,
1712
+ TheSeamIconModule,
1713
+ TheSeamFormFieldModule,
1714
+ AgmCoreModule,
1715
+ ],
1716
+ exports: [
1717
+ TheSeamGoogleMapsComponent,
1718
+ TheSeamGoogleMapsPlacesAutocompleteDirective,
1719
+ TheSeamGoogleMapsPlacesAutoCompleteComponent
1720
+ ]
1721
+ },] }
1722
+ ];
1723
+
1724
+ /**
1725
+ * Generated bundle index. Do not edit.
1726
+ */
1727
+
1728
+ export { AppFeaturePropertyName, GoogleMapsContextMenu, GoogleMapsControlsService, GoogleMapsService, MapControlRef, MapValueManagerService, MapValueSource, SEAM_GOOGLE_PLACES_AUTOCOMPLETE_DEFAULT_OPTIONS, TheSeamGoogleMapsComponent, TheSeamGoogleMapsModule, TheSeamGoogleMapsPlacesAutoCompleteComponent, TheSeamGoogleMapsPlacesAutocompleteDirective, TheSeamGoogleMapsRecenterButtonControlComponent, TheSeamGoogleMapsUploadButtonControlComponent, TheSeamMapFileDropComponent, TheSeamMapsControlComponent, addInnerFeatureCutoutToExteriorFeature, createDataFeatureFromPolygon, createFeatureChangeObservable, featureContains, fixPathDifferentStartingAndEndingPoint, getBoundsWithAllFeatures, getFeatureBounds, getFeatureCenter, getFeaturesCount, getPossibleExteriorFeature, isAppFeatureProperty, isFeatureSelected, multiPolygonCoordinates, polygonCoordinates, removeAllFeatures, setFeatureSelected, stripAppFeaturePropertiesFromJson, toTurfJsFeature, toTurfJsMultiPolygon, toTurfJsPolygon, ɵ0, MAP_CONTROLS_SERVICE as ɵb, MAP_CONTROL_DATA as ɵc };
1729
+ //# sourceMappingURL=theseam-ui-common-google-maps.js.map