@regionerne/gis-komponent 0.0.21 → 0.0.28
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/fesm2022/regionerne-gis-komponent.mjs +2267 -472
- package/fesm2022/regionerne-gis-komponent.mjs.map +1 -1
- package/lib/components/active-objects/activeObjects.component.d.ts +25 -3
- package/lib/components/confirm-dialog/confirm-dialog.component.d.ts +18 -0
- package/lib/components/gis-komponent/gis-komponent.component.d.ts +17 -3
- package/lib/components/layer-selector/layer-selector.component.d.ts +25 -13
- package/lib/components/legends-list/legends-list.component.d.ts +22 -20
- package/lib/components/map-search/map-search.component.d.ts +20 -5
- package/lib/components/selected-feature-info/selected-feature-info.component.d.ts +15 -0
- package/lib/components/toolbox/toolbox.component.d.ts +50 -39
- package/lib/models/GisKomponentSettings.d.ts +20 -0
- package/lib/models/ILayer.d.ts +9 -0
- package/lib/models/ILayerGroup.d.ts +2 -8
- package/lib/models/IProfile.d.ts +9 -0
- package/lib/models/icons.constants.d.ts +5 -0
- package/lib/models/profile.d.ts +2 -0
- package/lib/services/centerPoint.service.d.ts +17 -0
- package/lib/services/confirm-dialog.service.d.ts +11 -0
- package/lib/services/conflictAnalysisSearch.service.d.ts +19 -0
- package/lib/services/currentItems.service.d.ts +3 -0
- package/lib/services/drawLayerSource.service.d.ts +4 -0
- package/lib/services/featureHelper.service.d.ts +0 -1
- package/lib/services/geometry.service.d.ts +27 -0
- package/lib/services/highlight.service.d.ts +12 -9
- package/lib/services/hoverInfoSearch.service.d.ts +24 -0
- package/lib/services/infoSearch.service.d.ts +36 -0
- package/lib/services/layerError.service.d.ts +1 -0
- package/lib/services/layerHelper.service.d.ts +6 -3
- package/lib/services/layoutService.d.ts +12 -0
- package/lib/services/overlap.service.d.ts +21 -0
- package/lib/services/printDrawLayerSource.service.d.ts +1 -2
- package/lib/services/printHelper.service.d.ts +9 -0
- package/lib/services/searchProvider.service.d.ts +29 -0
- package/lib/services/showInfo.service.d.ts +15 -0
- package/lib/services/showInfoHover.service.d.ts +11 -0
- package/lib/services/wfsSearch.service.d.ts +39 -0
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as i1$1 from '@angular/common';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
2
|
+
import { CommonModule, AsyncPipe, JsonPipe } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { InjectionToken, inject, Injectable, Component, Input, ViewChild } from '@angular/core';
|
|
5
|
-
import * as
|
|
4
|
+
import { InjectionToken, inject, Injectable, Component, Input, ViewChild, Inject, EventEmitter, Output } from '@angular/core';
|
|
5
|
+
import * as i3 from '@angular/material/icon';
|
|
6
6
|
import { MatIconModule } from '@angular/material/icon';
|
|
7
7
|
import Map$1 from 'ol/Map';
|
|
8
8
|
import View from 'ol/View';
|
|
@@ -12,7 +12,7 @@ import WMTSCapabilities from 'ol/format/WMTSCapabilities';
|
|
|
12
12
|
import ImageLayer from 'ol/layer/Image';
|
|
13
13
|
import { HttpClient, HttpErrorResponse, HttpHeaders, provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
14
14
|
import OLLayerGroup from 'ol/layer/Group';
|
|
15
|
-
import * as
|
|
15
|
+
import * as i6$1 from '@angular/material/select';
|
|
16
16
|
import { MatSelectModule } from '@angular/material/select';
|
|
17
17
|
import * as i3$1 from '@angular/material/list';
|
|
18
18
|
import { MatListModule } from '@angular/material/list';
|
|
@@ -22,49 +22,66 @@ import { register } from 'ol/proj/proj4';
|
|
|
22
22
|
import proj4 from 'proj4';
|
|
23
23
|
import { Control, Rotate } from 'ol/control';
|
|
24
24
|
import { Vector, TileWMS } from 'ol/source';
|
|
25
|
-
import { BehaviorSubject,
|
|
25
|
+
import { Subject, BehaviorSubject, tap, switchMap, EMPTY, of, map, ReplaySubject, filter, interval, combineLatest, Observable, takeUntil, take, mergeWith, debounceTime, distinctUntilChanged, forkJoin, catchError, throwError } from 'rxjs';
|
|
26
26
|
import WMTS, { optionsFromCapabilities } from 'ol/source/WMTS';
|
|
27
|
-
import
|
|
27
|
+
import VectorLayer from 'ol/layer/Vector';
|
|
28
|
+
import TileSource from 'ol/source/Tile';
|
|
29
|
+
import ImageSource from 'ol/source/Image';
|
|
30
|
+
import VectorSource from 'ol/source/Vector';
|
|
31
|
+
import { unByKey } from 'ol/Observable';
|
|
32
|
+
import { MAT_SNACK_BAR_DATA, MatSnackBarRef, MatSnackBar } from '@angular/material/snack-bar';
|
|
33
|
+
import * as i5 from '@angular/cdk/drag-drop';
|
|
28
34
|
import { moveItemInArray, transferArrayItem, DragDropModule } from '@angular/cdk/drag-drop';
|
|
29
35
|
import * as i1 from '@angular/material/form-field';
|
|
30
36
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
31
|
-
import * as
|
|
37
|
+
import * as i1$2 from '@angular/forms';
|
|
32
38
|
import { FormsModule } from '@angular/forms';
|
|
33
|
-
import * as
|
|
39
|
+
import * as i6 from '@angular/material/expansion';
|
|
34
40
|
import { MatExpansionModule } from '@angular/material/expansion';
|
|
35
|
-
import * as
|
|
41
|
+
import * as i7 from '@angular/material/input';
|
|
36
42
|
import { MatInputModule } from '@angular/material/input';
|
|
37
43
|
import ol_control_Control from 'ol/control/Control';
|
|
38
|
-
import
|
|
39
|
-
import
|
|
40
|
-
import ImageSource from 'ol/source/Image';
|
|
41
|
-
import VectorSource from 'ol/source/Vector';
|
|
42
|
-
import { unByKey } from 'ol/Observable';
|
|
43
|
-
import { MAT_SNACK_BAR_DATA, MatSnackBarRef, MatSnackBar } from '@angular/material/snack-bar';
|
|
44
|
+
import * as i8 from '@angular/material/tooltip';
|
|
45
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
44
46
|
import 'ol/ol.css';
|
|
45
|
-
import {
|
|
47
|
+
import { Point as Point$1, LineString } from 'ol/geom';
|
|
46
48
|
import { getArea, getLength } from 'ol/sphere';
|
|
47
|
-
import Draw from 'ol/interaction/Draw';
|
|
49
|
+
import Draw, { createBox, createRegularPolygon } from 'ol/interaction/Draw';
|
|
48
50
|
import { Snap, Select as Select$1, Modify } from 'ol/interaction';
|
|
49
|
-
import { Style, Circle, Stroke, Fill, Text } from 'ol/style';
|
|
50
|
-
import * as i4
|
|
51
|
+
import { Style, Circle, Stroke, Fill, Icon, Text, RegularShape } from 'ol/style';
|
|
52
|
+
import * as i4 from '@angular/material/core';
|
|
51
53
|
import { MatOptionModule } from '@angular/material/core';
|
|
52
54
|
import * as SLDReader from '@nieuwlandgeo/sldreader';
|
|
53
55
|
import WKT from 'ol/format/WKT';
|
|
54
|
-
import { extend, createEmpty, buffer as buffer$1 } from 'ol/extent';
|
|
55
56
|
import Feature$1 from 'ol/Feature';
|
|
56
57
|
import { never, always } from 'ol/events/condition';
|
|
57
|
-
import { buffer, featureCollection, difference, booleanIntersects, union } from '@turf/turf';
|
|
58
|
+
import { buffer, lineIntersect, lineSplit, featureCollection, difference, booleanIntersects, union, point, booleanPointInPolygon, area, feature, booleanWithin, intersect } from '@turf/turf';
|
|
58
59
|
import GeoJSON from 'ol/format/GeoJSON';
|
|
59
|
-
import * as
|
|
60
|
-
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
61
|
-
import * as i8 from '@angular/material/slide-toggle';
|
|
60
|
+
import * as i9 from '@angular/material/slide-toggle';
|
|
62
61
|
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
63
62
|
import { Feature } from 'ol';
|
|
63
|
+
import { extend, createEmpty, buffer as buffer$1 } from 'ol/extent';
|
|
64
|
+
import { easeOut } from 'ol/easing';
|
|
64
65
|
import Select from 'ol/interaction/Select';
|
|
65
66
|
import html2canvas from 'html2canvas-pro';
|
|
67
|
+
import CircleStyle from 'ol/style/Circle';
|
|
68
|
+
import { transform } from 'ol/proj';
|
|
69
|
+
import * as i2 from '@angular/material/button';
|
|
70
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
71
|
+
import * as i1$3 from '@angular/material/dialog';
|
|
72
|
+
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogTitle, MatDialogContent, MatDialogActions } from '@angular/material/dialog';
|
|
73
|
+
import WFS from 'ol/format/WFS';
|
|
74
|
+
import Point from 'ol/geom/Point';
|
|
75
|
+
import { intersects, contains, like } from 'ol/format/filter';
|
|
76
|
+
import { BufferOp } from 'jsts/org/locationtech/jts/operation/buffer';
|
|
77
|
+
import { GeoJSONReader, GeoJSONWriter } from 'jsts/org/locationtech/jts/io';
|
|
78
|
+
import GeometryFactory from 'jsts/org/locationtech/jts/geom/GeometryFactory';
|
|
79
|
+
import PrecisionModel from 'jsts/org/locationtech/jts/geom/PrecisionModel';
|
|
66
80
|
import * as i5$1 from '@angular/material/autocomplete';
|
|
67
81
|
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
|
82
|
+
import { map as map$1 } from 'rxjs/operators';
|
|
83
|
+
import { createStringXY } from 'ol/coordinate';
|
|
84
|
+
import GeoJSON$1 from 'ol/format/GeoJSON.js';
|
|
68
85
|
|
|
69
86
|
const GISKOMPONENT_CONFIG = new InjectionToken('GisKomponentConfig');
|
|
70
87
|
|
|
@@ -116,83 +133,6 @@ class CopyrightControl extends Control {
|
|
|
116
133
|
}
|
|
117
134
|
}
|
|
118
135
|
|
|
119
|
-
class LayerHelperService {
|
|
120
|
-
activeLayersChanged = new BehaviorSubject(true);
|
|
121
|
-
_layerDbIdKey = 'layerDbId';
|
|
122
|
-
_layerGroupDbIdKey = 'layerGroupDbId';
|
|
123
|
-
_layerIdsToDisplayInMapKeyName = 'layerIdsToDisplayInMap';
|
|
124
|
-
setDbId(layer, id) {
|
|
125
|
-
layer.set(this._layerDbIdKey, id);
|
|
126
|
-
}
|
|
127
|
-
getDbId(layer) {
|
|
128
|
-
const dbId = layer.get(this._layerDbIdKey) ?? -1;
|
|
129
|
-
return +dbId;
|
|
130
|
-
}
|
|
131
|
-
setLayerGroupDbId(layer, id) {
|
|
132
|
-
layer.set(this._layerGroupDbIdKey, id);
|
|
133
|
-
}
|
|
134
|
-
getLayerGroupDbId(layer) {
|
|
135
|
-
const dbId = layer.get(this._layerGroupDbIdKey) ?? -1;
|
|
136
|
-
return +dbId;
|
|
137
|
-
}
|
|
138
|
-
applyCachedLayersToDisplayInMap(map, profileId) {
|
|
139
|
-
this.activeLayersChanged.next(true);
|
|
140
|
-
const layerIdsCachedToDisplay = localStorage.getItem(`${this._layerIdsToDisplayInMapKeyName}_${profileId}`)?.split(',');
|
|
141
|
-
if (layerIdsCachedToDisplay) {
|
|
142
|
-
//Bottom layers are rendered first, top layers are rendered last (on top)
|
|
143
|
-
layerIdsCachedToDisplay.reverse();
|
|
144
|
-
map.getLayers().getArray().forEach(layergroup => {
|
|
145
|
-
if (layergroup instanceof OLLayerGroup) {
|
|
146
|
-
layergroup.getLayers().getArray().forEach(l => {
|
|
147
|
-
if (!layerIdsCachedToDisplay.some(id => l.get(this._layerDbIdKey) == id)) {
|
|
148
|
-
const current = l.getVisible();
|
|
149
|
-
if (current) {
|
|
150
|
-
l.setVisible(!current);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
//Set z index to match the order in cache
|
|
155
|
-
l.setZIndex(layerIdsCachedToDisplay.indexOf(l.get(this._layerDbIdKey).toString()));
|
|
156
|
-
//console.log('layer id '+l.get(this._layerDbIdKey)+' - setZIndex:'+layerIdsCachedToDisplay.indexOf(l.get(this._layerDbIdKey).toString()));
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
updateLayerOpacityInMap(map, layer) {
|
|
164
|
-
map.getLayers().getArray().forEach(layergroup => {
|
|
165
|
-
if (layergroup instanceof OLLayerGroup) {
|
|
166
|
-
layergroup.getLayers().getArray().forEach(l => {
|
|
167
|
-
if (l.get(this._layerDbIdKey) === layer.id && layer.opacity) {
|
|
168
|
-
l.setOpacity(layer.opacity);
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
toggleLayerInMap(map, layer) {
|
|
175
|
-
map.getLayers().getArray().forEach(layergroup => {
|
|
176
|
-
if (layergroup instanceof OLLayerGroup) {
|
|
177
|
-
layergroup.getLayers().getArray().forEach(l => {
|
|
178
|
-
if (l.get(this._layerDbIdKey) === layer.id) {
|
|
179
|
-
const current = l.getVisible();
|
|
180
|
-
l.setVisible(!current);
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayerHelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
187
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayerHelperService, providedIn: 'root' });
|
|
188
|
-
}
|
|
189
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayerHelperService, decorators: [{
|
|
190
|
-
type: Injectable,
|
|
191
|
-
args: [{
|
|
192
|
-
providedIn: 'root'
|
|
193
|
-
}]
|
|
194
|
-
}] });
|
|
195
|
-
|
|
196
136
|
class LibNotificationComponent {
|
|
197
137
|
data = inject(MAT_SNACK_BAR_DATA);
|
|
198
138
|
_snackRef = inject((MatSnackBarRef));
|
|
@@ -257,6 +197,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
257
197
|
|
|
258
198
|
class LayerErrorService {
|
|
259
199
|
layerStatusChanged = new Subject();
|
|
200
|
+
layerErrored = new Subject();
|
|
260
201
|
layerStatuses = new Map();
|
|
261
202
|
listeners = new Map();
|
|
262
203
|
_errorService = inject(LibErrorService);
|
|
@@ -275,6 +216,7 @@ class LayerErrorService {
|
|
|
275
216
|
console.error(`[Layer ${layerId}] load error:`, event);
|
|
276
217
|
this._errorService.show(new Error(`Indlæsningsfejl for lag med id ${layerId}.`));
|
|
277
218
|
this.layerStatusChanged.next(layerId);
|
|
219
|
+
this.layerErrored.next(layerId);
|
|
278
220
|
};
|
|
279
221
|
const clearError = () => {
|
|
280
222
|
this.layerStatuses.set(layerId, { layerId, hasError: false });
|
|
@@ -324,10 +266,193 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
324
266
|
args: [{ providedIn: 'root' }]
|
|
325
267
|
}] });
|
|
326
268
|
|
|
327
|
-
class
|
|
328
|
-
|
|
329
|
-
|
|
269
|
+
class LayerHelperService {
|
|
270
|
+
activeLayersChanged = new BehaviorSubject(true);
|
|
271
|
+
_layerDbIdKey = 'layerDbId';
|
|
272
|
+
_layerGroupDbIdKey = 'layerGroupDbId';
|
|
273
|
+
_mapFilteredLayerGroupsKeyName = 'mapFilteredLayerGroups';
|
|
274
|
+
_layerErrorService = inject(LayerErrorService);
|
|
275
|
+
layerActivatedByBackgroundGroup = new Subject();
|
|
276
|
+
setDbId(layer, id) {
|
|
277
|
+
layer.set(this._layerDbIdKey, id);
|
|
278
|
+
}
|
|
279
|
+
getDbId(layer) {
|
|
280
|
+
const dbId = layer.get(this._layerDbIdKey) ?? -1;
|
|
281
|
+
return +dbId;
|
|
282
|
+
}
|
|
283
|
+
setLayerGroupDbId(layer, id) {
|
|
284
|
+
layer.set(this._layerGroupDbIdKey, id);
|
|
285
|
+
}
|
|
286
|
+
getLayerGroupDbId(layer) {
|
|
287
|
+
const dbId = layer.get(this._layerGroupDbIdKey) ?? -1;
|
|
288
|
+
return +dbId;
|
|
289
|
+
}
|
|
290
|
+
applyCachedLayersToDisplayInMap(map, profileId) {
|
|
291
|
+
this.activeLayersChanged.next(true);
|
|
292
|
+
const cacheValue = localStorage.getItem(`${this._mapFilteredLayerGroupsKeyName}_${profileId}`);
|
|
293
|
+
if (cacheValue) {
|
|
294
|
+
const layersCachedToDisplay = JSON.parse(cacheValue).cachedLayerGroups
|
|
295
|
+
.flatMap((lg) => lg.layers)
|
|
296
|
+
.map((l) => ({ id: l.id, visible: l.visible }));
|
|
297
|
+
//Bottom layers are rendered first, top layers are rendered last (on top)
|
|
298
|
+
layersCachedToDisplay.reverse();
|
|
299
|
+
map.getLayers().getArray().forEach(layergroup => {
|
|
300
|
+
if (layergroup instanceof OLLayerGroup) {
|
|
301
|
+
layergroup.getLayers().getArray().forEach(l => {
|
|
302
|
+
const cachedLayer = layersCachedToDisplay
|
|
303
|
+
.find((layer) => l.get(this._layerDbIdKey) == layer.id);
|
|
304
|
+
const current = l.getVisible();
|
|
305
|
+
if (cachedLayer != undefined && current != cachedLayer.visible) {
|
|
306
|
+
l.setVisible(cachedLayer.visible);
|
|
307
|
+
}
|
|
308
|
+
//Set z index to match the order in cache
|
|
309
|
+
l.setZIndex(layersCachedToDisplay.indexOf(cachedLayer));
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
startFailoverForBackgroundGroup(aMap, groupId) {
|
|
316
|
+
const currentIndex$ = new BehaviorSubject(0);
|
|
317
|
+
const layergroup = aMap.getLayers().getArray()
|
|
318
|
+
.find(layergroup => layergroup instanceof OLLayerGroup && layergroup.get('id') === groupId);
|
|
319
|
+
const items = layergroup.getLayers().getArray().sort((a, b) => (b.getZIndex() ?? 0) - (a.getZIndex() ?? 0));
|
|
320
|
+
// Handles activating the current item
|
|
321
|
+
const activation$ = currentIndex$.pipe(tap(index => {
|
|
322
|
+
// deactivate all first
|
|
323
|
+
items.forEach(layer => layer.setVisible(false));
|
|
324
|
+
// if out of range, stop completely
|
|
325
|
+
if (index >= items.length) {
|
|
326
|
+
console.warn('No more items left. Stopping failover.');
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
// activate current
|
|
330
|
+
const layer = items[index];
|
|
331
|
+
layer.setVisible(true);
|
|
332
|
+
this.layerActivatedByBackgroundGroup.next(layer.get(this._layerDbIdKey));
|
|
333
|
+
}),
|
|
334
|
+
// Listen for failures only while we have a valid index
|
|
335
|
+
switchMap(index => {
|
|
336
|
+
if (index >= items.length)
|
|
337
|
+
return EMPTY;
|
|
338
|
+
const currentItem = items[index];
|
|
339
|
+
return this._layerErrorService.layerErrored.pipe(tap(failedId => {
|
|
340
|
+
// If the current one failed, move to next
|
|
341
|
+
if (failedId === currentItem.get(this._layerDbIdKey)) {
|
|
342
|
+
currentIndex$.next(index + 1);
|
|
343
|
+
}
|
|
344
|
+
}));
|
|
345
|
+
}));
|
|
346
|
+
activation$.subscribe();
|
|
347
|
+
}
|
|
348
|
+
updateLayerOpacityInMap(map, layer) {
|
|
349
|
+
map.getLayers().getArray().forEach(layergroup => {
|
|
350
|
+
if (layergroup instanceof OLLayerGroup) {
|
|
351
|
+
layergroup.getLayers().getArray().forEach(l => {
|
|
352
|
+
if (l.get(this._layerDbIdKey) === layer.id && layer.opacity) {
|
|
353
|
+
l.setOpacity(layer.opacity);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
toggleLayerInMap(map, layerId) {
|
|
360
|
+
map.getLayers().getArray().forEach(layergroup => {
|
|
361
|
+
if (layergroup instanceof OLLayerGroup) {
|
|
362
|
+
layergroup.getLayers().getArray().forEach(l => {
|
|
363
|
+
if (l.get(this._layerDbIdKey) === layerId) {
|
|
364
|
+
const current = l.getVisible();
|
|
365
|
+
l.setVisible(!current);
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayerHelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
372
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayerHelperService, providedIn: 'root' });
|
|
373
|
+
}
|
|
374
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayerHelperService, decorators: [{
|
|
375
|
+
type: Injectable,
|
|
376
|
+
args: [{
|
|
377
|
+
providedIn: 'root'
|
|
378
|
+
}]
|
|
379
|
+
}] });
|
|
380
|
+
|
|
381
|
+
class LayoutService {
|
|
382
|
+
loadInitialPositionFromProfile(widgetName, initialPosition) {
|
|
383
|
+
let dragPosition = { x: 2, y: -25 };
|
|
384
|
+
switch (initialPosition) {
|
|
385
|
+
case 'øverst/venstre':
|
|
386
|
+
dragPosition = { x: 46, y: -119 };
|
|
387
|
+
this._savePosition(widgetName, dragPosition);
|
|
388
|
+
break;
|
|
389
|
+
case 'midte/venstre':
|
|
390
|
+
dragPosition = { x: 1, y: 247 };
|
|
391
|
+
this._savePosition(widgetName, dragPosition);
|
|
392
|
+
break;
|
|
393
|
+
case 'nederst/venstre':
|
|
394
|
+
dragPosition = { x: 0, y: 493 };
|
|
395
|
+
this._savePosition(widgetName, dragPosition);
|
|
396
|
+
break;
|
|
397
|
+
case 'øverst/midte':
|
|
398
|
+
dragPosition = { x: 849, y: -154 };
|
|
399
|
+
this._savePosition(widgetName, dragPosition);
|
|
400
|
+
break;
|
|
401
|
+
case 'nederst/midte':
|
|
402
|
+
dragPosition = { x: 895, y: 481 };
|
|
403
|
+
this._savePosition(widgetName, dragPosition);
|
|
404
|
+
break;
|
|
405
|
+
case 'øverst/højre':
|
|
406
|
+
dragPosition = { x: 1599, y: -121 };
|
|
407
|
+
this._savePosition(widgetName, dragPosition);
|
|
408
|
+
break;
|
|
409
|
+
case 'midte/højre':
|
|
410
|
+
dragPosition = { x: 1600, y: 164 };
|
|
411
|
+
this._savePosition(widgetName, dragPosition);
|
|
412
|
+
break;
|
|
413
|
+
case 'nederst/højre':
|
|
414
|
+
dragPosition = { x: 1600, y: 500 };
|
|
415
|
+
this._savePosition(widgetName, dragPosition);
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
return dragPosition;
|
|
419
|
+
}
|
|
420
|
+
bringElementIntoViewIfNeeded(elementClass, offsetValue, collapsed, map) {
|
|
421
|
+
const element = document.querySelector(elementClass);
|
|
422
|
+
const mapControls = map.getControls();
|
|
423
|
+
console.log('map controls', mapControls);
|
|
424
|
+
if (!element)
|
|
425
|
+
return;
|
|
426
|
+
const left = parseInt(element.style.left || '0', 10);
|
|
427
|
+
console.log('bringToolboxIntoViewIfNeeded left ', left, element, element.style);
|
|
428
|
+
if (collapsed) {
|
|
429
|
+
// Widget minimized, remove the style for left
|
|
430
|
+
element.style.left = '0em';
|
|
431
|
+
}
|
|
432
|
+
else {
|
|
433
|
+
// If widget expands outside screen on the right (left is > <offsetValue> em), then bring it back
|
|
434
|
+
element.style.left = `${left > offsetValue ? offsetValue : left}em`;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
_savePosition(widgetStorageKey, position) {
|
|
438
|
+
try {
|
|
439
|
+
localStorage.setItem(widgetStorageKey, JSON.stringify(position));
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
console.error('Error saving position to localStorage:', error);
|
|
443
|
+
}
|
|
330
444
|
}
|
|
445
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
446
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayoutService, providedIn: 'root' });
|
|
447
|
+
}
|
|
448
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayoutService, decorators: [{
|
|
449
|
+
type: Injectable,
|
|
450
|
+
args: [{
|
|
451
|
+
providedIn: 'root'
|
|
452
|
+
}]
|
|
453
|
+
}] });
|
|
454
|
+
|
|
455
|
+
class LayerSelectorComponent {
|
|
331
456
|
set contentBody(content) {
|
|
332
457
|
this._layerSelectorBody = content;
|
|
333
458
|
}
|
|
@@ -337,20 +462,26 @@ class LayerSelectorComponent {
|
|
|
337
462
|
searchText = '';
|
|
338
463
|
allLayerGroups = [];
|
|
339
464
|
filteredLayerGroups = [];
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
_layerSelectorIconControl;
|
|
465
|
+
filteredBackgroundLayerGroups = [];
|
|
466
|
+
showLegend = false;
|
|
467
|
+
collapsed = true;
|
|
468
|
+
dragPosition = { x: 0, y: 0 };
|
|
469
|
+
legendUrl = 'https://docs.geoserver.org/main/en/user/_images/samplelegend.png';
|
|
346
470
|
_layerSelectorBody;
|
|
347
471
|
_layerSelectorBodyControl;
|
|
472
|
+
layerSelectorDragPosition = { x: 0, y: 0 };
|
|
348
473
|
_mapFilteredLayerGroupsKeyName = 'mapFilteredLayerGroups';
|
|
349
|
-
|
|
474
|
+
POSITION_STORAGE_KEY = 'layerSelectorPosition';
|
|
350
475
|
_layerHelper = inject(LayerHelperService);
|
|
351
476
|
_layerErrorService = inject(LayerErrorService);
|
|
477
|
+
_layoutService = inject(LayoutService);
|
|
478
|
+
LAYER_SELECTOR_POSITION_KEY = 'layerSelectorPosition';
|
|
352
479
|
ngOnInit() {
|
|
353
|
-
this.
|
|
480
|
+
this._loadLayerSelectorPosition();
|
|
481
|
+
this._loadPosition();
|
|
482
|
+
this._layerHelper.layerActivatedByBackgroundGroup
|
|
483
|
+
.subscribe(layerId => this.toggleLayer(layerId, undefined, true));
|
|
484
|
+
this._layerErrorService.layerErrored
|
|
354
485
|
.subscribe(layerId => {
|
|
355
486
|
const layerHasErrors = this._layerErrorService.getLayerStatus(layerId)?.hasError;
|
|
356
487
|
if (layerHasErrors != undefined)
|
|
@@ -359,11 +490,12 @@ class LayerSelectorComponent {
|
|
|
359
490
|
}
|
|
360
491
|
ngOnChanges(changes) {
|
|
361
492
|
if (changes['profile'] && this.profile) {
|
|
493
|
+
this._loadPosition();
|
|
362
494
|
this.allLayerGroups = this.profile.layerGroups
|
|
363
495
|
.map((lg, idx) => ({ ...lg,
|
|
364
496
|
noOfVisibleLayers: lg.layers.filter(l => l.visible).length,
|
|
365
497
|
visible: lg.layers.some(l => l.visible),
|
|
366
|
-
expanded: lg.
|
|
498
|
+
expanded: lg.folded === false,
|
|
367
499
|
layers: lg.layers.filter((l) => l.activeInSelector),
|
|
368
500
|
sortOrder: idx }))
|
|
369
501
|
.filter(g => g.layers.length > 0);
|
|
@@ -372,31 +504,81 @@ class LayerSelectorComponent {
|
|
|
372
504
|
const cachedProfileInfo = JSON.parse(cacheValue);
|
|
373
505
|
if (cachedProfileInfo.profile.versionId < this.profile.versionId) {
|
|
374
506
|
//Profile version changed in backend, use that
|
|
375
|
-
this.
|
|
507
|
+
this.filterChanged();
|
|
376
508
|
this._cacheProfileInfo();
|
|
377
509
|
}
|
|
378
510
|
else {
|
|
379
|
-
this.filteredLayerGroups = cachedProfileInfo.cachedLayerGroups;
|
|
511
|
+
this.filteredLayerGroups = cachedProfileInfo.cachedLayerGroups.filter(gr => !gr.background);
|
|
512
|
+
;
|
|
513
|
+
this.filteredBackgroundLayerGroups = cachedProfileInfo.cachedLayerGroups.filter(gr => gr.background);
|
|
380
514
|
this._setVisibleLayersFromCache(cachedProfileInfo.cachedLayerGroups);
|
|
381
515
|
}
|
|
382
516
|
}
|
|
383
517
|
else {
|
|
384
|
-
this.
|
|
518
|
+
this.filterChanged();
|
|
385
519
|
this._cacheProfileInfo();
|
|
386
520
|
}
|
|
387
|
-
|
|
521
|
+
// Apply Failover logic to all background groups
|
|
522
|
+
this.filteredBackgroundLayerGroups
|
|
523
|
+
.forEach(group => {
|
|
524
|
+
group.layers.forEach(layer => layer.visible = false); //Turn all layers off in selector to begin with
|
|
525
|
+
group.visible = true; // Expand the group (there will be at least one active layer)
|
|
526
|
+
group.expanded = true;
|
|
527
|
+
this._layerHelper.startFailoverForBackgroundGroup(this.map, group.id);
|
|
528
|
+
});
|
|
529
|
+
this._initializeMapControl();
|
|
388
530
|
}
|
|
389
531
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
532
|
+
_loadLayerSelectorPosition() {
|
|
533
|
+
try {
|
|
534
|
+
const saved = localStorage.getItem(this.LAYER_SELECTOR_POSITION_KEY);
|
|
535
|
+
if (saved) {
|
|
536
|
+
this.layerSelectorDragPosition = JSON.parse(saved);
|
|
537
|
+
}
|
|
538
|
+
else if (this.profile) {
|
|
539
|
+
this.layerSelectorDragPosition = this._layoutService.loadInitialPositionFromProfile(this.LAYER_SELECTOR_POSITION_KEY, this.profile.layerSelectorInitialPosition);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
catch (error) {
|
|
543
|
+
console.error('Error loading layer selector position from localStorage:', error);
|
|
544
|
+
this.layerSelectorDragPosition = { x: 0, y: 0 };
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
onLayerSelectorDragEnded(event) {
|
|
548
|
+
const position = event.source.getFreeDragPosition();
|
|
549
|
+
this.layerSelectorDragPosition = position;
|
|
550
|
+
try {
|
|
551
|
+
localStorage.setItem(this.LAYER_SELECTOR_POSITION_KEY, JSON.stringify(position));
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
console.error('Error saving layer selector position to localStorage:', error);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
toggleLayer(layerId, event, skipMapToggle = false) {
|
|
558
|
+
event?.stopPropagation(); // Prevent the panel from expanding/collapsing
|
|
559
|
+
if (!skipMapToggle)
|
|
560
|
+
this._layerHelper.toggleLayerInMap(this.map, layerId);
|
|
393
561
|
// Toggle layer in all groups in the selector UI
|
|
394
|
-
this.filteredLayerGroups.forEach(group => {
|
|
562
|
+
this.filteredLayerGroups.concat(this.filteredBackgroundLayerGroups).forEach(group => {
|
|
563
|
+
let singleLaterIdToKeepOn = 0;
|
|
395
564
|
group.layers.forEach(l => {
|
|
396
|
-
if (
|
|
565
|
+
if (layerId === l.id) {
|
|
397
566
|
l.visible = !l.visible;
|
|
567
|
+
if (l.visible && !group.allowMultiSelect) {
|
|
568
|
+
// Group doesn't allow multi select and we just turned this layer on
|
|
569
|
+
// so turn all others off
|
|
570
|
+
singleLaterIdToKeepOn = l.id;
|
|
571
|
+
}
|
|
398
572
|
}
|
|
399
573
|
});
|
|
574
|
+
if (singleLaterIdToKeepOn > 0) {
|
|
575
|
+
group.layers.forEach(l => {
|
|
576
|
+
if (singleLaterIdToKeepOn !== l.id) {
|
|
577
|
+
l.visible = false;
|
|
578
|
+
this._layerHelper.toggleLayerInMap(this.map, l.id);
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
400
582
|
group.noOfVisibleLayers = group.layers.filter(l => l.visible).length;
|
|
401
583
|
group.visible = group.layers.some(l => l.visible);
|
|
402
584
|
group.expanded = group.layers.some(l => l.visible);
|
|
@@ -404,7 +586,7 @@ class LayerSelectorComponent {
|
|
|
404
586
|
this._cacheProfileInfo();
|
|
405
587
|
}
|
|
406
588
|
setLayerErrorStatus(layerId, errorStatus) {
|
|
407
|
-
this.filteredLayerGroups.forEach(group => {
|
|
589
|
+
this.filteredLayerGroups.concat(this.filteredBackgroundLayerGroups).forEach(group => {
|
|
408
590
|
group.layers.forEach(l => {
|
|
409
591
|
if (layerId === l.id) {
|
|
410
592
|
l.hasErrors = errorStatus;
|
|
@@ -415,34 +597,39 @@ class LayerSelectorComponent {
|
|
|
415
597
|
toggleGroup(event, layerGroup) {
|
|
416
598
|
event.stopPropagation(); // Prevent the panel from expanding/collapsing
|
|
417
599
|
const visible = !layerGroup.visible;
|
|
418
|
-
layerGroup.
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
600
|
+
if (visible && layerGroup.background) {
|
|
601
|
+
//Toggle background group on, apply failover logic
|
|
602
|
+
layerGroup.layers.forEach(layer => layer.visible = false); // Turn all off in selector to begin with
|
|
603
|
+
this._layerHelper.startFailoverForBackgroundGroup(this.map, layerGroup.id);
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
layerGroup.layers.forEach(layer => {
|
|
607
|
+
if (layer.visible != visible) {
|
|
608
|
+
//Toggle layer in map
|
|
609
|
+
this._layerHelper.toggleLayerInMap(this.map, layer.id);
|
|
610
|
+
// Toggle layer in all groups in the selector UI
|
|
611
|
+
this.filteredLayerGroups.concat(this.filteredBackgroundLayerGroups).forEach(group => {
|
|
612
|
+
group.layers.forEach(l => {
|
|
613
|
+
if (layer.id === l.id) {
|
|
614
|
+
l.visible = !l.visible;
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
group.noOfVisibleLayers = group.layers.filter(l => l.visible).length;
|
|
618
|
+
group.visible = group.layers.some(l => l.visible);
|
|
619
|
+
group.expanded = group.layers.some(l => l.visible);
|
|
428
620
|
});
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
});
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
}
|
|
435
624
|
layerGroup.visible = visible;
|
|
436
625
|
layerGroup.expanded = layerGroup.layers.some(l => l.visible);
|
|
437
626
|
this._cacheProfileInfo();
|
|
438
627
|
}
|
|
439
628
|
toggleLayerSelector() {
|
|
440
|
-
this.
|
|
441
|
-
if (this.
|
|
442
|
-
this.
|
|
443
|
-
|
|
444
|
-
else {
|
|
445
|
-
this._removeMapBodyControl();
|
|
629
|
+
this.collapsed = !this.collapsed;
|
|
630
|
+
if (this.collapsed) {
|
|
631
|
+
this.searchText = '';
|
|
632
|
+
this.filterChanged();
|
|
446
633
|
}
|
|
447
634
|
}
|
|
448
635
|
updateOpacity(layer) {
|
|
@@ -451,12 +638,16 @@ class LayerSelectorComponent {
|
|
|
451
638
|
stopDrag(event) {
|
|
452
639
|
event.stopPropagation(); // prevents drag container from activating
|
|
453
640
|
}
|
|
641
|
+
filterChanged() {
|
|
642
|
+
this.filteredLayerGroups = this.setfilteredGroups().filter(gr => !gr.background);
|
|
643
|
+
this.filteredBackgroundLayerGroups = this.setfilteredGroups().filter(gr => gr.background);
|
|
644
|
+
}
|
|
454
645
|
setfilteredGroups() {
|
|
455
646
|
const text = this.searchText.toLowerCase();
|
|
456
647
|
return this.allLayerGroups
|
|
457
648
|
.map((g, idx) => {
|
|
458
649
|
if (!text) {
|
|
459
|
-
return { ...g, expanded: false, sortOrder: idx,
|
|
650
|
+
return { ...g, expanded: g.folded === false, sortOrder: idx,
|
|
460
651
|
layers: g.layers.map(layer => ({ ...layer, opacity: 1 }))
|
|
461
652
|
}; // collapsed by default
|
|
462
653
|
}
|
|
@@ -470,17 +661,15 @@ class LayerSelectorComponent {
|
|
|
470
661
|
})
|
|
471
662
|
.filter(g => g.layers.length > 0)
|
|
472
663
|
.sort((a, b) => {
|
|
473
|
-
|
|
474
|
-
const bIsLast = this._namesToGoLast.includes(b.name) || b.layers.some(layer => layer.background);
|
|
475
|
-
if (aIsLast && !bIsLast)
|
|
664
|
+
if (a.background && !b.background)
|
|
476
665
|
return 1;
|
|
477
|
-
if (!
|
|
666
|
+
if (!a.background && b.background)
|
|
478
667
|
return -1;
|
|
479
668
|
return a.sortOrder - b.sortOrder;
|
|
480
669
|
});
|
|
481
670
|
}
|
|
482
|
-
dropGroup(event) {
|
|
483
|
-
moveItemInArray(
|
|
671
|
+
dropGroup(event, groupArray) {
|
|
672
|
+
moveItemInArray(groupArray, event.previousIndex, event.currentIndex);
|
|
484
673
|
this.updateGroupSortOrders();
|
|
485
674
|
this._cacheProfileInfo();
|
|
486
675
|
}
|
|
@@ -496,41 +685,57 @@ class LayerSelectorComponent {
|
|
|
496
685
|
}
|
|
497
686
|
clearSearchText() {
|
|
498
687
|
this.searchText = '';
|
|
499
|
-
this.
|
|
688
|
+
this.filterChanged();
|
|
500
689
|
this._cacheProfileInfo();
|
|
501
690
|
}
|
|
502
691
|
updateGroupSortOrders() {
|
|
503
692
|
this.filteredLayerGroups.forEach((g, idx) => (g.sortOrder = idx));
|
|
693
|
+
this.filteredBackgroundLayerGroups.forEach((g, idx) => (g.sortOrder = idx));
|
|
504
694
|
}
|
|
505
695
|
updateLayerSortOrders(group) {
|
|
506
696
|
group.layers.forEach((layer, idx) => (layer.sortOrder = idx));
|
|
507
697
|
}
|
|
698
|
+
onDragEnded(event) {
|
|
699
|
+
const position = event.source.getFreeDragPosition();
|
|
700
|
+
this.dragPosition = position;
|
|
701
|
+
this._savePosition(position);
|
|
702
|
+
}
|
|
703
|
+
_savePosition(position) {
|
|
704
|
+
try {
|
|
705
|
+
localStorage.setItem(this.POSITION_STORAGE_KEY, JSON.stringify(position));
|
|
706
|
+
}
|
|
707
|
+
catch (error) {
|
|
708
|
+
console.error('Error saving position to localStorage:', error);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
_loadPosition() {
|
|
712
|
+
try {
|
|
713
|
+
const savedPosition = localStorage.getItem(this.POSITION_STORAGE_KEY);
|
|
714
|
+
if (savedPosition) {
|
|
715
|
+
this.dragPosition = JSON.parse(savedPosition);
|
|
716
|
+
}
|
|
717
|
+
else if (this.profile) {
|
|
718
|
+
this.dragPosition = this._layoutService.loadInitialPositionFromProfile(this.POSITION_STORAGE_KEY, this.profile.layerSelectorInitialPosition);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
catch (error) {
|
|
722
|
+
console.error('Error loading position from localStorage:', error);
|
|
723
|
+
this.dragPosition = { x: 0, y: 0 };
|
|
724
|
+
}
|
|
725
|
+
}
|
|
508
726
|
_cacheProfileInfo() {
|
|
509
|
-
const cacheItem = { profile: this.profile, cachedLayerGroups: this.filteredLayerGroups };
|
|
727
|
+
const cacheItem = { profile: this.profile, cachedLayerGroups: this.filteredLayerGroups.concat(this.filteredBackgroundLayerGroups) };
|
|
510
728
|
localStorage.setItem(`${this._mapFilteredLayerGroupsKeyName}_${this.profile.id}`, JSON.stringify(cacheItem));
|
|
511
|
-
localStorage.setItem(`${this._layerIdsToDisplayInMapKeyName}_${this.profile.id}`, this.filteredLayerGroups
|
|
512
|
-
.flatMap(lg => lg.layers)
|
|
513
|
-
.filter(lg => lg.visible)
|
|
514
|
-
.map(lg => lg.id).join(','));
|
|
515
729
|
// Reflect new order in map
|
|
516
730
|
this._layerHelper.applyCachedLayersToDisplayInMap(this.map, this.profile.id);
|
|
517
731
|
}
|
|
518
|
-
|
|
519
|
-
this.map.removeControl(this._layerSelectorIconControl);
|
|
520
|
-
if (this._layerSelectorIcon?.nativeElement) {
|
|
521
|
-
const element = this._layerSelectorIcon.nativeElement;
|
|
522
|
-
this._layerSelectorIconControl = new ol_control_Control({ element: element });
|
|
523
|
-
this.map.addControl(this._layerSelectorIconControl);
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
_addMapBodyControl() {
|
|
527
|
-
this.map.removeControl(this._layerSelectorBodyControl);
|
|
528
|
-
const element = this._layerSelectorBody.nativeElement;
|
|
529
|
-
this._layerSelectorBodyControl = new ol_control_Control({ element: element });
|
|
530
|
-
this.map.addControl(this._layerSelectorBodyControl);
|
|
531
|
-
}
|
|
532
|
-
_removeMapBodyControl() {
|
|
732
|
+
_initializeMapControl() {
|
|
533
733
|
this.map.removeControl(this._layerSelectorBodyControl);
|
|
734
|
+
if (this._layerSelectorBody?.nativeElement) {
|
|
735
|
+
const element = this._layerSelectorBody.nativeElement;
|
|
736
|
+
this._layerSelectorBodyControl = new ol_control_Control({ element: element });
|
|
737
|
+
this.map.addControl(this._layerSelectorBodyControl);
|
|
738
|
+
}
|
|
534
739
|
}
|
|
535
740
|
_setVisibleLayersFromCache(cachedFilteredLayergroups) {
|
|
536
741
|
this.allLayerGroups.forEach(group => group.layers.forEach(layer => {
|
|
@@ -539,16 +744,13 @@ class LayerSelectorComponent {
|
|
|
539
744
|
}));
|
|
540
745
|
}
|
|
541
746
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayerSelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
542
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: LayerSelectorComponent, isStandalone: true, selector: "lib-layer-selector", inputs: { map: "map", profile: "profile", currentZoomLevel: "currentZoomLevel" }, viewQueries: [{ propertyName: "contentIcon", first: true, predicate: ["layerSelectorIcon"], descendants: true }, { propertyName: "contentBody", first: true, predicate: ["layerSelectorBody"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div #layerSelectorIcon id=\"layerSelector\" class=\"ol-unselectable ol-control layer-selector-icon\">\n <mat-icon (click)=\"toggleLayerSelector()\">layers</mat-icon>\n</div>\n<div #layerSelectorBody [class.display-none]=\"!showSelector\" class=\"layer-selector-body-wrapper\" cdkDrag cdkDragBoundary=\".map-container\">\n <div class=\"drag-handle-selector\" cdkDragHandle>\n <mat-icon>drag_indicator</mat-icon>\n </div>\n <div class=\"ol-unselectable ol-control layer-selector-body\">\n <div class=\"search-section\">\n <mat-form-field appearance=\"outline\" class=\"w-full\">\n <mat-label>Filtrer</mat-label>\n <input \n matInput \n type=\"text\" \n [(ngModel)]=\"searchText\" \n (ngModelChange)=\"filteredLayerGroups=setfilteredGroups()\"\n placeholder=\"Skriv for at filtrere...\"\n />\n </mat-form-field>\n <mat-icon (click)=\"clearSearchText()\">undo</mat-icon>\n </div>\n \n <div\n cdkDropList\n [cdkDropListData]=\"filteredLayerGroups\"\n (cdkDropListDropped)=\"dropGroup($event)\"\n class=\"item-list\">\n @for (group of filteredLayerGroups; track group.id; let gIndex = $index) {\n <div class=\"group\" cdkDrag cdkDragPreviewDisabled>\n <mat-expansion-panel [(expanded)]=\"group.expanded\">\n <mat-expansion-panel-header>\n <mat-panel-title>\n @if (group.expanded) {\n <mat-icon>arrow_upward</mat-icon>\n }\n @if (!group.expanded) {\n <mat-icon>arrow_downward</mat-icon> \n }\n {{ group.name }} \n <mat-icon class=\"lightbulb\">lightbulb</mat-icon>\n ({{ group.noOfVisibleLayers }}/{{ group.layers.length }})\n @if (group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-on\">power</mat-icon>(t\u00E6nd)\n }\n @if (!group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-off\">power_off</mat-icon>(sluk)\n }\n </mat-panel-title>\n </mat-expansion-panel-header>\n <!-- This is only shown during drag -->\n <!-- <div *cdkDragPreview class=\"drag-preview\">\n {{ group.name }}\n </div> -->\n\n <!-- Placeholder to avoid jump -->\n <!-- <div *cdkDragPlaceholder class=\"drag-placeholder\"></div> -->\n\n <div\n cdkDropList\n [cdkDropListData]=\"group.layers\"\n (cdkDropListDropped)=\"dropLayer($event, group)\"\n class=\"item-list\">\n @for (layer of group.layers; track layer.id; let iIndex = $index) {\n <mat-expansion-panel expanded=\"false\" [disabled]=\"!layer.description\"> \n <mat-expansion-panel-header>\n <mat-panel-title>\n <div class=\"item\" cdkDrag cdkDragPreviewDisabled>\n <div class=\"item-left\">\n <mat-icon class=\"drag-indicator\">drag_indicator</mat-icon>\n <span>{{ layer.name }}</span>\n </div>\n <div class=\"item-center\">\n @if (layer.maxZoom < currentZoomLevel || layer.minZoom > currentZoomLevel) {\n <mat-icon class=\"zoom-off\">browser_not_supported</mat-icon>\n <span class=\"icon-label\">(zoom)</span>\n }\n @if (layer.hasErrors) {\n <mat-icon class=\"zoom-off\">wifi_off</mat-icon>\n <span class=\"icon-label\">(fejle)</span>\n }\n </div>\n <div class=\"item-right\">\n @if (layer.visible) {\n <mat-icon (click)=\"toggleLayer($event, layer)\" class=\"power-on\">power</mat-icon>\n <span class=\"icon-label\">(t\u00E6nd)</span>\n }\n @if (!layer.visible) {\n <mat-icon (click)=\"toggleLayer($event, layer)\" class=\"power-off\">power_off</mat-icon>\n <span class=\"icon-label\">(sluk)</span>\n }\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"layer.opacity\"\n (click)=\"stopDrag($event)\"\n (input)=\"updateOpacity(layer)\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n </div>\n </div>\n </mat-panel-title>\n </mat-expansion-panel-header>\n <div class=\"item\">{{ layer.description }}</div>\n @if (showLegend) {\n <img [src]=\"legendUrl\" class=\"legend-thumbnail\"/>\n }\n </mat-expansion-panel>\n }\n </div>\n </mat-expansion-panel>\n </div>\n }\n </div>\n </div>\n</div>", styles: ["::ng-deep .layer-selector-icon{position:absolute;left:auto;right:1em;bottom:4.5em;z-index:1000}::ng-deep .layer-selector-icon mat-icon{display:flex;justify-content:center;align-items:center;cursor:pointer;transition:all .3s ease;outline:none;border:0;height:40px;border-radius:5px;width:40px;background:color-mix(in srgb,#000 60%,transparent);box-shadow:#0000004d 0 1px 4px -1px;font-size:2em;color:#fff}::ng-deep .layer-selector-icon mat-icon:hover{box-shadow:0 4px 12px #0003;color:#fff}.legend-thumbnail{max-width:200px;max-height:200px;width:auto;height:auto;border:2px solid #dee2e6;border-radius:6px;padding:6px}.layer-selector-body-wrapper{position:absolute;left:auto;right:4em;bottom:.2em;z-index:1000;cursor:grab;max-width:calc(100vw - 8em)}.layer-selector-body-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}.layer-selector-body-wrapper .ol-control{border-radius:0}@media (max-width: 767px){.layer-selector-body-wrapper{right:.5em;bottom:4em;max-width:calc(100vw - 7em);left:.5em;width:calc(100vw - 7em)}}@media (min-width: 768px) and (max-width: 1024px){.layer-selector-body-wrapper{right:1em;bottom:4em;max-width:calc(100vw - 2em)}}.drag-handle-selector{display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,#000 60%,transparent);border-radius:4px 4px 0 0;padding:4px;cursor:grab;box-shadow:0 -2px 8px #0003}.drag-handle-selector mat-icon{color:#fff;font-size:20px;width:20px;height:20px}::ng-deep .layer-selector-body{position:relative;left:auto;right:auto;bottom:auto;z-index:auto;background:color-mix(in srgb,#000 60%,transparent);box-shadow:0 4px 20px #00000026;width:480px;max-width:100%;max-height:660px;overflow:hidden;display:flex;flex-direction:column}@media (max-width: 767px){::ng-deep .layer-selector-body{width:100%;max-height:60vh}}@media (min-width: 768px) and (max-width: 1024px){::ng-deep .layer-selector-body{width:100%;max-width:480px;max-height:50vh}}::ng-deep .layer-selector-body .search-section{display:flex;align-items:center;gap:6px;padding:8px 12px 6px}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section{padding:6px 8px 4px;gap:4px}}::ng-deep .layer-selector-body .search-section mat-form-field{flex:1}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-text-field-wrapper{padding-bottom:0}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-wrapper{padding-bottom:0;margin-bottom:0}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-form-field-infix{padding-bottom:6px;min-height:auto}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-outline{background:#fff}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-outline-thick{color:#1976d2}::ng-deep .layer-selector-body .search-section mat-form-field input{font-size:13px;padding:3px 0}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-form-field input{font-size:12px}}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-label{color:#fff;font-weight:500;font-size:13px}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-label{font-size:12px}}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-form-field-subscript-wrapper{height:0;margin-top:0}::ng-deep .layer-selector-body .search-section mat-icon{color:#fff;cursor:pointer;padding:6px;border-radius:4px;transition:all .2s ease;font-size:24px;width:24px;height:24px;display:flex;justify-content:center;align-items:center}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-icon{font-size:20px;width:20px;height:20px;padding:4px}}::ng-deep .layer-selector-body .search-section mat-icon:hover{color:#f9fafb}::ng-deep .layer-selector-body .item-list{flex:1;overflow-y:auto;padding:6px;max-height:660px;width:100%}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list{padding:4px;max-height:calc(60vh - 80px)}}@media (min-width: 768px) and (max-width: 1024px){::ng-deep .layer-selector-body .item-list{max-height:calc(70vh - 80px)}}::ng-deep .layer-selector-body .item-list .group{margin-bottom:6px;overflow:hidden;box-shadow:0 -2px 2px #4868b20a,0 2px 2px #6a6f7517,0 1px 2px #4868b214}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel{box-shadow:none!important;border-radius:0!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header{padding:0 11px;height:40px;background:color-mix(in srgb,#000 55%,transparent)}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header{padding:0 20px;height:36px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header:hover{background:color-mix(in srgb,#000 60%,transparent)!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title{align-items:center;gap:6px;font-weight:600;color:#fff;font-size:13px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title{gap:4px;font-size:11px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon{color:#fff;font-size:16px;width:16px;height:16px;transition:transform .2s ease}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon{font-size:14px;width:14px;height:14px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.lightbulb{color:#dfca0e}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.power-on{color:#4caf50}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.power-off{color:#f44336}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content{background:color-mix(in srgb,#000 40%,transparent)}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content .mat-expansion-panel-body{padding:4px 0}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content .mat-expansion-panel-body{padding:2px 0}}::ng-deep .layer-selector-body .item-list .group .item-list{padding:0;max-height:none}::ng-deep .layer-selector-body .item-list .group .item-list .item{width:100%;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:6px;padding:8px 12px;background:transparent;transition:all .2s ease;color:#fff;cursor:grab}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item{gap:4px;padding:6px 8px}}::ng-deep .layer-selector-body .item-list .group .item-list .item:last-child{border-bottom:none}::ng-deep .layer-selector-body .item-list .group .item-list .item:hover{background-color:transparent;transition:all .2s ease}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left{display:flex;align-items:center;gap:3px;flex:1;min-width:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left span{flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left span{font-size:11px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center{display:flex;align-items:center;gap:2px;flex-shrink:0;justify-content:center;position:relative;left:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center .icon-label{font-size:11px;opacity:.8;margin-right:4px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center .icon-label{font-size:9px;margin-right:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right{display:flex;align-items:center;flex:1;justify-content:flex-end;min-width:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right .icon-label{font-size:11px;opacity:.8;margin-right:4px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right .icon-label{font-size:9px;margin-right:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right input[type=range]{width:80px;height:4px;margin:0;flex-shrink:0}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right input[type=range]{width:60px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon{flex-shrink:0}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.drag-indicator{color:#fff;font-size:16px;width:16px;height:16px;cursor:grab}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.drag-indicator{font-size:14px;width:14px;height:14px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on{color:#4caf50;font-size:18px;width:18px;height:18px;cursor:pointer;padding:3px;border-radius:3px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on{font-size:16px;width:16px;height:16px;padding:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on:hover{background:#4caf5033}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off{color:#f44336;font-size:18px;width:18px;height:18px;cursor:pointer;padding:3px;border-radius:3px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off{font-size:16px;width:16px;height:16px;padding:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off:hover{background:#f4433633}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.zoom-off{color:#f44336;font-size:16px;width:16px;height:16px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.zoom-off{font-size:14px;width:14px;height:14px}}::ng-deep .mat-expansion-indicator svg{fill:#fff!important}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 15px #00000026;background:#fff;padding:10px 12px}.cdk-drag-placeholder{opacity:.3}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.item-list.cdk-drop-list-dragging .item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.power-on{color:#4caf50}.power-off{color:#f44336}.display-none{display:none}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar{width:8px;border-radius:10px;border:5px solid transparent}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-thumb{background:#0000004d;border:5px solid transparent;border-radius:10px;background-clip:padding-box}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-thumb:hover{background:#0006;background-clip:padding-box;border:3px solid transparent}\n"], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i4.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i4.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i4.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i3.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i3.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i3.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }] });
|
|
747
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: LayerSelectorComponent, isStandalone: true, selector: "lib-layer-selector", inputs: { map: "map", profile: "profile", currentZoomLevel: "currentZoomLevel" }, viewQueries: [{ propertyName: "contentBody", first: true, predicate: ["layerSelectorBody"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #layerSelectorBody\n class=\"layer-selector-body-wrapper\"\n cdkDrag\n cdkDragBoundary=\".map-container\"\n [cdkDragFreeDragPosition]=\"layerSelectorDragPosition\"\n (cdkDragEnded)=\"onLayerSelectorDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n\n <div class=\"drag-handle-selector\" cdkDragHandle>\n <div class=\"drag-handle-content\">\n <div class=\"drag-handle-icons\">\n <mat-icon class=\"icon-left\">layers</mat-icon>\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleLayerSelector()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n </div>\n </div>\n\n <div class=\"ol-unselectable ol-control layer-selector-body\" *ngIf=\"!collapsed\">\n <div class=\"search-section\">\n <mat-form-field appearance=\"outline\" class=\"w-full\">\n <mat-label>Filtrer</mat-label>\n <input \n matInput \n type=\"text\" \n [(ngModel)]=\"searchText\" \n (ngModelChange)=\"filteredLayerGroups=setfilteredGroups()\"\n placeholder=\"Skriv for at filtrere...\"\n />\n </mat-form-field>\n <mat-icon (click)=\"clearSearchText()\">undo</mat-icon>\n </div>\n <div *ngIf=\"filteredLayerGroups && filteredLayerGroups.length > 0\" class=\"group-header\">Mine Temaer</div>\n <div\n cdkDropList\n [cdkDropListData]=\"filteredLayerGroups\"\n (cdkDropListDropped)=\"dropGroup($event, filteredLayerGroups)\"\n class=\"item-list\">\n @for (group of filteredLayerGroups; track group.id; let gIndex = $index) {\n <div class=\"group\" cdkDrag cdkDragPreviewDisabled>\n <mat-expansion-panel [(expanded)]=\"group.expanded\">\n <mat-expansion-panel-header>\n <mat-panel-title>\n @if (group.expanded) {\n <mat-icon>arrow_upward</mat-icon>\n }\n @if (!group.expanded) {\n <mat-icon>arrow_downward</mat-icon> \n }\n {{ group.name }} \n <mat-icon class=\"lightbulb\">lightbulb</mat-icon>\n ({{ group.noOfVisibleLayers }}/{{ group.layers.length }})\n @if (group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-on\" \n matTooltip=\"T\u00E6nd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon> \n }\n @if (!group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-off\"\n matTooltip=\"Sluk\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div\n cdkDropList\n [cdkDropListData]=\"group.layers\"\n (cdkDropListDropped)=\"dropLayer($event, group)\"\n class=\"item-list\">\n @for (layer of group.layers; track layer.id; let iIndex = $index) {\n <mat-expansion-panel expanded=\"false\" [disabled]=\"!layer.description\"> \n <mat-expansion-panel-header>\n <mat-panel-title>\n <div class=\"item\" cdkDrag cdkDragPreviewDisabled>\n <div class=\"item-left\">\n <mat-icon class=\"drag-indicator\">drag_indicator</mat-icon>\n <span>{{ layer.name }}</span>\n </div>\n <div class=\"item-center\">\n @if (layer.maxZoom < currentZoomLevel || layer.minZoom > currentZoomLevel) {\n <mat-icon class=\"zoom-off\" \n matTooltip=\"Zoom\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">browser_not_supported\n </mat-icon>\n }\n @if (layer.hasErrors) {\n <mat-icon class=\"zoom-off\" \n matTooltip=\"Fejl\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">priority_high\n </mat-icon>\n\n }\n </div>\n <div class=\"item-right\">\n @if (layer.visible) {\n <mat-icon (click)=\"toggleLayer(layer.id, $event)\" class=\"power-on\" \n matTooltip=\"T\u00E6nd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n @if (!layer.visible) {\n <mat-icon (click)=\"toggleLayer(layer.id, $event)\" class=\"power-off\"\n matTooltip=\"Sluk\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"layer.opacity\"\n (click)=\"stopDrag($event)\"\n (input)=\"updateOpacity(layer)\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n </div>\n </div>\n </mat-panel-title>\n </mat-expansion-panel-header>\n <div class=\"layer-description\">{{ layer.description }}</div>\n @if (showLegend) {\n <img [src]=\"legendUrl\" class=\"legend-thumbnail\"/>\n }\n </mat-expansion-panel>\n }\n </div>\n </mat-expansion-panel>\n </div>\n }\n </div>\n <div *ngIf=\"filteredBackgroundLayerGroups && filteredBackgroundLayerGroups.length > 0\" class=\"group-header\">Baggrundskort</div>\n <div\n cdkDropList\n [cdkDropListData]=\"filteredBackgroundLayerGroups\"\n (cdkDropListDropped)=\"dropGroup($event, filteredBackgroundLayerGroups)\"\n class=\"item-list\">\n @for (group of filteredBackgroundLayerGroups; track group.id; let gIndex = $index) {\n <div class=\"group\" cdkDrag cdkDragPreviewDisabled>\n <mat-expansion-panel [(expanded)]=\"group.expanded\">\n <mat-expansion-panel-header>\n <mat-panel-title>\n @if (group.expanded) {\n <mat-icon>arrow_upward</mat-icon>\n }\n @if (!group.expanded) {\n <mat-icon>arrow_downward</mat-icon> \n }\n {{ group.name }} \n <mat-icon class=\"lightbulb\">lightbulb</mat-icon>\n ({{ group.noOfVisibleLayers }}/{{ group.layers.length }})\n @if (group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-on\" \n matTooltip=\"T\u00E6nd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon> \n }\n @if (!group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-off\"\n matTooltip=\"Sluk\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div\n cdkDropList\n [cdkDropListData]=\"group.layers\"\n (cdkDropListDropped)=\"dropLayer($event, group)\"\n class=\"item-list\">\n @for (layer of group.layers; track layer.id; let iIndex = $index) {\n <mat-expansion-panel expanded=\"false\" [disabled]=\"!layer.description\"> \n <mat-expansion-panel-header>\n <mat-panel-title>\n <div class=\"item\" cdkDrag cdkDragPreviewDisabled>\n <div class=\"item-left\">\n <mat-icon class=\"drag-indicator\">drag_indicator</mat-icon>\n <span>{{ layer.name }}</span>\n </div>\n <div class=\"item-center\">\n @if (layer.maxZoom < currentZoomLevel || layer.minZoom > currentZoomLevel) {\n <mat-icon class=\"zoom-off\" \n matTooltip=\"Zoom\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">browser_not_supported\n </mat-icon>\n }\n @if (layer.hasErrors) {\n <mat-icon class=\"zoom-off\" \n matTooltip=\"Fejl\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">priority_high\n </mat-icon>\n\n }\n </div>\n <div class=\"item-right\">\n @if (layer.visible) {\n <mat-icon (click)=\"toggleLayer(layer.id, $event)\" class=\"power-on\" \n matTooltip=\"T\u00E6nd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n @if (!layer.visible) {\n <mat-icon (click)=\"toggleLayer(layer.id, $event)\" class=\"power-off\"\n matTooltip=\"Sluk\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"layer.opacity\"\n (click)=\"stopDrag($event)\"\n (input)=\"updateOpacity(layer)\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n </div>\n </div>\n </mat-panel-title>\n </mat-expansion-panel-header>\n <div class=\"layer-description\">{{ layer.description }}</div>\n @if (showLegend) {\n <img [src]=\"legendUrl\" class=\"legend-thumbnail\"/>\n }\n </mat-expansion-panel>\n }\n </div>\n </mat-expansion-panel>\n </div>\n }\n </div>\n </div>\n</div>", styles: [".legend-thumbnail{max-width:200px;max-height:200px;width:auto;height:auto;border:2px solid #dee2e6;border-radius:6px;padding:6px}.layer-selector-body-wrapper{position:absolute;left:1em;top:10em;z-index:1000;cursor:grab;max-width:calc(100vw - 8em);display:flex;flex-direction:column}.layer-selector-body-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}.layer-selector-body-wrapper:not(.collapsed) .drag-handle-icons{justify-content:space-between}.layer-selector-body-wrapper:not(.collapsed) .drag-handle-icons .icon-left{order:1;margin-right:auto}.layer-selector-body-wrapper:not(.collapsed) .drag-handle-icons .drag-indicator-right{order:1}.layer-selector-body-wrapper:not(.collapsed) .drag-handle-icons .toggle-icon{order:3}.layer-selector-body-wrapper.collapsed .layer-selector-body{display:none}.layer-selector-body-wrapper.collapsed .drag-handle-icons{justify-content:flex-end}.layer-selector-body-wrapper.collapsed .drag-handle-icons .icon-left{order:1;margin-right:0}.layer-selector-body-wrapper.collapsed .drag-handle-icons .drag-indicator-right{order:1}.layer-selector-body-wrapper.collapsed .drag-handle-icons .toggle-icon{order:3}.layer-selector-body-wrapper .ol-control{border-radius:0}.layer-selector-body-wrapper .group-header{color:#fff;padding:0 14px}@media (max-width: 767px){.layer-selector-body-wrapper{right:.5em;bottom:4em;max-width:calc(100vw - 7em);left:.5em;width:calc(100vw - 7em)}}@media (min-width: 768px) and (max-width: 1024px){.layer-selector-body-wrapper{right:3.5em;bottom:.5em;max-width:calc(100vw - 2em)}}.drag-handle-selector{display:flex;justify-content:flex-end;border-radius:5px 5px 0 0;padding:5px;cursor:grab;background:#292a2d}.drag-handle-content{display:flex;align-items:center;width:100%}.drag-handle-icons{display:flex;align-items:center;gap:16px;width:100%}.drag-handle-icons mat-icon{color:#fff;font-size:18px;width:18px;height:18px;cursor:pointer;transition:all .2s ease;display:flex;align-items:center;justify-content:center;flex-shrink:0}.drag-handle-icons mat-icon:first-child{cursor:grab}.drag-indicator-right{cursor:grab}.toggle-icon:hover{color:#fff;background:#ffffff26}::ng-deep .layer-selector-body{position:relative;left:auto;right:auto;bottom:auto;z-index:auto;background:#292a2d;box-shadow:0 4px 20px #00000026;width:480px;max-width:100%;max-height:317px;min-height:120px;overflow:hidden;display:flex;flex-direction:column}@media (max-width: 767px){::ng-deep .layer-selector-body{width:100%;max-height:70vh;min-height:140px}}@media (min-width: 768px) and (max-width: 1024px){::ng-deep .layer-selector-body{width:100%;max-width:445px;max-height:76vh;min-height:110px}}::ng-deep .layer-selector-body .search-section{display:flex;align-items:center;gap:6px;padding:8px 12px 6px}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section{padding:6px 8px 4px;gap:4px}}::ng-deep .layer-selector-body .search-section mat-form-field{flex:1}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-text-field-wrapper{padding-bottom:0;background:#000}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-wrapper{padding-bottom:0;margin-bottom:0}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-form-field-infix{padding-bottom:6px;min-height:auto}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-outline{background:#fff}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-outline-thick{color:#1976d2}::ng-deep .layer-selector-body .search-section mat-form-field input{font-size:13px;padding:3px 0}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-form-field input{font-size:12px}}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-label{color:#fff;font-weight:500;font-size:13px}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-label{font-size:12px}}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-form-field-subscript-wrapper{height:0;margin-top:0}::ng-deep .layer-selector-body .search-section mat-icon{color:#fff;cursor:pointer;padding:6px;border-radius:4px;transition:all .2s ease;font-size:24px;width:24px;height:24px;display:flex;justify-content:center;align-items:center}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-icon{font-size:20px;width:20px;height:20px;padding:4px}}::ng-deep .layer-selector-body .search-section mat-icon:hover{color:#f9fafb}::ng-deep .layer-selector-body .item-list{flex:1;overflow-y:auto;max-height:660px;width:100%}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list{padding:4px;max-height:calc(60vh - 80px)}}@media (min-width: 768px) and (max-width: 1024px){::ng-deep .layer-selector-body .item-list{max-height:calc(77vh - 78px)}}::ng-deep .layer-selector-body .item-list .group{overflow:hidden;box-shadow:0 -2px 2px #4868b20a,0 2px 2px #6a6f7517,0 1px 2px #4868b214}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel{box-shadow:none!important;border-radius:0!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header{padding:0 11px;height:40px;background:#000!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header:hover{background:#333!important}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header{padding:0 20px;height:36px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header:hover{background:color-mix(in srgb,#000 60%,transparent)!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title{align-items:center;gap:6px;font-weight:600;color:#bdc1c3cc;font-size:17px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title{gap:4px;font-size:11px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon{color:#bdc1c3cc;font-size:16px;width:16px;height:16px;transition:transform .2s ease}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon{font-size:14px;width:14px;height:14px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.lightbulb{color:#dfca0e}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.power-on{color:#4caf50}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.power-off{color:#f44336}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content{background:#4d4f55}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content .mat-expansion-panel-body{padding:4px 0;background:#000}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content .mat-expansion-panel-body{padding:2px 0}}::ng-deep .layer-selector-body .item-list .group .item-list{padding:0;max-height:none}::ng-deep .layer-selector-body .item-list .group .item-list .layer-description{font-size:13px;padding:0 31px;color:#fffc}::ng-deep .layer-selector-body .item-list .group .item-list .item{width:100%;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:6px;background:transparent;transition:all .2s ease;color:#fff;cursor:grab;font-size:14px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item{gap:4px;padding:6px 8px}}::ng-deep .layer-selector-body .item-list .group .item-list .item:last-child{border-bottom:none}::ng-deep .layer-selector-body .item-list .group .item-list .item:hover{background-color:transparent;transition:all .2s ease}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left{display:flex;align-items:center;gap:3px;flex:1;min-width:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left span{font-size:13px;word-wrap:break-word;word-break:break-word;overflow-wrap:break-word;white-space:normal;flex:1;min-width:0;color:#fff}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left span{font-size:11px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center{display:flex;align-items:center;gap:2px;flex-shrink:0;justify-content:center;position:relative;left:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center .icon-label{font-size:11px;opacity:.8;margin-right:4px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center .icon-label{font-size:9px;margin-right:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right{display:flex;align-items:center;flex:1;justify-content:flex-end;min-width:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right input[type=range]{width:80px;height:4px;margin:0;flex-shrink:0}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right input[type=range]{width:60px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon{flex-shrink:0}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.drag-indicator{color:#fff;font-size:16px;width:16px;height:16px;cursor:grab}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.drag-indicator{font-size:14px;width:14px;height:14px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on{color:#4caf50;font-size:18px;width:18px;height:18px;cursor:pointer;padding:3px;border-radius:3px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on{font-size:16px;width:16px;height:16px;padding:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on:hover{background:#4caf5033}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off{color:#f44336;font-size:18px;width:18px;height:18px;cursor:pointer;padding:3px;border-radius:3px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off{font-size:16px;width:16px;height:16px;padding:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off:hover{background:#f4433633}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.zoom-off{color:#f44336;font-size:16px;width:16px;height:16px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.zoom-off{font-size:14px;width:14px;height:14px}}::ng-deep .mat-expansion-indicator svg{fill:#fff!important}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 15px #00000026;background:#fff;padding:10px 12px}.cdk-drag-placeholder{opacity:.3}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.item-list.cdk-drop-list-dragging .item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.power-on{color:#4caf50}.power-off{color:#f44336}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar{width:12px}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}\n"], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i5.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i5.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i5.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i6.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i6.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i6.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
543
748
|
}
|
|
544
749
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LayerSelectorComponent, decorators: [{
|
|
545
750
|
type: Component,
|
|
546
751
|
args: [{ selector: 'lib-layer-selector', imports: [MatFormFieldModule, CommonModule, MatIconModule, FormsModule, DragDropModule,
|
|
547
|
-
MatExpansionModule, MatInputModule], template: "<div #layerSelectorIcon id=\"layerSelector\" class=\"ol-unselectable ol-control layer-selector-icon\">\n <mat-icon (click)=\"toggleLayerSelector()\">layers</mat-icon>\n</div>\n<div #layerSelectorBody [class.display-none]=\"!showSelector\" class=\"layer-selector-body-wrapper\" cdkDrag cdkDragBoundary=\".map-container\">\n <div class=\"drag-handle-selector\" cdkDragHandle>\n <mat-icon>drag_indicator</mat-icon>\n </div>\n <div class=\"ol-unselectable ol-control layer-selector-body\">\n <div class=\"search-section\">\n <mat-form-field appearance=\"outline\" class=\"w-full\">\n <mat-label>Filtrer</mat-label>\n <input \n matInput \n type=\"text\" \n [(ngModel)]=\"searchText\" \n (ngModelChange)=\"filteredLayerGroups=setfilteredGroups()\"\n placeholder=\"Skriv for at filtrere...\"\n />\n </mat-form-field>\n <mat-icon (click)=\"clearSearchText()\">undo</mat-icon>\n </div>\n \n <div\n cdkDropList\n [cdkDropListData]=\"filteredLayerGroups\"\n (cdkDropListDropped)=\"dropGroup($event)\"\n class=\"item-list\">\n @for (group of filteredLayerGroups; track group.id; let gIndex = $index) {\n <div class=\"group\" cdkDrag cdkDragPreviewDisabled>\n <mat-expansion-panel [(expanded)]=\"group.expanded\">\n <mat-expansion-panel-header>\n <mat-panel-title>\n @if (group.expanded) {\n <mat-icon>arrow_upward</mat-icon>\n }\n @if (!group.expanded) {\n <mat-icon>arrow_downward</mat-icon> \n }\n {{ group.name }} \n <mat-icon class=\"lightbulb\">lightbulb</mat-icon>\n ({{ group.noOfVisibleLayers }}/{{ group.layers.length }})\n @if (group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-on\">power</mat-icon>(t\u00E6nd)\n }\n @if (!group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-off\">power_off</mat-icon>(sluk)\n }\n </mat-panel-title>\n </mat-expansion-panel-header>\n <!-- This is only shown during drag -->\n <!-- <div *cdkDragPreview class=\"drag-preview\">\n {{ group.name }}\n </div> -->\n\n <!-- Placeholder to avoid jump -->\n <!-- <div *cdkDragPlaceholder class=\"drag-placeholder\"></div> -->\n\n <div\n cdkDropList\n [cdkDropListData]=\"group.layers\"\n (cdkDropListDropped)=\"dropLayer($event, group)\"\n class=\"item-list\">\n @for (layer of group.layers; track layer.id; let iIndex = $index) {\n <mat-expansion-panel expanded=\"false\" [disabled]=\"!layer.description\"> \n <mat-expansion-panel-header>\n <mat-panel-title>\n <div class=\"item\" cdkDrag cdkDragPreviewDisabled>\n <div class=\"item-left\">\n <mat-icon class=\"drag-indicator\">drag_indicator</mat-icon>\n <span>{{ layer.name }}</span>\n </div>\n <div class=\"item-center\">\n @if (layer.maxZoom < currentZoomLevel || layer.minZoom > currentZoomLevel) {\n <mat-icon class=\"zoom-off\">browser_not_supported</mat-icon>\n <span class=\"icon-label\">(zoom)</span>\n }\n @if (layer.hasErrors) {\n <mat-icon class=\"zoom-off\">wifi_off</mat-icon>\n <span class=\"icon-label\">(fejle)</span>\n }\n </div>\n <div class=\"item-right\">\n @if (layer.visible) {\n <mat-icon (click)=\"toggleLayer($event, layer)\" class=\"power-on\">power</mat-icon>\n <span class=\"icon-label\">(t\u00E6nd)</span>\n }\n @if (!layer.visible) {\n <mat-icon (click)=\"toggleLayer($event, layer)\" class=\"power-off\">power_off</mat-icon>\n <span class=\"icon-label\">(sluk)</span>\n }\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"layer.opacity\"\n (click)=\"stopDrag($event)\"\n (input)=\"updateOpacity(layer)\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n </div>\n </div>\n </mat-panel-title>\n </mat-expansion-panel-header>\n <div class=\"item\">{{ layer.description }}</div>\n @if (showLegend) {\n <img [src]=\"legendUrl\" class=\"legend-thumbnail\"/>\n }\n </mat-expansion-panel>\n }\n </div>\n </mat-expansion-panel>\n </div>\n }\n </div>\n </div>\n</div>", styles: ["::ng-deep .layer-selector-icon{position:absolute;left:auto;right:1em;bottom:4.5em;z-index:1000}::ng-deep .layer-selector-icon mat-icon{display:flex;justify-content:center;align-items:center;cursor:pointer;transition:all .3s ease;outline:none;border:0;height:40px;border-radius:5px;width:40px;background:color-mix(in srgb,#000 60%,transparent);box-shadow:#0000004d 0 1px 4px -1px;font-size:2em;color:#fff}::ng-deep .layer-selector-icon mat-icon:hover{box-shadow:0 4px 12px #0003;color:#fff}.legend-thumbnail{max-width:200px;max-height:200px;width:auto;height:auto;border:2px solid #dee2e6;border-radius:6px;padding:6px}.layer-selector-body-wrapper{position:absolute;left:auto;right:4em;bottom:.2em;z-index:1000;cursor:grab;max-width:calc(100vw - 8em)}.layer-selector-body-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}.layer-selector-body-wrapper .ol-control{border-radius:0}@media (max-width: 767px){.layer-selector-body-wrapper{right:.5em;bottom:4em;max-width:calc(100vw - 7em);left:.5em;width:calc(100vw - 7em)}}@media (min-width: 768px) and (max-width: 1024px){.layer-selector-body-wrapper{right:1em;bottom:4em;max-width:calc(100vw - 2em)}}.drag-handle-selector{display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,#000 60%,transparent);border-radius:4px 4px 0 0;padding:4px;cursor:grab;box-shadow:0 -2px 8px #0003}.drag-handle-selector mat-icon{color:#fff;font-size:20px;width:20px;height:20px}::ng-deep .layer-selector-body{position:relative;left:auto;right:auto;bottom:auto;z-index:auto;background:color-mix(in srgb,#000 60%,transparent);box-shadow:0 4px 20px #00000026;width:480px;max-width:100%;max-height:660px;overflow:hidden;display:flex;flex-direction:column}@media (max-width: 767px){::ng-deep .layer-selector-body{width:100%;max-height:60vh}}@media (min-width: 768px) and (max-width: 1024px){::ng-deep .layer-selector-body{width:100%;max-width:480px;max-height:50vh}}::ng-deep .layer-selector-body .search-section{display:flex;align-items:center;gap:6px;padding:8px 12px 6px}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section{padding:6px 8px 4px;gap:4px}}::ng-deep .layer-selector-body .search-section mat-form-field{flex:1}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-text-field-wrapper{padding-bottom:0}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-wrapper{padding-bottom:0;margin-bottom:0}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-form-field-infix{padding-bottom:6px;min-height:auto}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-outline{background:#fff}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-outline-thick{color:#1976d2}::ng-deep .layer-selector-body .search-section mat-form-field input{font-size:13px;padding:3px 0}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-form-field input{font-size:12px}}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-label{color:#fff;font-weight:500;font-size:13px}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-label{font-size:12px}}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-form-field-subscript-wrapper{height:0;margin-top:0}::ng-deep .layer-selector-body .search-section mat-icon{color:#fff;cursor:pointer;padding:6px;border-radius:4px;transition:all .2s ease;font-size:24px;width:24px;height:24px;display:flex;justify-content:center;align-items:center}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-icon{font-size:20px;width:20px;height:20px;padding:4px}}::ng-deep .layer-selector-body .search-section mat-icon:hover{color:#f9fafb}::ng-deep .layer-selector-body .item-list{flex:1;overflow-y:auto;padding:6px;max-height:660px;width:100%}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list{padding:4px;max-height:calc(60vh - 80px)}}@media (min-width: 768px) and (max-width: 1024px){::ng-deep .layer-selector-body .item-list{max-height:calc(70vh - 80px)}}::ng-deep .layer-selector-body .item-list .group{margin-bottom:6px;overflow:hidden;box-shadow:0 -2px 2px #4868b20a,0 2px 2px #6a6f7517,0 1px 2px #4868b214}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel{box-shadow:none!important;border-radius:0!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header{padding:0 11px;height:40px;background:color-mix(in srgb,#000 55%,transparent)}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header{padding:0 20px;height:36px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header:hover{background:color-mix(in srgb,#000 60%,transparent)!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title{align-items:center;gap:6px;font-weight:600;color:#fff;font-size:13px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title{gap:4px;font-size:11px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon{color:#fff;font-size:16px;width:16px;height:16px;transition:transform .2s ease}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon{font-size:14px;width:14px;height:14px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.lightbulb{color:#dfca0e}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.power-on{color:#4caf50}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.power-off{color:#f44336}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content{background:color-mix(in srgb,#000 40%,transparent)}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content .mat-expansion-panel-body{padding:4px 0}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content .mat-expansion-panel-body{padding:2px 0}}::ng-deep .layer-selector-body .item-list .group .item-list{padding:0;max-height:none}::ng-deep .layer-selector-body .item-list .group .item-list .item{width:100%;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:6px;padding:8px 12px;background:transparent;transition:all .2s ease;color:#fff;cursor:grab}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item{gap:4px;padding:6px 8px}}::ng-deep .layer-selector-body .item-list .group .item-list .item:last-child{border-bottom:none}::ng-deep .layer-selector-body .item-list .group .item-list .item:hover{background-color:transparent;transition:all .2s ease}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left{display:flex;align-items:center;gap:3px;flex:1;min-width:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left span{flex:1;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left span{font-size:11px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center{display:flex;align-items:center;gap:2px;flex-shrink:0;justify-content:center;position:relative;left:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center .icon-label{font-size:11px;opacity:.8;margin-right:4px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center .icon-label{font-size:9px;margin-right:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right{display:flex;align-items:center;flex:1;justify-content:flex-end;min-width:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right .icon-label{font-size:11px;opacity:.8;margin-right:4px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right .icon-label{font-size:9px;margin-right:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right input[type=range]{width:80px;height:4px;margin:0;flex-shrink:0}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right input[type=range]{width:60px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon{flex-shrink:0}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.drag-indicator{color:#fff;font-size:16px;width:16px;height:16px;cursor:grab}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.drag-indicator{font-size:14px;width:14px;height:14px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on{color:#4caf50;font-size:18px;width:18px;height:18px;cursor:pointer;padding:3px;border-radius:3px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on{font-size:16px;width:16px;height:16px;padding:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on:hover{background:#4caf5033}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off{color:#f44336;font-size:18px;width:18px;height:18px;cursor:pointer;padding:3px;border-radius:3px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off{font-size:16px;width:16px;height:16px;padding:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off:hover{background:#f4433633}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.zoom-off{color:#f44336;font-size:16px;width:16px;height:16px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.zoom-off{font-size:14px;width:14px;height:14px}}::ng-deep .mat-expansion-indicator svg{fill:#fff!important}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 15px #00000026;background:#fff;padding:10px 12px}.cdk-drag-placeholder{opacity:.3}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.item-list.cdk-drop-list-dragging .item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.power-on{color:#4caf50}.power-off{color:#f44336}.display-none{display:none}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar{width:8px;border-radius:10px;border:5px solid transparent}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-thumb{background:#0000004d;border:5px solid transparent;border-radius:10px;background-clip:padding-box}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-thumb:hover{background:#0006;background-clip:padding-box;border:3px solid transparent}\n"] }]
|
|
548
|
-
}], propDecorators: {
|
|
549
|
-
type: ViewChild,
|
|
550
|
-
args: ['layerSelectorIcon', { static: false }]
|
|
551
|
-
}], contentBody: [{
|
|
752
|
+
MatExpansionModule, MatInputModule, MatTooltipModule], template: "<div\n #layerSelectorBody\n class=\"layer-selector-body-wrapper\"\n cdkDrag\n cdkDragBoundary=\".map-container\"\n [cdkDragFreeDragPosition]=\"layerSelectorDragPosition\"\n (cdkDragEnded)=\"onLayerSelectorDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n\n <div class=\"drag-handle-selector\" cdkDragHandle>\n <div class=\"drag-handle-content\">\n <div class=\"drag-handle-icons\">\n <mat-icon class=\"icon-left\">layers</mat-icon>\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleLayerSelector()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n </div>\n </div>\n\n <div class=\"ol-unselectable ol-control layer-selector-body\" *ngIf=\"!collapsed\">\n <div class=\"search-section\">\n <mat-form-field appearance=\"outline\" class=\"w-full\">\n <mat-label>Filtrer</mat-label>\n <input \n matInput \n type=\"text\" \n [(ngModel)]=\"searchText\" \n (ngModelChange)=\"filteredLayerGroups=setfilteredGroups()\"\n placeholder=\"Skriv for at filtrere...\"\n />\n </mat-form-field>\n <mat-icon (click)=\"clearSearchText()\">undo</mat-icon>\n </div>\n <div *ngIf=\"filteredLayerGroups && filteredLayerGroups.length > 0\" class=\"group-header\">Mine Temaer</div>\n <div\n cdkDropList\n [cdkDropListData]=\"filteredLayerGroups\"\n (cdkDropListDropped)=\"dropGroup($event, filteredLayerGroups)\"\n class=\"item-list\">\n @for (group of filteredLayerGroups; track group.id; let gIndex = $index) {\n <div class=\"group\" cdkDrag cdkDragPreviewDisabled>\n <mat-expansion-panel [(expanded)]=\"group.expanded\">\n <mat-expansion-panel-header>\n <mat-panel-title>\n @if (group.expanded) {\n <mat-icon>arrow_upward</mat-icon>\n }\n @if (!group.expanded) {\n <mat-icon>arrow_downward</mat-icon> \n }\n {{ group.name }} \n <mat-icon class=\"lightbulb\">lightbulb</mat-icon>\n ({{ group.noOfVisibleLayers }}/{{ group.layers.length }})\n @if (group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-on\" \n matTooltip=\"T\u00E6nd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon> \n }\n @if (!group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-off\"\n matTooltip=\"Sluk\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div\n cdkDropList\n [cdkDropListData]=\"group.layers\"\n (cdkDropListDropped)=\"dropLayer($event, group)\"\n class=\"item-list\">\n @for (layer of group.layers; track layer.id; let iIndex = $index) {\n <mat-expansion-panel expanded=\"false\" [disabled]=\"!layer.description\"> \n <mat-expansion-panel-header>\n <mat-panel-title>\n <div class=\"item\" cdkDrag cdkDragPreviewDisabled>\n <div class=\"item-left\">\n <mat-icon class=\"drag-indicator\">drag_indicator</mat-icon>\n <span>{{ layer.name }}</span>\n </div>\n <div class=\"item-center\">\n @if (layer.maxZoom < currentZoomLevel || layer.minZoom > currentZoomLevel) {\n <mat-icon class=\"zoom-off\" \n matTooltip=\"Zoom\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">browser_not_supported\n </mat-icon>\n }\n @if (layer.hasErrors) {\n <mat-icon class=\"zoom-off\" \n matTooltip=\"Fejl\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">priority_high\n </mat-icon>\n\n }\n </div>\n <div class=\"item-right\">\n @if (layer.visible) {\n <mat-icon (click)=\"toggleLayer(layer.id, $event)\" class=\"power-on\" \n matTooltip=\"T\u00E6nd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n @if (!layer.visible) {\n <mat-icon (click)=\"toggleLayer(layer.id, $event)\" class=\"power-off\"\n matTooltip=\"Sluk\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"layer.opacity\"\n (click)=\"stopDrag($event)\"\n (input)=\"updateOpacity(layer)\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n </div>\n </div>\n </mat-panel-title>\n </mat-expansion-panel-header>\n <div class=\"layer-description\">{{ layer.description }}</div>\n @if (showLegend) {\n <img [src]=\"legendUrl\" class=\"legend-thumbnail\"/>\n }\n </mat-expansion-panel>\n }\n </div>\n </mat-expansion-panel>\n </div>\n }\n </div>\n <div *ngIf=\"filteredBackgroundLayerGroups && filteredBackgroundLayerGroups.length > 0\" class=\"group-header\">Baggrundskort</div>\n <div\n cdkDropList\n [cdkDropListData]=\"filteredBackgroundLayerGroups\"\n (cdkDropListDropped)=\"dropGroup($event, filteredBackgroundLayerGroups)\"\n class=\"item-list\">\n @for (group of filteredBackgroundLayerGroups; track group.id; let gIndex = $index) {\n <div class=\"group\" cdkDrag cdkDragPreviewDisabled>\n <mat-expansion-panel [(expanded)]=\"group.expanded\">\n <mat-expansion-panel-header>\n <mat-panel-title>\n @if (group.expanded) {\n <mat-icon>arrow_upward</mat-icon>\n }\n @if (!group.expanded) {\n <mat-icon>arrow_downward</mat-icon> \n }\n {{ group.name }} \n <mat-icon class=\"lightbulb\">lightbulb</mat-icon>\n ({{ group.noOfVisibleLayers }}/{{ group.layers.length }})\n @if (group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-on\" \n matTooltip=\"T\u00E6nd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon> \n }\n @if (!group.visible) {\n <mat-icon (click)=\"toggleGroup($event, group)\" class=\"power-off\"\n matTooltip=\"Sluk\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n </mat-panel-title>\n </mat-expansion-panel-header>\n\n <div\n cdkDropList\n [cdkDropListData]=\"group.layers\"\n (cdkDropListDropped)=\"dropLayer($event, group)\"\n class=\"item-list\">\n @for (layer of group.layers; track layer.id; let iIndex = $index) {\n <mat-expansion-panel expanded=\"false\" [disabled]=\"!layer.description\"> \n <mat-expansion-panel-header>\n <mat-panel-title>\n <div class=\"item\" cdkDrag cdkDragPreviewDisabled>\n <div class=\"item-left\">\n <mat-icon class=\"drag-indicator\">drag_indicator</mat-icon>\n <span>{{ layer.name }}</span>\n </div>\n <div class=\"item-center\">\n @if (layer.maxZoom < currentZoomLevel || layer.minZoom > currentZoomLevel) {\n <mat-icon class=\"zoom-off\" \n matTooltip=\"Zoom\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">browser_not_supported\n </mat-icon>\n }\n @if (layer.hasErrors) {\n <mat-icon class=\"zoom-off\" \n matTooltip=\"Fejl\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">priority_high\n </mat-icon>\n\n }\n </div>\n <div class=\"item-right\">\n @if (layer.visible) {\n <mat-icon (click)=\"toggleLayer(layer.id, $event)\" class=\"power-on\" \n matTooltip=\"T\u00E6nd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n @if (!layer.visible) {\n <mat-icon (click)=\"toggleLayer(layer.id, $event)\" class=\"power-off\"\n matTooltip=\"Sluk\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"above\">power_settings_new\n </mat-icon>\n }\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"layer.opacity\"\n (click)=\"stopDrag($event)\"\n (input)=\"updateOpacity(layer)\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n </div>\n </div>\n </mat-panel-title>\n </mat-expansion-panel-header>\n <div class=\"layer-description\">{{ layer.description }}</div>\n @if (showLegend) {\n <img [src]=\"legendUrl\" class=\"legend-thumbnail\"/>\n }\n </mat-expansion-panel>\n }\n </div>\n </mat-expansion-panel>\n </div>\n }\n </div>\n </div>\n</div>", styles: [".legend-thumbnail{max-width:200px;max-height:200px;width:auto;height:auto;border:2px solid #dee2e6;border-radius:6px;padding:6px}.layer-selector-body-wrapper{position:absolute;left:1em;top:10em;z-index:1000;cursor:grab;max-width:calc(100vw - 8em);display:flex;flex-direction:column}.layer-selector-body-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}.layer-selector-body-wrapper:not(.collapsed) .drag-handle-icons{justify-content:space-between}.layer-selector-body-wrapper:not(.collapsed) .drag-handle-icons .icon-left{order:1;margin-right:auto}.layer-selector-body-wrapper:not(.collapsed) .drag-handle-icons .drag-indicator-right{order:1}.layer-selector-body-wrapper:not(.collapsed) .drag-handle-icons .toggle-icon{order:3}.layer-selector-body-wrapper.collapsed .layer-selector-body{display:none}.layer-selector-body-wrapper.collapsed .drag-handle-icons{justify-content:flex-end}.layer-selector-body-wrapper.collapsed .drag-handle-icons .icon-left{order:1;margin-right:0}.layer-selector-body-wrapper.collapsed .drag-handle-icons .drag-indicator-right{order:1}.layer-selector-body-wrapper.collapsed .drag-handle-icons .toggle-icon{order:3}.layer-selector-body-wrapper .ol-control{border-radius:0}.layer-selector-body-wrapper .group-header{color:#fff;padding:0 14px}@media (max-width: 767px){.layer-selector-body-wrapper{right:.5em;bottom:4em;max-width:calc(100vw - 7em);left:.5em;width:calc(100vw - 7em)}}@media (min-width: 768px) and (max-width: 1024px){.layer-selector-body-wrapper{right:3.5em;bottom:.5em;max-width:calc(100vw - 2em)}}.drag-handle-selector{display:flex;justify-content:flex-end;border-radius:5px 5px 0 0;padding:5px;cursor:grab;background:#292a2d}.drag-handle-content{display:flex;align-items:center;width:100%}.drag-handle-icons{display:flex;align-items:center;gap:16px;width:100%}.drag-handle-icons mat-icon{color:#fff;font-size:18px;width:18px;height:18px;cursor:pointer;transition:all .2s ease;display:flex;align-items:center;justify-content:center;flex-shrink:0}.drag-handle-icons mat-icon:first-child{cursor:grab}.drag-indicator-right{cursor:grab}.toggle-icon:hover{color:#fff;background:#ffffff26}::ng-deep .layer-selector-body{position:relative;left:auto;right:auto;bottom:auto;z-index:auto;background:#292a2d;box-shadow:0 4px 20px #00000026;width:480px;max-width:100%;max-height:317px;min-height:120px;overflow:hidden;display:flex;flex-direction:column}@media (max-width: 767px){::ng-deep .layer-selector-body{width:100%;max-height:70vh;min-height:140px}}@media (min-width: 768px) and (max-width: 1024px){::ng-deep .layer-selector-body{width:100%;max-width:445px;max-height:76vh;min-height:110px}}::ng-deep .layer-selector-body .search-section{display:flex;align-items:center;gap:6px;padding:8px 12px 6px}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section{padding:6px 8px 4px;gap:4px}}::ng-deep .layer-selector-body .search-section mat-form-field{flex:1}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-text-field-wrapper{padding-bottom:0;background:#000}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-wrapper{padding-bottom:0;margin-bottom:0}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-form-field-infix{padding-bottom:6px;min-height:auto}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-outline{background:#fff}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-outline-thick{color:#1976d2}::ng-deep .layer-selector-body .search-section mat-form-field input{font-size:13px;padding:3px 0}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-form-field input{font-size:12px}}::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-label{color:#fff;font-weight:500;font-size:13px}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-form-field .mat-form-field-label{font-size:12px}}::ng-deep .layer-selector-body .search-section mat-form-field .mat-mdc-form-field-subscript-wrapper{height:0;margin-top:0}::ng-deep .layer-selector-body .search-section mat-icon{color:#fff;cursor:pointer;padding:6px;border-radius:4px;transition:all .2s ease;font-size:24px;width:24px;height:24px;display:flex;justify-content:center;align-items:center}@media (max-width: 767px){::ng-deep .layer-selector-body .search-section mat-icon{font-size:20px;width:20px;height:20px;padding:4px}}::ng-deep .layer-selector-body .search-section mat-icon:hover{color:#f9fafb}::ng-deep .layer-selector-body .item-list{flex:1;overflow-y:auto;max-height:660px;width:100%}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list{padding:4px;max-height:calc(60vh - 80px)}}@media (min-width: 768px) and (max-width: 1024px){::ng-deep .layer-selector-body .item-list{max-height:calc(77vh - 78px)}}::ng-deep .layer-selector-body .item-list .group{overflow:hidden;box-shadow:0 -2px 2px #4868b20a,0 2px 2px #6a6f7517,0 1px 2px #4868b214}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel{box-shadow:none!important;border-radius:0!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header{padding:0 11px;height:40px;background:#000!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header:hover{background:#333!important}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header{padding:0 20px;height:36px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header:hover{background:color-mix(in srgb,#000 60%,transparent)!important}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title{align-items:center;gap:6px;font-weight:600;color:#bdc1c3cc;font-size:17px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title{gap:4px;font-size:11px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon{color:#bdc1c3cc;font-size:16px;width:16px;height:16px;transition:transform .2s ease}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon{font-size:14px;width:14px;height:14px}}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.lightbulb{color:#dfca0e}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.power-on{color:#4caf50}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel mat-expansion-panel-header mat-panel-title mat-icon.power-off{color:#f44336}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content{background:#4d4f55}::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content .mat-expansion-panel-body{padding:4px 0;background:#000}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group mat-expansion-panel .mat-expansion-panel-content .mat-expansion-panel-body{padding:2px 0}}::ng-deep .layer-selector-body .item-list .group .item-list{padding:0;max-height:none}::ng-deep .layer-selector-body .item-list .group .item-list .layer-description{font-size:13px;padding:0 31px;color:#fffc}::ng-deep .layer-selector-body .item-list .group .item-list .item{width:100%;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:6px;background:transparent;transition:all .2s ease;color:#fff;cursor:grab;font-size:14px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item{gap:4px;padding:6px 8px}}::ng-deep .layer-selector-body .item-list .group .item-list .item:last-child{border-bottom:none}::ng-deep .layer-selector-body .item-list .group .item-list .item:hover{background-color:transparent;transition:all .2s ease}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left{display:flex;align-items:center;gap:3px;flex:1;min-width:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left span{font-size:13px;word-wrap:break-word;word-break:break-word;overflow-wrap:break-word;white-space:normal;flex:1;min-width:0;color:#fff}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-left span{font-size:11px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center{display:flex;align-items:center;gap:2px;flex-shrink:0;justify-content:center;position:relative;left:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center .icon-label{font-size:11px;opacity:.8;margin-right:4px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-center .icon-label{font-size:9px;margin-right:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right{display:flex;align-items:center;flex:1;justify-content:flex-end;min-width:0}::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right input[type=range]{width:80px;height:4px;margin:0;flex-shrink:0}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item .item-right input[type=range]{width:60px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon{flex-shrink:0}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.drag-indicator{color:#fff;font-size:16px;width:16px;height:16px;cursor:grab}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.drag-indicator{font-size:14px;width:14px;height:14px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on{color:#4caf50;font-size:18px;width:18px;height:18px;cursor:pointer;padding:3px;border-radius:3px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on{font-size:16px;width:16px;height:16px;padding:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-on:hover{background:#4caf5033}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off{color:#f44336;font-size:18px;width:18px;height:18px;cursor:pointer;padding:3px;border-radius:3px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off{font-size:16px;width:16px;height:16px;padding:2px}}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.power-off:hover{background:#f4433633}::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.zoom-off{color:#f44336;font-size:16px;width:16px;height:16px}@media (max-width: 767px){::ng-deep .layer-selector-body .item-list .group .item-list .item mat-icon.zoom-off{font-size:14px;width:14px;height:14px}}::ng-deep .mat-expansion-indicator svg{fill:#fff!important}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 15px #00000026;background:#fff;padding:10px 12px}.cdk-drag-placeholder{opacity:.3}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.item-list.cdk-drop-list-dragging .item:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.power-on{color:#4caf50}.power-off{color:#f44336}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar{width:12px}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .layer-selector-body .item-list::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}\n"] }]
|
|
753
|
+
}], propDecorators: { contentBody: [{
|
|
552
754
|
type: ViewChild,
|
|
553
755
|
args: ['layerSelectorBody', { static: false }]
|
|
554
756
|
}], map: [{
|
|
@@ -618,6 +820,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
618
820
|
}] });
|
|
619
821
|
|
|
620
822
|
class CurrentItemsService {
|
|
823
|
+
constructor() {
|
|
824
|
+
const dt = new Date();
|
|
825
|
+
console.log("🚀 ~ CurrentItemsService ~ constructor ~ dt:", dt);
|
|
826
|
+
}
|
|
621
827
|
_map;
|
|
622
828
|
get map() { return this._map; }
|
|
623
829
|
set map(value) {
|
|
@@ -625,25 +831,26 @@ class CurrentItemsService {
|
|
|
625
831
|
this._mapSubject.next(value);
|
|
626
832
|
}
|
|
627
833
|
profile;
|
|
628
|
-
_mapSubject = new ReplaySubject();
|
|
834
|
+
_mapSubject = new ReplaySubject(1);
|
|
629
835
|
map$ = this._mapSubject.asObservable();
|
|
836
|
+
gisKomponentSettings;
|
|
630
837
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CurrentItemsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
631
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CurrentItemsService
|
|
838
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CurrentItemsService });
|
|
632
839
|
}
|
|
633
840
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CurrentItemsService, decorators: [{
|
|
634
|
-
type: Injectable
|
|
635
|
-
|
|
636
|
-
providedIn: 'root'
|
|
637
|
-
}]
|
|
638
|
-
}] });
|
|
841
|
+
type: Injectable
|
|
842
|
+
}], ctorParameters: () => [] });
|
|
639
843
|
|
|
640
844
|
class DrawLayerSourceService {
|
|
641
845
|
_current = inject(CurrentItemsService);
|
|
642
846
|
_features = new Subject;
|
|
643
847
|
features$ = this._features.asObservable();
|
|
848
|
+
_selectedForHighlight = new Subject();
|
|
849
|
+
selectedForHighlight$ = this._selectedForHighlight.asObservable();
|
|
644
850
|
source = new VectorSource();
|
|
645
851
|
layer = new VectorLayer({
|
|
646
|
-
source: this.source
|
|
852
|
+
source: this.source,
|
|
853
|
+
zIndex: 999
|
|
647
854
|
});
|
|
648
855
|
_disabled = false;
|
|
649
856
|
constructor() {
|
|
@@ -673,6 +880,16 @@ class DrawLayerSourceService {
|
|
|
673
880
|
return newFeature;
|
|
674
881
|
});
|
|
675
882
|
}
|
|
883
|
+
get allCleanedFeatures() {
|
|
884
|
+
return this.allFeatures.map(f => {
|
|
885
|
+
f.unset('_centerpoint');
|
|
886
|
+
f.unset('_parentPolyId');
|
|
887
|
+
f.unset('LOCKED');
|
|
888
|
+
f.unset('STYLENAME');
|
|
889
|
+
f.unset('showlabelfrom');
|
|
890
|
+
return f;
|
|
891
|
+
});
|
|
892
|
+
}
|
|
676
893
|
remove(id) {
|
|
677
894
|
const feature = this.source.getFeatureById(id);
|
|
678
895
|
if (feature) {
|
|
@@ -690,25 +907,26 @@ class DrawLayerSourceService {
|
|
|
690
907
|
this._features.next(features);
|
|
691
908
|
this._disabled = false;
|
|
692
909
|
}
|
|
910
|
+
setFeaturesSelectedForHighlight(features) {
|
|
911
|
+
if (!Array.isArray(features)) {
|
|
912
|
+
this.setFeaturesSelectedForHighlight([features]);
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
this._selectedForHighlight.next(features);
|
|
916
|
+
}
|
|
693
917
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DrawLayerSourceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
694
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DrawLayerSourceService
|
|
918
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DrawLayerSourceService });
|
|
695
919
|
}
|
|
696
920
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: DrawLayerSourceService, decorators: [{
|
|
697
|
-
type: Injectable
|
|
698
|
-
args: [{
|
|
699
|
-
providedIn: 'root'
|
|
700
|
-
}]
|
|
921
|
+
type: Injectable
|
|
701
922
|
}], ctorParameters: () => [] });
|
|
702
923
|
|
|
703
924
|
class FeatureHelperService {
|
|
704
925
|
FEATURE_TYPE_ID = 'TypeId';
|
|
705
926
|
FEATURE_LOCKED = 'LOCKED';
|
|
706
|
-
_idCounter =
|
|
927
|
+
_idCounter = 1;
|
|
707
928
|
isLocked = (feature) => feature.get(this.FEATURE_LOCKED) === 'true';
|
|
708
929
|
lock(feature) { feature.set(this.FEATURE_LOCKED, 'true'); }
|
|
709
|
-
constructor() {
|
|
710
|
-
console.log('FeatureHelperService, constructor');
|
|
711
|
-
}
|
|
712
930
|
setTypeId(feature, typeId) {
|
|
713
931
|
feature.set(this.FEATURE_TYPE_ID, typeId);
|
|
714
932
|
}
|
|
@@ -724,7 +942,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
724
942
|
args: [{
|
|
725
943
|
providedIn: 'root'
|
|
726
944
|
}]
|
|
727
|
-
}]
|
|
945
|
+
}] });
|
|
728
946
|
|
|
729
947
|
class UndoRedoService {
|
|
730
948
|
_drawlayerSourceService;
|
|
@@ -786,13 +1004,10 @@ class UndoRedoService {
|
|
|
786
1004
|
this._drawlayerSourceService.setFeatures(features);
|
|
787
1005
|
}
|
|
788
1006
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: UndoRedoService, deps: [{ token: DrawLayerSourceService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
789
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: UndoRedoService
|
|
1007
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: UndoRedoService });
|
|
790
1008
|
}
|
|
791
1009
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: UndoRedoService, decorators: [{
|
|
792
|
-
type: Injectable
|
|
793
|
-
args: [{
|
|
794
|
-
providedIn: 'root'
|
|
795
|
-
}]
|
|
1010
|
+
type: Injectable
|
|
796
1011
|
}], ctorParameters: () => [{ type: DrawLayerSourceService }] });
|
|
797
1012
|
|
|
798
1013
|
class GeometrySplitService {
|
|
@@ -812,8 +1027,25 @@ class GeometrySplitService {
|
|
|
812
1027
|
const bufferedLine = buffer(lineGeoJSON, bufferMeters, { units: 'meters' });
|
|
813
1028
|
// Move back to 25832
|
|
814
1029
|
bufferedLine.geometry.coordinates = bufferedLine.geometry.coordinates.map(a => a.map(c => proj4('EPSG:4326', 'EPSG:25832', c)));
|
|
815
|
-
const overlappingFeatures = vectorSource.getFeatures().filter(f => f.getGeometry()?.intersectsExtent(lineFeature.getGeometry()?.getExtent()));
|
|
816
|
-
overlappingFeatures.
|
|
1030
|
+
const overlappingFeatures = vectorSource.getFeatures().filter(f => !this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(lineFeature.getGeometry()?.getExtent()));
|
|
1031
|
+
overlappingFeatures.filter(f => f.getGeometry()?.getType() === 'LineString').forEach(feature => {
|
|
1032
|
+
const linestringFeatureObject = this.geoJsonFormat.writeFeatureObject(feature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' });
|
|
1033
|
+
const lineFeatureObject = this.geoJsonFormat.writeFeatureObject(lineFeature, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' });
|
|
1034
|
+
if (lineIntersect(lineFeatureObject, linestringFeatureObject)) {
|
|
1035
|
+
const lines = lineSplit(linestringFeatureObject, lineFeatureObject);
|
|
1036
|
+
const newFeatures = lines.features.map(lineSplitFeature => {
|
|
1037
|
+
const newFeature = feature.clone();
|
|
1038
|
+
this._featureHelper.setId(newFeature);
|
|
1039
|
+
const newGeometry = this.geoJsonFormat.readGeometry(lineSplitFeature.geometry, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' });
|
|
1040
|
+
newFeature.setGeometry(newGeometry);
|
|
1041
|
+
return newFeature;
|
|
1042
|
+
});
|
|
1043
|
+
vectorSource.addFeatures(newFeatures);
|
|
1044
|
+
vectorSource.removeFeature(feature);
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
// Handle polygons
|
|
1048
|
+
overlappingFeatures.filter(f => f.getGeometry()?.getType() === 'Polygon').forEach((feature) => {
|
|
817
1049
|
const overlappingFeatureGeoJson = this.geoJsonFormat.writeFeatureObject(feature);
|
|
818
1050
|
const features = featureCollection([overlappingFeatureGeoJson, bufferedLine]);
|
|
819
1051
|
const clipped = difference(features);
|
|
@@ -858,61 +1090,103 @@ class ZoomService {
|
|
|
858
1090
|
});
|
|
859
1091
|
}
|
|
860
1092
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ZoomService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
861
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ZoomService
|
|
1093
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ZoomService });
|
|
862
1094
|
}
|
|
863
1095
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ZoomService, decorators: [{
|
|
864
|
-
type: Injectable
|
|
865
|
-
args: [{
|
|
866
|
-
providedIn: 'root'
|
|
867
|
-
}]
|
|
1096
|
+
type: Injectable
|
|
868
1097
|
}] });
|
|
869
1098
|
|
|
870
|
-
class
|
|
871
|
-
|
|
872
|
-
console.log('highlightservice, constructor');
|
|
873
|
-
}
|
|
1099
|
+
class HighlightService {
|
|
1100
|
+
_wktFormat = new WKT();
|
|
874
1101
|
_zoomService = inject(ZoomService);
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
width: 3
|
|
879
|
-
}),
|
|
880
|
-
fill: new Fill({
|
|
881
|
-
color: 'rgba(0, 0, 255, 0.3)'
|
|
882
|
-
}),
|
|
883
|
-
image: new Circle({
|
|
884
|
-
fill: new Fill({ color: [175, 202, 10, 1] }),
|
|
885
|
-
stroke: new Stroke({ color: [40, 112, 133, 1], width: 2 }),
|
|
886
|
-
radius: 5
|
|
887
|
-
})
|
|
888
|
-
});
|
|
1102
|
+
_current = inject(CurrentItemsService);
|
|
1103
|
+
fadeStart = '_fadeStart';
|
|
1104
|
+
fadeEnd = '_fadeEnd';
|
|
889
1105
|
_highlightSource = new Vector({ wrapX: false });
|
|
890
|
-
|
|
1106
|
+
_highlightLayer = new VectorLayer({
|
|
891
1107
|
source: this._highlightSource,
|
|
892
|
-
|
|
1108
|
+
zIndex: 999
|
|
893
1109
|
});
|
|
1110
|
+
constructor() {
|
|
1111
|
+
this._current.map$.subscribe({
|
|
1112
|
+
next: map => {
|
|
1113
|
+
map.addLayer(this._highlightLayer);
|
|
1114
|
+
}
|
|
1115
|
+
});
|
|
1116
|
+
// To make the highlight fade out, I reset the style every 20 ms
|
|
1117
|
+
interval(20).subscribe({
|
|
1118
|
+
next: () => {
|
|
1119
|
+
this._highlightSource.getFeatures().forEach(f => {
|
|
1120
|
+
const start = f.get(this.fadeStart);
|
|
1121
|
+
const end = f.get(this.fadeEnd);
|
|
1122
|
+
const now = performance.now();
|
|
1123
|
+
const t = Math.min(1, (now - start) / (end - start));
|
|
1124
|
+
// Adding and removing forces a redraw of the features
|
|
1125
|
+
if (t < 1) {
|
|
1126
|
+
const progress = 1 - easeOut(t);
|
|
1127
|
+
const newStyle = this._getFadedStyle(progress);
|
|
1128
|
+
const newFeature = f.clone();
|
|
1129
|
+
newFeature.setStyle(newStyle);
|
|
1130
|
+
this._highlightSource.addFeature(newFeature);
|
|
1131
|
+
}
|
|
1132
|
+
queueMicrotask(() => this._highlightSource.removeFeature(f));
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
894
1137
|
clear() {
|
|
895
1138
|
this._highlightSource.clear();
|
|
896
1139
|
}
|
|
897
1140
|
highlight(feature, zoomToFeatures = true) {
|
|
898
1141
|
if (!Array.isArray(feature)) {
|
|
899
|
-
this.highlight([feature]);
|
|
1142
|
+
this.highlight([this._ensureFeature(feature)]);
|
|
900
1143
|
return;
|
|
901
1144
|
}
|
|
902
|
-
|
|
903
|
-
|
|
1145
|
+
const newFeatures = feature.map(f => {
|
|
1146
|
+
const newFeature = new Feature({ geometry: f.getGeometry(), style: this._getFadedStyle(1) });
|
|
1147
|
+
const now = performance.now();
|
|
1148
|
+
newFeature.set(this.fadeStart, now);
|
|
1149
|
+
const fadeMs = this._current.gisKomponentSettings?.highlightFadeTimerMs ?? 2000;
|
|
1150
|
+
newFeature.set(this.fadeEnd, now + fadeMs); // set the style to fade (and be removed) to two seconds
|
|
1151
|
+
return newFeature;
|
|
1152
|
+
});
|
|
1153
|
+
this._highlightSource.addFeatures(newFeatures);
|
|
904
1154
|
if (zoomToFeatures) {
|
|
905
1155
|
this._zoomService.zoomToFeatures(feature);
|
|
906
1156
|
}
|
|
907
1157
|
}
|
|
908
|
-
|
|
909
|
-
|
|
1158
|
+
_ensureFeature(feature) {
|
|
1159
|
+
if (typeof feature === 'string') {
|
|
1160
|
+
const newFeature = this._wktFormat.readFeature(feature, { dataProjection: 'EPSG:25832', featureProjection: 'EPSG:25832' });
|
|
1161
|
+
return newFeature;
|
|
1162
|
+
}
|
|
1163
|
+
else {
|
|
1164
|
+
return feature;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
_getFadedStyle(fade) {
|
|
1168
|
+
const newStyle = new Style({
|
|
1169
|
+
stroke: new Stroke({
|
|
1170
|
+
color: [0, 255, 255, fade],
|
|
1171
|
+
width: 3
|
|
1172
|
+
}),
|
|
1173
|
+
fill: new Fill({
|
|
1174
|
+
//color: 'rgba(0, 0, 255, 0.3)'
|
|
1175
|
+
color: [0, 0, 255, fade]
|
|
1176
|
+
}),
|
|
1177
|
+
image: new Circle({
|
|
1178
|
+
fill: new Fill({ color: [175, 202, 10, fade] }),
|
|
1179
|
+
stroke: new Stroke({ color: [40, 112, 133, fade], width: 2 }),
|
|
1180
|
+
radius: 5
|
|
1181
|
+
})
|
|
1182
|
+
});
|
|
1183
|
+
return newStyle;
|
|
1184
|
+
}
|
|
1185
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HighlightService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1186
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HighlightService });
|
|
910
1187
|
}
|
|
911
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type:
|
|
912
|
-
type: Injectable
|
|
913
|
-
args: [{
|
|
914
|
-
providedIn: 'root'
|
|
915
|
-
}]
|
|
1188
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HighlightService, decorators: [{
|
|
1189
|
+
type: Injectable
|
|
916
1190
|
}], ctorParameters: () => [] });
|
|
917
1191
|
|
|
918
1192
|
class InteractionHelperService {
|
|
@@ -932,13 +1206,10 @@ class InteractionHelperService {
|
|
|
932
1206
|
});
|
|
933
1207
|
}
|
|
934
1208
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InteractionHelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
935
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InteractionHelperService
|
|
1209
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InteractionHelperService });
|
|
936
1210
|
}
|
|
937
1211
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InteractionHelperService, decorators: [{
|
|
938
|
-
type: Injectable
|
|
939
|
-
args: [{
|
|
940
|
-
providedIn: 'root'
|
|
941
|
-
}]
|
|
1212
|
+
type: Injectable
|
|
942
1213
|
}] });
|
|
943
1214
|
|
|
944
1215
|
class MergeFeaturesService {
|
|
@@ -950,6 +1221,9 @@ class MergeFeaturesService {
|
|
|
950
1221
|
formatter = new GeoJSON();
|
|
951
1222
|
_formatterOptions = { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' };
|
|
952
1223
|
_selectFilter(f, typeId) {
|
|
1224
|
+
if (this._featureHelper.isLocked(f)) {
|
|
1225
|
+
return false;
|
|
1226
|
+
}
|
|
953
1227
|
if (this._selectedMergeFeature) {
|
|
954
1228
|
const previusFeatureObject = this.formatter.writeFeatureObject(this._selectedMergeFeature, this._formatterOptions);
|
|
955
1229
|
const bufferedPreviouslySelected = buffer(previusFeatureObject, 5, { units: 'centimeters' });
|
|
@@ -994,13 +1268,10 @@ class MergeFeaturesService {
|
|
|
994
1268
|
});
|
|
995
1269
|
}
|
|
996
1270
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MergeFeaturesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
997
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MergeFeaturesService
|
|
1271
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MergeFeaturesService });
|
|
998
1272
|
}
|
|
999
1273
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MergeFeaturesService, decorators: [{
|
|
1000
|
-
type: Injectable
|
|
1001
|
-
args: [{
|
|
1002
|
-
providedIn: 'root'
|
|
1003
|
-
}]
|
|
1274
|
+
type: Injectable
|
|
1004
1275
|
}] });
|
|
1005
1276
|
|
|
1006
1277
|
class IconsConstants {
|
|
@@ -1019,30 +1290,20 @@ class IconsConstants {
|
|
|
1019
1290
|
static lineStringIconBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAA1BJREFUSEutVmtIk2EYXb/EWBDZ7UdQP6L+WZkQEfVDCNR/gWAQqCAKQhJJUSK0KV7nZdbWdLk5pyjeFbcpzsuWSzfRTQfS5ty8X0rNOW0OiTh970cbbqYu5+Dd923wnfOe5znveb5TjL+fysrKWIfDwXK5XFd3d3dPu///n2tQUNBOcHDwHJPJ5CclJQk8z1ZVVcmLioqgVqthNBphs9mOtcizBEMoFJJlpgkqKiriBALBsQA/G+eQ2rKOiE+b+GqZ9sKQSqUQiUSlDC6XO6vRaPwm0E3MIqtzFTdKnQjhbCFeYkKUeAIZ8jUvjJGREXA4HDuDzWb/MplMhxKQ3RV0f0eEyIGQfAceS80QDfRCbWyhF7knhL6lZbFYYJCvg2peplrBk2o7mDkbiJJMI7tL6wF1g7uvd/jLqB1c8sL6J4FsZAFPa+04l7eNh/xFvO0YhdLQfiCwm4CQE4V7N7uP4CbXietcB9LaDWgdVhwJulcF2cR5zjZIj9wk+wgYbPgN2mtsRbWuD2WaAYgGVegZa6MbTlx1IgQyvQzPOhcQLt3E/fJvKJB8RPOQDBc5To9lA1KgMMiQLLPg3vtFhL/WIvHVS/SMNtB9I+YgKgIiICUpUXYjJrsS0WkFyOZloc/QhNK+AYQLtgIn8LXp3t/EKMSNASmQUyWKU8zRPXgknkdJnRD9Y020SRIkRsTX/wiMoMMgR2znMm619CMscwXJ6eno1TegXttFu+lB+ebJEVxhLyIyhY3bpbO0i5Ib1kGCMKASEQWR7esIbVbhMmsJ9xOLIVXPHH6S/Tlo1V+UiKmx4kLhFsLqdhHaogJRkJqeB9/Q9FsBiQ0SH8Qd14p3kCFbQ/f4PBKU21QPjiCg4vq3xWKhpfkqeKcYpg8OCT4SgMR67hjQT874R0CNylWdTuchEKhUdN4zM9cQLd7wnErfSDeYZ5CitONu7QZVIiqD3uR4lYiMz9zcXCeDmp0fampqaIIzOVsI5f2kJ9aYybthvgSTUzbIhifxnNOM2BeFyMkvgtls9iiUSCTg8/lqei7zeDx7Y2PjviYdNfynpqwwGMah1eqg1+thtVppDAJOjWJXW1vbWc+bhVgslpPxSTofyCIY1EvEEDXwLxHwP1I4uvOad9ZNAAAAAElFTkSuQmCC';
|
|
1020
1291
|
static printBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAxBJREFUeNqslctrJFUUxn+3Xv2o6q6uHjs9rWjC6CIiAQMtAV0JYhYuRFy4ExcJwb/CletBMgxITIib+QcmuBhEXEQN6mQhOEPbY3AIjGmTVPUz/arKdZFJd6e7egxtvk3VPbfu99W557vnCp5iY2Pjo0ql8lmz2Zxut9txJkAkEjmJxWKPLcu6tby8fBtAAGxubm4dHR29l8/ncRwHy7Im4ader+N5HoVCAaCwsrIyK9bW1j7udrtfLy4ucpXY3t6m2+1+ofi+//nCwgJXjfn5eRqNxieKruu5eDx+5QKmaeK6rq0BqmEYvQmv1qDkVScivZ5OkrLMCzFtcHBYrvLl3W+RwbOJpJQACCEukgmVpfffJpNKhgv89fchMoBXXnuDROoaJ7UKhd9+6s036zVqZZduuw1INN3AtG3MZBohwJcB+wdH4wUGfhHkKVKe9kLV40Nq1Spy+i1kdg4Ule7xIyp/fke72SR9/XkEAjmcVRj/owe/Xhi3ThrUqmVO8yvIzCxRDVQFGs4NRO51Wj/epO55JJz0CJd2meI1Kh4yl4fMLPNZhRcSClJCpS3ZeZIlePld6n9skXCckbXKZQQ6rRZyavYsGx/u7QV8s+dTakg0RULmVU4DnyAYdYd27ohn4XxbJfDwuF+Xonf23tv1EColTHUYeiSK+Ofh+A8OH6BqGqqmjgoMezn0VNoO4sl9ROn3kA53gFK8h2U7g7n0t0hR/rsM0bhJIuVQ2/0K+eKbPZtyXETsfU8sqmPa6dC12mUyAEimn0OPRKmX7tN5/MPZQTMMLMfBtO1+vYZqesGmM7kMmlDxx/SKmGkRMy2kBIHsV/+cTBVM5zLjBTKpJJ9++A4H7mTNLnfNxjbjIwIyCAKhqmcOSMSipF7qd8QgCFBVtfccFxsHpdVqua7r9gLDC87Hg/GwWNj1mUwmm4qu63eKxeKVXzi7u7tEIpGfBcDq6qqXzWZTc3NzDF4+k6DT6bCzs0O5XG7NzMzkejZYX1/f2t/fX5RSav9HQAjhT01N/WIYxgdLS0ulfwcAKTQlaNRcuW0AAAAASUVORK5CYII=';
|
|
1021
1292
|
static drawBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAilJREFUSImt1UlsTXEUx/FPJyFNTEHQEE2R1FzRRpSILSsrFlaEjSWJhQUrC7GzEjVUY1gQImJadEHEEBIRFWNoqVjowlAxhFqc/0uf29e+tvpLXu5993/u93/O/wyXoWs0ZqT7eSgfBqNfTcUD/MBZ/MHmkYLPwWtcwRP0oBt1OIPa/4EvxAc0Y3aC38Fb/BIRLcKU4cDr0YUjKEUJ1os8vEibPcMB/EbNUOAr8CnBSzJrDSKqDenag1MpkobBwFfhM5oKwPO1JcG70IZvuFwMvhpfcbQInPB2tzi2HlFZa7BXlHRBeDdOiDPP13zsQWOB956jXeTje/rNyhqtTJ6fzsDX4n6eh9MLbLBMlOzzZHcwa1AvEnrev925Du+xXJzt7QLwnLbhC1pTBFW5hXn4iGsYlYmoHQtSROewfYANYGJyojXHmpAg91CZZ1iHV1iS4M24mnEgq3JcEONkbO5hjTjXTXmGC/A0bVKGk2L2DAQvTXZtmJRdPIw3KZrFeCwapkzMmZZ0359KREm/VLgAVOIhbiUPapNHLTiub7lm4U1iEM4cwM5OMVuq86I6VgRemuAdee8V1EaR5Nw03K9vL2RVJqLrVGTAzcYjjE//d4mkH9L/mKgQuekU34kBVYW7IsE7RP0uxTsxLrKfxDG4lOBzi8FzahQVcFFvL1SLnFwXzQPjcGOwng9Gk3FTJHGrqLCOkYLnVIF9+CminDWS8HxN01sIg9Zflop8Ez+7Xi0AAAAASUVORK5CYII=';
|
|
1293
|
+
static featureSearchIconBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAA59JREFUSEullm9MU1cYxi+fCNolRhQ+jkSjCRoTk0Y+NDMEMLEmbiMRNXMRTYDSCWE4smCMtPUPuoZYsjbFri0FUYONDqIwIm6jShw0ZULR9rYNLeg2zUTFoigJMc/ue/BWKi0U1+TJbU/vfX7nPe97z3uSuHefxsbGPeFwWDU9Pf2poGXieFJSEgdA/LngNTk5+XVKSsoDiURiKC4uNkZubmpq6qirq4PD4YDb7UYwGPwo0bPkYTKZSD4GMJvN+41G40cZ3nI/QPnVp8j56QW8gVCUR3NzMywWSz2n0+nGent7Ewb03x/D8V+eYF39FFK1kyi08ZBb7+Nox3iUh8vlglarneA0Gs0Mz/MLAmh2P9z4FzmWMFLPhLGt2QfL7V/hcF9lou8E/HBpVSoVOLVaHde8oecx8s9PQHLqOeS2EE529UVMRXPxutnwCBfv/BPlFRNw3fUX9l6cwMrTL/GZ4W9UXxtA9932uMYigOAU4dwo5gHW66awVhfG4fa7+NnZuajp3ChoEqu0L0E5EiHzAJwa80y7B+w4UaeBUqmEorQUikMV76Usg0KhYP+dPHsChY1eVlVRAKKIA7EANMsiRQlCYw+ZgqPRGhXG/hz24OvKKtjvXEOadipSsiyCRAD7lJW40vU7yo4ch+J7dZQqa2rRfvMW8ovL0D1wmeWNioMmnTAg0QgIUP/bbUiNk0sD7D/03aIR0BIRgJaUCoWqMeEICOAPhuD2+DHo4aM07A3AOXiP5UAEHLC5Udj6bAmA8uqYEZRU1UDMwVcVh3HD1YrWvi62fcjOvVgaIFYV5eXlIXt7NnJ25WJjbi4yVQ6sPjOJkstPQRth4ksUJwICpF1Pw4ZjG5D1RRa27v4SnV0d8Pv9S0yyAIgXAQG4cQ7L3cshPSiFLF+GBlMDvF7vbARzN7t4L9qebypi5kCMgAAkgmWqMpEtz4bT6YwA3gYCARbSh4CaTid7cQ4UlcSsormA9PZ0rDm7hi2VWqOGx+OZBQit8kl/f38EYOzpYfu9RDOOHdbn7K3UN5hQVPotisqroiQCMswZ2LJvC6Q7pTCZTcx8aGgItbW1U5zQO39saWlhgE9OTWKT/hXrWIP8KBsbGRkBz/vA++aLALICGbI+z4K8QI4Lly7AJ9wXCoVgs9lgMBgcrC/r9foJu90uGC3c2RY7DFD1UHKFQwSEVvymra1tReRkYbVaO4SEz9C6/R+Rh3CI+ENo+Olk/h8veXXcPn9a8AAAAABJRU5ErkJggg==';
|
|
1294
|
+
static zoomIconBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO1JREFUeNqsk+ERwiAMhdtOwAiOwAg4gYzACI7gJp4ToBPoBu0GukG7gYZeehcjgZxt7t4fCB8JvLSNHA5kQQY0gQbQo/kjAugJemeU1o9aUKokCiCuO+YXI2YOBWw9CPvFNpfEESHSu44kV2yfvpmrdOLYm/6E1bZB4iwV0LGFixJ4YxV/AelvvZTASdromo2jY+4/KM/RvCFnaGoZoxgAah1T+7W+ADXohCU3am9N/vIsx+NlfAyDBLUMSiuuzXYRWgP0wsUztBXAHn9yxzyaDH1FM+emar/GciFT5WmtjznUbTEcDiubYR8BBgD2fnjD/AKVHwAAAABJRU5ErkJggg==';
|
|
1295
|
+
static cutIconBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gYDDB8MtOM2YAAAAdBJREFUSMfl1T2MTFEUB/DfjOcjviq7DRsRRCKiY+kVmleKwkchKgmrZWhEVqFhswqVRLIFiShOfBSi0C2xUSgVxGKzIxIJdmVHRnMneXmZtxijcpp33jnn/v/3no97+cdS62VRnuftsi0ian0hKIC/xzRWYGcVSb1H8DFsx14cwFTVyeo9ZGgatzGHDG9xpiq4F4IPeIcF/EAb+/pJsAuBw9iGdRjpSw0KADswiocpRcv6eYKT6bsBQ31t0zzPB9BIKRmMiGae57uxCQOpFpciYvK3CfI8X5XUlQmos3gYe3C1EN5Ohb+GRkR8zRYB3pgKebEiZLKgz+IxnuBKSuMzTGQV4Edws2SeT1MrFbaT/1c4iudo4TXu4SAmaiXg9WmQivIZH3ELZ5OtERGjaXK/YDO+4Xvyz2EGQ/VFwGdxB1sjYktENJL9DR4V4lbjFJZgKcaT/gnLswrwkYgYq7iHXhZbM9kbiaSNtcn9IiLms8L90pFjEXGjBH45qTO4EBFPu5CsSaZmRAx2/OUin+sC/gD70++JIvivhqxMMFxeXLp+D0XE3T8d+6zbDkrATRzH/b9+Mrs8GKdxHa2IaPVCkBXA62m3UzifumDBfy8/ARhwrGEODAGpAAAAAElFTkSuQmCC';
|
|
1296
|
+
static copyIconBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gYDDCItkmJugAAAAHBJREFUSMftlEEOgDAIBIvp93jtPtCevBhT10m10bjXEmAWSilvV7iBmbk6cZICdeIUOIqppJCk2CfDnQ8lOEuyvWMC2uXlGTg+/wTzCVzV3nfvJXSLYwKXBhO4Wu4+18gi93QPX9MpFj0/A+zvZ9UAaFN03sNpI7gAAAAASUVORK5CYII=';
|
|
1297
|
+
static copyWithBufferBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gYDDCQhzY6FLQAAAIJJREFUSMftVW0KwCAIreH1PK0HrF9BuOVHErIxIQqrl74nVsrbrXIHIjYiqisfIjYL8Dh/A9IuPQVgCVJ8ZPaN9TzPw5OlOQDpDOwASXsafduRujPggnGwVVX9GbgzuE63CogCaBSFNdA4B2vTMovHLF8Db5kea2ppFOVqEPo4PmMdpg1975VbWTEAAAAASUVORK5CYII=';
|
|
1022
1298
|
}
|
|
1023
1299
|
|
|
1024
1300
|
class PrintDrawLayerSourceService {
|
|
1025
1301
|
_current = inject(CurrentItemsService);
|
|
1026
|
-
// private _features = new Subject<Feature[]>;
|
|
1027
|
-
// features$ = this._features.asObservable();
|
|
1028
1302
|
source = new VectorSource();
|
|
1029
1303
|
layer = new VectorLayer({
|
|
1030
1304
|
source: this.source,
|
|
1031
|
-
|
|
1032
|
-
stroke: new Stroke({
|
|
1033
|
-
color: 'blue',
|
|
1034
|
-
width: 2
|
|
1035
|
-
}),
|
|
1036
|
-
text: new Text({
|
|
1037
|
-
text: 'MySpecialText',
|
|
1038
|
-
font: '12px Calibri,sans-serif',
|
|
1039
|
-
fill: new Fill({ color: '#000' }),
|
|
1040
|
-
stroke: new Stroke({ color: '#fff', width: 3 }),
|
|
1041
|
-
placement: 'line'
|
|
1042
|
-
})
|
|
1043
|
-
})
|
|
1305
|
+
zIndex: 999
|
|
1044
1306
|
});
|
|
1045
|
-
// private _disabled = false;
|
|
1046
1307
|
constructor() {
|
|
1047
1308
|
this.layer.set('PRINTDRAWLAYER', 'true');
|
|
1048
1309
|
this._initListener();
|
|
@@ -1050,25 +1311,594 @@ class PrintDrawLayerSourceService {
|
|
|
1050
1311
|
_initListener() {
|
|
1051
1312
|
this._current.map$.subscribe({
|
|
1052
1313
|
next: map => {
|
|
1053
|
-
console.log("🚀 ~ PrintDrawLayerSourceService ~ _initListener ~ map:", map);
|
|
1054
1314
|
map.addLayer(this.layer);
|
|
1055
1315
|
}
|
|
1056
1316
|
});
|
|
1057
|
-
// this.source.on(['addfeature', 'changefeature', 'removefeature'], evt => {
|
|
1058
|
-
// if (this._disabled) { return; }
|
|
1059
|
-
// const features = this.source.getFeatures();
|
|
1060
|
-
// this._features.next(features);
|
|
1061
|
-
// });
|
|
1062
1317
|
}
|
|
1063
1318
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PrintDrawLayerSourceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1064
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PrintDrawLayerSourceService
|
|
1319
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PrintDrawLayerSourceService });
|
|
1065
1320
|
}
|
|
1066
1321
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PrintDrawLayerSourceService, decorators: [{
|
|
1322
|
+
type: Injectable
|
|
1323
|
+
}], ctorParameters: () => [] });
|
|
1324
|
+
|
|
1325
|
+
class CenterPointService {
|
|
1326
|
+
_centerPointProperty = '_centerpoint';
|
|
1327
|
+
_settingsHelper = inject(KomponentSettingsHelperService);
|
|
1328
|
+
_current = inject(CurrentItemsService);
|
|
1329
|
+
_drawLayerService = inject(DrawLayerSourceService);
|
|
1330
|
+
_interactionHelper = inject(InteractionHelperService);
|
|
1331
|
+
_geoJson = new GeoJSON();
|
|
1332
|
+
_snackbar = inject(MatSnackBar);
|
|
1333
|
+
_featureHelper = inject(FeatureHelperService);
|
|
1334
|
+
handleFeatureDeleted(featureId) {
|
|
1335
|
+
const centerFeature = this._drawLayerService.source.getFeatures().find(f => f.get('_parentPolyId') == featureId);
|
|
1336
|
+
if (centerFeature) {
|
|
1337
|
+
this._drawLayerService.remove(centerFeature.getId());
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
isCenterpoint(feature) {
|
|
1341
|
+
return feature.get(this._centerPointProperty) === true;
|
|
1342
|
+
}
|
|
1343
|
+
setCenterPoint(style, withinPolygon, callBack) {
|
|
1344
|
+
const style$ = this._settingsHelper.getStyle(style, this._current.profile.styleRepositoryWorkspace, this._current.profile.styleRepositoryGeoserver, 'Point');
|
|
1345
|
+
combineLatest([style$, this._current.map$]).subscribe({
|
|
1346
|
+
next: ([loadedStyle, map]) => {
|
|
1347
|
+
let parentPolyId;
|
|
1348
|
+
const centerDraw = new Draw({
|
|
1349
|
+
type: 'Point',
|
|
1350
|
+
source: this._drawLayerService.source,
|
|
1351
|
+
condition: evt => {
|
|
1352
|
+
if (!withinPolygon) {
|
|
1353
|
+
return true;
|
|
1354
|
+
}
|
|
1355
|
+
// The center needs to be inside a feature, so since turf is great for figuring out if something is in something, move the click and features to EPSG:4326
|
|
1356
|
+
const lonlat = transform(evt.coordinate, 'EPSG:25832', 'EPSG:4326');
|
|
1357
|
+
const pt = point(lonlat);
|
|
1358
|
+
const polygons = this._drawLayerService.source.getFeatures().filter(f => f.getGeometry() && f.getGeometry().getType() === 'Polygon'); // No point in checking linestrings and points
|
|
1359
|
+
const features = this._geoJson.writeFeaturesObject(polygons, { dataProjection: 'EPSG:4326', featureProjection: 'EPSG:25832' });
|
|
1360
|
+
const parentPoly = features.features.find(f => booleanPointInPolygon(pt, f));
|
|
1361
|
+
if (!parentPoly) {
|
|
1362
|
+
this._snackbar.open('Centerpunktet skal være inde i en flade', '', { duration: 3000 });
|
|
1363
|
+
return false;
|
|
1364
|
+
}
|
|
1365
|
+
// Save the parent polygon's id on the center. If the parent is deleted, the point will be deleted too
|
|
1366
|
+
parentPolyId = parentPoly.id;
|
|
1367
|
+
return !!parentPoly;
|
|
1368
|
+
},
|
|
1369
|
+
style: loadedStyle
|
|
1370
|
+
});
|
|
1371
|
+
this._interactionHelper.setAsTemp(centerDraw);
|
|
1372
|
+
map.addInteraction(centerDraw);
|
|
1373
|
+
centerDraw.on('drawend', evt => {
|
|
1374
|
+
const existing = this._drawLayerService.source.getFeatures().filter(f => f.get(this._centerPointProperty) === true);
|
|
1375
|
+
// There can only be ONE centerpoint, so remove previous if exists
|
|
1376
|
+
if (existing) {
|
|
1377
|
+
this._drawLayerService.source.removeFeatures(existing);
|
|
1378
|
+
}
|
|
1379
|
+
// Mark feature as centerpoint - this is to find it again an remove
|
|
1380
|
+
evt.feature.set(this._centerPointProperty, true);
|
|
1381
|
+
evt.feature.set('_parentPolyId', parentPolyId);
|
|
1382
|
+
this._featureHelper.setId(evt.feature);
|
|
1383
|
+
callBack();
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CenterPointService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1389
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CenterPointService });
|
|
1390
|
+
}
|
|
1391
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: CenterPointService, decorators: [{
|
|
1392
|
+
type: Injectable
|
|
1393
|
+
}] });
|
|
1394
|
+
|
|
1395
|
+
class ConfirmDialogComponent {
|
|
1396
|
+
dialogRef;
|
|
1397
|
+
data;
|
|
1398
|
+
constructor(dialogRef, data) {
|
|
1399
|
+
this.dialogRef = dialogRef;
|
|
1400
|
+
this.data = data;
|
|
1401
|
+
}
|
|
1402
|
+
choose(choice) {
|
|
1403
|
+
this.dialogRef.close(choice);
|
|
1404
|
+
}
|
|
1405
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ConfirmDialogComponent, deps: [{ token: i1$3.MatDialogRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
|
|
1406
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: ConfirmDialogComponent, isStandalone: true, selector: "app-confirm-dialog", ngImport: i0, template: "\n@if(data.title) {\n <h2 mat-dialog-title>{{ data.title }}</h2>\n}\n<mat-dialog-content>\n <p>{{ data.message }}</p>\n</mat-dialog-content>\n\n<mat-dialog-actions align=\"end\">\n <!-- Sekund\u00E6r handling -->\n <button mat-button (click)=\"choose('secondary')\">\n {{ data.secondaryText }}\n </button>\n\n <!-- Prim\u00E6r handling -->\n <button mat-raised-button color=\"primary\" (click)=\"choose('primary')\">\n {{ data.primaryText }}\n </button>\n</mat-dialog-actions>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1$3.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$3.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$3.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }] });
|
|
1407
|
+
}
|
|
1408
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ConfirmDialogComponent, decorators: [{
|
|
1409
|
+
type: Component,
|
|
1410
|
+
args: [{ selector: 'app-confirm-dialog', imports: [CommonModule, MatDialogModule, MatButtonModule, MatDialogTitle, MatDialogContent, MatDialogActions], template: "\n@if(data.title) {\n <h2 mat-dialog-title>{{ data.title }}</h2>\n}\n<mat-dialog-content>\n <p>{{ data.message }}</p>\n</mat-dialog-content>\n\n<mat-dialog-actions align=\"end\">\n <!-- Sekund\u00E6r handling -->\n <button mat-button (click)=\"choose('secondary')\">\n {{ data.secondaryText }}\n </button>\n\n <!-- Prim\u00E6r handling -->\n <button mat-raised-button color=\"primary\" (click)=\"choose('primary')\">\n {{ data.primaryText }}\n </button>\n</mat-dialog-actions>\n" }]
|
|
1411
|
+
}], ctorParameters: () => [{ type: i1$3.MatDialogRef }, { type: undefined, decorators: [{
|
|
1412
|
+
type: Inject,
|
|
1413
|
+
args: [MAT_DIALOG_DATA]
|
|
1414
|
+
}] }] });
|
|
1415
|
+
|
|
1416
|
+
class ConfirmDialogService {
|
|
1417
|
+
dialog;
|
|
1418
|
+
constructor(dialog) {
|
|
1419
|
+
this.dialog = dialog;
|
|
1420
|
+
}
|
|
1421
|
+
open(data) {
|
|
1422
|
+
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
|
1423
|
+
width: '400px',
|
|
1424
|
+
disableClose: !!data.disableClose,
|
|
1425
|
+
data
|
|
1426
|
+
});
|
|
1427
|
+
return dialogRef.afterClosed();
|
|
1428
|
+
}
|
|
1429
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ConfirmDialogService, deps: [{ token: i1$3.MatDialog }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1430
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ConfirmDialogService, providedIn: 'root' });
|
|
1431
|
+
}
|
|
1432
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ConfirmDialogService, decorators: [{
|
|
1433
|
+
type: Injectable,
|
|
1434
|
+
args: [{ providedIn: 'root' }]
|
|
1435
|
+
}], ctorParameters: () => [{ type: i1$3.MatDialog }] });
|
|
1436
|
+
|
|
1437
|
+
class OverlapService {
|
|
1438
|
+
_drawLayerService = inject(DrawLayerSourceService);
|
|
1439
|
+
_featureHelper = inject(FeatureHelperService);
|
|
1440
|
+
_snackbar = inject(MatSnackBar);
|
|
1441
|
+
_confirmService = inject(ConfirmDialogService);
|
|
1442
|
+
_geoJsonFormat = new GeoJSON();
|
|
1443
|
+
EPSILON = 0.1;
|
|
1444
|
+
handleOverlaps(features) {
|
|
1445
|
+
let newClippedFeature = null;
|
|
1446
|
+
let unlockedFeaturesAsGeoJson = [];
|
|
1447
|
+
let lockedClipped = false;
|
|
1448
|
+
let anyOverlappingLockedFeatures = false;
|
|
1449
|
+
features.forEach(feature => {
|
|
1450
|
+
// Handle the locked.
|
|
1451
|
+
const overlappingLockedFeatures = this._drawLayerService.source.getFeatures().filter(f => this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(feature.getGeometry().getExtent()));
|
|
1452
|
+
const clipped = this._handleLockedFeaturesOverlapping(overlappingLockedFeatures, feature);
|
|
1453
|
+
if (!lockedClipped && clipped) {
|
|
1454
|
+
lockedClipped = clipped;
|
|
1455
|
+
}
|
|
1456
|
+
//Handle the unlocked.
|
|
1457
|
+
const overlappingUnlockedFeatures = this._drawLayerService.source.getFeatures().filter(f => !this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(feature.getGeometry().getExtent()));
|
|
1458
|
+
if (overlappingUnlockedFeatures.length > 0) {
|
|
1459
|
+
anyOverlappingLockedFeatures = true;
|
|
1460
|
+
let newFeatureGeoJson = this._geoJsonFormat.writeFeatureObject(feature);
|
|
1461
|
+
const newFeatureArea = area(newFeatureGeoJson);
|
|
1462
|
+
unlockedFeaturesAsGeoJson = overlappingUnlockedFeatures.map(f => this._geoJsonFormat.writeFeatureObject(f));
|
|
1463
|
+
// If null the whole new feature is inside a the existing
|
|
1464
|
+
newClippedFeature = difference(featureCollection([newFeatureGeoJson, ...unlockedFeaturesAsGeoJson]));
|
|
1465
|
+
// if the new feature is completely inside one of the existing features, newClippedFeature will be null
|
|
1466
|
+
const areaNewClippedFeature = newClippedFeature ? area(newClippedFeature) : 1;
|
|
1467
|
+
if (Math.abs(newFeatureArea - areaNewClippedFeature) < this.EPSILON) {
|
|
1468
|
+
anyOverlappingLockedFeatures = false;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
});
|
|
1472
|
+
if (lockedClipped) {
|
|
1473
|
+
this._snackbar.open("Der var overlap med låste flader, så den indtegnede flade er blevet beskåret", '', { duration: 3000 });
|
|
1474
|
+
}
|
|
1475
|
+
if (anyOverlappingLockedFeatures) {
|
|
1476
|
+
return this._confirmService.open({
|
|
1477
|
+
primaryText: 'Nye',
|
|
1478
|
+
secondaryText: 'Eksisterende',
|
|
1479
|
+
disableClose: true,
|
|
1480
|
+
message: 'Den nye flade overlapper med eksisterende flade. Ønsker du at beskære de nye eller de eksisterende?',
|
|
1481
|
+
title: 'Beskæring'
|
|
1482
|
+
}).pipe(map(msg => {
|
|
1483
|
+
return this._handleUnlockedFeaturesOverlapping(features, msg);
|
|
1484
|
+
}));
|
|
1485
|
+
}
|
|
1486
|
+
else {
|
|
1487
|
+
return of(features);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
_handleUnlockedFeaturesOverlapping(features, msg) {
|
|
1491
|
+
features.forEach(feature => {
|
|
1492
|
+
const overlappingUnlockedFeatures = this._drawLayerService.source.getFeatures().filter(f => !this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(feature.getGeometry().getExtent()));
|
|
1493
|
+
if (overlappingUnlockedFeatures.length > 0) {
|
|
1494
|
+
let newFeatureGeoJson = this._geoJsonFormat.writeFeatureObject(feature);
|
|
1495
|
+
const unlockedFeaturesAsGeoJson = overlappingUnlockedFeatures.map(f => this._geoJsonFormat.writeFeatureObject(f));
|
|
1496
|
+
const newClippedFeature = difference(featureCollection([newFeatureGeoJson, ...unlockedFeaturesAsGeoJson]));
|
|
1497
|
+
if (msg === 'primary') {
|
|
1498
|
+
if (newClippedFeature) {
|
|
1499
|
+
const newGeometry = this._geoJsonFormat.readGeometry(newClippedFeature.geometry);
|
|
1500
|
+
feature.setGeometry(newGeometry);
|
|
1501
|
+
}
|
|
1502
|
+
else {
|
|
1503
|
+
feature.setGeometry(undefined);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
else {
|
|
1507
|
+
unlockedFeaturesAsGeoJson.forEach(f => {
|
|
1508
|
+
const featureArea = area(f.geometry);
|
|
1509
|
+
const fc = featureCollection([f, newFeatureGeoJson]);
|
|
1510
|
+
const featureDiff = difference(fc);
|
|
1511
|
+
if (featureDiff !== null) {
|
|
1512
|
+
const featureDiffArea = area(featureDiff.geometry);
|
|
1513
|
+
if (Math.abs(featureArea - featureDiffArea) > this.EPSILON) {
|
|
1514
|
+
const existingFeature = this._drawLayerService.source.getFeatureById(f.id);
|
|
1515
|
+
if (existingFeature) {
|
|
1516
|
+
const newGeometry = this._geoJsonFormat.readGeometry(featureDiff?.geometry);
|
|
1517
|
+
existingFeature.setGeometry(newGeometry);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1525
|
+
features = features.filter(feature => feature.getGeometry() !== undefined);
|
|
1526
|
+
return features;
|
|
1527
|
+
}
|
|
1528
|
+
handleOverlap(feature) {
|
|
1529
|
+
// Handle the locked.
|
|
1530
|
+
const overlappingLockedFeatures = this._drawLayerService.source.getFeatures().filter(f => this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(feature.getGeometry().getExtent()));
|
|
1531
|
+
const clipped = this._handleLockedFeaturesOverlapping(overlappingLockedFeatures, feature);
|
|
1532
|
+
if (clipped) {
|
|
1533
|
+
this._snackbar.open("Der var overlap med låste flader, så den indtegnede flade er blevet beskåret", '', { duration: 3000 });
|
|
1534
|
+
}
|
|
1535
|
+
// Handle the unlocked.
|
|
1536
|
+
const overlappingUnlockedFeatures = this._drawLayerService.source.getFeatures().filter(f => !this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(feature.getGeometry().getExtent()));
|
|
1537
|
+
if (overlappingUnlockedFeatures.length === 0) {
|
|
1538
|
+
return of(feature);
|
|
1539
|
+
}
|
|
1540
|
+
else {
|
|
1541
|
+
let newFeatureGeoJson = this._geoJsonFormat.writeFeatureObject(feature);
|
|
1542
|
+
const newFeatureArea = area(newFeatureGeoJson);
|
|
1543
|
+
const unlockedFeaturesAsGeoJson = overlappingUnlockedFeatures.map(f => this._geoJsonFormat.writeFeatureObject(f));
|
|
1544
|
+
const newClippedFeature = difference(featureCollection([newFeatureGeoJson, ...unlockedFeaturesAsGeoJson]));
|
|
1545
|
+
// if the new feature is completely inside one of the existing features, newClippedFeature will be null
|
|
1546
|
+
const areaNewClippedFeature = newClippedFeature ? area(newClippedFeature) : 1;
|
|
1547
|
+
if (Math.abs(newFeatureArea - areaNewClippedFeature) < this.EPSILON) {
|
|
1548
|
+
return of(feature);
|
|
1549
|
+
}
|
|
1550
|
+
else {
|
|
1551
|
+
return this._confirmService.open({
|
|
1552
|
+
primaryText: 'Nye',
|
|
1553
|
+
secondaryText: 'Eksisterende',
|
|
1554
|
+
disableClose: true,
|
|
1555
|
+
message: 'Den nye flade overlapper med eksisterende flade. Ønsker du at beskære de nye eller de eksisterende?',
|
|
1556
|
+
title: 'Beskæring'
|
|
1557
|
+
}).pipe(map(msg => {
|
|
1558
|
+
if (msg === 'primary') {
|
|
1559
|
+
const newGeometry = this._geoJsonFormat.readGeometry(newClippedFeature.geometry);
|
|
1560
|
+
feature.setGeometry(newGeometry);
|
|
1561
|
+
return feature;
|
|
1562
|
+
}
|
|
1563
|
+
else {
|
|
1564
|
+
unlockedFeaturesAsGeoJson.forEach(f => {
|
|
1565
|
+
const featureArea = area(f.geometry);
|
|
1566
|
+
const fc = featureCollection([f, newFeatureGeoJson]);
|
|
1567
|
+
const featureDiff = difference(fc);
|
|
1568
|
+
const featureDiffArea = area(featureDiff.geometry);
|
|
1569
|
+
if (Math.abs(featureArea - featureDiffArea) > this.EPSILON) {
|
|
1570
|
+
const existingFeature = this._drawLayerService.source.getFeatureById(f.id);
|
|
1571
|
+
if (existingFeature) {
|
|
1572
|
+
const newGeometry = this._geoJsonFormat.readGeometry(featureDiff?.geometry);
|
|
1573
|
+
existingFeature.setGeometry(newGeometry);
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
});
|
|
1577
|
+
return feature;
|
|
1578
|
+
}
|
|
1579
|
+
}));
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
_handleLockedFeaturesOverlapping(overlappingFeatures, orgFeature) {
|
|
1584
|
+
let newFeatureGeoJson = this._geoJsonFormat.writeFeatureObject(orgFeature);
|
|
1585
|
+
const orgFeatureArea = area(newFeatureGeoJson);
|
|
1586
|
+
if (overlappingFeatures.length > 0) {
|
|
1587
|
+
const overlappingLockedFeaturesAsGeoJson = overlappingFeatures.map(f => this._geoJsonFormat.writeFeatureObject(f));
|
|
1588
|
+
const features = featureCollection([newFeatureGeoJson, ...overlappingLockedFeaturesAsGeoJson]);
|
|
1589
|
+
const clipped = difference(features);
|
|
1590
|
+
if (clipped) {
|
|
1591
|
+
const clippedArea = area(clipped.geometry);
|
|
1592
|
+
// The overlap is done by checking extent. To make sure there's an actual change, I check if the areas are diffent
|
|
1593
|
+
// but sometimes, the calculations of the same area can be a bit of. Like 0.01. To make sure that doesn't register as a change
|
|
1594
|
+
// I check that there's actually a change.
|
|
1595
|
+
const actuallyClipped = Math.abs(orgFeatureArea - clippedArea) > this.EPSILON;
|
|
1596
|
+
if (actuallyClipped) {
|
|
1597
|
+
const geom = this._geoJsonFormat.readGeometry(clipped.geometry);
|
|
1598
|
+
orgFeature.setGeometry(geom);
|
|
1599
|
+
return true;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
return false;
|
|
1604
|
+
}
|
|
1605
|
+
splitByFeature(cutterFeature, remove = false) {
|
|
1606
|
+
let result = [];
|
|
1607
|
+
const cutterGeo = this._olToGeoJSON(cutterFeature.getGeometry());
|
|
1608
|
+
const cutter = feature(cutterGeo);
|
|
1609
|
+
const overlappingFeatures = this._drawLayerService.source.getFeatures().filter(f => f.getGeometry()?.intersectsExtent(cutterFeature.getGeometry().getExtent()));
|
|
1610
|
+
overlappingFeatures.forEach(feature$1 => {
|
|
1611
|
+
const geom = feature$1.getGeometry();
|
|
1612
|
+
if (!geom)
|
|
1613
|
+
return;
|
|
1614
|
+
const geo = this._olToGeoJSON(geom);
|
|
1615
|
+
const aTurfFeature = feature(geo);
|
|
1616
|
+
if (!booleanIntersects(aTurfFeature, cutter)) {
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1619
|
+
// Feature is fully inside the cutter, so remove the whole feature
|
|
1620
|
+
if (remove && booleanWithin(aTurfFeature, cutter)) {
|
|
1621
|
+
this._drawLayerService.source.removeFeature(feature$1);
|
|
1622
|
+
return;
|
|
1623
|
+
}
|
|
1624
|
+
// Outside part(s)
|
|
1625
|
+
const fc = featureCollection([aTurfFeature, cutter]);
|
|
1626
|
+
const diff = difference(fc);
|
|
1627
|
+
// Inside part(s)
|
|
1628
|
+
const inter = intersect(fc);
|
|
1629
|
+
// Add outside part(s)
|
|
1630
|
+
if (diff)
|
|
1631
|
+
result = result.concat(this._addTurfToResult(diff));
|
|
1632
|
+
// Add inside part(s)
|
|
1633
|
+
if (!remove && inter)
|
|
1634
|
+
result = result.concat(this._addTurfToResult(inter));
|
|
1635
|
+
// Remove the original overlapping feature (it was split into diff + inter)
|
|
1636
|
+
if (result.length > 0)
|
|
1637
|
+
this._drawLayerService.source.removeFeature(feature$1);
|
|
1638
|
+
});
|
|
1639
|
+
return of(result);
|
|
1640
|
+
}
|
|
1641
|
+
_addTurfToResult(aTurfFeature) {
|
|
1642
|
+
const result = [];
|
|
1643
|
+
if (aTurfFeature.geometry.type === 'MultiPolygon') {
|
|
1644
|
+
aTurfFeature.geometry.coordinates.forEach((coords) => {
|
|
1645
|
+
result.push(new Feature(this._geoJSONToOl({
|
|
1646
|
+
type: 'Polygon',
|
|
1647
|
+
coordinates: coords
|
|
1648
|
+
})));
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
else {
|
|
1652
|
+
result.push(new Feature(this._geoJSONToOl(aTurfFeature.geometry)));
|
|
1653
|
+
}
|
|
1654
|
+
return result;
|
|
1655
|
+
}
|
|
1656
|
+
_olToGeoJSON(geometry) {
|
|
1657
|
+
const geoJson = new GeoJSON();
|
|
1658
|
+
return geoJson.writeGeometryObject(geometry.clone().transform('EPSG:25832', 'EPSG:4326'));
|
|
1659
|
+
}
|
|
1660
|
+
_geoJSONToOl(geo) {
|
|
1661
|
+
const geoJson = new GeoJSON();
|
|
1662
|
+
return geoJson.readGeometry(geo).transform('EPSG:4326', 'EPSG:25832');
|
|
1663
|
+
}
|
|
1664
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: OverlapService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1665
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: OverlapService });
|
|
1666
|
+
}
|
|
1667
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: OverlapService, decorators: [{
|
|
1668
|
+
type: Injectable
|
|
1669
|
+
}] });
|
|
1670
|
+
|
|
1671
|
+
class SearchProviderBase {
|
|
1672
|
+
_http = inject(HttpClient);
|
|
1673
|
+
wfsFormat = new WFS();
|
|
1674
|
+
_serializer = new XMLSerializer();
|
|
1675
|
+
search(searchValue, maxCount) {
|
|
1676
|
+
const wftSearches = [];
|
|
1677
|
+
const searchLayers = this.getSearchableLayers();
|
|
1678
|
+
searchLayers.forEach(layer => {
|
|
1679
|
+
const filter = this.getFilter(searchValue, layer); // like(layer.searchField!, `*${searchValue}*`, '*', '?', '/', false);
|
|
1680
|
+
var searchFeature = this.wfsFormat.writeGetFeature({
|
|
1681
|
+
featureTypes: [layer.layers.includes(':') ? layer.layers.split(':')[1] : ''],
|
|
1682
|
+
outputFormat: 'application/json',
|
|
1683
|
+
featureNS: '',
|
|
1684
|
+
featurePrefix: '',
|
|
1685
|
+
srsName: 'EPSG:25832',
|
|
1686
|
+
maxFeatures: maxCount,
|
|
1687
|
+
filter
|
|
1688
|
+
});
|
|
1689
|
+
wftSearches.push(this._http.post(layer.baseUrl.replace('wms', 'wfs'), this._serializer.serializeToString(searchFeature), { headers: { 'Content-Type': 'text/xml' }, responseType: 'json' }).pipe(map(r => {
|
|
1690
|
+
const result = this.map(layer, r);
|
|
1691
|
+
return result;
|
|
1692
|
+
})));
|
|
1693
|
+
});
|
|
1694
|
+
return combineLatest(wftSearches);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
class InfoSearchProvider extends SearchProviderBase {
|
|
1698
|
+
_current = inject(CurrentItemsService);
|
|
1699
|
+
getSearchableLayers() {
|
|
1700
|
+
return this._current.profile.layerGroups.flatMap(lg => lg.layers).filter(f => f.enableShowInfo);
|
|
1701
|
+
}
|
|
1702
|
+
getFilter(searchValue, layer) {
|
|
1703
|
+
const point = new Point(searchValue);
|
|
1704
|
+
return intersects(layer.geometryField, point);
|
|
1705
|
+
}
|
|
1706
|
+
map(layer, f) {
|
|
1707
|
+
const fieldsToExclude = new Set(layer.fieldsToExcludeFromInfoFromInfo.split(',').map(f => f.toLowerCase().trim()));
|
|
1708
|
+
return {
|
|
1709
|
+
layerName: layer.name,
|
|
1710
|
+
values: f.features.map(f => this._mapFeature(f, fieldsToExclude))
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
_mapFeature(f, excludeSet) {
|
|
1714
|
+
const result = {};
|
|
1715
|
+
const props = f.properties || {};
|
|
1716
|
+
for (const [key, value] of Object.entries(props)) {
|
|
1717
|
+
if (excludeSet.has(key.toLowerCase()))
|
|
1718
|
+
continue;
|
|
1719
|
+
const kind = this._getValueKind(value);
|
|
1720
|
+
result[key] = { kind, data: value, name: key };
|
|
1721
|
+
}
|
|
1722
|
+
return result;
|
|
1723
|
+
}
|
|
1724
|
+
_getValueKind(value) {
|
|
1725
|
+
const imgTypes = ['.png', '.jpg', '.gif', '.jpeg'];
|
|
1726
|
+
if (typeof value === 'string') {
|
|
1727
|
+
if (value.startsWith('http://') || value.startsWith('https://')) {
|
|
1728
|
+
if (imgTypes.some(ext => value.endsWith(ext))) {
|
|
1729
|
+
return 'img';
|
|
1730
|
+
}
|
|
1731
|
+
return 'url';
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
return 'data';
|
|
1735
|
+
}
|
|
1736
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InfoSearchProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
1737
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InfoSearchProvider });
|
|
1738
|
+
}
|
|
1739
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: InfoSearchProvider, decorators: [{
|
|
1740
|
+
type: Injectable
|
|
1741
|
+
}] });
|
|
1742
|
+
|
|
1743
|
+
class ShowInfoService {
|
|
1744
|
+
_current = inject(CurrentItemsService);
|
|
1745
|
+
_listenKey = null;
|
|
1746
|
+
_active = false;
|
|
1747
|
+
_infoSearchProvider = inject(InfoSearchProvider);
|
|
1748
|
+
_features = new Subject();
|
|
1749
|
+
features$ = this._features.asObservable();
|
|
1750
|
+
stopShowInfo() {
|
|
1751
|
+
this._features.next(null);
|
|
1752
|
+
}
|
|
1753
|
+
startShowInfo() {
|
|
1754
|
+
if (this._active) {
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
this._active = true;
|
|
1758
|
+
this._current.map$.subscribe({
|
|
1759
|
+
next: map => {
|
|
1760
|
+
this._listenKey = this._listenKey ?? map.on('singleclick', evt => {
|
|
1761
|
+
this.disable();
|
|
1762
|
+
this._infoSearchProvider.search(evt.coordinate, 5).subscribe({
|
|
1763
|
+
next: r => {
|
|
1764
|
+
if (r.flatMap(l => l.values).length > 0) {
|
|
1765
|
+
this._features.next(r);
|
|
1766
|
+
}
|
|
1767
|
+
else {
|
|
1768
|
+
this._features.next(null);
|
|
1769
|
+
}
|
|
1770
|
+
this.disable();
|
|
1771
|
+
},
|
|
1772
|
+
error: err => {
|
|
1773
|
+
this.disable();
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
});
|
|
1777
|
+
}
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
disable() {
|
|
1781
|
+
if (!this._active) {
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
if (this._listenKey) {
|
|
1785
|
+
unByKey(this._listenKey);
|
|
1786
|
+
this._listenKey = null;
|
|
1787
|
+
}
|
|
1788
|
+
this._active = false;
|
|
1789
|
+
}
|
|
1790
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ShowInfoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1791
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ShowInfoService });
|
|
1792
|
+
}
|
|
1793
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ShowInfoService, decorators: [{
|
|
1794
|
+
type: Injectable
|
|
1795
|
+
}] });
|
|
1796
|
+
|
|
1797
|
+
class GeometryService {
|
|
1798
|
+
config = inject(GISKOMPONENT_CONFIG);
|
|
1799
|
+
_baseUrl = this.config.apiBaseUrl;
|
|
1800
|
+
_http = inject(HttpClient);
|
|
1801
|
+
validate(wkt) {
|
|
1802
|
+
const url = `${this._baseUrl}/api/geometry/validate`;
|
|
1803
|
+
return this._http.post(url, { wkt: wkt });
|
|
1804
|
+
}
|
|
1805
|
+
dmpValidate(wkt) {
|
|
1806
|
+
const url = `${this._baseUrl}/api/geometry/dmpvalidate`;
|
|
1807
|
+
return this._http.post(url, { wkt: wkt });
|
|
1808
|
+
}
|
|
1809
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GeometryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1810
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GeometryService, providedIn: 'root' });
|
|
1811
|
+
}
|
|
1812
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GeometryService, decorators: [{
|
|
1067
1813
|
type: Injectable,
|
|
1068
1814
|
args: [{
|
|
1069
1815
|
providedIn: 'root'
|
|
1070
1816
|
}]
|
|
1071
|
-
}]
|
|
1817
|
+
}] });
|
|
1818
|
+
|
|
1819
|
+
class PrintHelperService {
|
|
1820
|
+
setVisibiltyOnDOMElements(baseElement, visible) {
|
|
1821
|
+
const elements = ['activeobjects', '.ol-zoom', 'map-toolbox', '.ol-mouse-position', '.layer-selector-body-wrapper'];
|
|
1822
|
+
this._setVisibiltyOnDOMElements(baseElement, elements, visible);
|
|
1823
|
+
}
|
|
1824
|
+
getImgData(map, printFormat, printDimensions) {
|
|
1825
|
+
const htmlElement = map.getViewport();
|
|
1826
|
+
this.setVisibiltyOnDOMElements(htmlElement, false);
|
|
1827
|
+
return new Promise((resolve, reject) => {
|
|
1828
|
+
html2canvas(htmlElement, {
|
|
1829
|
+
useCORS: true,
|
|
1830
|
+
}).then(originalCanvas => {
|
|
1831
|
+
if (printDimensions) {
|
|
1832
|
+
const srcW = originalCanvas.width;
|
|
1833
|
+
const srcH = originalCanvas.height;
|
|
1834
|
+
const scale = Math.min(printDimensions[0] / srcW, printDimensions[1] / srcH);
|
|
1835
|
+
const outW = Math.round(srcW * scale);
|
|
1836
|
+
const outH = Math.round(srcH * scale);
|
|
1837
|
+
// 3) Lav nyt canvas til nedskalering
|
|
1838
|
+
const scaledCanvas = document.createElement('canvas');
|
|
1839
|
+
scaledCanvas.width = outW;
|
|
1840
|
+
scaledCanvas.height = outH;
|
|
1841
|
+
const ctx = scaledCanvas.getContext('2d');
|
|
1842
|
+
ctx.imageSmoothingEnabled = true;
|
|
1843
|
+
ctx.imageSmoothingQuality = 'high';
|
|
1844
|
+
ctx.drawImage(originalCanvas, 0, 0, outW, outH);
|
|
1845
|
+
const dataUrl = scaledCanvas.toDataURL(printFormat);
|
|
1846
|
+
resolve(dataUrl);
|
|
1847
|
+
}
|
|
1848
|
+
else {
|
|
1849
|
+
const imgData = originalCanvas.toDataURL(printFormat);
|
|
1850
|
+
resolve(imgData);
|
|
1851
|
+
}
|
|
1852
|
+
});
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
_setVisibiltyOnDOMElements(baseElement, elements, visible) {
|
|
1856
|
+
let visibilityValue = 'hidden';
|
|
1857
|
+
if (visible) {
|
|
1858
|
+
visibilityValue = 'visible';
|
|
1859
|
+
}
|
|
1860
|
+
elements.forEach(e => {
|
|
1861
|
+
const activeobjects = baseElement.querySelector(e);
|
|
1862
|
+
if (activeobjects) {
|
|
1863
|
+
activeobjects.style.visibility = visibilityValue;
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PrintHelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1868
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PrintHelperService, providedIn: 'root' });
|
|
1869
|
+
}
|
|
1870
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: PrintHelperService, decorators: [{
|
|
1871
|
+
type: Injectable,
|
|
1872
|
+
args: [{
|
|
1873
|
+
providedIn: 'root'
|
|
1874
|
+
}]
|
|
1875
|
+
}] });
|
|
1876
|
+
|
|
1877
|
+
class SearchProviderService {
|
|
1878
|
+
_cancelSearch = new Subject();
|
|
1879
|
+
maxSearchResults = 8;
|
|
1880
|
+
searchProviders = [];
|
|
1881
|
+
search(searchString, geometry) {
|
|
1882
|
+
this._cancelSearch.next('');
|
|
1883
|
+
let combinedSearch = new Observable();
|
|
1884
|
+
this.searchProviders.forEach(searchProvider => {
|
|
1885
|
+
const search = searchProvider
|
|
1886
|
+
.search(searchString, geometry, this.maxSearchResults)
|
|
1887
|
+
.pipe(takeUntil(this._cancelSearch.asObservable()))
|
|
1888
|
+
.pipe(take(this.maxSearchResults));
|
|
1889
|
+
combinedSearch = combinedSearch ? combinedSearch.pipe(mergeWith(search)) : search;
|
|
1890
|
+
});
|
|
1891
|
+
return combinedSearch;
|
|
1892
|
+
}
|
|
1893
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SearchProviderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1894
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SearchProviderService, providedIn: 'root' });
|
|
1895
|
+
}
|
|
1896
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SearchProviderService, decorators: [{
|
|
1897
|
+
type: Injectable,
|
|
1898
|
+
args: [{
|
|
1899
|
+
providedIn: 'root'
|
|
1900
|
+
}]
|
|
1901
|
+
}] });
|
|
1072
1902
|
|
|
1073
1903
|
class ToolboxComponent {
|
|
1074
1904
|
// Inputs
|
|
@@ -1088,13 +1918,23 @@ class ToolboxComponent {
|
|
|
1088
1918
|
_featureHelper = inject(FeatureHelperService);
|
|
1089
1919
|
_undoRedo = inject(UndoRedoService);
|
|
1090
1920
|
_geomSplitService = inject(GeometrySplitService);
|
|
1091
|
-
_highlight = inject(
|
|
1921
|
+
_highlight = inject(HighlightService);
|
|
1092
1922
|
_interactionHelper = inject(InteractionHelperService);
|
|
1093
1923
|
_mergeService = inject(MergeFeaturesService);
|
|
1924
|
+
_centerPointService = inject(CenterPointService);
|
|
1925
|
+
_overlap = inject(OverlapService);
|
|
1926
|
+
_zoomService = inject(ZoomService);
|
|
1927
|
+
_showInfo = inject(ShowInfoService);
|
|
1928
|
+
_geometryService = inject(GeometryService);
|
|
1929
|
+
_printHelper = inject(PrintHelperService);
|
|
1930
|
+
_layoutService = inject(LayoutService);
|
|
1931
|
+
_searchService = inject(SearchProviderService);
|
|
1094
1932
|
_POSITION_STORAGE_KEY = 'toolbox_position';
|
|
1095
|
-
_current = inject(CurrentItemsService);
|
|
1933
|
+
// private _current = inject(CurrentItemsService);
|
|
1096
1934
|
_originalMapWidth = 0;
|
|
1097
1935
|
_originalMapHeight = 0;
|
|
1936
|
+
pointClickKey;
|
|
1937
|
+
drawInteraction;
|
|
1098
1938
|
mapWidth = 0;
|
|
1099
1939
|
mapHeight = 0;
|
|
1100
1940
|
format = "image/png";
|
|
@@ -1106,7 +1946,10 @@ class ToolboxComponent {
|
|
|
1106
1946
|
[800, 600]
|
|
1107
1947
|
];
|
|
1108
1948
|
printDrawLabel = "";
|
|
1109
|
-
|
|
1949
|
+
bufferInMeters = 0;
|
|
1950
|
+
printDrawTool = "Point";
|
|
1951
|
+
filteredResults = [];
|
|
1952
|
+
filteredResultsMetadata = [];
|
|
1110
1953
|
selectedGeometrySetting = undefined;
|
|
1111
1954
|
undoIconBase64 = IconsConstants.undoIconBase64;
|
|
1112
1955
|
redoIconBase64 = IconsConstants.redoIconBase64;
|
|
@@ -1119,6 +1962,11 @@ class ToolboxComponent {
|
|
|
1119
1962
|
removePointsIconBase64 = IconsConstants.removePointsIconBase64;
|
|
1120
1963
|
wktIconBase64 = IconsConstants.wktIconBase64;
|
|
1121
1964
|
pointIconBase64 = IconsConstants.pointIconBase64;
|
|
1965
|
+
featureSearchIconBase64 = IconsConstants.featureSearchIconBase64;
|
|
1966
|
+
objectSearchCopyIconBase64 = IconsConstants.copyIconBase64;
|
|
1967
|
+
objectSearchCopyWithBufferIconBase64 = IconsConstants.copyWithBufferBase64;
|
|
1968
|
+
objectSearchCutIconBase64 = IconsConstants.cutIconBase64;
|
|
1969
|
+
objectSearchZoomIconBase64 = IconsConstants.zoomIconBase64;
|
|
1122
1970
|
polygonIconBase64 = IconsConstants.polygonIconBase64;
|
|
1123
1971
|
lineStringIconBase64 = IconsConstants.lineStringIconBase64;
|
|
1124
1972
|
printBase64 = IconsConstants.printBase64;
|
|
@@ -1126,6 +1974,8 @@ class ToolboxComponent {
|
|
|
1126
1974
|
dragPosition = { x: 0, y: 0 };
|
|
1127
1975
|
snap = false;
|
|
1128
1976
|
showInputWKT = false;
|
|
1977
|
+
showGeometryTypes = false;
|
|
1978
|
+
filteredGeometryTypeSettings = [];
|
|
1129
1979
|
WKTString;
|
|
1130
1980
|
activeMode = null;
|
|
1131
1981
|
activateShowInputWKT() {
|
|
@@ -1136,8 +1986,186 @@ class ToolboxComponent {
|
|
|
1136
1986
|
this._clearAllInteractions();
|
|
1137
1987
|
this.showInputWKT = false;
|
|
1138
1988
|
}
|
|
1989
|
+
toggleFeatureSearch() {
|
|
1990
|
+
if (this.activeMode != 'search-feature') {
|
|
1991
|
+
this._clearAllInteractions();
|
|
1992
|
+
this.activeMode = 'search-feature';
|
|
1993
|
+
this.showGeometryTypes = true;
|
|
1994
|
+
this._updateFilteredGeometryTypeSettings('Polygon');
|
|
1995
|
+
this._enablePointSearch();
|
|
1996
|
+
}
|
|
1997
|
+
else {
|
|
1998
|
+
this.activeMode = null;
|
|
1999
|
+
this.showGeometryTypes = false;
|
|
2000
|
+
this._disablePointSearch();
|
|
2001
|
+
this.filteredResults = [];
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
togglePointSearch() {
|
|
2005
|
+
if (this.activeMode != 'search-point') {
|
|
2006
|
+
this._clearAllInteractions();
|
|
2007
|
+
this._disablePolygonSearch();
|
|
2008
|
+
this.activeMode = 'search-point';
|
|
2009
|
+
this._enablePointSearch();
|
|
2010
|
+
}
|
|
2011
|
+
else {
|
|
2012
|
+
this.activeMode = null;
|
|
2013
|
+
this._disablePointSearch();
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
togglePolygonSearch() {
|
|
2017
|
+
this._disablePointSearch();
|
|
2018
|
+
if (this.activeMode != 'search-polygon') {
|
|
2019
|
+
this.activeMode = 'search-polygon';
|
|
2020
|
+
this.drawInteraction = new Draw({
|
|
2021
|
+
source: new VectorSource(),
|
|
2022
|
+
type: 'Polygon'
|
|
2023
|
+
});
|
|
2024
|
+
this.map.addInteraction(this.drawInteraction);
|
|
2025
|
+
this.drawInteraction.on('drawend', (evt) => {
|
|
2026
|
+
this._searchService.search(undefined, evt.feature.getGeometry())
|
|
2027
|
+
.subscribe({
|
|
2028
|
+
next: result => {
|
|
2029
|
+
this.filteredResults = result.filter(result => result.total > 0);
|
|
2030
|
+
}
|
|
2031
|
+
});
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
else {
|
|
2035
|
+
this._disablePolygonSearch();
|
|
2036
|
+
this.activeMode = null;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
_updateFilteredGeometryTypeSettings(geomType) {
|
|
2040
|
+
this.filteredGeometryTypeSettings = this.settings.geometryTypeSettings.filter(setting => setting.availableGeometryTypes?.includes(geomType));
|
|
2041
|
+
if (this.filteredGeometryTypeSettings.length === 1) {
|
|
2042
|
+
this.selectedGeometrySetting = this.filteredGeometryTypeSettings[0];
|
|
2043
|
+
this.settingsChanged();
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
_disablePolygonSearch() {
|
|
2047
|
+
if (this.drawInteraction) {
|
|
2048
|
+
this.map.removeInteraction(this.drawInteraction);
|
|
2049
|
+
this.drawInteraction = undefined;
|
|
2050
|
+
}
|
|
2051
|
+
this.filteredResults = [];
|
|
2052
|
+
}
|
|
2053
|
+
_enablePointSearch() {
|
|
2054
|
+
this.pointClickKey = this.map.on('singleclick', (evt) => {
|
|
2055
|
+
const point = new Point$1(evt.coordinate);
|
|
2056
|
+
this._searchService.search(undefined, point)
|
|
2057
|
+
.subscribe({
|
|
2058
|
+
next: result => {
|
|
2059
|
+
this.filteredResults = result.filter(result => result.total > 0);
|
|
2060
|
+
}
|
|
2061
|
+
});
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
_disablePointSearch() {
|
|
2065
|
+
if (this.pointClickKey) {
|
|
2066
|
+
unByKey(this.pointClickKey);
|
|
2067
|
+
this.pointClickKey = undefined;
|
|
2068
|
+
}
|
|
2069
|
+
this.filteredResults = [];
|
|
2070
|
+
}
|
|
2071
|
+
splitBySearchedObject(item, event) {
|
|
2072
|
+
event.stopPropagation();
|
|
2073
|
+
if (!item.wkt) {
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
if (!this.selectedGeometrySetting) {
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
const wktFormat = new WKT();
|
|
2080
|
+
let feature = wktFormat.readFeature(item.wkt, { featureProjection: 'EPSG:25832', dataProjection: 'EPSG:25832' });
|
|
2081
|
+
const geomType = feature.getGeometry()?.getType();
|
|
2082
|
+
if (!geomType) {
|
|
2083
|
+
return;
|
|
2084
|
+
}
|
|
2085
|
+
combineLatest([this._settingsHelper.getStyle(this.selectedGeometrySetting?.style, this.profile.styleRepositoryWorkspace, this.profile.styleRepositoryGeoserver, geomType),
|
|
2086
|
+
this._overlap.splitByFeature(feature)])
|
|
2087
|
+
.subscribe({
|
|
2088
|
+
next: ([style, features]) => {
|
|
2089
|
+
this._undoRedo.enable();
|
|
2090
|
+
features.forEach(feature => {
|
|
2091
|
+
this._featureHelper.setTypeId(feature, this.selectedGeometrySetting?.typeId || '');
|
|
2092
|
+
this._featureHelper.setId(feature);
|
|
2093
|
+
feature.setStyle(style);
|
|
2094
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
zoomSearchedObject(item, event) {
|
|
2100
|
+
event.stopPropagation();
|
|
2101
|
+
this.highlight(item.wkt, event);
|
|
2102
|
+
}
|
|
2103
|
+
toggleItemInfo(item, event) {
|
|
2104
|
+
event.stopPropagation();
|
|
2105
|
+
item.showMetadata = !item.showMetadata;
|
|
2106
|
+
}
|
|
2107
|
+
cutBySearchedObject(item, event) {
|
|
2108
|
+
event.stopPropagation();
|
|
2109
|
+
if (!item.wkt) {
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
if (!this.selectedGeometrySetting) {
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
const wktFormat = new WKT();
|
|
2116
|
+
let feature = wktFormat.readFeature(item.wkt, { featureProjection: 'EPSG:25832', dataProjection: 'EPSG:25832' });
|
|
2117
|
+
const geomType = feature.getGeometry()?.getType();
|
|
2118
|
+
if (!geomType) {
|
|
2119
|
+
return;
|
|
2120
|
+
}
|
|
2121
|
+
combineLatest([this._settingsHelper.getStyle(this.selectedGeometrySetting?.style, this.profile.styleRepositoryWorkspace, this.profile.styleRepositoryGeoserver, geomType),
|
|
2122
|
+
this._overlap.splitByFeature(feature, true)])
|
|
2123
|
+
.subscribe({
|
|
2124
|
+
next: ([style, features]) => {
|
|
2125
|
+
this._undoRedo.enable();
|
|
2126
|
+
features.forEach(feature => {
|
|
2127
|
+
this._featureHelper.setTypeId(feature, this.selectedGeometrySetting?.typeId || '');
|
|
2128
|
+
this._featureHelper.setId(feature);
|
|
2129
|
+
feature.setStyle(style);
|
|
2130
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2131
|
+
});
|
|
2132
|
+
}
|
|
2133
|
+
});
|
|
2134
|
+
}
|
|
2135
|
+
_bufferGeometry(geometry, bufferMeters) {
|
|
2136
|
+
const format = new GeoJSON();
|
|
2137
|
+
const precisionModel = new PrecisionModel(); // floating precision
|
|
2138
|
+
const geometryFactory = new GeometryFactory(precisionModel);
|
|
2139
|
+
const reader = new GeoJSONReader(geometryFactory);
|
|
2140
|
+
const writer = new GeoJSONWriter();
|
|
2141
|
+
// Convert OL geometry → GeoJSON → JSTS
|
|
2142
|
+
const geoJson = format.writeGeometryObject(geometry);
|
|
2143
|
+
const jstsGeom = reader.read(geoJson);
|
|
2144
|
+
// Create buffer
|
|
2145
|
+
const bufferedJstsGeom = BufferOp.bufferOp(jstsGeom, bufferMeters);
|
|
2146
|
+
// Convert back to OL geometry
|
|
2147
|
+
const bufferedGeoJson = writer.write(bufferedJstsGeom);
|
|
2148
|
+
return format.readGeometry(bufferedGeoJson);
|
|
2149
|
+
}
|
|
1139
2150
|
settingsChanged(evt) {
|
|
1140
2151
|
this._clearAllInteractions();
|
|
2152
|
+
setTimeout(() => {
|
|
2153
|
+
switch (this.activeMode) {
|
|
2154
|
+
case 'draw-point': {
|
|
2155
|
+
this._startDraw('Point');
|
|
2156
|
+
break;
|
|
2157
|
+
}
|
|
2158
|
+
case 'draw-polygon': {
|
|
2159
|
+
this._startDraw('Polygon');
|
|
2160
|
+
break;
|
|
2161
|
+
}
|
|
2162
|
+
case 'draw-linestring': {
|
|
2163
|
+
this._startDraw('LineString');
|
|
2164
|
+
break;
|
|
2165
|
+
}
|
|
2166
|
+
default: break;
|
|
2167
|
+
}
|
|
2168
|
+
}, 300);
|
|
1141
2169
|
}
|
|
1142
2170
|
undo() {
|
|
1143
2171
|
this._undoRedo.undo();
|
|
@@ -1145,6 +2173,10 @@ class ToolboxComponent {
|
|
|
1145
2173
|
redo() {
|
|
1146
2174
|
this._undoRedo.redo();
|
|
1147
2175
|
}
|
|
2176
|
+
startShowInfo() {
|
|
2177
|
+
this._clearAllInteractions();
|
|
2178
|
+
this._showInfo.startShowInfo();
|
|
2179
|
+
}
|
|
1148
2180
|
onSnapChange() {
|
|
1149
2181
|
if (this.snap) {
|
|
1150
2182
|
this._addSnap();
|
|
@@ -1168,11 +2200,42 @@ class ToolboxComponent {
|
|
|
1168
2200
|
}
|
|
1169
2201
|
this._settingsHelper.getStyle(this.selectedGeometrySetting.style, this.profile.styleRepositoryWorkspace, this.profile.styleRepositoryGeoserver, featureType).subscribe({
|
|
1170
2202
|
next: featureStyle => {
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
2203
|
+
if (featureType === 'Polygon') {
|
|
2204
|
+
this.handleFeatureValidation(feature).subscribe({
|
|
2205
|
+
next: (result) => {
|
|
2206
|
+
if (result) {
|
|
2207
|
+
result.forEach(feature => {
|
|
2208
|
+
feature.setStyle(featureStyle);
|
|
2209
|
+
this._featureHelper.setTypeId(feature, this.selectedGeometrySetting?.typeId || '');
|
|
2210
|
+
this._featureHelper.setId(feature);
|
|
2211
|
+
});
|
|
2212
|
+
this._overlap.handleOverlaps(result).pipe(filter(f => !!f)).subscribe({
|
|
2213
|
+
next: f => {
|
|
2214
|
+
if (f) {
|
|
2215
|
+
f.forEach(feature => {
|
|
2216
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2217
|
+
});
|
|
2218
|
+
this._zoomService.zoomToFeatures(f);
|
|
2219
|
+
if (f.length > 1) {
|
|
2220
|
+
this._snackbar.open(`Den indtegnede flade var ikke gyldig, men rettet til ${f.length} nye flader`, '', { duration: 3000 });
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
else {
|
|
2227
|
+
this._snackbar.open(`Validering af de tegnede flader resulterede i ingen flader`, '', { duration: 3000 });
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
else {
|
|
2233
|
+
feature.setStyle(featureStyle);
|
|
2234
|
+
this._featureHelper.setTypeId(feature, this.selectedGeometrySetting?.typeId || '');
|
|
2235
|
+
this._featureHelper.setId(feature);
|
|
2236
|
+
this._zoomService.zoomToFeatures([feature]);
|
|
2237
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2238
|
+
}
|
|
1176
2239
|
}
|
|
1177
2240
|
});
|
|
1178
2241
|
}
|
|
@@ -1184,6 +2247,14 @@ class ToolboxComponent {
|
|
|
1184
2247
|
type: 'Polygon',
|
|
1185
2248
|
source: this._drawLayerService.source
|
|
1186
2249
|
});
|
|
2250
|
+
setCenterPoint() {
|
|
2251
|
+
this._clearAllInteractions();
|
|
2252
|
+
this.activeMode = 'center-point';
|
|
2253
|
+
this._centerPointService.setCenterPoint(this.settings.centerPoint.style, this.settings.centerPoint.withinPolygon, () => {
|
|
2254
|
+
this.activeMode = null;
|
|
2255
|
+
this._clearAllInteractions();
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
1187
2258
|
_actionSource = new VectorSource();
|
|
1188
2259
|
clipHole() {
|
|
1189
2260
|
this._clearAllInteractions();
|
|
@@ -1194,7 +2265,7 @@ class ToolboxComponent {
|
|
|
1194
2265
|
});
|
|
1195
2266
|
this._interactionHelper.setAsTemp(clipHoleDraw);
|
|
1196
2267
|
clipHoleDraw.on('drawend', evt => {
|
|
1197
|
-
const overlappingFeatures = this._drawLayerService.source.getFeatures().filter(f => f.getGeometry()?.intersectsExtent(evt.feature.getGeometry().getExtent()));
|
|
2268
|
+
const overlappingFeatures = this._drawLayerService.source.getFeatures().filter(f => !this._featureHelper.isLocked(f) && f.getGeometry()?.intersectsExtent(evt.feature.getGeometry().getExtent()));
|
|
1198
2269
|
const geoJsonFormat = new GeoJSON();
|
|
1199
2270
|
const holeGeoJson = geoJsonFormat.writeFeatureObject(evt.feature);
|
|
1200
2271
|
overlappingFeatures.forEach(f => {
|
|
@@ -1243,14 +2314,52 @@ class ToolboxComponent {
|
|
|
1243
2314
|
this.map.addInteraction(splitInteraction);
|
|
1244
2315
|
this._addSnap();
|
|
1245
2316
|
}
|
|
2317
|
+
startDrawPointUrl(url) {
|
|
2318
|
+
this._clearAllInteractions();
|
|
2319
|
+
const style = new Style({
|
|
2320
|
+
image: new Icon({
|
|
2321
|
+
src: url,
|
|
2322
|
+
scale: 1,
|
|
2323
|
+
anchor: [0.5, 1],
|
|
2324
|
+
anchorXUnits: 'fraction',
|
|
2325
|
+
anchorYUnits: 'fraction'
|
|
2326
|
+
})
|
|
2327
|
+
});
|
|
2328
|
+
const drawInteraction = new Draw({
|
|
2329
|
+
type: 'Point',
|
|
2330
|
+
source: new VectorSource(),
|
|
2331
|
+
style
|
|
2332
|
+
});
|
|
2333
|
+
this.activeMode = 'draw-point';
|
|
2334
|
+
this._updateFilteredGeometryTypeSettings('Point');
|
|
2335
|
+
this.showGeometryTypes = true;
|
|
2336
|
+
drawInteraction.on('drawend', evt => {
|
|
2337
|
+
const feature = evt.feature.clone();
|
|
2338
|
+
this._featureHelper.setId(feature);
|
|
2339
|
+
this._featureHelper.setTypeId(feature, this.selectedGeometrySetting.typeId);
|
|
2340
|
+
feature.setStyle(style);
|
|
2341
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2342
|
+
});
|
|
2343
|
+
this._interactionHelper.setAsTemp(drawInteraction);
|
|
2344
|
+
this.map.addInteraction(drawInteraction);
|
|
2345
|
+
}
|
|
1246
2346
|
startDrawPoint() {
|
|
1247
2347
|
this._startDraw('Point');
|
|
2348
|
+
this.showGeometryTypes = false;
|
|
2349
|
+
this._updateFilteredGeometryTypeSettings('Point');
|
|
2350
|
+
this.showGeometryTypes = true;
|
|
1248
2351
|
}
|
|
1249
2352
|
startDrawLineString() {
|
|
1250
2353
|
this._startDraw('LineString');
|
|
2354
|
+
this.showGeometryTypes = false;
|
|
2355
|
+
this._updateFilteredGeometryTypeSettings('LineString');
|
|
2356
|
+
this.showGeometryTypes = true;
|
|
1251
2357
|
}
|
|
1252
2358
|
startDrawPolygon() {
|
|
1253
2359
|
this._startDraw('Polygon');
|
|
2360
|
+
this.showGeometryTypes = false;
|
|
2361
|
+
this._updateFilteredGeometryTypeSettings('Polygon');
|
|
2362
|
+
this.showGeometryTypes = true;
|
|
1254
2363
|
}
|
|
1255
2364
|
_deleteSelect;
|
|
1256
2365
|
get deleteSelect() {
|
|
@@ -1264,13 +2373,14 @@ class ToolboxComponent {
|
|
|
1264
2373
|
this._interactionHelper.setAsTemp(this.deleteSelect);
|
|
1265
2374
|
this.deleteSelect.on('select', evt => {
|
|
1266
2375
|
this._drawLayerService.source.removeFeatures(evt.selected);
|
|
2376
|
+
evt.selected.forEach(f => this._centerPointService.handleFeatureDeleted(f.getId()));
|
|
1267
2377
|
});
|
|
1268
2378
|
return this._deleteSelect;
|
|
1269
2379
|
}
|
|
1270
|
-
_deleting = false;
|
|
2380
|
+
// private _deleting: boolean = false;
|
|
1271
2381
|
startDelete() {
|
|
1272
2382
|
this._clearAllInteractions();
|
|
1273
|
-
this._deleting = true;
|
|
2383
|
+
// this._deleting = true;
|
|
1274
2384
|
this.activeMode = 'delete';
|
|
1275
2385
|
this.map.addInteraction(this.deleteSelect);
|
|
1276
2386
|
this._addSnap();
|
|
@@ -1280,38 +2390,143 @@ class ToolboxComponent {
|
|
|
1280
2390
|
this.activeMode = 'edit-remove';
|
|
1281
2391
|
const modifyRemove = new Modify({
|
|
1282
2392
|
source: this._drawLayerService.source,
|
|
2393
|
+
condition: evt => {
|
|
2394
|
+
// first, get all features from the draw-layer
|
|
2395
|
+
const feature = this.map.forEachFeatureAtPixel(evt.pixel, f => f, { layerFilter: l => l == this._drawLayerService.layer });
|
|
2396
|
+
if (!feature) {
|
|
2397
|
+
return false;
|
|
2398
|
+
}
|
|
2399
|
+
return !this._featureHelper.isLocked(feature);
|
|
2400
|
+
},
|
|
1283
2401
|
// Make sure delete is allowed and other interactions are not.
|
|
1284
2402
|
deleteCondition: always,
|
|
1285
2403
|
insertVertexCondition: never,
|
|
1286
|
-
snapToPointer: this.snap
|
|
2404
|
+
snapToPointer: this.snap,
|
|
1287
2405
|
});
|
|
1288
2406
|
this._interactionHelper.setAsTemp(modifyRemove);
|
|
1289
2407
|
this.map.addInteraction(modifyRemove);
|
|
1290
2408
|
this._addSnap();
|
|
1291
2409
|
}
|
|
2410
|
+
highlight(wkt, event) {
|
|
2411
|
+
event.stopPropagation();
|
|
2412
|
+
this._highlight.highlight(wkt);
|
|
2413
|
+
}
|
|
2414
|
+
addToActiveObjectsList(item, event, withBuffer = false) {
|
|
2415
|
+
event.stopPropagation();
|
|
2416
|
+
if (!item.wkt) {
|
|
2417
|
+
return;
|
|
2418
|
+
}
|
|
2419
|
+
if (!this.selectedGeometrySetting) {
|
|
2420
|
+
return;
|
|
2421
|
+
}
|
|
2422
|
+
const wktFormat = new WKT();
|
|
2423
|
+
let feature = wktFormat.readFeature(item.wkt, { featureProjection: 'EPSG:25832', dataProjection: 'EPSG:25832' });
|
|
2424
|
+
if (withBuffer) {
|
|
2425
|
+
const bufferedGeometry = this._bufferGeometry(feature.getGeometry(), this.bufferInMeters);
|
|
2426
|
+
feature = new Feature$1({ geometry: bufferedGeometry });
|
|
2427
|
+
}
|
|
2428
|
+
const geomType = feature.getGeometry()?.getType();
|
|
2429
|
+
if (!geomType) {
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2432
|
+
combineLatest([this.handleFeatureValidation(feature), this._settingsHelper.getStyle(this.selectedGeometrySetting?.style, this.profile.styleRepositoryWorkspace, this.profile.styleRepositoryGeoserver, geomType)])
|
|
2433
|
+
.subscribe({
|
|
2434
|
+
next: ([validationResult, featureStyle]) => {
|
|
2435
|
+
if (validationResult) {
|
|
2436
|
+
validationResult.forEach(feature => {
|
|
2437
|
+
feature.setStyle(featureStyle);
|
|
2438
|
+
this._featureHelper.setTypeId(feature, this.selectedGeometrySetting?.typeId || '');
|
|
2439
|
+
this._featureHelper.setId(feature);
|
|
2440
|
+
});
|
|
2441
|
+
this._overlap.handleOverlaps(validationResult).pipe(filter(f => !!f)).subscribe({
|
|
2442
|
+
next: f => {
|
|
2443
|
+
if (f) {
|
|
2444
|
+
f.forEach(feature => {
|
|
2445
|
+
this._undoRedo.enable();
|
|
2446
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2447
|
+
});
|
|
2448
|
+
this._zoomService.zoomToFeatures(f);
|
|
2449
|
+
if (f.length > 1) {
|
|
2450
|
+
this._snackbar.open(`Den indtegnede flade var ikke gyldig, men rettet til ${f.length} nye flader`, '', { duration: 3000 });
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
});
|
|
2455
|
+
}
|
|
2456
|
+
else {
|
|
2457
|
+
this._snackbar.open(`Validering af de tegnede flader resulterede i ingen flader`, '', { duration: 3000 });
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
});
|
|
2461
|
+
}
|
|
1292
2462
|
startEdit() {
|
|
1293
2463
|
this._clearAllInteractions();
|
|
1294
2464
|
this.activeMode = 'edit';
|
|
1295
2465
|
const modify = new Modify({
|
|
1296
2466
|
source: this._drawLayerService.source,
|
|
2467
|
+
condition: evt => {
|
|
2468
|
+
// first, get all features from the draw-layer
|
|
2469
|
+
const feature = this.map.forEachFeatureAtPixel(evt.pixel, f => f, { layerFilter: l => l == this._drawLayerService.layer });
|
|
2470
|
+
if (!feature) {
|
|
2471
|
+
return false;
|
|
2472
|
+
}
|
|
2473
|
+
return !this._featureHelper.isLocked(feature);
|
|
2474
|
+
},
|
|
1297
2475
|
// No delete
|
|
1298
2476
|
deleteCondition: () => false,
|
|
1299
2477
|
// Allow moving existing and add new points
|
|
1300
|
-
condition: always,
|
|
2478
|
+
// condition: always,
|
|
1301
2479
|
insertVertexCondition: always,
|
|
1302
2480
|
});
|
|
1303
2481
|
/* Modify fires changes to features a LOT, so to not flood the UndoRedo service, I disable until ending the modify
|
|
1304
2482
|
and then force an update, to add the updated feature to the undo-service. */
|
|
1305
2483
|
modify.on('modifystart', () => this._undoRedo.disable());
|
|
1306
|
-
modify.on('modifyend', (evt) => {
|
|
2484
|
+
modify.on('modifyend', (evt) => {
|
|
2485
|
+
this._undoRedo.enable();
|
|
2486
|
+
evt.features.forEach(f => {
|
|
2487
|
+
f.set('updated', new Date().toISOString());
|
|
2488
|
+
const geom = f.getGeometry();
|
|
2489
|
+
if (geom && geom.getType() === 'Polygon') {
|
|
2490
|
+
//START VALIDATING
|
|
2491
|
+
this.handleFeatureValidation(f).subscribe({
|
|
2492
|
+
next: (result) => {
|
|
2493
|
+
if (result && result.length > 0) {
|
|
2494
|
+
const featureStyle = f.getStyle();
|
|
2495
|
+
const featureTypeId = this._featureHelper.typeId(f);
|
|
2496
|
+
this._drawLayerService.source.removeFeature(f);
|
|
2497
|
+
result.forEach(feature => {
|
|
2498
|
+
feature.setStyle(featureStyle);
|
|
2499
|
+
this._featureHelper.setTypeId(feature, featureTypeId || '');
|
|
2500
|
+
this._featureHelper.setId(feature);
|
|
2501
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2502
|
+
});
|
|
2503
|
+
this._overlap.handleOverlaps(result).pipe(filter(f => !!f)).subscribe({
|
|
2504
|
+
next: f => {
|
|
2505
|
+
if (f) {
|
|
2506
|
+
f.forEach(feature => {
|
|
2507
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2508
|
+
});
|
|
2509
|
+
if (f.length > 1) {
|
|
2510
|
+
this._snackbar.open(`Den indtegnede flade var ikke gyldig, men rettet til ${f.length} nye flader`, '', { duration: 3000 });
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
});
|
|
2515
|
+
}
|
|
2516
|
+
else {
|
|
2517
|
+
this._snackbar.open(`Validering af de tegnede flader resulterede i ingen flader`, '', { duration: 3000 });
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
});
|
|
2521
|
+
//END VALIDATING
|
|
2522
|
+
}
|
|
2523
|
+
});
|
|
2524
|
+
});
|
|
1307
2525
|
this._interactionHelper.setAsTemp(modify);
|
|
1308
2526
|
this.map.addInteraction(modify);
|
|
1309
2527
|
}
|
|
1310
2528
|
_startDraw(geomType) {
|
|
1311
2529
|
this._clearAllInteractions();
|
|
1312
|
-
if (!this.selectedGeometrySetting) {
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
2530
|
// Set the active mode after clearing
|
|
1316
2531
|
if (geomType === 'Polygon')
|
|
1317
2532
|
this.activeMode = 'draw-polygon';
|
|
@@ -1319,21 +2534,58 @@ class ToolboxComponent {
|
|
|
1319
2534
|
this.activeMode = 'draw-linestring';
|
|
1320
2535
|
else if (geomType === 'Point')
|
|
1321
2536
|
this.activeMode = 'draw-point';
|
|
2537
|
+
if (!this.selectedGeometrySetting) {
|
|
2538
|
+
return;
|
|
2539
|
+
}
|
|
1322
2540
|
this._settingsHelper.getStyle(this.selectedGeometrySetting.style, this.profile.styleRepositoryWorkspace, this.profile.styleRepositoryGeoserver, geomType)
|
|
1323
2541
|
.subscribe({
|
|
1324
2542
|
next: style => {
|
|
1325
2543
|
const drawInteraction = new Draw({
|
|
1326
2544
|
type: geomType,
|
|
1327
|
-
source:
|
|
2545
|
+
source: new VectorSource(),
|
|
1328
2546
|
style: style
|
|
1329
2547
|
});
|
|
2548
|
+
this._undoRedo.disable();
|
|
1330
2549
|
drawInteraction.on('drawend', evt => {
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
2550
|
+
if (geomType === 'Polygon') {
|
|
2551
|
+
// Validate feature
|
|
2552
|
+
this.handleFeatureValidation(evt.feature).subscribe({
|
|
2553
|
+
next: (result) => {
|
|
2554
|
+
if (result) {
|
|
2555
|
+
result.forEach(feature => {
|
|
2556
|
+
this._featureHelper.setTypeId(feature, this.selectedGeometrySetting?.typeId || '');
|
|
2557
|
+
this._featureHelper.setId(feature);
|
|
2558
|
+
feature.setStyle(style);
|
|
2559
|
+
});
|
|
2560
|
+
this._overlap.handleOverlaps(result).pipe(filter(f => !!f)).subscribe({
|
|
2561
|
+
next: f => {
|
|
2562
|
+
if (f) {
|
|
2563
|
+
f.forEach(feature => {
|
|
2564
|
+
this._undoRedo.enable();
|
|
2565
|
+
this._drawLayerService.source.addFeature(feature);
|
|
2566
|
+
});
|
|
2567
|
+
if (f.length > 1) {
|
|
2568
|
+
this._snackbar.open(`Den indtegnede flade var ikke gyldig, men rettet til ${f.length} nye flader`, '', { duration: 3000 });
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
});
|
|
2573
|
+
}
|
|
2574
|
+
else {
|
|
2575
|
+
this._snackbar.open(`Validering af de tegnede flader resulterede i ingen flader`, '', { duration: 3000 });
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
});
|
|
2579
|
+
}
|
|
2580
|
+
else {
|
|
2581
|
+
this._featureHelper.setTypeId(evt.feature, this.selectedGeometrySetting?.typeId || '');
|
|
2582
|
+
this._featureHelper.setId(evt.feature);
|
|
2583
|
+
evt.feature.setStyle(style);
|
|
2584
|
+
this._undoRedo.enable();
|
|
2585
|
+
this._drawLayerService.source.addFeature(evt.feature);
|
|
2586
|
+
}
|
|
1334
2587
|
});
|
|
1335
2588
|
this._interactionHelper.setAsTemp(drawInteraction);
|
|
1336
|
-
// this._setDrawLayer()
|
|
1337
2589
|
this.map.addInteraction(drawInteraction);
|
|
1338
2590
|
this._addSnap();
|
|
1339
2591
|
this.map.getTargetElement().style.cursor = 'crosshair'; // Placeholder for now
|
|
@@ -1344,6 +2596,7 @@ class ToolboxComponent {
|
|
|
1344
2596
|
_areaSource = new VectorSource();
|
|
1345
2597
|
_areaLayer = new VectorLayer({
|
|
1346
2598
|
source: this._areaSource,
|
|
2599
|
+
zIndex: 999,
|
|
1347
2600
|
style: (feature) => {
|
|
1348
2601
|
const geom = feature.getGeometry();
|
|
1349
2602
|
const area = getArea(geom);
|
|
@@ -1369,6 +2622,7 @@ class ToolboxComponent {
|
|
|
1369
2622
|
_distanceLabelSource = new VectorSource();
|
|
1370
2623
|
_distanceLabelLayer = new VectorLayer({
|
|
1371
2624
|
source: this._distanceLabelSource,
|
|
2625
|
+
zIndex: 999,
|
|
1372
2626
|
style: (feature) => {
|
|
1373
2627
|
return new Style({
|
|
1374
2628
|
text: new Text({
|
|
@@ -1383,6 +2637,7 @@ class ToolboxComponent {
|
|
|
1383
2637
|
_distanceSource = new VectorSource();
|
|
1384
2638
|
_distanceLayer = new VectorLayer({
|
|
1385
2639
|
source: this._distanceSource,
|
|
2640
|
+
zIndex: 999,
|
|
1386
2641
|
style: (feature) => {
|
|
1387
2642
|
const geom = feature.getGeometry();
|
|
1388
2643
|
const length = getLength(geom);
|
|
@@ -1433,7 +2688,7 @@ class ToolboxComponent {
|
|
|
1433
2688
|
const mid = [(c1[0] + c2[0]) / 2, (c1[1] + c2[1]) / 2];
|
|
1434
2689
|
const formatted = `${length.toFixed(2)} m`;
|
|
1435
2690
|
const labelFeature = new Feature$1({
|
|
1436
|
-
geometry: new Point(mid),
|
|
2691
|
+
geometry: new Point$1(mid),
|
|
1437
2692
|
label: formatted
|
|
1438
2693
|
});
|
|
1439
2694
|
this._distanceLabelSource.addFeature(labelFeature);
|
|
@@ -1443,7 +2698,7 @@ class ToolboxComponent {
|
|
|
1443
2698
|
const endPoint = coords[coords.length - 1];
|
|
1444
2699
|
const formattedTotal = `${totalLength.toFixed(2)} m`;
|
|
1445
2700
|
const totalFeature = new Feature$1({
|
|
1446
|
-
geometry: new Point(endPoint),
|
|
2701
|
+
geometry: new Point$1(endPoint),
|
|
1447
2702
|
label: `Total: ${formattedTotal}`
|
|
1448
2703
|
});
|
|
1449
2704
|
this._distanceLabelSource.addFeature(totalFeature);
|
|
@@ -1455,8 +2710,8 @@ class ToolboxComponent {
|
|
|
1455
2710
|
this._highlight.clear();
|
|
1456
2711
|
this.stopMeasureArea();
|
|
1457
2712
|
this.stopMeasureLength();
|
|
1458
|
-
this._deleting = false;
|
|
1459
2713
|
this._interactionHelper.clearTempFromMap();
|
|
2714
|
+
this._showInfo.disable();
|
|
1460
2715
|
this._undoRedo.enable();
|
|
1461
2716
|
}
|
|
1462
2717
|
ngOnInit() {
|
|
@@ -1470,6 +2725,11 @@ class ToolboxComponent {
|
|
|
1470
2725
|
});
|
|
1471
2726
|
this._loadPosition();
|
|
1472
2727
|
}
|
|
2728
|
+
ngOnChanges(changes) {
|
|
2729
|
+
if (changes['profile'] && this.profile) {
|
|
2730
|
+
this._loadPosition();
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
1473
2733
|
onDragEnded(event) {
|
|
1474
2734
|
this.dragPosition = {
|
|
1475
2735
|
x: event.source.getFreeDragPosition().x,
|
|
@@ -1481,12 +2741,15 @@ class ToolboxComponent {
|
|
|
1481
2741
|
try {
|
|
1482
2742
|
const savedPosition = localStorage.getItem(this._POSITION_STORAGE_KEY);
|
|
1483
2743
|
if (savedPosition) {
|
|
1484
|
-
|
|
1485
|
-
|
|
2744
|
+
this.dragPosition = JSON.parse(savedPosition);
|
|
2745
|
+
}
|
|
2746
|
+
else if (this.profile) {
|
|
2747
|
+
this.dragPosition = this._layoutService.loadInitialPositionFromProfile(this._POSITION_STORAGE_KEY, this.profile.toolboxInitialPosition);
|
|
1486
2748
|
}
|
|
1487
2749
|
}
|
|
1488
2750
|
catch (error) {
|
|
1489
|
-
console.
|
|
2751
|
+
console.error('Error loading position from localStorage:', error);
|
|
2752
|
+
this.dragPosition = { x: 0, y: 0 };
|
|
1490
2753
|
}
|
|
1491
2754
|
}
|
|
1492
2755
|
_savePosition() {
|
|
@@ -1494,7 +2757,7 @@ class ToolboxComponent {
|
|
|
1494
2757
|
localStorage.setItem(this._POSITION_STORAGE_KEY, JSON.stringify(this.dragPosition));
|
|
1495
2758
|
}
|
|
1496
2759
|
catch (error) {
|
|
1497
|
-
console.
|
|
2760
|
+
console.error('Error saving position to localStorage:', error);
|
|
1498
2761
|
}
|
|
1499
2762
|
}
|
|
1500
2763
|
startMergeFeatures() {
|
|
@@ -1540,6 +2803,9 @@ class ToolboxComponent {
|
|
|
1540
2803
|
this.stopMeasureArea();
|
|
1541
2804
|
this.stopMeasureLength();
|
|
1542
2805
|
}
|
|
2806
|
+
if (this.profile.toolboxInitialPosition.includes('højre')) {
|
|
2807
|
+
this._layoutService.bringElementIntoViewIfNeeded('.toolbox-wrapper', -57, this.collapsed, this.map);
|
|
2808
|
+
}
|
|
1543
2809
|
}
|
|
1544
2810
|
startMeasureArea() {
|
|
1545
2811
|
if (this._active === 'Area') {
|
|
@@ -1614,7 +2880,7 @@ class ToolboxComponent {
|
|
|
1614
2880
|
}
|
|
1615
2881
|
doPrint() {
|
|
1616
2882
|
let htmlElement = this.map.getViewport();
|
|
1617
|
-
this.
|
|
2883
|
+
this._printHelper.setVisibiltyOnDOMElements(htmlElement, false);
|
|
1618
2884
|
html2canvas(htmlElement, {
|
|
1619
2885
|
useCORS: true,
|
|
1620
2886
|
}).then(canvas => {
|
|
@@ -1630,66 +2896,124 @@ class ToolboxComponent {
|
|
|
1630
2896
|
}
|
|
1631
2897
|
link.download = download;
|
|
1632
2898
|
link.click();
|
|
1633
|
-
this.
|
|
2899
|
+
this._printHelper.setVisibiltyOnDOMElements(htmlElement, true);
|
|
1634
2900
|
});
|
|
1635
2901
|
}
|
|
1636
|
-
_setVisibiltyOnDOMElements(baseElement, visible) {
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
const mousePosition = baseElement.querySelector('.ol-mouse-position');
|
|
1654
|
-
if (mousePosition) {
|
|
1655
|
-
mousePosition.style.visibility = visibilityValue;
|
|
1656
|
-
}
|
|
1657
|
-
const layerSelector = baseElement.querySelector('.layer-selector-body-wrapper');
|
|
1658
|
-
if (layerSelector) {
|
|
1659
|
-
layerSelector.style.visibility = visibilityValue;
|
|
2902
|
+
// private _setVisibiltyOnDOMElements(baseElement: HTMLElement, visible: boolean): void {
|
|
2903
|
+
// let visibilityValue = 'hidden';
|
|
2904
|
+
// if (visible) { visibilityValue = 'visible'; }
|
|
2905
|
+
// const activeobjects = baseElement.querySelector('activeobjects') as HTMLElement;
|
|
2906
|
+
// if (activeobjects) { activeobjects!.style.visibility = visibilityValue; }
|
|
2907
|
+
// const zoom = baseElement.querySelector('.ol-zoom') as HTMLElement;
|
|
2908
|
+
// if (zoom) { zoom!.style.visibility = visibilityValue; }
|
|
2909
|
+
// const mapToolbox = baseElement.querySelector('map-toolbox') as HTMLElement;
|
|
2910
|
+
// if (mapToolbox) { mapToolbox!.style.visibility = visibilityValue; }
|
|
2911
|
+
// const mousePosition = baseElement.querySelector('.ol-mouse-position') as HTMLElement;
|
|
2912
|
+
// if (mousePosition) { mousePosition!.style.visibility = visibilityValue; }
|
|
2913
|
+
// const layerSelector = baseElement.querySelector('.layer-selector-body-wrapper') as HTMLElement;
|
|
2914
|
+
// if (layerSelector) { layerSelector!.style.visibility = visibilityValue; }
|
|
2915
|
+
// }
|
|
2916
|
+
startSelectFeatureHighlight() {
|
|
2917
|
+
if (this.activeMode === 'select-highlight') {
|
|
2918
|
+
return;
|
|
1660
2919
|
}
|
|
2920
|
+
this._clearAllInteractions();
|
|
2921
|
+
this.activeMode = 'select-highlight';
|
|
2922
|
+
const highlightSelect = new Select$1({
|
|
2923
|
+
layers: [this._drawLayerService.layer],
|
|
2924
|
+
style: undefined,
|
|
2925
|
+
});
|
|
2926
|
+
this._interactionHelper.setAsTemp(highlightSelect);
|
|
2927
|
+
highlightSelect.on('select', evt => {
|
|
2928
|
+
this._drawLayerService.setFeaturesSelectedForHighlight(evt.selected);
|
|
2929
|
+
this.activeMode = null;
|
|
2930
|
+
this._clearAllInteractions();
|
|
2931
|
+
});
|
|
2932
|
+
this.map.addInteraction(highlightSelect);
|
|
1661
2933
|
}
|
|
1662
2934
|
startDrawMode() {
|
|
1663
2935
|
if (this._active === 'PrintDraw') {
|
|
1664
2936
|
this._active = 'No';
|
|
1665
2937
|
this._removePrintDrawToolInteraction();
|
|
1666
2938
|
this.activeMode = null;
|
|
2939
|
+
this.printDrawTool = 'Point';
|
|
1667
2940
|
return;
|
|
1668
2941
|
}
|
|
1669
2942
|
this._active = 'PrintDraw';
|
|
1670
2943
|
this._clearAllInteractions();
|
|
1671
2944
|
this._addPrintDrawToolInteraction();
|
|
1672
2945
|
this.activeMode = null;
|
|
2946
|
+
this.printDrawTool = 'Point';
|
|
1673
2947
|
}
|
|
1674
2948
|
handlePrintDrawToolChanged() {
|
|
1675
2949
|
if (this.active === 'PrintDraw') {
|
|
1676
|
-
this.
|
|
1677
|
-
|
|
2950
|
+
this._removePrintDrawToolInteraction();
|
|
2951
|
+
this._addPrintDrawToolInteraction();
|
|
1678
2952
|
}
|
|
1679
2953
|
}
|
|
2954
|
+
handleClearPrintDrawFeatures() {
|
|
2955
|
+
this._printDrawLayerService.source.clear();
|
|
2956
|
+
}
|
|
1680
2957
|
printDraw;
|
|
1681
2958
|
_addPrintDrawToolInteraction() {
|
|
1682
2959
|
if (this.active === 'PrintDraw') {
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
2960
|
+
switch (this.printDrawTool) {
|
|
2961
|
+
case 'Arrow':
|
|
2962
|
+
this.printDraw = new Draw({
|
|
2963
|
+
source: this._printDrawLayerService.source,
|
|
2964
|
+
type: 'LineString',
|
|
2965
|
+
});
|
|
2966
|
+
break;
|
|
2967
|
+
case 'Square':
|
|
2968
|
+
this.printDraw = new Draw({
|
|
2969
|
+
source: this._printDrawLayerService.source,
|
|
2970
|
+
type: 'Circle',
|
|
2971
|
+
geometryFunction: createRegularPolygon(4)
|
|
2972
|
+
});
|
|
2973
|
+
break;
|
|
2974
|
+
case 'Rectangle':
|
|
2975
|
+
this.printDraw = new Draw({
|
|
2976
|
+
source: this._printDrawLayerService.source,
|
|
2977
|
+
type: 'Circle',
|
|
2978
|
+
geometryFunction: createBox()
|
|
2979
|
+
});
|
|
2980
|
+
break;
|
|
2981
|
+
default:
|
|
2982
|
+
this.printDraw = new Draw({
|
|
2983
|
+
source: this._printDrawLayerService.source,
|
|
2984
|
+
type: this.printDrawTool,
|
|
2985
|
+
});
|
|
2986
|
+
break;
|
|
2987
|
+
}
|
|
1691
2988
|
this.printDraw.on('drawend', evt => {
|
|
1692
|
-
evt.feature
|
|
2989
|
+
const feature = evt.feature;
|
|
2990
|
+
feature.set("printDrawLabel", this.printDrawLabel);
|
|
2991
|
+
feature.set("printDrawTool", this.printDrawTool);
|
|
2992
|
+
if (this.printDrawTool === 'Arrow') {
|
|
2993
|
+
feature.setStyle((feature) => {
|
|
2994
|
+
const styles = this._getDrawToolStyle(feature);
|
|
2995
|
+
const geom = feature.getGeometry();
|
|
2996
|
+
const rot = this._lastSegmentRotation(geom);
|
|
2997
|
+
const arrowHead = new RegularShape({
|
|
2998
|
+
points: 3,
|
|
2999
|
+
radius: 10,
|
|
3000
|
+
angle: Math.PI / 2,
|
|
3001
|
+
rotation: -rot,
|
|
3002
|
+
rotateWithView: true,
|
|
3003
|
+
stroke: new Stroke({ color: '#1f6feb', width: 3 })
|
|
3004
|
+
});
|
|
3005
|
+
const endCoord = geom.getCoordinateAt(1);
|
|
3006
|
+
const arrowEndStyle = new Style({
|
|
3007
|
+
image: arrowHead,
|
|
3008
|
+
geometry: () => new Point$1(endCoord)
|
|
3009
|
+
});
|
|
3010
|
+
styles.push(arrowEndStyle);
|
|
3011
|
+
return styles;
|
|
3012
|
+
});
|
|
3013
|
+
}
|
|
3014
|
+
else {
|
|
3015
|
+
feature.setStyle((feature) => this._getDrawToolStyle(feature));
|
|
3016
|
+
}
|
|
1693
3017
|
});
|
|
1694
3018
|
}
|
|
1695
3019
|
this.map.addInteraction(this.printDraw);
|
|
@@ -1698,55 +3022,57 @@ class ToolboxComponent {
|
|
|
1698
3022
|
_removePrintDrawToolInteraction() {
|
|
1699
3023
|
this.map.removeInteraction(this.printDraw);
|
|
1700
3024
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
3025
|
+
_lastSegmentRotation(lineString) {
|
|
3026
|
+
const coords = lineString.getCoordinates();
|
|
3027
|
+
if (!coords || coords.length < 2)
|
|
3028
|
+
return 0;
|
|
3029
|
+
const [x1, y1] = coords[coords.length - 2];
|
|
3030
|
+
const [x2, y2] = coords[coords.length - 1];
|
|
3031
|
+
return Math.atan2(y2 - y1, x2 - x1);
|
|
3032
|
+
}
|
|
3033
|
+
_getDrawToolStyle(feature) {
|
|
3034
|
+
const textStyle = new Style({
|
|
3035
|
+
text: new Text({
|
|
3036
|
+
text: feature.get("printDrawLabel"),
|
|
3037
|
+
font: '12px Calibri,sans-serif',
|
|
3038
|
+
fill: new Fill({ color: '#000' }),
|
|
3039
|
+
stroke: new Stroke({ color: '#fff', width: 3 }),
|
|
3040
|
+
placement: 'point'
|
|
3041
|
+
})
|
|
3042
|
+
});
|
|
3043
|
+
const lineStyle = new Style({
|
|
3044
|
+
stroke: new Stroke({
|
|
3045
|
+
color: '#1f6feb',
|
|
3046
|
+
width: 3
|
|
3047
|
+
})
|
|
3048
|
+
});
|
|
3049
|
+
const circleStyle = new Style({
|
|
3050
|
+
image: new CircleStyle({
|
|
3051
|
+
radius: 5,
|
|
3052
|
+
fill: new Fill({ color: '#7da8e9ff' }), // teal fill
|
|
3053
|
+
stroke: new Stroke({ color: '#1f6feb', width: 2 }),
|
|
3054
|
+
})
|
|
3055
|
+
});
|
|
3056
|
+
let styles = [textStyle, lineStyle];
|
|
3057
|
+
if (feature.get("printDrawTool") === 'Point') {
|
|
3058
|
+
styles.push(circleStyle);
|
|
3059
|
+
}
|
|
3060
|
+
return styles;
|
|
3061
|
+
}
|
|
3062
|
+
handleFeatureValidation(feature) {
|
|
3063
|
+
const wktFormat = new WKT();
|
|
3064
|
+
const wkt = wktFormat.writeFeature(feature);
|
|
3065
|
+
return this._geometryService.validate(wkt)
|
|
3066
|
+
.pipe(map(result => {
|
|
3067
|
+
return result.correctedGeometries?.map(wkt => wktFormat.readFeature(wkt));
|
|
3068
|
+
}));
|
|
3069
|
+
}
|
|
1744
3070
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ToolboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1745
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: ToolboxComponent, isStandalone: true, selector: "map-toolbox", inputs: { map: "map", showMeasureDistance: "showMeasureDistance", showMeasureArea: "showMeasureArea", collapsed: "collapsed", settings: "settings", profile: "profile", WKTInputEnabled: "WKTInputEnabled", deleteEnabled: "deleteEnabled" }, ngImport: i0, template: "<div class=\"toolbox-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\"\n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\">\n <div class=\"drag-handle-toolbox\" cdkDragHandle>\n <mat-icon>build_circle</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleCollapsed($event)\">{{ collapsed ? 'flip_to_front' : 'remove' }}</mat-icon> </div>\n <div class=\"toolbox-container\" [class.collapsed]=\"collapsed\">\n @if(!collapsed) {\n <div class=\"toolbox-content\">\n @if (settings.geometryTypeSettings && settings.geometryTypeSettings.length) {\n <mat-select class=\"geometry-selector\" (selectionChange)=\"settingsChanged($event)\" [(ngModel)]=\"selectedGeometrySetting\" [compareWith]=\"compareGeometrySetting\">\n @for (setting of settings.geometryTypeSettings; track setting) {\n <mat-option [value]=\"setting\">{{setting.typeName}}</mat-option>\n }\n </mat-select> \n }\n <div class=\"all-tools-container\">\n <div class=\"main-tools\">\n @if(!settings?.undoDisabled) {\n <img \n [src]=\"undoIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"undo()\" \n matTooltip=\"Fortryd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Undo\">\n\n <img \n [src]=\"redoIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"redo()\" \n matTooltip=\"Gentag\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Redo\">\n }\n <mat-slide-toggle [(ngModel)]=\"snap\" (change)=\"onSnapChange()\">Snap</mat-slide-toggle>\n @if(settings.editEnabled) {\n <img \n [src]=\"editIconBase64\" \n [class.active]=\"activeMode === 'edit'\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"startEdit()\" \n matTooltip=\"Rediger\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Rediger\">\n\n <img \n [src]=\"removePointsIconBase64\" \n [class.active]=\"activeMode === 'edit-remove'\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"startEditRemovePoints()\" \n matTooltip=\"Fjern punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Fjern punkter\">\n }\n @if(settings.cutHoleEnabled) {\n <img \n [src]=\"trimIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'clip-hole'\" \n (click)=\"clipHole()\" \n matTooltip=\"Klip hul\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Klip hul\">\n }\n @if(settings.splitEnabled) {\n <img \n [src]=\"splitIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'split'\"\n (click)=\"split()\" \n matTooltip=\"Sk\u00E6r over\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Sk\u00E6r over\">\n }\n @if(settings.changeTypeEnabled) {\n <mat-icon \n class=\"compact-icon\" \n [class.active]=\"activeMode === 'change-type'\" \n (click)=\"startChangeType()\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Skift type\" \n matTooltipPosition=\"below\">\n find_replace\n </mat-icon>\n }\n @if(settings.mergeEnabled) {\n <mat-icon \n class=\"compact-icon\" \n (click)=\"startMergeFeatures()\" \n matTooltipPosition=\"below\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Saml flader\" \n [class.active]=\"activeMode === 'merge-features'\">\n merge\n </mat-icon>\n }\n </div>\n @if(selectedGeometrySetting && selectedGeometrySetting.availableGeometryTypes?.length) {\n <div class=\"geometry-tools\">\n @for(geomType of selectedGeometrySetting.availableGeometryTypes;track geomType) {\n @if(geomType === 'Polygon') {\n <img \n [src]=\"polygonIconBase64\" \n [class.active]=\"activeMode === 'draw-polygon'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPolygon()\" \n matTooltip=\"Polygon\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Polygon\">\n }\n @if(geomType === 'LineString') {\n <img \n [src]=\"lineStringIconBase64\" \n [class.active]=\"activeMode === 'draw-linestring'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawLineString()\" \n matTooltip=\"LineString\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"LineString\">\n }\n @if(geomType === 'Point') {\n <img \n [src]=\"pointIconBase64\" \n [class.active]=\"activeMode === 'draw-point'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPoint()\" \n matTooltip=\"Punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Punkter\">\n }\n }\n <img \n [src]=\"wktIconBase64\" \n class=\"compact-icon secondary custom-image-icon\"\n (click)=\"activateShowInputWKT()\" \n matTooltip=\"WKT\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"WKT\">\n </div>\n }\n <div class=\"tool-separator\" *ngIf=\"deleteEnabled || showMeasureDistance || showMeasureArea || profile.showPrint\"></div>\n <div class=\"measurement-print-tools\">\n <div class=\"measurement-tools\">\n @if (deleteEnabled) {\n <img \n [src]=\"deleteIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'delete'\"\n (click)=\"startDelete()\" \n matTooltip=\"Slet\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Slet\">\n }\n @if (showMeasureDistance) {\n <img \n [src]=\"measureDistanceIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'measure-distance'\"\n (click)=\"startMeasureLength()\" \n matTooltip=\"M\u00E5le afstand\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"M\u00E5le afstand\">\n }\n @if(showMeasureArea) {\n <img \n [src]=\"measureAreaIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'measure-area'\"\n (click)=\"startMeasureArea()\" \n matTooltip=\"M\u00E5le areal\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"M\u00E5le areal\">\n }\n </div>\n @if(profile.showPrint) {\n <div class=\"tool-separator print-separator\"></div>\n <div class=\"print-tools\">\n <img \n [src]=\"printBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"active === 'Print'\"\n (click)=\"startPrintMode()\" \n matTooltip=\"Udskriv\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Udskriv\">\n <!-- <img \n [src]=\"drawBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"active === 'Draw'\"\n (click)=\"startDrawMode()\" \n matTooltip=\"Tegn\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Tegn\"> -->\n </div>\n }\n </div>\n </div>\n @if(showInputWKT) {\n <div class=\"wkt-section\">\n <input class=\"compact-input\" [(ngModel)]=\"WKTString\">\n <div class=\"wkt-actions\">\n <button class=\"compact-button primary\" (click)=\"ReadWKT()\">Indl\u00E6s WKT</button>\n <button class=\"compact-button\" (click)=\"cancelWKT()\">Annuller</button>\n </div>\n </div>\n }\n @if(profile.showPrint) {\n @if(active === \"Print\") {\n <div class=\"print-config\">\n <img \n [src]=\"printBase64\" \n class=\"compact-icon\"\n (click)=\"doPrint()\" \n alt=\"Udskriv\"> \n <span class=\"icon-separator\">i</span>\n <select id=\"formatSelector\" [(ngModel)]=\"format\">\n <option value=\"image/png\" selected>.PNG</option>\n <option value=\"image/jpeg\">.JPG</option>\n </select>\n <select id=\"dimensionSelector\" [(ngModel)]=\"dimId\" (change)=\"handleDimensionSelected()\">\n <option value=\"99\" selected></option>\n <option value=\"0\">1920 X 1080</option>\n <option value=\"1\">1680 X 1050</option>\n <option value=\"2\">1280 X 800</option>\n <option value=\"3\">800 X 600</option>\n </select>\n <input type=\"text\" [(ngModel)]=\"mapWidth\"/> \n <span class=\"icon-separator\">x</span>\n <input type=\"text\" [(ngModel)]=\"mapHeight\"/>\n <button (click)=\"setNewMapDimensions()\">V\u00E6lg</button>\n </div>\n }\n @if(active === \"PrintDraw\") {\n <div class=\"print-draw-config\">\n <span class=\"icon-separator\">Label</span>\n <input type=\"text\" [(ngModel)]=\"printDrawLabel\"/>\n <select id=\"drawToolSelector\" [(ngModel)]=\"printDrawTool\" (change)=\"handlePrintDrawToolChanged()\">\n <option value=\"arrow\" selected>Pil</option>\n <option value=\"point\">Punkt</option>\n <option value=\"line\">Linje</option>\n <option value=\"polygon\">Polygon</option>\n <option value=\"cirkel\">Cirkel</option>\n <option value=\"square\">Kvadrat</option>\n <option value=\"rectangle\">Firkant</option>\n </select>\n <button>Ryd</button>\n </div>\n }\n }\n </div>\n }\n </div>\n</div>\n", styles: [".toolbox-wrapper{position:absolute;left:1em;top:31.5em;z-index:1000;cursor:grab;max-width:95vw}.toolbox-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}.drag-handle-toolbox{display:flex;align-items:center;justify-content:space-between;background:color-mix(in srgb,#000 60%,transparent);padding:2px 10px;cursor:grab;gap:8px}.drag-handle-toolbox mat-icon{color:#fff;font-size:18px;width:18px;height:18px}.drag-handle-toolbox mat-icon:first-child{flex:1;text-align:center}.toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.toggle-icon:hover{color:#fff;background:#ffffff26}.toggle-icon:active{background:#ffffff40}:host{position:relative;display:flex;justify-content:center}:host.expanded{width:auto;min-width:320px;padding:12px}.toolbox-container{display:flex;flex-direction:column;align-items:center;width:100%;gap:10px;background:color-mix(in srgb,#000 60%,transparent);box-shadow:#0000004d 0 1px 4px -1px;padding:10px;width:auto;min-width:32px;transition:all .3s ease;cursor:default}.toolbox-container.collapsed{display:none}.toolbox-content{display:flex;flex-direction:column;width:100%;gap:3px;animation:slideDown .3s cubic-bezier(.4,0,.2,1)}.all-tools-container{display:flex;flex-direction:row;align-items:center;flex-wrap:nowrap;width:100%;justify-content:flex-start;overflow-x:hidden}.all-tools-container::-webkit-scrollbar{height:4px}.all-tools-container::-webkit-scrollbar-thumb{background:#ccc;border-radius:2px}.main-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.main-tools ::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:12px;font-weight:500;color:#fff}.geometry-selector{width:100%}.geometry-selector ::ng-deep .mat-mdc-select{font-size:14px;line-height:1.4;border-radius:6px}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:32px;min-height:32px;padding:0 10px;border:none;border-radius:6px;background:color-mix(in srgb,#000 60%,transparent);transition:all .2s ease}.geometry-selector ::ng-deep .mat-mdc-select-trigger:hover{background:color-mix(in srgb,#000 70%,transparent);border-color:#667eea;box-shadow:0 4px 12px #0003}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:14px;font-weight:500;color:#fff}.geometry-selector ::ng-deep .mat-mdc-select-arrow-wrapper{height:16px;transform:scale(.85)}.geometry-selector ::ng-deep .mat-mdc-form-field-infix{min-height:32px;padding:6px 0}.geometry-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}::ng-deep .mat-mdc-select-panel{min-width:fit-content!important;max-width:320px!important;background:color-mix(in srgb,#000 100%,transparent)!important;border:none!important;border-radius:8px!important;box-shadow:0 8px 24px #0000001f,0 2px 6px #00000014!important;margin-top:6px!important;padding:4px 0!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:14px!important;min-height:36px!important;padding:8px 14px!important;transition:all .15s ease!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option:hover:not(.mat-mdc-option-disabled){background:#444849!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option.mat-active{background:color-mix(in srgb,#000 60%,transparent)!important;color:#fff!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px!important;font-weight:500!important;color:#fff!important}::ng-deep .cdk-overlay-pane{z-index:1001}::ng-deep .cdk-overlay-backdrop{z-index:1000}.geometry-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.measurement-print-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap;background:color-mix(in srgb,#000 20%,transparent);border-radius:8px;padding:4px 8px;border:1px solid rgba(255,255,255,.1)}.measurement-tools,.print-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.measurement-tools .compact-icon,.print-tools .compact-icon{transition:all .3s cubic-bezier(.4,0,.2,1)}.measurement-tools .compact-icon.custom-image-icon,.print-tools .compact-icon.custom-image-icon{padding:4px;background:none;border:1px solid rgba(255,255,255,.2)}.measurement-tools .compact-icon.custom-image-icon img,.print-tools .compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:filter .2s ease}.measurement-tools .compact-icon.custom-image-icon.active,.print-tools .compact-icon.custom-image-icon.active{background:linear-gradient(147.38deg,#0ea5e9,#075985);border-color:transparent;box-shadow:0 4px 12px #0ea5e966}.measurement-tools .compact-icon.custom-image-icon.active img,.print-tools .compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1)}.measurement-tools .compact-icon.custom-image-icon.active:hover,.print-tools .compact-icon.custom-image-icon.active:hover{box-shadow:0 6px 20px #0ea5e980}.measurement-tools .compact-icon.custom-image-icon:hover:not(.active),.print-tools .compact-icon.custom-image-icon:hover:not(.active){background:color-mix(in srgb,#000 70%,transparent);border-color:#0ea5e9;box-shadow:0 2px 8px #0ea5e94d}.measurement-tools .compact-icon.custom-image-icon:hover:not(.active) img,.print-tools .compact-icon.custom-image-icon:hover:not(.active) img{filter:brightness(0) invert(.8)}.print-tools .compact-icon{background:linear-gradient(147.38deg,#4f46e5,#3730a3);color:#fff;border:1px solid rgba(255,255,255,.2)}.print-tools .compact-icon.print-icon{background:linear-gradient(147.38deg,#10b981,#047857)}.print-tools .compact-icon.draw-icon{background:linear-gradient(147.38deg,#f59e0b,#d97706)}.print-tools .compact-icon.active{background:linear-gradient(147.38deg,#ef4444,#dc2626);box-shadow:0 4px 12px #ef444466;border-color:transparent;transform:scale(1.05)}.print-tools .compact-icon.active:hover{box-shadow:0 6px 20px #ef444480;transform:scale(1.08)}.print-tools .compact-icon:hover:not(.active){box-shadow:0 4px 12px #0000004d;opacity:.9}.tool-separator{width:1px;height:24px;background:linear-gradient(to bottom,transparent,rgba(255,255,255,.3),transparent);margin:0 4px}.tool-separator.print-separator{height:28px;background:linear-gradient(to bottom,transparent,rgba(255,255,255,.5),transparent)}.compact-icon{cursor:pointer;color:#fff;transition:all .3s cubic-bezier(.4,0,.2,1);width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:6px;background:color-mix(in srgb,#000 40%,transparent);border:1px solid rgba(255,255,255,.2);box-shadow:0 1px 2px #0000001a;flex-shrink:0}.compact-icon.active{color:#fff;background:linear-gradient(135deg,#667eea,#764ba2);border-color:transparent;box-shadow:0 8px 25px #667eea4d;transform:scale(1.05)}.compact-icon.active:hover{box-shadow:0 12px 35px #667eea66;transform:scale(1.08)}.compact-icon:hover:not(.active){color:#fff;background:color-mix(in srgb,#000 70%,transparent);border-color:#667eea;box-shadow:0 4px 12px #0003}.compact-icon.custom-image-icon{padding:0;background:none;border:none}.compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:transform .2s ease}.compact-icon.custom-image-icon.active{background:linear-gradient(135deg,#667eea,#764ba2);border-color:transparent}.compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1);transform:scale(1.1)}.compact-icon.custom-image-icon:hover:not(.active) img{transform:scale(1.05)}.wkt-section{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid rgba(255,255,255,.1);animation:fadeIn .2s ease}.wkt-actions{display:flex;gap:6px;justify-content:space-between}.compact-button{padding:6px 10px;border:none;border-radius:6px;background:color-mix(in srgb,#000 60%,transparent);color:#fff;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);text-transform:uppercase;letter-spacing:.4px;min-height:32px;display:flex;align-items:center;justify-content:center;flex:1;box-shadow:0 1px 2px #0000000d}.compact-button.primary.active{background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 8px 25px #667eea4d;color:#fff}.compact-button.primary.active:hover{box-shadow:0 12px 35px #667eea66}.compact-button.secondary{background:color-mix(in srgb,#000 20%,transparent);color:#fff}.compact-button.secondary:hover{background:color-mix(in srgb,#5a6268 60%,transparent)}.compact-button:hover:not(.active){background:color-mix(in srgb,#000 70%,transparent);color:#fff}.compact-input{padding:8px 10px;border:none;border-radius:6px;font-size:13px;transition:all .2s ease;background:color-mix(in srgb,#000 60%,transparent);color:#fff}.compact-input:focus{outline:none;border-color:#1976d2;background:color-mix(in srgb,#000 70%,transparent);box-shadow:0 0 0 3px #1976d233}.print-config,.print-draw-config{display:flex;align-items:center;gap:8px;padding:5px;background:color-mix(in srgb,#000 40%,transparent);border-radius:8px;border:1px solid rgba(255,255,255,.1);animation:slideDown .3s ease}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{background:color-mix(in srgb,#000 60%,transparent);border:1px solid rgba(255,255,255,.2);color:#fff;border-radius:6px;font-size:12px;height:32px;min-height:32px;padding:0 10px}.print-config select:focus,.print-config input:focus,.print-draw-config select:focus,.print-draw-config input:focus{outline:none;border-color:#0ea5e9;box-shadow:0 0 0 2px #0ea5e933}.print-config select,.print-draw-config select{cursor:pointer}.print-config option,.print-draw-config option{background:color-mix(in srgb,#000 98%,transparent)!important;border:none!important}.print-config input,.print-draw-config input{width:60px;text-align:center}.print-config button,.print-draw-config button{background:linear-gradient(147.38deg,#10b981,#047857);color:#fff;border:none;padding:6px 12px;border-radius:4px;font-size:12px;cursor:pointer;transition:all .2s ease}.print-config button:hover,.print-draw-config button:hover{box-shadow:0 4px 12px #10b9814d}.print-config .icon-separator,.print-draw-config .icon-separator{color:#70706f}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes pulse{0%{box-shadow:0 0 #667eeab3}70%{box-shadow:0 0 0 6px #667eea00}to{box-shadow:0 0 #667eea00}}.compact-icon.active{animation:pulse 2s infinite}@media (max-width: 768px){.toolbox-wrapper{left:.5em;top:8em;max-width:calc(100vw - 2.5em)}.drag-handle-toolbox{padding:3px 6px;gap:6px}.drag-handle-toolbox mat-icon{font-size:16px;width:16px;height:16px}.toggle-icon{font-size:16px!important;width:16px!important;height:16px!important}.toolbox-container{padding:8px;min-width:28px;max-width:calc(100vw - 3em)}:host{padding:8px;min-width:32px}:host.expanded{min-width:280px;padding:10px}.all-tools-container{flex-wrap:wrap;gap:6px;max-height:50vh;overflow-y:auto;padding:0;-ms-overflow-style:none;scrollbar-width:none}.all-tools-container::-webkit-scrollbar{display:none}.main-tools,.geometry-tools,.measurement-print-tools,.print-tools{display:flex;flex-wrap:wrap;justify-content:center;gap:4px}.compact-icon{width:28px;height:28px;flex-shrink:0}.measurement-print-tools{padding:3px 6px}.geometry-selector{width:100%;margin-bottom:8px}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:28px;min-height:28px;padding:0 8px;font-size:12px}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:12px}::ng-deep .mat-mdc-select-panel{max-width:calc(100vw - 2em)!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:13px!important;min-height:32px!important;padding:6px 12px!important}.print-config,.print-draw-config{flex-direction:column;align-items:stretch;gap:6px}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{font-size:11px;padding:4px 8px;height:28px;min-height:28px}.print-config input,.print-draw-config input{width:50px}.print-config button,.print-draw-config button{padding:4px 8px;font-size:11px;height:28px}.wkt-section .compact-input{font-size:12px;padding:6px 8px}.wkt-section .compact-button{font-size:11px;padding:5px 8px;min-height:28px}::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:11px!important}}@media (max-width: 480px){.toolbox-wrapper{left:.25em;top:6em;transform-origin:left top;max-width:calc(100vw - .5em)}.drag-handle-toolbox{padding:2px 4px;gap:4px}.drag-handle-toolbox mat-icon{font-size:14px;width:14px;height:14px}.toggle-icon{font-size:14px!important;width:14px!important;height:14px!important}.toolbox-container{padding:6px;min-width:24px}.toolbox-content{gap:8px}.all-tools-container{flex-direction:row;align-items:center;max-height:60vh}.main-tools,.geometry-tools{gap:3px;flex-wrap:wrap;justify-content:center}.measurement-print-tools{gap:3px;flex-wrap:wrap;padding:2px 4px;width:100%;justify-content:center}.measurement-tools,.print-tools{gap:3px}.compact-icon{width:26px;height:26px}.tool-separator{display:none}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:26px;min-height:26px;padding:0 6px;font-size:11px}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:11px}.compact-button{font-size:10px;letter-spacing:.2px;padding:4px 6px;min-height:26px}.compact-input{font-size:11px;padding:4px 6px}.print-config,.print-draw-config{gap:4px;padding:6px}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{font-size:10px;height:26px;min-height:26px;padding:2px 6px}.print-config input,.print-draw-config input{width:45px}.print-config button,.print-draw-config button{flex:1;min-width:60px;font-size:10px;padding:3px 6px;height:26px}.print-config .icon-separator,.print-draw-config .icon-separator{font-size:10px}.wkt-section{gap:6px;padding-top:8px}::ng-deep .mat-mdc-slide-toggle{transform:scale(.9)}::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:10px!important}::ng-deep .mat-mdc-select-panel{max-width:calc(100vw - 1em)!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:12px!important;min-height:28px!important;padding:4px 10px!important}}::ng-deep .mat-mdc-simple-snack-bar{background-color:#fff!important}::ng-deep .mat-mdc-tooltip{--mdc-plain-tooltip-container-color: #050505 !important;--mdc-plain-tooltip-supporting-text-color: white !important;border-radius:6px}::ng-deep .mat-mdc-tooltip .mdc-tooltip__surface{background-color:#050505!important;color:#fff!important;border-radius:6px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "component", type: i4$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i4.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i4.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i8.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] });
|
|
3071
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: ToolboxComponent, isStandalone: true, selector: "map-toolbox", inputs: { map: "map", showMeasureDistance: "showMeasureDistance", showMeasureArea: "showMeasureArea", collapsed: "collapsed", settings: "settings", profile: "profile", WKTInputEnabled: "WKTInputEnabled", deleteEnabled: "deleteEnabled" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"toolbox-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\"\n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\">\n <div class=\"drag-handle-toolbox\" cdkDragHandle>\n <mat-icon class=\"left-icon\">handyman</mat-icon>\n \n <div class=\"right-icons\">\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleCollapsed($event)\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n </div>\n \n <div class=\"toolbox-container\" [class.collapsed]=\"collapsed\">\n @if(!collapsed) {\n <div class=\"toolbox-content\">\n @if (showGeometryTypes && filteredGeometryTypeSettings.length > 0) {\n <mat-select class=\"geometry-selector\" (selectionChange)=\"settingsChanged($event)\" [(ngModel)]=\"selectedGeometrySetting\" [compareWith]=\"compareGeometrySetting\">\n @for (setting of filteredGeometryTypeSettings; track setting) {\n <mat-option [value]=\"setting\">{{setting.typeName}}</mat-option>\n }\n </mat-select> \n }\n <div class=\"all-tools-container\">\n <div class=\"main-tools\">\n @if(!settings?.undoDisabled) {\n <img \n [src]=\"undoIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"undo()\" \n matTooltip=\"Fortryd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Undo\">\n\n <img \n [src]=\"redoIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"redo()\" \n matTooltip=\"Gendan\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Redo\">\n }\n <mat-icon \n class=\"compact-icon\" \n (click)=\"startShowInfo()\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Vis info\" \n matTooltipPosition=\"below\">\n info\n </mat-icon>\n <mat-icon \n class=\"compact-icon\" \n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"S\u00F8g punkt\" \n matTooltipPosition=\"below\"\n (click)=\"togglePointSearch()\">adjust\n </mat-icon>\n <mat-icon \n class=\"compact-icon\" \n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"S\u00F8g polygon\" \n matTooltipPosition=\"below\"\n (click)=\"togglePolygonSearch()\">crop_din\n </mat-icon>\n <mat-icon\n class=\"compact-icon\" \n (click)=\"startSelectFeatureHighlight()\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Fremh\u00E6v\" \n matTooltipPosition=\"below\"\n >star</mat-icon> // TODO: set correct icon for this\n\n <mat-slide-toggle [(ngModel)]=\"snap\" (change)=\"onSnapChange()\">Snap</mat-slide-toggle>\n @if(settings.editEnabled) {\n <img \n [src]=\"editIconBase64\" \n [class.active]=\"activeMode === 'edit'\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"startEdit()\" \n matTooltip=\"Rediger\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Rediger\">\n\n <img \n [src]=\"removePointsIconBase64\" \n [class.active]=\"activeMode === 'edit-remove'\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"startEditRemovePoints()\" \n matTooltip=\"Fjern punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Fjern punkter\">\n }\n @if(settings.cutHoleEnabled) {\n <img \n [src]=\"trimIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'clip-hole'\" \n (click)=\"clipHole()\" \n matTooltip=\"Klip hul\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Klip hul\">\n }\n @if(settings.splitEnabled) {\n <img \n [src]=\"splitIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'split'\"\n (click)=\"split()\" \n matTooltip=\"Sk\u00E6r over\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Sk\u00E6r over\">\n }\n @if(settings.changeTypeEnabled) {\n <mat-icon \n class=\"compact-icon\" \n [class.active]=\"activeMode === 'change-type'\" \n (click)=\"startChangeType()\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Skift type\" \n matTooltipPosition=\"below\">\n find_replace\n </mat-icon>\n }\n @if(settings.mergeEnabled) {\n <mat-icon \n class=\"compact-icon\" \n (click)=\"startMergeFeatures()\" \n matTooltipPosition=\"below\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Saml flader\" \n [class.active]=\"activeMode === 'merge-features'\">\n merge\n </mat-icon>\n }\n @if(settings.centerPoint) {\n <mat-icon\n (click)=\"setCenterPoint()\"\n matTooltipPosition=\"below\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"S\u00E6t centerpunkt\" \n [class.active]=\"activeMode === 'center-point'\"\n >adjust</mat-icon>\n }\n </div>\n <div class=\"geometry-tools\">\n <img \n [src]=\"featureSearchIconBase64\" \n [class.active]=\"activeMode === 'search-feature'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"toggleFeatureSearch()\" \n matTooltip=\"Udpegede objekter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Punkt\">\n\n <img \n [src]=\"polygonIconBase64\" \n [class.active]=\"activeMode === 'draw-polygon'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPolygon()\" \n matTooltip=\"Polygon\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Polygon\">\n <img \n [src]=\"lineStringIconBase64\" \n [class.active]=\"activeMode === 'draw-linestring'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawLineString()\" \n matTooltip=\"LineString\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"LineString\">\n \n @if(selectedGeometrySetting && selectedGeometrySetting.icons && selectedGeometrySetting.icons.length > 0) {\n @for(iconUrl of selectedGeometrySetting.icons;track iconUrl) {\n <img \n [src]=\"iconUrl\" \n [class.active]=\"activeMode === 'draw-point'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPointUrl(iconUrl)\" \n matTooltip=\"Punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Punkter\">}\n } @else {\n <img \n [src]=\"pointIconBase64\" \n [class.active]=\"activeMode === 'draw-point'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPoint()\" \n matTooltip=\"Punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Punkter\">\n }\n <img \n [src]=\"wktIconBase64\" \n class=\"compact-icon secondary custom-image-icon\"\n (click)=\"activateShowInputWKT()\" \n matTooltip=\"WKT\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"WKT\">\n </div>\n <div class=\"tool-separator\" *ngIf=\"deleteEnabled || showMeasureDistance || showMeasureArea || profile.showPrint\"></div>\n <div class=\"measurement-print-tools\">\n <div class=\"measurement-tools\">\n @if (deleteEnabled) {\n <img \n [src]=\"deleteIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'delete'\"\n (click)=\"startDelete()\" \n matTooltip=\"Slet\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Slet\">\n }\n @if (showMeasureDistance) {\n <img \n [src]=\"measureDistanceIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'measure-distance'\"\n (click)=\"startMeasureLength()\" \n matTooltip=\"M\u00E5le afstand\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"M\u00E5le afstand\">\n }\n @if(showMeasureArea) {\n <img \n [src]=\"measureAreaIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'measure-area'\"\n (click)=\"startMeasureArea()\" \n matTooltip=\"M\u00E5le areal\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"M\u00E5le areal\">\n }\n </div>\n @if(profile.showPrint) {\n <div class=\"tool-separator print-separator\"></div>\n <div class=\"print-tools\">\n <img \n [src]=\"printBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"active === 'Print'\"\n (click)=\"startPrintMode()\" \n matTooltip=\"Udskriv\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Udskriv\">\n <img \n [src]=\"drawBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"active === 'Draw'\"\n (click)=\"startDrawMode()\" \n matTooltip=\"Tegn\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Tegn\">\n </div>\n }\n </div>\n </div>\n @if(showInputWKT) {\n <div class=\"wkt-section\">\n <input class=\"compact-input\" [(ngModel)]=\"WKTString\">\n <div class=\"wkt-actions\">\n <button class=\"compact-button primary\" (click)=\"ReadWKT()\">Indl\u00E6s WKT</button>\n <button class=\"compact-button\" (click)=\"cancelWKT()\">Annuller</button>\n </div>\n </div>\n }\n @if(profile.showPrint) {\n @if(active === \"Print\") {\n <div class=\"print-config\">\n <img \n [src]=\"printBase64\" \n class=\"compact-icon\"\n (click)=\"doPrint()\" \n alt=\"Udskriv\"> \n <span class=\"icon-separator\">i</span>\n <select id=\"formatSelector\" [(ngModel)]=\"format\">\n <option value=\"image/png\" selected>.PNG</option>\n <option value=\"image/jpeg\">.JPG</option>\n </select>\n <select id=\"dimensionSelector\" [(ngModel)]=\"dimId\" (change)=\"handleDimensionSelected()\">\n <option value=\"99\" selected></option>\n <option value=\"0\">1920 X 1080</option>\n <option value=\"1\">1680 X 1050</option>\n <option value=\"2\">1280 X 800</option>\n <option value=\"3\">800 X 600</option>\n </select>\n <input type=\"text\" [(ngModel)]=\"mapWidth\"/> \n <span class=\"icon-separator\">x</span>\n <input type=\"text\" [(ngModel)]=\"mapHeight\"/>\n <button (click)=\"setNewMapDimensions()\">V\u00E6lg</button>\n </div>\n }\n @if(active === \"PrintDraw\") {\n <div class=\"print-draw-config\">\n <span class=\"icon-separator\">Label</span>\n <input type=\"text\" [(ngModel)]=\"printDrawLabel\"/>\n <select id=\"drawToolSelector\" [(ngModel)]=\"printDrawTool\" (change)=\"handlePrintDrawToolChanged()\">\n <option value=\"Arrow\" selected>Pil</option>\n <option value=\"Point\">Punkt</option>\n <option value=\"LineString\">Linje</option>\n <option value=\"Polygon\">Polygon</option>\n <option value=\"Circle\">Cirkel</option>\n <option value=\"Square\">Kvadrat</option>\n <option value=\"Rectangle\">Firkant</option>\n </select>\n <button class=\"compact-button\" (click)=\"handleClearPrintDrawFeatures()\">Ryd</button>\n </div>\n }\n }\n </div>\n }\n </div>\n @if (activeMode === 'search-feature' && filteredResults.length > 0) {\n <div class=\"geometry-search-panel\">\n <div class=\"buffer-item\">\n <mat-label>Buffer</mat-label>\n <input matInput type=\"number\" name=\"buffer\" [(ngModel)]=\"bufferInMeters\">\n <mat-label>m</mat-label>\n </div>\n <mat-option *ngFor=\"let result of filteredResults\" [value]=\"result\" class=\"search-result-option\">\n <span class=\"result-title\">\n {{ result.title }} ({{result.items.length}} af {{ result.total }})\n </span>\n <div (click)=\"highlight(item.wkt, $event)\" *ngFor=\"let item of result.items\" class=\"search-result-item\">\n <div class=\"item-left\">\n <span class=\"item-header\"> {{item.header}} </span> \n </div>\n <div class=\"item-right\">\n <img \n [src]=\"objectSearchCopyIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"addToActiveObjectsList(item, $event)\" \n matTooltip=\"Kopier\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Kopier\">\n <img \n [src]=\"objectSearchCutIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"cutBySearchedObject(item, $event)\" \n matTooltip=\"Fjern\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Fjern\">\n <img \n [src]=\"objectSearchCutIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"splitBySearchedObject(item, $event)\" \n matTooltip=\"Opsk\u00E6r\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Opsk\u00E6r\">\n <img \n [src]=\"objectSearchCopyWithBufferIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"addToActiveObjectsList(item, $event, true)\" \n matTooltip=\"Kopier med buffer\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Kopier med buffer\">\n <img \n [src]=\"objectSearchZoomIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"zoomSearchedObject(item, $event)\" \n matTooltip=\"Zoom\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Zoom\">\n <button\n (click)=\"toggleItemInfo(item, $event)\">\n <mat-icon class=\"button-icon\">info_outline</mat-icon>\n </button>\n </div> \n @if (item.showMetadata) {\n <div class=\"metadata-panel\">\n @for(feature of item.metadata; track feature) {\n <div class=\"feature-item\">\n <div *ngFor=\"let kv of (feature | keyvalue)\">\n {{ kv.value.name }}:\n <ng-container [ngSwitch]=\"kv.value.kind\">\n <img *ngSwitchCase=\"'img'\" [src]=\"kv.value.data\" alt=\"{{ kv.key }}\" style=\"max-width:240px;\" />\n <a *ngSwitchCase=\"'url'\" [href]=\"kv.value.data\" target=\"_blank\" rel=\"noopener noreferrer\">\n {{ kv.key }}\n <mat-icon class=\"link-icon\">open_in_new</mat-icon>\n </a>\n <span *ngSwitchDefault>{{ kv.value.data }}</span>\n </ng-container>\n </div>\n </div>\n }\n </div>\n }\n </div>\n </mat-option>\n </div>\n }\n @if ((activeMode === \"search-point\" || activeMode === \"search-polygon\") && filteredResults.length > 0) {\n <div class=\"geometry-search-panel\">\n <mat-option *ngFor=\"let result of filteredResults\" [value]=\"result\" class=\"search-result-option\">\n <span class=\"result-title\">\n {{ result.title }} ({{result.items.length}} af {{ result.total }})\n </span>\n <div (click)=\"highlight(item.wkt, $event)\" *ngFor=\"let item of result.items\" class=\"search-result-item\">\n <div class=\"item-left\">\n <span class=\"item-header\"> {{item.header}} </span> \n </div>\n </div>\n </mat-option>\n </div>\n }\n</div>\n", styles: [".toolbox-wrapper{position:absolute;left:1em;top:10em;z-index:10;cursor:grab;max-width:95vw}.toolbox-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}::ng-deep .metadata-panel{margin-top:5px;margin-bottom:5px;border:white;border-width:2px}::ng-deep .geometry-search-panel{border-radius:5px!important;max-height:320px!important;background:color-mix(in srgb,#000 85%,transparent)!important;box-shadow:0 8px 24px #00000026!important;margin-top:10px;overflow-y:auto!important;padding:8px!important;max-width:430px}::ng-deep .geometry-search-panel .buffer-item{align-items:end}::ng-deep .geometry-search-panel .buffer-item input{width:45px;margin:5px}::ng-deep .geometry-search-panel .search-result-item{display:flex;flex-wrap:wrap;margin:5px}::ng-deep .geometry-search-panel .search-result-item .item-left{display:flex;align-items:center;gap:3px;flex:1;min-width:0}::ng-deep .geometry-search-panel .search-result-item .item-right{display:flex;align-items:center;flex:1;justify-content:flex-end;min-width:0;margin-left:10px}::ng-deep .geometry-search-panel .search-result-item .item-right .custom-image-icon{background:#fff!important;margin-left:5px}::ng-deep .geometry-search-panel .search-result-item .item-right button{width:38px;margin-left:5px}::ng-deep .geometry-search-panel .search-result-item .metadata-panel{flex-basis:98%}::ng-deep .geometry-search-panel::-webkit-scrollbar{width:12px}::ng-deep .geometry-search-panel::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .geometry-search-panel::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .geometry-search-panel::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .geometry-search-panel::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .geometry-search-panel::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .geometry-search-panel::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .geometry-search-panel::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .geometry-search-panel::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}::ng-deep .geometry-search-panel .mat-mdc-option{min-height:30px!important;border-radius:5px!important;transition:all .2s cubic-bezier(.4,0,.2,1);position:relative;overflow:auto;margin-bottom:6px!important;padding:8px 0!important}::ng-deep .geometry-search-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px;font-weight:400;color:#fff;line-height:1.5}::ng-deep .geometry-search-panel mat-label{color:#fff}.drag-handle-toolbox{display:flex;align-items:center;justify-content:space-between;background:#292a2d;padding:2px 8px;cursor:grab;gap:8px;border-radius:5px 5px 0 0;color:#fff}.drag-handle-toolbox mat-icon{color:#fff;font-size:18px;width:18px;height:18px}.drag-handle-toolbox mat-icon:first-child{flex:1;text-align:left}.right-icons{display:flex;align-items:center;gap:6px}.left-icon{flex-shrink:0}.toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.toggle-icon:hover{color:#fff;background:#ffffff26}.toggle-icon:active{background:#ffffff40}:host{position:relative;display:flex;justify-content:center}:host.expanded{width:auto;min-width:320px;padding:12px}.toolbox-container{display:flex;flex-direction:column;align-items:center;width:100%;gap:10px;background:#292a2d;box-shadow:#0000004d 0 1px 4px -1px;padding:10px;width:auto;min-width:32px;transition:all .3s ease;cursor:default;border-radius:0 0 5px 5px}.toolbox-container.collapsed{display:none}.toolbox-content{display:flex;flex-direction:column;width:100%;gap:3px;animation:slideDown .3s cubic-bezier(.4,0,.2,1)}.all-tools-container{display:flex;flex-direction:row;align-items:center;flex-wrap:nowrap;width:100%;justify-content:flex-start;overflow-x:hidden}.all-tools-container::-webkit-scrollbar{height:4px}.all-tools-container::-webkit-scrollbar-thumb{background:#ccc;border-radius:2px}.main-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.main-tools ::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:12px;font-weight:500;color:#fff}.geometry-selector{width:100%}.geometry-selector ::ng-deep .mat-mdc-select{font-size:14px;line-height:1.4;border-radius:6px}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:32px;min-height:32px;padding:0 10px;border:none;border-radius:6px;background:color-mix(in srgb,#000 60%,transparent);transition:all .2s ease}.geometry-selector ::ng-deep .mat-mdc-select-trigger:hover{background:color-mix(in srgb,#000 70%,transparent);border-color:#667eea;box-shadow:0 4px 12px #0003}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:14px;font-weight:500;color:#fff}.geometry-selector ::ng-deep .mat-mdc-select-arrow-wrapper{height:16px;transform:scale(.85)}.geometry-selector ::ng-deep .mat-mdc-form-field-infix{min-height:32px;padding:6px 0}.geometry-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}::ng-deep .mat-mdc-select-panel{min-width:fit-content!important;max-width:320px!important;background:color-mix(in srgb,#000 100%,transparent)!important;border:none!important;border-radius:8px!important;box-shadow:0 8px 24px #0000001f,0 2px 6px #00000014!important;margin-top:6px!important;padding:4px 0!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:14px!important;min-height:36px!important;padding:8px 14px!important;transition:all .15s ease!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option:hover:not(.mat-mdc-option-disabled){background:#444849!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option.mat-active{background:color-mix(in srgb,#000 60%,transparent)!important;color:#fff!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px!important;font-weight:500!important;color:#fff!important}::ng-deep .cdk-overlay-pane{z-index:1001}::ng-deep .cdk-overlay-backdrop{z-index:1000}.geometry-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.measurement-print-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap;background:color-mix(in srgb,#000 20%,transparent);border-radius:8px;padding:4px 8px;border:1px solid rgba(255,255,255,.1)}.measurement-tools,.print-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.measurement-tools .compact-icon,.print-tools .compact-icon{transition:all .3s cubic-bezier(.4,0,.2,1)}.measurement-tools .compact-icon.custom-image-icon,.print-tools .compact-icon.custom-image-icon{padding:4px;background:none;border:1px solid rgba(255,255,255,.2)}.measurement-tools .compact-icon.custom-image-icon img,.print-tools .compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:filter .2s ease}.measurement-tools .compact-icon.custom-image-icon.active,.print-tools .compact-icon.custom-image-icon.active{background:linear-gradient(147.38deg,#0ea5e9,#075985);border-color:transparent;box-shadow:0 4px 12px #0ea5e966}.measurement-tools .compact-icon.custom-image-icon.active img,.print-tools .compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1)}.measurement-tools .compact-icon.custom-image-icon.active:hover,.print-tools .compact-icon.custom-image-icon.active:hover{box-shadow:0 6px 20px #0ea5e980}.measurement-tools .compact-icon.custom-image-icon:hover:not(.active),.print-tools .compact-icon.custom-image-icon:hover:not(.active){background:color-mix(in srgb,#000 70%,transparent);border-color:#0ea5e9;box-shadow:0 2px 8px #0ea5e94d}.measurement-tools .compact-icon.custom-image-icon:hover:not(.active) img,.print-tools .compact-icon.custom-image-icon:hover:not(.active) img{filter:brightness(0) invert(.8)}.print-tools .compact-icon{background:linear-gradient(147.38deg,#4f46e5,#3730a3);color:#fff;border:1px solid rgba(255,255,255,.2)}.print-tools .compact-icon.print-icon{background:linear-gradient(147.38deg,#10b981,#047857)}.print-tools .compact-icon.draw-icon{background:linear-gradient(147.38deg,#f59e0b,#d97706)}.print-tools .compact-icon.active{background:linear-gradient(147.38deg,#ef4444,#dc2626);box-shadow:0 4px 12px #ef444466;border-color:transparent;transform:scale(1.05)}.print-tools .compact-icon.active:hover{box-shadow:0 6px 20px #ef444480;transform:scale(1.08)}.print-tools .compact-icon:hover:not(.active){box-shadow:0 4px 12px #0000004d;opacity:.9}.tool-separator{width:1px;height:24px;background:linear-gradient(to bottom,transparent,rgba(255,255,255,.3),transparent);margin:0 4px}.tool-separator.print-separator{height:28px;background:linear-gradient(to bottom,transparent,rgba(255,255,255,.5),transparent)}.compact-icon{cursor:pointer;color:#fff;transition:all .3s cubic-bezier(.4,0,.2,1);width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:6px;background:color-mix(in srgb,#000 40%,transparent);border:1px solid rgba(255,255,255,.2);box-shadow:0 1px 2px #0000001a;flex-shrink:0}.compact-icon.active{color:#fff;background:linear-gradient(135deg,#667eea,#764ba2);border-color:transparent;box-shadow:0 8px 25px #667eea4d;transform:scale(1.05)}.compact-icon.active:hover{box-shadow:0 12px 35px #667eea66;transform:scale(1.08)}.compact-icon:hover:not(.active){color:#fff;background:color-mix(in srgb,#000 70%,transparent);border-color:#667eea;box-shadow:0 4px 12px #0003}.compact-icon.custom-image-icon{padding:0;background:none;border:none}.compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:transform .2s ease}.compact-icon.custom-image-icon.active{background:linear-gradient(135deg,#667eea,#764ba2);border-color:transparent}.compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1);transform:scale(1.1)}.compact-icon.custom-image-icon:hover:not(.active) img{transform:scale(1.05)}.wkt-section{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid rgba(255,255,255,.1);animation:fadeIn .2s ease}.wkt-actions{display:flex;gap:6px;justify-content:space-between}.compact-button{padding:6px 10px;border:none;border-radius:6px;background:color-mix(in srgb,#000 60%,transparent);color:#fff;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);text-transform:uppercase;letter-spacing:.4px;min-height:32px;display:flex;align-items:center;justify-content:center;flex:1;box-shadow:0 1px 2px #0000000d}.compact-button.primary.active{background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 8px 25px #667eea4d;color:#fff}.compact-button.primary.active:hover{box-shadow:0 12px 35px #667eea66}.compact-button.secondary{background:color-mix(in srgb,#000 20%,transparent);color:#fff}.compact-button.secondary:hover{background:color-mix(in srgb,#5a6268 60%,transparent)}.compact-input{padding:8px 10px;border:none;border-radius:6px;font-size:13px;transition:all .2s ease;background:color-mix(in srgb,#000 60%,transparent);color:#fff}.compact-input:focus{outline:none;border-color:#1976d2;background:color-mix(in srgb,#000 70%,transparent);box-shadow:0 0 0 3px #1976d233}.print-config,.print-draw-config{display:flex;align-items:center;gap:8px;padding:5px;background:color-mix(in srgb,#000 40%,transparent);border-radius:8px;border:1px solid rgba(255,255,255,.1);animation:slideDown .3s ease}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{background:color-mix(in srgb,#000 60%,transparent);border:1px solid rgba(255,255,255,.2);color:#fff;border-radius:6px;font-size:12px;height:32px;min-height:32px;padding:0 10px}.print-config select:focus,.print-config input:focus,.print-draw-config select:focus,.print-draw-config input:focus{outline:none;border-color:#0ea5e9;box-shadow:0 0 0 2px #0ea5e933}.print-config select,.print-draw-config select{cursor:pointer}.print-config option,.print-draw-config option{background:color-mix(in srgb,#000 98%,transparent)!important;border:none!important}.print-config input,.print-draw-config input{width:60px;text-align:center}.print-config button,.print-draw-config button{background:linear-gradient(147.38deg,#10b981,#047857);color:#fff;border:none;padding:6px 12px;border-radius:4px;font-size:12px;cursor:pointer;transition:all .2s ease}.print-config button:hover,.print-draw-config button:hover{box-shadow:0 4px 12px #10b9814d}.print-config .icon-separator,.print-draw-config .icon-separator{color:#fff}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes pulse{0%{box-shadow:0 0 #667eeab3}70%{box-shadow:0 0 0 6px #667eea00}to{box-shadow:0 0 #667eea00}}.compact-icon.active{animation:pulse 2s infinite}@media (max-width: 768px){.toolbox-wrapper{left:.5em;top:8em;max-width:calc(100vw - 2.5em)}.drag-handle-toolbox{padding:3px 6px;gap:6px}.drag-handle-toolbox mat-icon{font-size:16px;width:16px;height:16px}.toggle-icon{font-size:16px!important;width:16px!important;height:16px!important}.toolbox-container{padding:8px;min-width:28px;max-width:calc(100vw - 3em)}:host{padding:8px;min-width:32px}:host.expanded{min-width:280px;padding:10px}.all-tools-container{flex-wrap:wrap;gap:6px;max-height:50vh;overflow-y:auto;padding:0;-ms-overflow-style:none;scrollbar-width:none}.all-tools-container::-webkit-scrollbar{display:none}.main-tools,.geometry-tools,.measurement-print-tools,.print-tools{display:flex;flex-wrap:wrap;justify-content:center;gap:4px}.compact-icon{width:28px;height:28px;flex-shrink:0}.measurement-print-tools{padding:3px 6px}.geometry-selector{width:100%;margin-bottom:8px}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:28px;min-height:28px;padding:0 8px;font-size:12px}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:12px}::ng-deep .mat-mdc-select-panel{max-width:calc(100vw - 2em)!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:13px!important;min-height:32px!important;padding:6px 12px!important}.print-config,.print-draw-config{flex-direction:column;align-items:stretch;gap:6px}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{font-size:11px;padding:4px 8px;height:28px;min-height:28px}.print-config input,.print-draw-config input{width:50px}.print-config button,.print-draw-config button{padding:4px 8px;font-size:11px;height:28px}.wkt-section .compact-input{font-size:12px;padding:6px 8px}.wkt-section .compact-button{font-size:11px;padding:5px 8px;min-height:28px}::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:11px!important}}@media (max-width: 480px){.toolbox-wrapper{left:.25em;top:6em;transform-origin:left top;max-width:calc(100vw - .5em)}.drag-handle-toolbox{padding:2px 4px;gap:4px}.drag-handle-toolbox mat-icon{font-size:14px;width:14px;height:14px}.toggle-icon{font-size:14px!important;width:14px!important;height:14px!important}.toolbox-container{padding:6px;min-width:24px}.toolbox-content{gap:8px}.all-tools-container{flex-direction:row;align-items:center;max-height:60vh}.main-tools,.geometry-tools{gap:3px;flex-wrap:wrap;justify-content:center}.measurement-print-tools{gap:3px;flex-wrap:wrap;padding:2px 4px;width:100%;justify-content:center}.measurement-tools,.print-tools{gap:3px}.compact-icon{width:26px;height:26px}.tool-separator{display:none}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:26px;min-height:26px;padding:0 6px;font-size:11px}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:11px}.compact-button{font-size:10px;letter-spacing:.2px;padding:4px 6px;min-height:26px}.compact-input{font-size:11px;padding:4px 6px}.print-config,.print-draw-config{gap:4px;padding:6px}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{font-size:10px;height:26px;min-height:26px;padding:2px 6px}.print-config input,.print-draw-config input{width:45px}.print-config button,.print-draw-config button{flex:1;min-width:60px;font-size:10px;padding:3px 6px;height:26px}.print-config .icon-separator,.print-draw-config .icon-separator{font-size:10px}.wkt-section{gap:6px;padding-top:8px}::ng-deep .mat-mdc-slide-toggle{transform:scale(.9)}::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:10px!important}::ng-deep .mat-mdc-select-panel{max-width:calc(100vw - 1em)!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:12px!important;min-height:28px!important;padding:4px 10px!important}}::ng-deep .mat-mdc-simple-snack-bar{background-color:#fff!important}::ng-deep .mat-mdc-tooltip{--mdc-plain-tooltip-container-color: #050505 !important;--mdc-plain-tooltip-supporting-text-color: white !important;border-radius:6px}::ng-deep .mat-mdc-tooltip .mdc-tooltip__surface{background-color:#050505!important;color:#fff!important;border-radius:6px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "pipe", type: i1$1.KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "component", type: i4.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "directive", type: i1.MatLabel, selector: "mat-label" }, { kind: "component", type: i6$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i5.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i5.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i9.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] });
|
|
1746
3072
|
}
|
|
1747
3073
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ToolboxComponent, decorators: [{
|
|
1748
3074
|
type: Component,
|
|
1749
|
-
args: [{ selector: 'map-toolbox', imports: [FormsModule, CommonModule, MatIconModule, MatOptionModule, MatSelectModule, DragDropModule, MatTooltipModule, MatSlideToggleModule], template: "<div class=\"toolbox-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\"\n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\">\n <div class=\"drag-handle-toolbox\" cdkDragHandle>\n <mat-icon>build_circle</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleCollapsed($event)\">{{ collapsed ? 'flip_to_front' : 'remove' }}</mat-icon> </div>\n <div class=\"toolbox-container\" [class.collapsed]=\"collapsed\">\n @if(!collapsed) {\n <div class=\"toolbox-content\">\n @if (settings.geometryTypeSettings && settings.geometryTypeSettings.length) {\n <mat-select class=\"geometry-selector\" (selectionChange)=\"settingsChanged($event)\" [(ngModel)]=\"selectedGeometrySetting\" [compareWith]=\"compareGeometrySetting\">\n @for (setting of settings.geometryTypeSettings; track setting) {\n <mat-option [value]=\"setting\">{{setting.typeName}}</mat-option>\n }\n </mat-select> \n }\n <div class=\"all-tools-container\">\n <div class=\"main-tools\">\n @if(!settings?.undoDisabled) {\n <img \n [src]=\"undoIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"undo()\" \n matTooltip=\"Fortryd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Undo\">\n\n <img \n [src]=\"redoIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"redo()\" \n matTooltip=\"Gentag\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Redo\">\n }\n <mat-slide-toggle [(ngModel)]=\"snap\" (change)=\"onSnapChange()\">Snap</mat-slide-toggle>\n @if(settings.editEnabled) {\n <img \n [src]=\"editIconBase64\" \n [class.active]=\"activeMode === 'edit'\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"startEdit()\" \n matTooltip=\"Rediger\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Rediger\">\n\n <img \n [src]=\"removePointsIconBase64\" \n [class.active]=\"activeMode === 'edit-remove'\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"startEditRemovePoints()\" \n matTooltip=\"Fjern punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Fjern punkter\">\n }\n @if(settings.cutHoleEnabled) {\n <img \n [src]=\"trimIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'clip-hole'\" \n (click)=\"clipHole()\" \n matTooltip=\"Klip hul\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Klip hul\">\n }\n @if(settings.splitEnabled) {\n <img \n [src]=\"splitIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'split'\"\n (click)=\"split()\" \n matTooltip=\"Sk\u00E6r over\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Sk\u00E6r over\">\n }\n @if(settings.changeTypeEnabled) {\n <mat-icon \n class=\"compact-icon\" \n [class.active]=\"activeMode === 'change-type'\" \n (click)=\"startChangeType()\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Skift type\" \n matTooltipPosition=\"below\">\n find_replace\n </mat-icon>\n }\n @if(settings.mergeEnabled) {\n <mat-icon \n class=\"compact-icon\" \n (click)=\"startMergeFeatures()\" \n matTooltipPosition=\"below\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Saml flader\" \n [class.active]=\"activeMode === 'merge-features'\">\n merge\n </mat-icon>\n }\n </div>\n @if(selectedGeometrySetting && selectedGeometrySetting.availableGeometryTypes?.length) {\n <div class=\"geometry-tools\">\n @for(geomType of selectedGeometrySetting.availableGeometryTypes;track geomType) {\n @if(geomType === 'Polygon') {\n <img \n [src]=\"polygonIconBase64\" \n [class.active]=\"activeMode === 'draw-polygon'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPolygon()\" \n matTooltip=\"Polygon\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Polygon\">\n }\n @if(geomType === 'LineString') {\n <img \n [src]=\"lineStringIconBase64\" \n [class.active]=\"activeMode === 'draw-linestring'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawLineString()\" \n matTooltip=\"LineString\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"LineString\">\n }\n @if(geomType === 'Point') {\n <img \n [src]=\"pointIconBase64\" \n [class.active]=\"activeMode === 'draw-point'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPoint()\" \n matTooltip=\"Punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Punkter\">\n }\n }\n <img \n [src]=\"wktIconBase64\" \n class=\"compact-icon secondary custom-image-icon\"\n (click)=\"activateShowInputWKT()\" \n matTooltip=\"WKT\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"WKT\">\n </div>\n }\n <div class=\"tool-separator\" *ngIf=\"deleteEnabled || showMeasureDistance || showMeasureArea || profile.showPrint\"></div>\n <div class=\"measurement-print-tools\">\n <div class=\"measurement-tools\">\n @if (deleteEnabled) {\n <img \n [src]=\"deleteIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'delete'\"\n (click)=\"startDelete()\" \n matTooltip=\"Slet\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Slet\">\n }\n @if (showMeasureDistance) {\n <img \n [src]=\"measureDistanceIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'measure-distance'\"\n (click)=\"startMeasureLength()\" \n matTooltip=\"M\u00E5le afstand\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"M\u00E5le afstand\">\n }\n @if(showMeasureArea) {\n <img \n [src]=\"measureAreaIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'measure-area'\"\n (click)=\"startMeasureArea()\" \n matTooltip=\"M\u00E5le areal\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"M\u00E5le areal\">\n }\n </div>\n @if(profile.showPrint) {\n <div class=\"tool-separator print-separator\"></div>\n <div class=\"print-tools\">\n <img \n [src]=\"printBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"active === 'Print'\"\n (click)=\"startPrintMode()\" \n matTooltip=\"Udskriv\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Udskriv\">\n <!-- <img \n [src]=\"drawBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"active === 'Draw'\"\n (click)=\"startDrawMode()\" \n matTooltip=\"Tegn\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Tegn\"> -->\n </div>\n }\n </div>\n </div>\n @if(showInputWKT) {\n <div class=\"wkt-section\">\n <input class=\"compact-input\" [(ngModel)]=\"WKTString\">\n <div class=\"wkt-actions\">\n <button class=\"compact-button primary\" (click)=\"ReadWKT()\">Indl\u00E6s WKT</button>\n <button class=\"compact-button\" (click)=\"cancelWKT()\">Annuller</button>\n </div>\n </div>\n }\n @if(profile.showPrint) {\n @if(active === \"Print\") {\n <div class=\"print-config\">\n <img \n [src]=\"printBase64\" \n class=\"compact-icon\"\n (click)=\"doPrint()\" \n alt=\"Udskriv\"> \n <span class=\"icon-separator\">i</span>\n <select id=\"formatSelector\" [(ngModel)]=\"format\">\n <option value=\"image/png\" selected>.PNG</option>\n <option value=\"image/jpeg\">.JPG</option>\n </select>\n <select id=\"dimensionSelector\" [(ngModel)]=\"dimId\" (change)=\"handleDimensionSelected()\">\n <option value=\"99\" selected></option>\n <option value=\"0\">1920 X 1080</option>\n <option value=\"1\">1680 X 1050</option>\n <option value=\"2\">1280 X 800</option>\n <option value=\"3\">800 X 600</option>\n </select>\n <input type=\"text\" [(ngModel)]=\"mapWidth\"/> \n <span class=\"icon-separator\">x</span>\n <input type=\"text\" [(ngModel)]=\"mapHeight\"/>\n <button (click)=\"setNewMapDimensions()\">V\u00E6lg</button>\n </div>\n }\n @if(active === \"PrintDraw\") {\n <div class=\"print-draw-config\">\n <span class=\"icon-separator\">Label</span>\n <input type=\"text\" [(ngModel)]=\"printDrawLabel\"/>\n <select id=\"drawToolSelector\" [(ngModel)]=\"printDrawTool\" (change)=\"handlePrintDrawToolChanged()\">\n <option value=\"arrow\" selected>Pil</option>\n <option value=\"point\">Punkt</option>\n <option value=\"line\">Linje</option>\n <option value=\"polygon\">Polygon</option>\n <option value=\"cirkel\">Cirkel</option>\n <option value=\"square\">Kvadrat</option>\n <option value=\"rectangle\">Firkant</option>\n </select>\n <button>Ryd</button>\n </div>\n }\n }\n </div>\n }\n </div>\n</div>\n", styles: [".toolbox-wrapper{position:absolute;left:1em;top:31.5em;z-index:1000;cursor:grab;max-width:95vw}.toolbox-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}.drag-handle-toolbox{display:flex;align-items:center;justify-content:space-between;background:color-mix(in srgb,#000 60%,transparent);padding:2px 10px;cursor:grab;gap:8px}.drag-handle-toolbox mat-icon{color:#fff;font-size:18px;width:18px;height:18px}.drag-handle-toolbox mat-icon:first-child{flex:1;text-align:center}.toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.toggle-icon:hover{color:#fff;background:#ffffff26}.toggle-icon:active{background:#ffffff40}:host{position:relative;display:flex;justify-content:center}:host.expanded{width:auto;min-width:320px;padding:12px}.toolbox-container{display:flex;flex-direction:column;align-items:center;width:100%;gap:10px;background:color-mix(in srgb,#000 60%,transparent);box-shadow:#0000004d 0 1px 4px -1px;padding:10px;width:auto;min-width:32px;transition:all .3s ease;cursor:default}.toolbox-container.collapsed{display:none}.toolbox-content{display:flex;flex-direction:column;width:100%;gap:3px;animation:slideDown .3s cubic-bezier(.4,0,.2,1)}.all-tools-container{display:flex;flex-direction:row;align-items:center;flex-wrap:nowrap;width:100%;justify-content:flex-start;overflow-x:hidden}.all-tools-container::-webkit-scrollbar{height:4px}.all-tools-container::-webkit-scrollbar-thumb{background:#ccc;border-radius:2px}.main-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.main-tools ::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:12px;font-weight:500;color:#fff}.geometry-selector{width:100%}.geometry-selector ::ng-deep .mat-mdc-select{font-size:14px;line-height:1.4;border-radius:6px}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:32px;min-height:32px;padding:0 10px;border:none;border-radius:6px;background:color-mix(in srgb,#000 60%,transparent);transition:all .2s ease}.geometry-selector ::ng-deep .mat-mdc-select-trigger:hover{background:color-mix(in srgb,#000 70%,transparent);border-color:#667eea;box-shadow:0 4px 12px #0003}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:14px;font-weight:500;color:#fff}.geometry-selector ::ng-deep .mat-mdc-select-arrow-wrapper{height:16px;transform:scale(.85)}.geometry-selector ::ng-deep .mat-mdc-form-field-infix{min-height:32px;padding:6px 0}.geometry-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}::ng-deep .mat-mdc-select-panel{min-width:fit-content!important;max-width:320px!important;background:color-mix(in srgb,#000 100%,transparent)!important;border:none!important;border-radius:8px!important;box-shadow:0 8px 24px #0000001f,0 2px 6px #00000014!important;margin-top:6px!important;padding:4px 0!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:14px!important;min-height:36px!important;padding:8px 14px!important;transition:all .15s ease!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option:hover:not(.mat-mdc-option-disabled){background:#444849!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option.mat-active{background:color-mix(in srgb,#000 60%,transparent)!important;color:#fff!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px!important;font-weight:500!important;color:#fff!important}::ng-deep .cdk-overlay-pane{z-index:1001}::ng-deep .cdk-overlay-backdrop{z-index:1000}.geometry-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.measurement-print-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap;background:color-mix(in srgb,#000 20%,transparent);border-radius:8px;padding:4px 8px;border:1px solid rgba(255,255,255,.1)}.measurement-tools,.print-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.measurement-tools .compact-icon,.print-tools .compact-icon{transition:all .3s cubic-bezier(.4,0,.2,1)}.measurement-tools .compact-icon.custom-image-icon,.print-tools .compact-icon.custom-image-icon{padding:4px;background:none;border:1px solid rgba(255,255,255,.2)}.measurement-tools .compact-icon.custom-image-icon img,.print-tools .compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:filter .2s ease}.measurement-tools .compact-icon.custom-image-icon.active,.print-tools .compact-icon.custom-image-icon.active{background:linear-gradient(147.38deg,#0ea5e9,#075985);border-color:transparent;box-shadow:0 4px 12px #0ea5e966}.measurement-tools .compact-icon.custom-image-icon.active img,.print-tools .compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1)}.measurement-tools .compact-icon.custom-image-icon.active:hover,.print-tools .compact-icon.custom-image-icon.active:hover{box-shadow:0 6px 20px #0ea5e980}.measurement-tools .compact-icon.custom-image-icon:hover:not(.active),.print-tools .compact-icon.custom-image-icon:hover:not(.active){background:color-mix(in srgb,#000 70%,transparent);border-color:#0ea5e9;box-shadow:0 2px 8px #0ea5e94d}.measurement-tools .compact-icon.custom-image-icon:hover:not(.active) img,.print-tools .compact-icon.custom-image-icon:hover:not(.active) img{filter:brightness(0) invert(.8)}.print-tools .compact-icon{background:linear-gradient(147.38deg,#4f46e5,#3730a3);color:#fff;border:1px solid rgba(255,255,255,.2)}.print-tools .compact-icon.print-icon{background:linear-gradient(147.38deg,#10b981,#047857)}.print-tools .compact-icon.draw-icon{background:linear-gradient(147.38deg,#f59e0b,#d97706)}.print-tools .compact-icon.active{background:linear-gradient(147.38deg,#ef4444,#dc2626);box-shadow:0 4px 12px #ef444466;border-color:transparent;transform:scale(1.05)}.print-tools .compact-icon.active:hover{box-shadow:0 6px 20px #ef444480;transform:scale(1.08)}.print-tools .compact-icon:hover:not(.active){box-shadow:0 4px 12px #0000004d;opacity:.9}.tool-separator{width:1px;height:24px;background:linear-gradient(to bottom,transparent,rgba(255,255,255,.3),transparent);margin:0 4px}.tool-separator.print-separator{height:28px;background:linear-gradient(to bottom,transparent,rgba(255,255,255,.5),transparent)}.compact-icon{cursor:pointer;color:#fff;transition:all .3s cubic-bezier(.4,0,.2,1);width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:6px;background:color-mix(in srgb,#000 40%,transparent);border:1px solid rgba(255,255,255,.2);box-shadow:0 1px 2px #0000001a;flex-shrink:0}.compact-icon.active{color:#fff;background:linear-gradient(135deg,#667eea,#764ba2);border-color:transparent;box-shadow:0 8px 25px #667eea4d;transform:scale(1.05)}.compact-icon.active:hover{box-shadow:0 12px 35px #667eea66;transform:scale(1.08)}.compact-icon:hover:not(.active){color:#fff;background:color-mix(in srgb,#000 70%,transparent);border-color:#667eea;box-shadow:0 4px 12px #0003}.compact-icon.custom-image-icon{padding:0;background:none;border:none}.compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:transform .2s ease}.compact-icon.custom-image-icon.active{background:linear-gradient(135deg,#667eea,#764ba2);border-color:transparent}.compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1);transform:scale(1.1)}.compact-icon.custom-image-icon:hover:not(.active) img{transform:scale(1.05)}.wkt-section{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid rgba(255,255,255,.1);animation:fadeIn .2s ease}.wkt-actions{display:flex;gap:6px;justify-content:space-between}.compact-button{padding:6px 10px;border:none;border-radius:6px;background:color-mix(in srgb,#000 60%,transparent);color:#fff;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);text-transform:uppercase;letter-spacing:.4px;min-height:32px;display:flex;align-items:center;justify-content:center;flex:1;box-shadow:0 1px 2px #0000000d}.compact-button.primary.active{background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 8px 25px #667eea4d;color:#fff}.compact-button.primary.active:hover{box-shadow:0 12px 35px #667eea66}.compact-button.secondary{background:color-mix(in srgb,#000 20%,transparent);color:#fff}.compact-button.secondary:hover{background:color-mix(in srgb,#5a6268 60%,transparent)}.compact-button:hover:not(.active){background:color-mix(in srgb,#000 70%,transparent);color:#fff}.compact-input{padding:8px 10px;border:none;border-radius:6px;font-size:13px;transition:all .2s ease;background:color-mix(in srgb,#000 60%,transparent);color:#fff}.compact-input:focus{outline:none;border-color:#1976d2;background:color-mix(in srgb,#000 70%,transparent);box-shadow:0 0 0 3px #1976d233}.print-config,.print-draw-config{display:flex;align-items:center;gap:8px;padding:5px;background:color-mix(in srgb,#000 40%,transparent);border-radius:8px;border:1px solid rgba(255,255,255,.1);animation:slideDown .3s ease}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{background:color-mix(in srgb,#000 60%,transparent);border:1px solid rgba(255,255,255,.2);color:#fff;border-radius:6px;font-size:12px;height:32px;min-height:32px;padding:0 10px}.print-config select:focus,.print-config input:focus,.print-draw-config select:focus,.print-draw-config input:focus{outline:none;border-color:#0ea5e9;box-shadow:0 0 0 2px #0ea5e933}.print-config select,.print-draw-config select{cursor:pointer}.print-config option,.print-draw-config option{background:color-mix(in srgb,#000 98%,transparent)!important;border:none!important}.print-config input,.print-draw-config input{width:60px;text-align:center}.print-config button,.print-draw-config button{background:linear-gradient(147.38deg,#10b981,#047857);color:#fff;border:none;padding:6px 12px;border-radius:4px;font-size:12px;cursor:pointer;transition:all .2s ease}.print-config button:hover,.print-draw-config button:hover{box-shadow:0 4px 12px #10b9814d}.print-config .icon-separator,.print-draw-config .icon-separator{color:#70706f}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes pulse{0%{box-shadow:0 0 #667eeab3}70%{box-shadow:0 0 0 6px #667eea00}to{box-shadow:0 0 #667eea00}}.compact-icon.active{animation:pulse 2s infinite}@media (max-width: 768px){.toolbox-wrapper{left:.5em;top:8em;max-width:calc(100vw - 2.5em)}.drag-handle-toolbox{padding:3px 6px;gap:6px}.drag-handle-toolbox mat-icon{font-size:16px;width:16px;height:16px}.toggle-icon{font-size:16px!important;width:16px!important;height:16px!important}.toolbox-container{padding:8px;min-width:28px;max-width:calc(100vw - 3em)}:host{padding:8px;min-width:32px}:host.expanded{min-width:280px;padding:10px}.all-tools-container{flex-wrap:wrap;gap:6px;max-height:50vh;overflow-y:auto;padding:0;-ms-overflow-style:none;scrollbar-width:none}.all-tools-container::-webkit-scrollbar{display:none}.main-tools,.geometry-tools,.measurement-print-tools,.print-tools{display:flex;flex-wrap:wrap;justify-content:center;gap:4px}.compact-icon{width:28px;height:28px;flex-shrink:0}.measurement-print-tools{padding:3px 6px}.geometry-selector{width:100%;margin-bottom:8px}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:28px;min-height:28px;padding:0 8px;font-size:12px}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:12px}::ng-deep .mat-mdc-select-panel{max-width:calc(100vw - 2em)!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:13px!important;min-height:32px!important;padding:6px 12px!important}.print-config,.print-draw-config{flex-direction:column;align-items:stretch;gap:6px}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{font-size:11px;padding:4px 8px;height:28px;min-height:28px}.print-config input,.print-draw-config input{width:50px}.print-config button,.print-draw-config button{padding:4px 8px;font-size:11px;height:28px}.wkt-section .compact-input{font-size:12px;padding:6px 8px}.wkt-section .compact-button{font-size:11px;padding:5px 8px;min-height:28px}::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:11px!important}}@media (max-width: 480px){.toolbox-wrapper{left:.25em;top:6em;transform-origin:left top;max-width:calc(100vw - .5em)}.drag-handle-toolbox{padding:2px 4px;gap:4px}.drag-handle-toolbox mat-icon{font-size:14px;width:14px;height:14px}.toggle-icon{font-size:14px!important;width:14px!important;height:14px!important}.toolbox-container{padding:6px;min-width:24px}.toolbox-content{gap:8px}.all-tools-container{flex-direction:row;align-items:center;max-height:60vh}.main-tools,.geometry-tools{gap:3px;flex-wrap:wrap;justify-content:center}.measurement-print-tools{gap:3px;flex-wrap:wrap;padding:2px 4px;width:100%;justify-content:center}.measurement-tools,.print-tools{gap:3px}.compact-icon{width:26px;height:26px}.tool-separator{display:none}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:26px;min-height:26px;padding:0 6px;font-size:11px}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:11px}.compact-button{font-size:10px;letter-spacing:.2px;padding:4px 6px;min-height:26px}.compact-input{font-size:11px;padding:4px 6px}.print-config,.print-draw-config{gap:4px;padding:6px}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{font-size:10px;height:26px;min-height:26px;padding:2px 6px}.print-config input,.print-draw-config input{width:45px}.print-config button,.print-draw-config button{flex:1;min-width:60px;font-size:10px;padding:3px 6px;height:26px}.print-config .icon-separator,.print-draw-config .icon-separator{font-size:10px}.wkt-section{gap:6px;padding-top:8px}::ng-deep .mat-mdc-slide-toggle{transform:scale(.9)}::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:10px!important}::ng-deep .mat-mdc-select-panel{max-width:calc(100vw - 1em)!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:12px!important;min-height:28px!important;padding:4px 10px!important}}::ng-deep .mat-mdc-simple-snack-bar{background-color:#fff!important}::ng-deep .mat-mdc-tooltip{--mdc-plain-tooltip-container-color: #050505 !important;--mdc-plain-tooltip-supporting-text-color: white !important;border-radius:6px}::ng-deep .mat-mdc-tooltip .mdc-tooltip__surface{background-color:#050505!important;color:#fff!important;border-radius:6px}\n"] }]
|
|
3075
|
+
args: [{ selector: 'map-toolbox', imports: [FormsModule, CommonModule, MatIconModule, MatOptionModule, MatSelectModule, DragDropModule, MatTooltipModule, MatSlideToggleModule], template: "<div class=\"toolbox-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\"\n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\">\n <div class=\"drag-handle-toolbox\" cdkDragHandle>\n <mat-icon class=\"left-icon\">handyman</mat-icon>\n \n <div class=\"right-icons\">\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleCollapsed($event)\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n </div>\n \n <div class=\"toolbox-container\" [class.collapsed]=\"collapsed\">\n @if(!collapsed) {\n <div class=\"toolbox-content\">\n @if (showGeometryTypes && filteredGeometryTypeSettings.length > 0) {\n <mat-select class=\"geometry-selector\" (selectionChange)=\"settingsChanged($event)\" [(ngModel)]=\"selectedGeometrySetting\" [compareWith]=\"compareGeometrySetting\">\n @for (setting of filteredGeometryTypeSettings; track setting) {\n <mat-option [value]=\"setting\">{{setting.typeName}}</mat-option>\n }\n </mat-select> \n }\n <div class=\"all-tools-container\">\n <div class=\"main-tools\">\n @if(!settings?.undoDisabled) {\n <img \n [src]=\"undoIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"undo()\" \n matTooltip=\"Fortryd\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Undo\">\n\n <img \n [src]=\"redoIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"redo()\" \n matTooltip=\"Gendan\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Redo\">\n }\n <mat-icon \n class=\"compact-icon\" \n (click)=\"startShowInfo()\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Vis info\" \n matTooltipPosition=\"below\">\n info\n </mat-icon>\n <mat-icon \n class=\"compact-icon\" \n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"S\u00F8g punkt\" \n matTooltipPosition=\"below\"\n (click)=\"togglePointSearch()\">adjust\n </mat-icon>\n <mat-icon \n class=\"compact-icon\" \n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"S\u00F8g polygon\" \n matTooltipPosition=\"below\"\n (click)=\"togglePolygonSearch()\">crop_din\n </mat-icon>\n <mat-icon\n class=\"compact-icon\" \n (click)=\"startSelectFeatureHighlight()\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Fremh\u00E6v\" \n matTooltipPosition=\"below\"\n >star</mat-icon> // TODO: set correct icon for this\n\n <mat-slide-toggle [(ngModel)]=\"snap\" (change)=\"onSnapChange()\">Snap</mat-slide-toggle>\n @if(settings.editEnabled) {\n <img \n [src]=\"editIconBase64\" \n [class.active]=\"activeMode === 'edit'\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"startEdit()\" \n matTooltip=\"Rediger\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Rediger\">\n\n <img \n [src]=\"removePointsIconBase64\" \n [class.active]=\"activeMode === 'edit-remove'\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"startEditRemovePoints()\" \n matTooltip=\"Fjern punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Fjern punkter\">\n }\n @if(settings.cutHoleEnabled) {\n <img \n [src]=\"trimIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'clip-hole'\" \n (click)=\"clipHole()\" \n matTooltip=\"Klip hul\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Klip hul\">\n }\n @if(settings.splitEnabled) {\n <img \n [src]=\"splitIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'split'\"\n (click)=\"split()\" \n matTooltip=\"Sk\u00E6r over\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Sk\u00E6r over\">\n }\n @if(settings.changeTypeEnabled) {\n <mat-icon \n class=\"compact-icon\" \n [class.active]=\"activeMode === 'change-type'\" \n (click)=\"startChangeType()\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Skift type\" \n matTooltipPosition=\"below\">\n find_replace\n </mat-icon>\n }\n @if(settings.mergeEnabled) {\n <mat-icon \n class=\"compact-icon\" \n (click)=\"startMergeFeatures()\" \n matTooltipPosition=\"below\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"Saml flader\" \n [class.active]=\"activeMode === 'merge-features'\">\n merge\n </mat-icon>\n }\n @if(settings.centerPoint) {\n <mat-icon\n (click)=\"setCenterPoint()\"\n matTooltipPosition=\"below\"\n [matTooltipShowDelay]=\"200\"\n matTooltipClass=\"custom-tooltip\"\n [matTooltipHideDelay]=\"300\" \n matTooltip=\"S\u00E6t centerpunkt\" \n [class.active]=\"activeMode === 'center-point'\"\n >adjust</mat-icon>\n }\n </div>\n <div class=\"geometry-tools\">\n <img \n [src]=\"featureSearchIconBase64\" \n [class.active]=\"activeMode === 'search-feature'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"toggleFeatureSearch()\" \n matTooltip=\"Udpegede objekter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Punkt\">\n\n <img \n [src]=\"polygonIconBase64\" \n [class.active]=\"activeMode === 'draw-polygon'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPolygon()\" \n matTooltip=\"Polygon\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Polygon\">\n <img \n [src]=\"lineStringIconBase64\" \n [class.active]=\"activeMode === 'draw-linestring'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawLineString()\" \n matTooltip=\"LineString\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"LineString\">\n \n @if(selectedGeometrySetting && selectedGeometrySetting.icons && selectedGeometrySetting.icons.length > 0) {\n @for(iconUrl of selectedGeometrySetting.icons;track iconUrl) {\n <img \n [src]=\"iconUrl\" \n [class.active]=\"activeMode === 'draw-point'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPointUrl(iconUrl)\" \n matTooltip=\"Punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Punkter\">}\n } @else {\n <img \n [src]=\"pointIconBase64\" \n [class.active]=\"activeMode === 'draw-point'\"\n class=\"compact-icon primary custom-image-icon\"\n (click)=\"startDrawPoint()\" \n matTooltip=\"Punkter\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Punkter\">\n }\n <img \n [src]=\"wktIconBase64\" \n class=\"compact-icon secondary custom-image-icon\"\n (click)=\"activateShowInputWKT()\" \n matTooltip=\"WKT\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"WKT\">\n </div>\n <div class=\"tool-separator\" *ngIf=\"deleteEnabled || showMeasureDistance || showMeasureArea || profile.showPrint\"></div>\n <div class=\"measurement-print-tools\">\n <div class=\"measurement-tools\">\n @if (deleteEnabled) {\n <img \n [src]=\"deleteIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'delete'\"\n (click)=\"startDelete()\" \n matTooltip=\"Slet\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Slet\">\n }\n @if (showMeasureDistance) {\n <img \n [src]=\"measureDistanceIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'measure-distance'\"\n (click)=\"startMeasureLength()\" \n matTooltip=\"M\u00E5le afstand\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"M\u00E5le afstand\">\n }\n @if(showMeasureArea) {\n <img \n [src]=\"measureAreaIconBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"activeMode === 'measure-area'\"\n (click)=\"startMeasureArea()\" \n matTooltip=\"M\u00E5le areal\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"M\u00E5le areal\">\n }\n </div>\n @if(profile.showPrint) {\n <div class=\"tool-separator print-separator\"></div>\n <div class=\"print-tools\">\n <img \n [src]=\"printBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"active === 'Print'\"\n (click)=\"startPrintMode()\" \n matTooltip=\"Udskriv\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Udskriv\">\n <img \n [src]=\"drawBase64\" \n class=\"compact-icon custom-image-icon\"\n [class.active]=\"active === 'Draw'\"\n (click)=\"startDrawMode()\" \n matTooltip=\"Tegn\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Tegn\">\n </div>\n }\n </div>\n </div>\n @if(showInputWKT) {\n <div class=\"wkt-section\">\n <input class=\"compact-input\" [(ngModel)]=\"WKTString\">\n <div class=\"wkt-actions\">\n <button class=\"compact-button primary\" (click)=\"ReadWKT()\">Indl\u00E6s WKT</button>\n <button class=\"compact-button\" (click)=\"cancelWKT()\">Annuller</button>\n </div>\n </div>\n }\n @if(profile.showPrint) {\n @if(active === \"Print\") {\n <div class=\"print-config\">\n <img \n [src]=\"printBase64\" \n class=\"compact-icon\"\n (click)=\"doPrint()\" \n alt=\"Udskriv\"> \n <span class=\"icon-separator\">i</span>\n <select id=\"formatSelector\" [(ngModel)]=\"format\">\n <option value=\"image/png\" selected>.PNG</option>\n <option value=\"image/jpeg\">.JPG</option>\n </select>\n <select id=\"dimensionSelector\" [(ngModel)]=\"dimId\" (change)=\"handleDimensionSelected()\">\n <option value=\"99\" selected></option>\n <option value=\"0\">1920 X 1080</option>\n <option value=\"1\">1680 X 1050</option>\n <option value=\"2\">1280 X 800</option>\n <option value=\"3\">800 X 600</option>\n </select>\n <input type=\"text\" [(ngModel)]=\"mapWidth\"/> \n <span class=\"icon-separator\">x</span>\n <input type=\"text\" [(ngModel)]=\"mapHeight\"/>\n <button (click)=\"setNewMapDimensions()\">V\u00E6lg</button>\n </div>\n }\n @if(active === \"PrintDraw\") {\n <div class=\"print-draw-config\">\n <span class=\"icon-separator\">Label</span>\n <input type=\"text\" [(ngModel)]=\"printDrawLabel\"/>\n <select id=\"drawToolSelector\" [(ngModel)]=\"printDrawTool\" (change)=\"handlePrintDrawToolChanged()\">\n <option value=\"Arrow\" selected>Pil</option>\n <option value=\"Point\">Punkt</option>\n <option value=\"LineString\">Linje</option>\n <option value=\"Polygon\">Polygon</option>\n <option value=\"Circle\">Cirkel</option>\n <option value=\"Square\">Kvadrat</option>\n <option value=\"Rectangle\">Firkant</option>\n </select>\n <button class=\"compact-button\" (click)=\"handleClearPrintDrawFeatures()\">Ryd</button>\n </div>\n }\n }\n </div>\n }\n </div>\n @if (activeMode === 'search-feature' && filteredResults.length > 0) {\n <div class=\"geometry-search-panel\">\n <div class=\"buffer-item\">\n <mat-label>Buffer</mat-label>\n <input matInput type=\"number\" name=\"buffer\" [(ngModel)]=\"bufferInMeters\">\n <mat-label>m</mat-label>\n </div>\n <mat-option *ngFor=\"let result of filteredResults\" [value]=\"result\" class=\"search-result-option\">\n <span class=\"result-title\">\n {{ result.title }} ({{result.items.length}} af {{ result.total }})\n </span>\n <div (click)=\"highlight(item.wkt, $event)\" *ngFor=\"let item of result.items\" class=\"search-result-item\">\n <div class=\"item-left\">\n <span class=\"item-header\"> {{item.header}} </span> \n </div>\n <div class=\"item-right\">\n <img \n [src]=\"objectSearchCopyIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"addToActiveObjectsList(item, $event)\" \n matTooltip=\"Kopier\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Kopier\">\n <img \n [src]=\"objectSearchCutIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"cutBySearchedObject(item, $event)\" \n matTooltip=\"Fjern\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Fjern\">\n <img \n [src]=\"objectSearchCutIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"splitBySearchedObject(item, $event)\" \n matTooltip=\"Opsk\u00E6r\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Opsk\u00E6r\">\n <img \n [src]=\"objectSearchCopyWithBufferIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"addToActiveObjectsList(item, $event, true)\" \n matTooltip=\"Kopier med buffer\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Kopier med buffer\">\n <img \n [src]=\"objectSearchZoomIconBase64\" \n class=\"compact-icon custom-image-icon\"\n (click)=\"zoomSearchedObject(item, $event)\" \n matTooltip=\"Zoom\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipClass=\"custom-tooltip\"\n matTooltipPosition=\"below\"\n alt=\"Zoom\">\n <button\n (click)=\"toggleItemInfo(item, $event)\">\n <mat-icon class=\"button-icon\">info_outline</mat-icon>\n </button>\n </div> \n @if (item.showMetadata) {\n <div class=\"metadata-panel\">\n @for(feature of item.metadata; track feature) {\n <div class=\"feature-item\">\n <div *ngFor=\"let kv of (feature | keyvalue)\">\n {{ kv.value.name }}:\n <ng-container [ngSwitch]=\"kv.value.kind\">\n <img *ngSwitchCase=\"'img'\" [src]=\"kv.value.data\" alt=\"{{ kv.key }}\" style=\"max-width:240px;\" />\n <a *ngSwitchCase=\"'url'\" [href]=\"kv.value.data\" target=\"_blank\" rel=\"noopener noreferrer\">\n {{ kv.key }}\n <mat-icon class=\"link-icon\">open_in_new</mat-icon>\n </a>\n <span *ngSwitchDefault>{{ kv.value.data }}</span>\n </ng-container>\n </div>\n </div>\n }\n </div>\n }\n </div>\n </mat-option>\n </div>\n }\n @if ((activeMode === \"search-point\" || activeMode === \"search-polygon\") && filteredResults.length > 0) {\n <div class=\"geometry-search-panel\">\n <mat-option *ngFor=\"let result of filteredResults\" [value]=\"result\" class=\"search-result-option\">\n <span class=\"result-title\">\n {{ result.title }} ({{result.items.length}} af {{ result.total }})\n </span>\n <div (click)=\"highlight(item.wkt, $event)\" *ngFor=\"let item of result.items\" class=\"search-result-item\">\n <div class=\"item-left\">\n <span class=\"item-header\"> {{item.header}} </span> \n </div>\n </div>\n </mat-option>\n </div>\n }\n</div>\n", styles: [".toolbox-wrapper{position:absolute;left:1em;top:10em;z-index:10;cursor:grab;max-width:95vw}.toolbox-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}::ng-deep .metadata-panel{margin-top:5px;margin-bottom:5px;border:white;border-width:2px}::ng-deep .geometry-search-panel{border-radius:5px!important;max-height:320px!important;background:color-mix(in srgb,#000 85%,transparent)!important;box-shadow:0 8px 24px #00000026!important;margin-top:10px;overflow-y:auto!important;padding:8px!important;max-width:430px}::ng-deep .geometry-search-panel .buffer-item{align-items:end}::ng-deep .geometry-search-panel .buffer-item input{width:45px;margin:5px}::ng-deep .geometry-search-panel .search-result-item{display:flex;flex-wrap:wrap;margin:5px}::ng-deep .geometry-search-panel .search-result-item .item-left{display:flex;align-items:center;gap:3px;flex:1;min-width:0}::ng-deep .geometry-search-panel .search-result-item .item-right{display:flex;align-items:center;flex:1;justify-content:flex-end;min-width:0;margin-left:10px}::ng-deep .geometry-search-panel .search-result-item .item-right .custom-image-icon{background:#fff!important;margin-left:5px}::ng-deep .geometry-search-panel .search-result-item .item-right button{width:38px;margin-left:5px}::ng-deep .geometry-search-panel .search-result-item .metadata-panel{flex-basis:98%}::ng-deep .geometry-search-panel::-webkit-scrollbar{width:12px}::ng-deep .geometry-search-panel::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .geometry-search-panel::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .geometry-search-panel::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .geometry-search-panel::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .geometry-search-panel::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .geometry-search-panel::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .geometry-search-panel::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .geometry-search-panel::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}::ng-deep .geometry-search-panel .mat-mdc-option{min-height:30px!important;border-radius:5px!important;transition:all .2s cubic-bezier(.4,0,.2,1);position:relative;overflow:auto;margin-bottom:6px!important;padding:8px 0!important}::ng-deep .geometry-search-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px;font-weight:400;color:#fff;line-height:1.5}::ng-deep .geometry-search-panel mat-label{color:#fff}.drag-handle-toolbox{display:flex;align-items:center;justify-content:space-between;background:#292a2d;padding:2px 8px;cursor:grab;gap:8px;border-radius:5px 5px 0 0;color:#fff}.drag-handle-toolbox mat-icon{color:#fff;font-size:18px;width:18px;height:18px}.drag-handle-toolbox mat-icon:first-child{flex:1;text-align:left}.right-icons{display:flex;align-items:center;gap:6px}.left-icon{flex-shrink:0}.toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.toggle-icon:hover{color:#fff;background:#ffffff26}.toggle-icon:active{background:#ffffff40}:host{position:relative;display:flex;justify-content:center}:host.expanded{width:auto;min-width:320px;padding:12px}.toolbox-container{display:flex;flex-direction:column;align-items:center;width:100%;gap:10px;background:#292a2d;box-shadow:#0000004d 0 1px 4px -1px;padding:10px;width:auto;min-width:32px;transition:all .3s ease;cursor:default;border-radius:0 0 5px 5px}.toolbox-container.collapsed{display:none}.toolbox-content{display:flex;flex-direction:column;width:100%;gap:3px;animation:slideDown .3s cubic-bezier(.4,0,.2,1)}.all-tools-container{display:flex;flex-direction:row;align-items:center;flex-wrap:nowrap;width:100%;justify-content:flex-start;overflow-x:hidden}.all-tools-container::-webkit-scrollbar{height:4px}.all-tools-container::-webkit-scrollbar-thumb{background:#ccc;border-radius:2px}.main-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.main-tools ::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:12px;font-weight:500;color:#fff}.geometry-selector{width:100%}.geometry-selector ::ng-deep .mat-mdc-select{font-size:14px;line-height:1.4;border-radius:6px}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:32px;min-height:32px;padding:0 10px;border:none;border-radius:6px;background:color-mix(in srgb,#000 60%,transparent);transition:all .2s ease}.geometry-selector ::ng-deep .mat-mdc-select-trigger:hover{background:color-mix(in srgb,#000 70%,transparent);border-color:#667eea;box-shadow:0 4px 12px #0003}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:14px;font-weight:500;color:#fff}.geometry-selector ::ng-deep .mat-mdc-select-arrow-wrapper{height:16px;transform:scale(.85)}.geometry-selector ::ng-deep .mat-mdc-form-field-infix{min-height:32px;padding:6px 0}.geometry-selector ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}::ng-deep .mat-mdc-select-panel{min-width:fit-content!important;max-width:320px!important;background:color-mix(in srgb,#000 100%,transparent)!important;border:none!important;border-radius:8px!important;box-shadow:0 8px 24px #0000001f,0 2px 6px #00000014!important;margin-top:6px!important;padding:4px 0!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:14px!important;min-height:36px!important;padding:8px 14px!important;transition:all .15s ease!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option:hover:not(.mat-mdc-option-disabled){background:#444849!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option.mat-active{background:color-mix(in srgb,#000 60%,transparent)!important;color:#fff!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px!important;font-weight:500!important;color:#fff!important}::ng-deep .cdk-overlay-pane{z-index:1001}::ng-deep .cdk-overlay-backdrop{z-index:1000}.geometry-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.measurement-print-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap;background:color-mix(in srgb,#000 20%,transparent);border-radius:8px;padding:4px 8px;border:1px solid rgba(255,255,255,.1)}.measurement-tools,.print-tools{display:flex;flex-direction:row;align-items:center;gap:6px;flex-wrap:nowrap}.measurement-tools .compact-icon,.print-tools .compact-icon{transition:all .3s cubic-bezier(.4,0,.2,1)}.measurement-tools .compact-icon.custom-image-icon,.print-tools .compact-icon.custom-image-icon{padding:4px;background:none;border:1px solid rgba(255,255,255,.2)}.measurement-tools .compact-icon.custom-image-icon img,.print-tools .compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:filter .2s ease}.measurement-tools .compact-icon.custom-image-icon.active,.print-tools .compact-icon.custom-image-icon.active{background:linear-gradient(147.38deg,#0ea5e9,#075985);border-color:transparent;box-shadow:0 4px 12px #0ea5e966}.measurement-tools .compact-icon.custom-image-icon.active img,.print-tools .compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1)}.measurement-tools .compact-icon.custom-image-icon.active:hover,.print-tools .compact-icon.custom-image-icon.active:hover{box-shadow:0 6px 20px #0ea5e980}.measurement-tools .compact-icon.custom-image-icon:hover:not(.active),.print-tools .compact-icon.custom-image-icon:hover:not(.active){background:color-mix(in srgb,#000 70%,transparent);border-color:#0ea5e9;box-shadow:0 2px 8px #0ea5e94d}.measurement-tools .compact-icon.custom-image-icon:hover:not(.active) img,.print-tools .compact-icon.custom-image-icon:hover:not(.active) img{filter:brightness(0) invert(.8)}.print-tools .compact-icon{background:linear-gradient(147.38deg,#4f46e5,#3730a3);color:#fff;border:1px solid rgba(255,255,255,.2)}.print-tools .compact-icon.print-icon{background:linear-gradient(147.38deg,#10b981,#047857)}.print-tools .compact-icon.draw-icon{background:linear-gradient(147.38deg,#f59e0b,#d97706)}.print-tools .compact-icon.active{background:linear-gradient(147.38deg,#ef4444,#dc2626);box-shadow:0 4px 12px #ef444466;border-color:transparent;transform:scale(1.05)}.print-tools .compact-icon.active:hover{box-shadow:0 6px 20px #ef444480;transform:scale(1.08)}.print-tools .compact-icon:hover:not(.active){box-shadow:0 4px 12px #0000004d;opacity:.9}.tool-separator{width:1px;height:24px;background:linear-gradient(to bottom,transparent,rgba(255,255,255,.3),transparent);margin:0 4px}.tool-separator.print-separator{height:28px;background:linear-gradient(to bottom,transparent,rgba(255,255,255,.5),transparent)}.compact-icon{cursor:pointer;color:#fff;transition:all .3s cubic-bezier(.4,0,.2,1);width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:6px;background:color-mix(in srgb,#000 40%,transparent);border:1px solid rgba(255,255,255,.2);box-shadow:0 1px 2px #0000001a;flex-shrink:0}.compact-icon.active{color:#fff;background:linear-gradient(135deg,#667eea,#764ba2);border-color:transparent;box-shadow:0 8px 25px #667eea4d;transform:scale(1.05)}.compact-icon.active:hover{box-shadow:0 12px 35px #667eea66;transform:scale(1.08)}.compact-icon:hover:not(.active){color:#fff;background:color-mix(in srgb,#000 70%,transparent);border-color:#667eea;box-shadow:0 4px 12px #0003}.compact-icon.custom-image-icon{padding:0;background:none;border:none}.compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:transform .2s ease}.compact-icon.custom-image-icon.active{background:linear-gradient(135deg,#667eea,#764ba2);border-color:transparent}.compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1);transform:scale(1.1)}.compact-icon.custom-image-icon:hover:not(.active) img{transform:scale(1.05)}.wkt-section{display:flex;flex-direction:column;gap:8px;padding-top:10px;border-top:1px solid rgba(255,255,255,.1);animation:fadeIn .2s ease}.wkt-actions{display:flex;gap:6px;justify-content:space-between}.compact-button{padding:6px 10px;border:none;border-radius:6px;background:color-mix(in srgb,#000 60%,transparent);color:#fff;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s cubic-bezier(.4,0,.2,1);text-transform:uppercase;letter-spacing:.4px;min-height:32px;display:flex;align-items:center;justify-content:center;flex:1;box-shadow:0 1px 2px #0000000d}.compact-button.primary.active{background:linear-gradient(135deg,#667eea,#764ba2);box-shadow:0 8px 25px #667eea4d;color:#fff}.compact-button.primary.active:hover{box-shadow:0 12px 35px #667eea66}.compact-button.secondary{background:color-mix(in srgb,#000 20%,transparent);color:#fff}.compact-button.secondary:hover{background:color-mix(in srgb,#5a6268 60%,transparent)}.compact-input{padding:8px 10px;border:none;border-radius:6px;font-size:13px;transition:all .2s ease;background:color-mix(in srgb,#000 60%,transparent);color:#fff}.compact-input:focus{outline:none;border-color:#1976d2;background:color-mix(in srgb,#000 70%,transparent);box-shadow:0 0 0 3px #1976d233}.print-config,.print-draw-config{display:flex;align-items:center;gap:8px;padding:5px;background:color-mix(in srgb,#000 40%,transparent);border-radius:8px;border:1px solid rgba(255,255,255,.1);animation:slideDown .3s ease}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{background:color-mix(in srgb,#000 60%,transparent);border:1px solid rgba(255,255,255,.2);color:#fff;border-radius:6px;font-size:12px;height:32px;min-height:32px;padding:0 10px}.print-config select:focus,.print-config input:focus,.print-draw-config select:focus,.print-draw-config input:focus{outline:none;border-color:#0ea5e9;box-shadow:0 0 0 2px #0ea5e933}.print-config select,.print-draw-config select{cursor:pointer}.print-config option,.print-draw-config option{background:color-mix(in srgb,#000 98%,transparent)!important;border:none!important}.print-config input,.print-draw-config input{width:60px;text-align:center}.print-config button,.print-draw-config button{background:linear-gradient(147.38deg,#10b981,#047857);color:#fff;border:none;padding:6px 12px;border-radius:4px;font-size:12px;cursor:pointer;transition:all .2s ease}.print-config button:hover,.print-draw-config button:hover{box-shadow:0 4px 12px #10b9814d}.print-config .icon-separator,.print-draw-config .icon-separator{color:#fff}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes pulse{0%{box-shadow:0 0 #667eeab3}70%{box-shadow:0 0 0 6px #667eea00}to{box-shadow:0 0 #667eea00}}.compact-icon.active{animation:pulse 2s infinite}@media (max-width: 768px){.toolbox-wrapper{left:.5em;top:8em;max-width:calc(100vw - 2.5em)}.drag-handle-toolbox{padding:3px 6px;gap:6px}.drag-handle-toolbox mat-icon{font-size:16px;width:16px;height:16px}.toggle-icon{font-size:16px!important;width:16px!important;height:16px!important}.toolbox-container{padding:8px;min-width:28px;max-width:calc(100vw - 3em)}:host{padding:8px;min-width:32px}:host.expanded{min-width:280px;padding:10px}.all-tools-container{flex-wrap:wrap;gap:6px;max-height:50vh;overflow-y:auto;padding:0;-ms-overflow-style:none;scrollbar-width:none}.all-tools-container::-webkit-scrollbar{display:none}.main-tools,.geometry-tools,.measurement-print-tools,.print-tools{display:flex;flex-wrap:wrap;justify-content:center;gap:4px}.compact-icon{width:28px;height:28px;flex-shrink:0}.measurement-print-tools{padding:3px 6px}.geometry-selector{width:100%;margin-bottom:8px}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:28px;min-height:28px;padding:0 8px;font-size:12px}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:12px}::ng-deep .mat-mdc-select-panel{max-width:calc(100vw - 2em)!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:13px!important;min-height:32px!important;padding:6px 12px!important}.print-config,.print-draw-config{flex-direction:column;align-items:stretch;gap:6px}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{font-size:11px;padding:4px 8px;height:28px;min-height:28px}.print-config input,.print-draw-config input{width:50px}.print-config button,.print-draw-config button{padding:4px 8px;font-size:11px;height:28px}.wkt-section .compact-input{font-size:12px;padding:6px 8px}.wkt-section .compact-button{font-size:11px;padding:5px 8px;min-height:28px}::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:11px!important}}@media (max-width: 480px){.toolbox-wrapper{left:.25em;top:6em;transform-origin:left top;max-width:calc(100vw - .5em)}.drag-handle-toolbox{padding:2px 4px;gap:4px}.drag-handle-toolbox mat-icon{font-size:14px;width:14px;height:14px}.toggle-icon{font-size:14px!important;width:14px!important;height:14px!important}.toolbox-container{padding:6px;min-width:24px}.toolbox-content{gap:8px}.all-tools-container{flex-direction:row;align-items:center;max-height:60vh}.main-tools,.geometry-tools{gap:3px;flex-wrap:wrap;justify-content:center}.measurement-print-tools{gap:3px;flex-wrap:wrap;padding:2px 4px;width:100%;justify-content:center}.measurement-tools,.print-tools{gap:3px}.compact-icon{width:26px;height:26px}.tool-separator{display:none}.geometry-selector ::ng-deep .mat-mdc-select-trigger{height:26px;min-height:26px;padding:0 6px;font-size:11px}.geometry-selector ::ng-deep .mat-mdc-select-value{font-size:11px}.compact-button{font-size:10px;letter-spacing:.2px;padding:4px 6px;min-height:26px}.compact-input{font-size:11px;padding:4px 6px}.print-config,.print-draw-config{gap:4px;padding:6px}.print-config select,.print-config input,.print-draw-config select,.print-draw-config input{font-size:10px;height:26px;min-height:26px;padding:2px 6px}.print-config input,.print-draw-config input{width:45px}.print-config button,.print-draw-config button{flex:1;min-width:60px;font-size:10px;padding:3px 6px;height:26px}.print-config .icon-separator,.print-draw-config .icon-separator{font-size:10px}.wkt-section{gap:6px;padding-top:8px}::ng-deep .mat-mdc-slide-toggle{transform:scale(.9)}::ng-deep .mat-mdc-slide-toggle .mdc-label{font-size:10px!important}::ng-deep .mat-mdc-select-panel{max-width:calc(100vw - 1em)!important}::ng-deep .mat-mdc-select-panel .mat-mdc-option{font-size:12px!important;min-height:28px!important;padding:4px 10px!important}}::ng-deep .mat-mdc-simple-snack-bar{background-color:#fff!important}::ng-deep .mat-mdc-tooltip{--mdc-plain-tooltip-container-color: #050505 !important;--mdc-plain-tooltip-supporting-text-color: white !important;border-radius:6px}::ng-deep .mat-mdc-tooltip .mdc-tooltip__surface{background-color:#050505!important;color:#fff!important;border-radius:6px}\n"] }]
|
|
1750
3076
|
}], ctorParameters: () => [], propDecorators: { map: [{
|
|
1751
3077
|
type: Input,
|
|
1752
3078
|
args: [{ required: true }]
|
|
@@ -1768,46 +3094,134 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
1768
3094
|
type: Input
|
|
1769
3095
|
}] } });
|
|
1770
3096
|
|
|
3097
|
+
class ConflictAnalysisSearchProvider extends SearchProviderBase {
|
|
3098
|
+
_current = inject(CurrentItemsService);
|
|
3099
|
+
getSearchableLayers() {
|
|
3100
|
+
return this._current.profile ? this._current.profile.layerGroups.flatMap(lg => lg.layers).filter(l => l.useInConflictAnalysis) : [];
|
|
3101
|
+
}
|
|
3102
|
+
getFilter(searchValue, layer) {
|
|
3103
|
+
return contains(layer.geometryField, searchValue);
|
|
3104
|
+
}
|
|
3105
|
+
map(l, f) {
|
|
3106
|
+
return {
|
|
3107
|
+
conflict: f.features.length > 0,
|
|
3108
|
+
layerName: l.name
|
|
3109
|
+
};
|
|
3110
|
+
}
|
|
3111
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ConflictAnalysisSearchProvider, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
3112
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ConflictAnalysisSearchProvider });
|
|
3113
|
+
}
|
|
3114
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ConflictAnalysisSearchProvider, decorators: [{
|
|
3115
|
+
type: Injectable
|
|
3116
|
+
}] });
|
|
3117
|
+
|
|
1771
3118
|
class ActiveObjectsComponent {
|
|
1772
3119
|
_drawLayerService = inject(DrawLayerSourceService);
|
|
3120
|
+
_centerPointService = inject(CenterPointService);
|
|
3121
|
+
_conflictService = inject(ConflictAnalysisSearchProvider);
|
|
3122
|
+
_undoRedo = inject(UndoRedoService);
|
|
3123
|
+
isZoomedToAll = false;
|
|
1773
3124
|
features$ = this._drawLayerService.features$;
|
|
1774
|
-
collapsed =
|
|
3125
|
+
collapsed = true;
|
|
1775
3126
|
settings;
|
|
3127
|
+
sessionDone = new EventEmitter();
|
|
3128
|
+
profile;
|
|
1776
3129
|
activeFeatures = [];
|
|
1777
3130
|
_featureHelper = inject(FeatureHelperService);
|
|
1778
|
-
_highlight = inject(
|
|
3131
|
+
_highlight = inject(HighlightService);
|
|
1779
3132
|
_zoomService = inject(ZoomService);
|
|
3133
|
+
_current = inject(CurrentItemsService);
|
|
3134
|
+
_layoutService = inject(LayoutService);
|
|
1780
3135
|
opacity = 1;
|
|
1781
3136
|
dragPosition = { x: 0, y: 0 };
|
|
1782
3137
|
highlightedId = null;
|
|
1783
3138
|
POSITION_STORAGE_KEY = 'activeObjects';
|
|
3139
|
+
_hasCenterpoint = false;
|
|
3140
|
+
_featuresForHighlight$ = this._drawLayerService.selectedForHighlight$;
|
|
3141
|
+
get centerPointOk() {
|
|
3142
|
+
return this._hasCenterpoint || !this._current.gisKomponentSettings.centerPoint || !this._current.gisKomponentSettings.centerPoint.required;
|
|
3143
|
+
}
|
|
3144
|
+
conflictAnalysisAvailable = false;
|
|
3145
|
+
get allFeaturesOk() {
|
|
3146
|
+
return !this._current.gisKomponentSettings.containsCheck ||
|
|
3147
|
+
!this._current.gisKomponentSettings.containsCheck.requiredForEndSession ||
|
|
3148
|
+
this.activeFeatures.flatMap(af => af.features).every(f => f.containedOk === 'yes');
|
|
3149
|
+
}
|
|
3150
|
+
get endSessionEnabled() {
|
|
3151
|
+
return !this._current.gisKomponentSettings.endSessionDisabled && this.allFeaturesOk;
|
|
3152
|
+
}
|
|
1784
3153
|
constructor() {
|
|
1785
3154
|
this.features$.subscribe({
|
|
1786
3155
|
next: features => {
|
|
3156
|
+
this._hasCenterpoint = features.some(f => this._centerPointService.isCenterpoint(f));
|
|
1787
3157
|
const featureTypes = [...new Set(features.map(f => this._featureHelper.typeId(f)).filter(typeId => !!typeId))];
|
|
1788
3158
|
const featuresObj = featureTypes
|
|
1789
3159
|
.map(ft => ({ featureType: ft,
|
|
1790
3160
|
display: this.settings.geometryTypeSettings.find(gts => gts.typeId === ft).typeName,
|
|
1791
3161
|
features: features.filter(f => this._featureHelper.typeId(f) === ft)
|
|
1792
|
-
.map(f => ({
|
|
3162
|
+
.map(f => ({
|
|
3163
|
+
id: f.getId(),
|
|
3164
|
+
feature: f,
|
|
3165
|
+
containedOk: this.conflictAnalysisAvailable ? 'unknown' : 'yes',
|
|
3166
|
+
locked: this._featureHelper.isLocked(f),
|
|
3167
|
+
area: this._getAreaString(f)
|
|
3168
|
+
})) }));
|
|
1793
3169
|
this.activeFeatures = [...featuresObj];
|
|
3170
|
+
this.runConflictAnalysis();
|
|
3171
|
+
}
|
|
3172
|
+
});
|
|
3173
|
+
this._featuresForHighlight$.subscribe({
|
|
3174
|
+
next: features => {
|
|
3175
|
+
console.log("🚀 ~ ActiveObjectsComponent ~ constructor ~ features:", features);
|
|
1794
3176
|
}
|
|
1795
3177
|
});
|
|
1796
3178
|
}
|
|
1797
3179
|
ngOnInit() {
|
|
1798
3180
|
this._loadPosition();
|
|
3181
|
+
this.conflictAnalysisAvailable = !!this._current.gisKomponentSettings.containsCheck && this._current.gisKomponentSettings.containsCheck.enabled &&
|
|
3182
|
+
this._current.profile.layerGroups.flatMap(lg => lg.layers).some(l => l.useInConflictAnalysis);
|
|
3183
|
+
}
|
|
3184
|
+
endSession() {
|
|
3185
|
+
this.sessionDone.emit();
|
|
3186
|
+
}
|
|
3187
|
+
runConflictAnalysis() {
|
|
3188
|
+
this.activeFeatures.forEach(af => {
|
|
3189
|
+
const unlockedFeatures = af.features.filter(f => !f.locked);
|
|
3190
|
+
// unlockedFeatures.forEach(f => f.conflicts = 'unknown');
|
|
3191
|
+
const conflictSearches$ = unlockedFeatures.map(f => this._conflictService.search(f.feature.getGeometry(), 1));
|
|
3192
|
+
combineLatest(conflictSearches$).subscribe({
|
|
3193
|
+
next: result => {
|
|
3194
|
+
result.forEach((f, i) => {
|
|
3195
|
+
af.features[i].containedOk = f.some(fx => fx.conflict) ? 'yes' : 'no';
|
|
3196
|
+
af.features[i].containedMissingIn = f.filter(fx => !fx.conflict).map(fx => fx.layerName);
|
|
3197
|
+
});
|
|
3198
|
+
}
|
|
3199
|
+
});
|
|
3200
|
+
});
|
|
3201
|
+
}
|
|
3202
|
+
ngOnChanges(changes) {
|
|
3203
|
+
if (changes['profile'] && this.profile) {
|
|
3204
|
+
this._loadPosition();
|
|
3205
|
+
}
|
|
1799
3206
|
}
|
|
1800
3207
|
_getAreaString(feature) {
|
|
1801
|
-
if (feature.getGeometry()?.getType() !== 'Polygon') { // We only have polygon, linestring and points and only polygons have area
|
|
3208
|
+
if (feature.getGeometry()?.getType() !== 'Polygon' && feature.getGeometry()?.getType() !== 'MultiPolygon') { // We only have polygon, linestring and points and only multi/polygons have area
|
|
1802
3209
|
return '';
|
|
1803
3210
|
}
|
|
1804
3211
|
return this.settings.sizeInHa ? `(${(getArea(feature.getGeometry()) / 10000).toFixed(2)} ha)` : `(${getArea(feature.getGeometry()).toFixed(2)} m2)`;
|
|
1805
3212
|
}
|
|
3213
|
+
reset() {
|
|
3214
|
+
this._undoRedo.reset();
|
|
3215
|
+
this.highlightedId = null;
|
|
3216
|
+
this._highlight.clear();
|
|
3217
|
+
this.zoomToAll();
|
|
3218
|
+
}
|
|
1806
3219
|
zoomToAll() {
|
|
1807
|
-
const formatter = new GeoJSON({ dataProjection: 'EPSG:25832', featureProjection: 'EPSG:25832' });
|
|
1808
|
-
const allTheFeatures = formatter.writeFeaturesObject(this._drawLayerService.allFeatures);
|
|
1809
|
-
console.log("🚀 ~ ActiveObjectsComponent ~ zoomToAll ~ allTheFeatures:", JSON.stringify(allTheFeatures));
|
|
1810
3220
|
this._zoomService.zoomToFeatures(this._drawLayerService.allFeatures);
|
|
3221
|
+
this.isZoomedToAll = true;
|
|
3222
|
+
}
|
|
3223
|
+
onMapInteraction() {
|
|
3224
|
+
this.isZoomedToAll = false;
|
|
1811
3225
|
}
|
|
1812
3226
|
highlight(id) {
|
|
1813
3227
|
if (this.highlightedId === id) {
|
|
@@ -1827,6 +3241,7 @@ class ActiveObjectsComponent {
|
|
|
1827
3241
|
}
|
|
1828
3242
|
delete(id) {
|
|
1829
3243
|
this._drawLayerService.remove(id);
|
|
3244
|
+
this._centerPointService.handleFeatureDeleted(id);
|
|
1830
3245
|
this._highlight.clear();
|
|
1831
3246
|
}
|
|
1832
3247
|
togglePanel() {
|
|
@@ -1851,6 +3266,9 @@ class ActiveObjectsComponent {
|
|
|
1851
3266
|
if (savedPosition) {
|
|
1852
3267
|
this.dragPosition = JSON.parse(savedPosition);
|
|
1853
3268
|
}
|
|
3269
|
+
else if (this.profile) {
|
|
3270
|
+
this.dragPosition = this._layoutService.loadInitialPositionFromProfile(this.POSITION_STORAGE_KEY, this.profile.activeObjectsInitialPosition);
|
|
3271
|
+
}
|
|
1854
3272
|
}
|
|
1855
3273
|
catch (error) {
|
|
1856
3274
|
console.error('Error loading position from localStorage:', error);
|
|
@@ -1858,33 +3276,167 @@ class ActiveObjectsComponent {
|
|
|
1858
3276
|
}
|
|
1859
3277
|
}
|
|
1860
3278
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ActiveObjectsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1861
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: ActiveObjectsComponent, isStandalone: true, selector: "activeObjects", inputs: { settings: "settings" }, ngImport: i0, template: "<div class=\"active-objects-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n <div class=\"drag-handle-active-objects\" cdkDragHandle>\n <mat-icon class=\"zoom-icon\" (click)=\"zoomToAll()\">share_reviewsr</mat-icon>\n @if(!collapsed) {\n <h4>Aktive flader</h4>\n }\n <mat-icon class=\"toggle-icon\" (click)=\"togglePanel()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n <div class=\"active-objects-container\">\n @if(!collapsed) {\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"opacity\"\n (input)=\"updateOpacity()\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n }\n\n @if(!collapsed) {\n <div class=\"active-objects-content\">\n <mat-icon class=\"zoom-icon\" (click)=\"zoomToAll()\">highlight</mat-icon>\n @for(featureTypeObj of activeFeatures; track featureTypeObj.featureType) {\n <mat-expansion-panel>\n <mat-expansion-panel-header \n [matTooltip]=\"featureTypeObj.display\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"right\">\n <span class=\"panel-title\">\n {{featureTypeObj.display}} ({{featureTypeObj.features.length}})\n </span>\n </mat-expansion-panel-header>\n <div class=\"item-list\">\n @for(item of featureTypeObj.features; track item.id) {\n <div class=\"item\">\n <div class=\"item-text\">\n <span class=\"item-id\">{{item.id}}</span>\n <span class=\"item-area\">{{item.area}}</span>\n </div>\n <mat-icon *ngIf=\"!item.locked\" (click)=\"delete(item.id)\">delete</mat-icon>\n <mat-icon (click)=\"highlight(item.id)\" [class.highlight-active]=\"highlightedId === item.id\">highlight</mat-icon>\n </div>\n }\n </div>\n </mat-expansion-panel>\n }\n </div>\n }\n </div> \n</div>", styles: ["@charset \"UTF-8\";.active-objects-wrapper{position:absolute;top:15em;left:1em;z-index:1000;cursor:grab;box-shadow:0 2px 10px #0000001a;background:color-mix(in srgb,#000 60%,transparent);width:fit-content;max-width:295px;transition:width .3s ease}.active-objects-wrapper.collapsed{width:70px;max-width:150px}.active-objects-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}mat-expansion-panel ::ng-deep .mat-expansion-panel-header .panel-title{display:block;overflow:visible;text-overflow:clip;white-space:normal;max-width:220px;margin-right:10px;line-height:1.3;word-break:break-word}.item{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-radius:4px;background:color-mix(in srgb,#000 60%,transparent)!important;transition:all .2s ease;font-size:14px;color:#fff;min-height:40px;cursor:default}.item .item-text{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden}.item .item-id{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:2px}.item .item-area{font-size:12px;color:#ccc;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.item mat-icon{cursor:pointer;color:#f44336;font-size:18px;width:18px;height:18px;flex-shrink:0;margin-left:8px;transition:color .2s ease,background .2s ease}.item mat-icon:hover{color:#d32f2f}.highlight-active{color:#4caf50!important;text-shadow:0 0 6px #4caf50;transform:scale(1.1);transition:all .2s ease}.drag-handle-active-objects{display:flex;align-items:center;justify-content:space-between;background:color-mix(in srgb,#000 0%,transparent);border-radius:8px 8px 0 0;padding:4px 8px;cursor:grab}.drag-handle-active-objects h4{margin:0;padding:5px;background:transparent;font-weight:600;color:#fff;flex:1;font-size:16px;-webkit-user-select:none;user-select:none;transition:color .2s ease;white-space:nowrap;text-align:center}.drag-handle-active-objects .zoom-icon{color:#fff;font-size:18px;width:18px;height:18px}.drag-handle-active-objects .toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:22px;width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:6px;flex-shrink:0;margin:0}.drag-handle-active-objects .toggle-icon:hover{color:#ffffffb3;background:#1976d214}.active-objects-container{display:flex;flex-direction:column;align-items:center;width:100%;gap:10px;transition:all .3s ease;cursor:default;box-sizing:border-box}.active-objects-container .panel-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:5px;cursor:default}.active-objects-container .panel-header h4{margin:0;padding:5px;background:transparent;font-weight:600;color:#fff;flex:1;font-size:16px;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease;white-space:nowrap;text-align:center}.active-objects-container .panel-header .toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:22px;width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:6px;flex-shrink:0;margin:0}.active-objects-container .panel-header .toggle-icon:hover{color:#ffffffb3;background:#1976d214}.active-objects-container .collapsed-title{color:#fff;font-weight:600;font-size:12px;padding:8px 4px;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease;white-space:nowrap;text-align:center}.active-objects-container .collapsed-title:hover{color:#1976d2}.active-objects-content{display:block;max-height:278px;overflow:auto}.active-objects-content::-webkit-scrollbar{width:8px;border-radius:10px;border:5px solid transparent}.active-objects-content::-webkit-scrollbar-thumb{background:#0000004d;border:5px solid transparent;border-radius:10px;background-clip:padding-box}.active-objects-content::-webkit-scrollbar-thumb:hover{background:#0006;background-clip:padding-box;border:3px solid transparent}.active-objects-content .zoom-icon{color:#4caf50!important;border-radius:50%;padding:6px;margin:4px;cursor:pointer;transition:all .3s ease;font-size:20px;width:20px;height:20px}.active-objects-content .zoom-icon:hover{background:#4caf5033!important}mat-expansion-panel{border-radius:0!important;box-shadow:none!important}mat-expansion-panel:last-child{border-bottom:none}mat-expansion-panel ::ng-deep .mat-expansion-panel-header{padding:0 16px;font-weight:500}mat-expansion-panel ::ng-deep .mat-expansion-panel-header .mat-content{display:flex;justify-content:space-between;align-items:center;color:#fff}mat-expansion-panel ::ng-deep .mat-expansion-panel-body{padding:0}.item-list{display:flex;flex-direction:column;gap:4px;padding:8px;max-height:300px;overflow-y:auto}.item-list::-webkit-scrollbar{width:6px}.item-list::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.item-list::-webkit-scrollbar-thumb{background:#c1c1c1;border-radius:3px}.item-list::-webkit-scrollbar-thumb:hover{background:#a8a8a8}@media (max-width: 768px){.active-objects-wrapper{right:.5em;top:8em;max-width:280px;width:280px}.item{font-size:13px;padding:6px 10px}}@media (max-width: 480px){.active-objects-wrapper{right:.5em;left:.5em;max-width:calc(100vw - 1em);width:auto}.item-list{max-height:200px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i3.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i3.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i4.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i4.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
3279
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: ActiveObjectsComponent, isStandalone: true, selector: "activeObjects", inputs: { settings: "settings", profile: "profile" }, outputs: { sessionDone: "sessionDone" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"active-objects-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n <div class=\"drag-handle-active-objects\" cdkDragHandle>\n <mat-icon class=\"zoom-icon\" (click)=\"zoomToAll()\">dynamic_form</mat-icon>\n \n <div class=\"right-icons\">\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"togglePanel()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n </div>\n \n <div class=\"active-objects-container\">\n @if(!collapsed) {\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"opacity\"\n (input)=\"updateOpacity()\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n }\n\n @if(!collapsed) {\n <div class=\"active-objects-content\">\n <div class=\"header-icons\">\n <mat-icon \n class=\"zoom-icon\" \n [class.zoom-active]=\"isZoomedToAll\"\n (click)=\"zoomToAll()\" \n matTooltip=\"Zoom til alle\" \n matTooltipPosition=\"above\">\n fit_screen\n </mat-icon> \n <mat-icon class=\"reset-icon\" (click)=\"reset()\" matTooltip=\"Nulstilles\" matTooltipPosition=\"above\">replay</mat-icon>\n </div>\n @for(featureTypeObj of activeFeatures; track featureTypeObj.featureType) {\n <mat-expansion-panel>\n <mat-expansion-panel-header \n [matTooltip]=\"featureTypeObj.display\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"right\">\n <span class=\"panel-title\">\n {{featureTypeObj.display}} ({{featureTypeObj.features.length}})\n </span>\n </mat-expansion-panel-header>\n <div class=\"item-list\">\n @for(item of featureTypeObj.features; track item.id) {\n <div class=\"item\">\n <div class=\"item-text\">\n <span class=\"item-id\">{{item.id}}</span>\n <span class=\"item-area\">{{item.area}}</span>\n @if(item.containedMissingIn && item.containedMissingIn.length > 0) {\n <span>Udenfor {{item.containedMissingIn.join(', ')}} </span> \n }\n </div>\n @if(!item.locked) {\n <mat-icon (click)=\"delete(item.id)\">delete</mat-icon>\n }\n <mat-icon (click)=\"highlight(item.id)\" [class.highlight-active]=\"highlightedId === item.id\">power_settings_new</mat-icon>\n </div>\n }\n </div>\n </mat-expansion-panel>\n }\n @if(!centerPointOk) {\n <span>\n Der er ikke noget centerpunkt og det skal der v\u00E6re\n </span>\n } @else {\n @if (endSessionEnabled) {\n <button (click)=\"endSession()\">Afslut</button>\n }\n }\n </div>\n }\n </div> \n</div>", styles: [".active-objects-wrapper{position:absolute;top:8em;left:1em;z-index:2;cursor:grab;box-shadow:0 2px 10px #0000001a;background:#292a2d;width:350px;max-width:350px;transition:width .3s ease,max-width .3s ease;border-radius:5px 5px 0 0}.active-objects-wrapper.collapsed{width:90px}.active-objects-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}mat-expansion-panel ::ng-deep .mat-expansion-panel-header .panel-title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:320px;margin-right:10px;line-height:1.3;font-weight:600;color:#bdc1c3cc;font-size:17px}.item{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-radius:4px;background:color-mix(in srgb,#000 60%,transparent)!important;transition:all .2s ease;font-size:14px;color:#fff;min-height:40px;cursor:default}.item .item-text{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden}.item .item-id{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:2px;max-width:250px;font-size:13px}.item .item-area{font-size:12px;color:#ccc;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:250px}.item mat-icon{cursor:pointer;color:#f44336;font-size:18px;width:18px;height:18px;flex-shrink:0;margin-left:8px;transition:color .2s ease,background .2s ease}.item mat-icon:hover{color:#d32f2f}.highlight-active{color:#4caf50!important;text-shadow:0 0 6px #4caf50;transform:scale(1.1);transition:all .2s ease}.drag-handle-active-objects{display:flex;align-items:center;justify-content:space-between;background:#292a2d;padding:2px 8px;cursor:grab;color:#fff;border-radius:5px 5px 0 0}.drag-handle-active-objects .toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.drag-handle-active-objects .toggle-icon:hover{color:#fff;background:#ffffff26}.right-icons{display:flex;align-items:center;gap:6px}.right-icons .drag-indicator-right{font-size:18px!important;width:18px!important;height:18px!important}.active-objects-container{display:flex;flex-direction:column;align-items:center;width:100%;gap:10px;transition:all .3s ease;cursor:default;box-sizing:border-box}.active-objects-container .panel-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:8px 12px;cursor:default;background:color-mix(in srgb,#000 70%,transparent);border-bottom:1px solid rgba(255,255,255,.1)}.active-objects-container .collapsed-title{color:#fff;font-weight:600;font-size:12px;padding:8px 4px;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease;white-space:nowrap;text-align:center}.active-objects-container .collapsed-title:hover{color:#1976d2}.header-icons{display:flex!important;align-items:center!important;justify-content:flex-end!important;gap:8px!important;padding:0 10px!important}.header-icons .reset-icon{cursor:pointer;color:#fff;font-size:20px;width:20px;height:20px;transition:all .2s ease;padding:4px}.header-icons .reset-icon:hover{color:#ff9800}.active-objects-container input[type=range]{width:95%;margin:8px auto}.active-objects-content{display:block;width:100%;max-height:278px;overflow:auto;background:#000}.active-objects-content::-webkit-scrollbar{width:12px}.active-objects-content::-webkit-scrollbar-track{background:#757474;border-radius:8px}.active-objects-content::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}.active-objects-content::-webkit-scrollbar-thumb:hover{background:#0f1012}.active-objects-content::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}.active-objects-content::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}.active-objects-content::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}.active-objects-content::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}.active-objects-content::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}.active-objects-content .zoom-icon{color:#fff;font-size:18px;width:18px;height:18px;opacity:.6;transition:all .2s ease}.active-objects-content .zoom-icon:hover{color:#4caf50;opacity:1}.active-objects-content .zoom-icon.zoom-active{color:#4caf50!important;text-shadow:0 0 6px #4caf50;opacity:1}mat-expansion-panel{border-radius:0!important;box-shadow:none!important;width:100%}mat-expansion-panel:last-child{border-bottom:none}mat-expansion-panel ::ng-deep .mat-expansion-panel-header{padding:0 16px;font-weight:500}mat-expansion-panel ::ng-deep .mat-expansion-panel-header .mat-content{display:flex;justify-content:space-between;align-items:center;color:#fff}mat-expansion-panel ::ng-deep .mat-expansion-panel-body{padding:0}.item-list{display:flex;flex-direction:column;padding:8px}@media (max-width: 768px){.active-objects-wrapper{right:.5em;top:8em;max-width:280px;width:280px}.item{font-size:13px;padding:6px 10px}}@media (max-width: 480px){.active-objects-wrapper{right:.5em;left:.5em;max-width:calc(100vw - 1em);width:auto}.item-list{max-height:200px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i6.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i6.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i5.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i5.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
1862
3280
|
}
|
|
1863
3281
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ActiveObjectsComponent, decorators: [{
|
|
1864
3282
|
type: Component,
|
|
1865
|
-
args: [{ selector: 'activeObjects', imports: [CommonModule, FormsModule, MatExpansionModule, MatIconModule, DragDropModule, MatTooltipModule], template: "<div class=\"active-objects-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n <div class=\"drag-handle-active-objects\" cdkDragHandle>\n <mat-icon class=\"zoom-icon\" (click)=\"zoomToAll()\">share_reviewsr</mat-icon>\n @if(!collapsed) {\n <h4>Aktive flader</h4>\n }\n <mat-icon class=\"toggle-icon\" (click)=\"togglePanel()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n <div class=\"active-objects-container\">\n @if(!collapsed) {\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"opacity\"\n (input)=\"updateOpacity()\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n }\n\n @if(!collapsed) {\n <div class=\"active-objects-content\">\n <mat-icon class=\"zoom-icon\" (click)=\"zoomToAll()\">highlight</mat-icon>\n @for(featureTypeObj of activeFeatures; track featureTypeObj.featureType) {\n <mat-expansion-panel>\n <mat-expansion-panel-header \n [matTooltip]=\"featureTypeObj.display\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"right\">\n <span class=\"panel-title\">\n {{featureTypeObj.display}} ({{featureTypeObj.features.length}})\n </span>\n </mat-expansion-panel-header>\n <div class=\"item-list\">\n @for(item of featureTypeObj.features; track item.id) {\n <div class=\"item\">\n <div class=\"item-text\">\n <span class=\"item-id\">{{item.id}}</span>\n <span class=\"item-area\">{{item.area}}</span>\n </div>\n <mat-icon *ngIf=\"!item.locked\" (click)=\"delete(item.id)\">delete</mat-icon>\n <mat-icon (click)=\"highlight(item.id)\" [class.highlight-active]=\"highlightedId === item.id\">highlight</mat-icon>\n </div>\n }\n </div>\n </mat-expansion-panel>\n }\n </div>\n }\n </div> \n</div>", styles: ["@charset \"UTF-8\";.active-objects-wrapper{position:absolute;top:15em;left:1em;z-index:1000;cursor:grab;box-shadow:0 2px 10px #0000001a;background:color-mix(in srgb,#000 60%,transparent);width:fit-content;max-width:295px;transition:width .3s ease}.active-objects-wrapper.collapsed{width:70px;max-width:150px}.active-objects-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}mat-expansion-panel ::ng-deep .mat-expansion-panel-header .panel-title{display:block;overflow:visible;text-overflow:clip;white-space:normal;max-width:220px;margin-right:10px;line-height:1.3;word-break:break-word}.item{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-radius:4px;background:color-mix(in srgb,#000 60%,transparent)!important;transition:all .2s ease;font-size:14px;color:#fff;min-height:40px;cursor:default}.item .item-text{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden}.item .item-id{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:2px}.item .item-area{font-size:12px;color:#ccc;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.item mat-icon{cursor:pointer;color:#f44336;font-size:18px;width:18px;height:18px;flex-shrink:0;margin-left:8px;transition:color .2s ease,background .2s ease}.item mat-icon:hover{color:#d32f2f}.highlight-active{color:#4caf50!important;text-shadow:0 0 6px #4caf50;transform:scale(1.1);transition:all .2s ease}.drag-handle-active-objects{display:flex;align-items:center;justify-content:space-between;background:color-mix(in srgb,#000 0%,transparent);border-radius:8px 8px 0 0;padding:4px 8px;cursor:grab}.drag-handle-active-objects h4{margin:0;padding:5px;background:transparent;font-weight:600;color:#fff;flex:1;font-size:16px;-webkit-user-select:none;user-select:none;transition:color .2s ease;white-space:nowrap;text-align:center}.drag-handle-active-objects .zoom-icon{color:#fff;font-size:18px;width:18px;height:18px}.drag-handle-active-objects .toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:22px;width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:6px;flex-shrink:0;margin:0}.drag-handle-active-objects .toggle-icon:hover{color:#ffffffb3;background:#1976d214}.active-objects-container{display:flex;flex-direction:column;align-items:center;width:100%;gap:10px;transition:all .3s ease;cursor:default;box-sizing:border-box}.active-objects-container .panel-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:5px;cursor:default}.active-objects-container .panel-header h4{margin:0;padding:5px;background:transparent;font-weight:600;color:#fff;flex:1;font-size:16px;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease;white-space:nowrap;text-align:center}.active-objects-container .panel-header .toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:22px;width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:6px;flex-shrink:0;margin:0}.active-objects-container .panel-header .toggle-icon:hover{color:#ffffffb3;background:#1976d214}.active-objects-container .collapsed-title{color:#fff;font-weight:600;font-size:12px;padding:8px 4px;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease;white-space:nowrap;text-align:center}.active-objects-container .collapsed-title:hover{color:#1976d2}.active-objects-content{display:block;max-height:278px;overflow:auto}.active-objects-content::-webkit-scrollbar{width:8px;border-radius:10px;border:5px solid transparent}.active-objects-content::-webkit-scrollbar-thumb{background:#0000004d;border:5px solid transparent;border-radius:10px;background-clip:padding-box}.active-objects-content::-webkit-scrollbar-thumb:hover{background:#0006;background-clip:padding-box;border:3px solid transparent}.active-objects-content .zoom-icon{color:#4caf50!important;border-radius:50%;padding:6px;margin:4px;cursor:pointer;transition:all .3s ease;font-size:20px;width:20px;height:20px}.active-objects-content .zoom-icon:hover{background:#4caf5033!important}mat-expansion-panel{border-radius:0!important;box-shadow:none!important}mat-expansion-panel:last-child{border-bottom:none}mat-expansion-panel ::ng-deep .mat-expansion-panel-header{padding:0 16px;font-weight:500}mat-expansion-panel ::ng-deep .mat-expansion-panel-header .mat-content{display:flex;justify-content:space-between;align-items:center;color:#fff}mat-expansion-panel ::ng-deep .mat-expansion-panel-body{padding:0}.item-list{display:flex;flex-direction:column;gap:4px;padding:8px;max-height:300px;overflow-y:auto}.item-list::-webkit-scrollbar{width:6px}.item-list::-webkit-scrollbar-track{background:#f1f1f1;border-radius:3px}.item-list::-webkit-scrollbar-thumb{background:#c1c1c1;border-radius:3px}.item-list::-webkit-scrollbar-thumb:hover{background:#a8a8a8}@media (max-width: 768px){.active-objects-wrapper{right:.5em;top:8em;max-width:280px;width:280px}.item{font-size:13px;padding:6px 10px}}@media (max-width: 480px){.active-objects-wrapper{right:.5em;left:.5em;max-width:calc(100vw - 1em);width:auto}.item-list{max-height:200px}}\n"] }]
|
|
3283
|
+
args: [{ selector: 'activeObjects', imports: [CommonModule, FormsModule, MatExpansionModule, MatIconModule, DragDropModule, MatTooltipModule], template: "<div class=\"active-objects-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n <div class=\"drag-handle-active-objects\" cdkDragHandle>\n <mat-icon class=\"zoom-icon\" (click)=\"zoomToAll()\">dynamic_form</mat-icon>\n \n <div class=\"right-icons\">\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"togglePanel()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n </div>\n \n <div class=\"active-objects-container\">\n @if(!collapsed) {\n <input \n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [(ngModel)]=\"opacity\"\n (input)=\"updateOpacity()\"\n (mousedown)=\"stopDrag($event)\"\n (touchstart)=\"stopDrag($event)\"\n (pointerdown)=\"stopDrag($event)\"\n >\n }\n\n @if(!collapsed) {\n <div class=\"active-objects-content\">\n <div class=\"header-icons\">\n <mat-icon \n class=\"zoom-icon\" \n [class.zoom-active]=\"isZoomedToAll\"\n (click)=\"zoomToAll()\" \n matTooltip=\"Zoom til alle\" \n matTooltipPosition=\"above\">\n fit_screen\n </mat-icon> \n <mat-icon class=\"reset-icon\" (click)=\"reset()\" matTooltip=\"Nulstilles\" matTooltipPosition=\"above\">replay</mat-icon>\n </div>\n @for(featureTypeObj of activeFeatures; track featureTypeObj.featureType) {\n <mat-expansion-panel>\n <mat-expansion-panel-header \n [matTooltip]=\"featureTypeObj.display\" \n [matTooltipShowDelay]=\"200\"\n [matTooltipHideDelay]=\"300\" \n matTooltipPosition=\"right\">\n <span class=\"panel-title\">\n {{featureTypeObj.display}} ({{featureTypeObj.features.length}})\n </span>\n </mat-expansion-panel-header>\n <div class=\"item-list\">\n @for(item of featureTypeObj.features; track item.id) {\n <div class=\"item\">\n <div class=\"item-text\">\n <span class=\"item-id\">{{item.id}}</span>\n <span class=\"item-area\">{{item.area}}</span>\n @if(item.containedMissingIn && item.containedMissingIn.length > 0) {\n <span>Udenfor {{item.containedMissingIn.join(', ')}} </span> \n }\n </div>\n @if(!item.locked) {\n <mat-icon (click)=\"delete(item.id)\">delete</mat-icon>\n }\n <mat-icon (click)=\"highlight(item.id)\" [class.highlight-active]=\"highlightedId === item.id\">power_settings_new</mat-icon>\n </div>\n }\n </div>\n </mat-expansion-panel>\n }\n @if(!centerPointOk) {\n <span>\n Der er ikke noget centerpunkt og det skal der v\u00E6re\n </span>\n } @else {\n @if (endSessionEnabled) {\n <button (click)=\"endSession()\">Afslut</button>\n }\n }\n </div>\n }\n </div> \n</div>", styles: [".active-objects-wrapper{position:absolute;top:8em;left:1em;z-index:2;cursor:grab;box-shadow:0 2px 10px #0000001a;background:#292a2d;width:350px;max-width:350px;transition:width .3s ease,max-width .3s ease;border-radius:5px 5px 0 0}.active-objects-wrapper.collapsed{width:90px}.active-objects-wrapper.cdk-drag-dragging{opacity:.8;cursor:grab;z-index:1001}mat-expansion-panel ::ng-deep .mat-expansion-panel-header .panel-title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:320px;margin-right:10px;line-height:1.3;font-weight:600;color:#bdc1c3cc;font-size:17px}.item{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-radius:4px;background:color-mix(in srgb,#000 60%,transparent)!important;transition:all .2s ease;font-size:14px;color:#fff;min-height:40px;cursor:default}.item .item-text{flex:1;min-width:0;display:flex;flex-direction:column;overflow:hidden}.item .item-id{font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:2px;max-width:250px;font-size:13px}.item .item-area{font-size:12px;color:#ccc;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:250px}.item mat-icon{cursor:pointer;color:#f44336;font-size:18px;width:18px;height:18px;flex-shrink:0;margin-left:8px;transition:color .2s ease,background .2s ease}.item mat-icon:hover{color:#d32f2f}.highlight-active{color:#4caf50!important;text-shadow:0 0 6px #4caf50;transform:scale(1.1);transition:all .2s ease}.drag-handle-active-objects{display:flex;align-items:center;justify-content:space-between;background:#292a2d;padding:2px 8px;cursor:grab;color:#fff;border-radius:5px 5px 0 0}.drag-handle-active-objects .toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.drag-handle-active-objects .toggle-icon:hover{color:#fff;background:#ffffff26}.right-icons{display:flex;align-items:center;gap:6px}.right-icons .drag-indicator-right{font-size:18px!important;width:18px!important;height:18px!important}.active-objects-container{display:flex;flex-direction:column;align-items:center;width:100%;gap:10px;transition:all .3s ease;cursor:default;box-sizing:border-box}.active-objects-container .panel-header{display:flex;align-items:center;justify-content:space-between;width:100%;padding:8px 12px;cursor:default;background:color-mix(in srgb,#000 70%,transparent);border-bottom:1px solid rgba(255,255,255,.1)}.active-objects-container .collapsed-title{color:#fff;font-weight:600;font-size:12px;padding:8px 4px;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease;white-space:nowrap;text-align:center}.active-objects-container .collapsed-title:hover{color:#1976d2}.header-icons{display:flex!important;align-items:center!important;justify-content:flex-end!important;gap:8px!important;padding:0 10px!important}.header-icons .reset-icon{cursor:pointer;color:#fff;font-size:20px;width:20px;height:20px;transition:all .2s ease;padding:4px}.header-icons .reset-icon:hover{color:#ff9800}.active-objects-container input[type=range]{width:95%;margin:8px auto}.active-objects-content{display:block;width:100%;max-height:278px;overflow:auto;background:#000}.active-objects-content::-webkit-scrollbar{width:12px}.active-objects-content::-webkit-scrollbar-track{background:#757474;border-radius:8px}.active-objects-content::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}.active-objects-content::-webkit-scrollbar-thumb:hover{background:#0f1012}.active-objects-content::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}.active-objects-content::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}.active-objects-content::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}.active-objects-content::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}.active-objects-content::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}.active-objects-content .zoom-icon{color:#fff;font-size:18px;width:18px;height:18px;opacity:.6;transition:all .2s ease}.active-objects-content .zoom-icon:hover{color:#4caf50;opacity:1}.active-objects-content .zoom-icon.zoom-active{color:#4caf50!important;text-shadow:0 0 6px #4caf50;opacity:1}mat-expansion-panel{border-radius:0!important;box-shadow:none!important;width:100%}mat-expansion-panel:last-child{border-bottom:none}mat-expansion-panel ::ng-deep .mat-expansion-panel-header{padding:0 16px;font-weight:500}mat-expansion-panel ::ng-deep .mat-expansion-panel-header .mat-content{display:flex;justify-content:space-between;align-items:center;color:#fff}mat-expansion-panel ::ng-deep .mat-expansion-panel-body{padding:0}.item-list{display:flex;flex-direction:column;padding:8px}@media (max-width: 768px){.active-objects-wrapper{right:.5em;top:8em;max-width:280px;width:280px}.item{font-size:13px;padding:6px 10px}}@media (max-width: 480px){.active-objects-wrapper{right:.5em;left:.5em;max-width:calc(100vw - 1em);width:auto}.item-list{max-height:200px}}\n"] }]
|
|
1866
3284
|
}], ctorParameters: () => [], propDecorators: { settings: [{
|
|
1867
3285
|
type: Input,
|
|
1868
3286
|
args: [{ required: true }]
|
|
3287
|
+
}], sessionDone: [{
|
|
3288
|
+
type: Output
|
|
3289
|
+
}], profile: [{
|
|
3290
|
+
type: Input,
|
|
3291
|
+
args: [{ required: true }]
|
|
1869
3292
|
}] } });
|
|
1870
3293
|
|
|
3294
|
+
class WFSSearchService {
|
|
3295
|
+
name = 'WFS Search';
|
|
3296
|
+
_http = inject(HttpClient);
|
|
3297
|
+
wfsFormat = new WFS();
|
|
3298
|
+
wktFormat = new WKT();
|
|
3299
|
+
_searcheableLayers = [];
|
|
3300
|
+
geoJsonFormat = new GeoJSON({ dataProjection: 'EPSG:25832', featureProjection: 'EPSG:25832' });
|
|
3301
|
+
_serializer = new XMLSerializer();
|
|
3302
|
+
search(searchValue, geometry, maxCount = 5) {
|
|
3303
|
+
const wftSearches = [];
|
|
3304
|
+
this._searcheableLayers.flatMap(layer => {
|
|
3305
|
+
const filter = searchValue ? like(layer.searchField, `*${searchValue}*`, '*', '?', '/', false) :
|
|
3306
|
+
geometry ? intersects(layer.geometryField, geometry, 'EPSG:25832') : undefined;
|
|
3307
|
+
var searchFeature = this.wfsFormat.writeGetFeature({
|
|
3308
|
+
featureTypes: [layer.featureType.includes(':') ? layer.featureType.split(':')[1] : ''],
|
|
3309
|
+
outputFormat: 'application/json',
|
|
3310
|
+
featureNS: '',
|
|
3311
|
+
featurePrefix: '',
|
|
3312
|
+
srsName: 'EPSG:25832',
|
|
3313
|
+
maxFeatures: maxCount,
|
|
3314
|
+
filter
|
|
3315
|
+
});
|
|
3316
|
+
const fieldsToExclude = new Set(layer.fieldsToExcludeFromInfoFromInfo.split(',').map(f => f.toLowerCase().trim()));
|
|
3317
|
+
wftSearches.push(this._http.post(layer.baseUrl.replace('wms', 'wfs'), this._serializer.serializeToString(searchFeature), { headers: { 'Content-Type': 'text/xml' }, responseType: 'json' }).pipe(map$1(r => {
|
|
3318
|
+
const result = {
|
|
3319
|
+
title: layer.name,
|
|
3320
|
+
total: r.numberMatched ?? 0,
|
|
3321
|
+
items: r.features.map(f => ({ header: f.properties[layer.headerField], wkt: this._formatWKT(f), metadata: this._mapFeatureMetadata(f, fieldsToExclude), showMetadata: false }))
|
|
3322
|
+
};
|
|
3323
|
+
return result;
|
|
3324
|
+
})));
|
|
3325
|
+
});
|
|
3326
|
+
return combineLatest(wftSearches);
|
|
3327
|
+
}
|
|
3328
|
+
onSelect(searchResult, targetSrs) {
|
|
3329
|
+
// TO DO : add logic for when an item is selected (right now, the map search component does a highlight on it)
|
|
3330
|
+
}
|
|
3331
|
+
onClear() {
|
|
3332
|
+
// TO DO : add logic for when the results list is cleared
|
|
3333
|
+
}
|
|
3334
|
+
setSearcheableLayers(layers) {
|
|
3335
|
+
this._searcheableLayers = layers;
|
|
3336
|
+
}
|
|
3337
|
+
_formatWKT(feature) {
|
|
3338
|
+
const olFeature = this.geoJsonFormat.readFeature(feature);
|
|
3339
|
+
return this.wktFormat.writeFeature(olFeature);
|
|
3340
|
+
}
|
|
3341
|
+
_mapFeatureMetadata(f, excludeSet) {
|
|
3342
|
+
const result = {};
|
|
3343
|
+
const props = f.properties || {};
|
|
3344
|
+
for (const [key, value] of Object.entries(props)) {
|
|
3345
|
+
if (excludeSet.has(key.toLowerCase()))
|
|
3346
|
+
continue;
|
|
3347
|
+
const kind = this._getValueKind(value);
|
|
3348
|
+
result[key] = { kind, data: value, name: key };
|
|
3349
|
+
}
|
|
3350
|
+
return [result];
|
|
3351
|
+
}
|
|
3352
|
+
_getValueKind(value) {
|
|
3353
|
+
const imgTypes = ['.png', '.jpg', '.gif', '.jpeg'];
|
|
3354
|
+
if (typeof value === 'string') {
|
|
3355
|
+
if (value.startsWith('http://') || value.startsWith('https://')) {
|
|
3356
|
+
if (imgTypes.some(ext => value.endsWith(ext))) {
|
|
3357
|
+
return 'img';
|
|
3358
|
+
}
|
|
3359
|
+
return 'url';
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
return 'data';
|
|
3363
|
+
}
|
|
3364
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: WFSSearchService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3365
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: WFSSearchService, providedIn: 'root' });
|
|
3366
|
+
}
|
|
3367
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: WFSSearchService, decorators: [{
|
|
3368
|
+
type: Injectable,
|
|
3369
|
+
args: [{
|
|
3370
|
+
providedIn: 'root'
|
|
3371
|
+
}]
|
|
3372
|
+
}] });
|
|
3373
|
+
|
|
1871
3374
|
class MapSearchComponent {
|
|
1872
3375
|
searchAddress = '';
|
|
1873
|
-
|
|
3376
|
+
profile;
|
|
3377
|
+
// allResults = ['address1', 'address2', 'address3', 'address4'];
|
|
1874
3378
|
filteredResults = [];
|
|
1875
3379
|
collapsed = true;
|
|
1876
3380
|
dragPosition = { x: 0, y: 0 };
|
|
1877
3381
|
POSITION_STORAGE_KEY = 'mapSearchPosition';
|
|
3382
|
+
_mapFilteredLayerGroupsKeyName = 'mapFilteredLayerGroups';
|
|
3383
|
+
_highlight = inject(HighlightService);
|
|
3384
|
+
_searchSubject = new Subject();
|
|
3385
|
+
_searchService = inject(SearchProviderService);
|
|
3386
|
+
_searchProviderService = inject(SearchProviderService);
|
|
3387
|
+
_wfsSearch = inject(WFSSearchService);
|
|
3388
|
+
_layerHelperService = inject(LayerHelperService);
|
|
3389
|
+
_layoutService = inject(LayoutService);
|
|
1878
3390
|
ngOnInit() {
|
|
3391
|
+
this._layerHelperService.activeLayersChanged
|
|
3392
|
+
.subscribe(() => this._addWFSSearchLayers());
|
|
1879
3393
|
this.filterResults();
|
|
1880
3394
|
this._loadPosition();
|
|
3395
|
+
this._addWFSSearch();
|
|
3396
|
+
this._searchSubject.pipe(debounceTime(200), distinctUntilChanged(), switchMap(value => this._searchService.search(value, undefined))).subscribe({
|
|
3397
|
+
next: result => {
|
|
3398
|
+
this.filteredResults = result.filter(result => result.total > 0);
|
|
3399
|
+
}
|
|
3400
|
+
});
|
|
3401
|
+
}
|
|
3402
|
+
ngOnChanges(changes) {
|
|
3403
|
+
if (changes['profile'] && this.profile) {
|
|
3404
|
+
this._loadPosition();
|
|
3405
|
+
this._addWFSSearchLayers();
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
_addWFSSearch() {
|
|
3409
|
+
this._searchProviderService.searchProviders = [];
|
|
3410
|
+
this._searchProviderService.searchProviders.push(this._wfsSearch);
|
|
3411
|
+
}
|
|
3412
|
+
_addWFSSearchLayers() {
|
|
3413
|
+
if (this.profile) {
|
|
3414
|
+
const cacheValue = localStorage.getItem(`${this._mapFilteredLayerGroupsKeyName}_${this.profile.id}`);
|
|
3415
|
+
if (cacheValue) {
|
|
3416
|
+
const cachedProfileInfo = JSON.parse(cacheValue);
|
|
3417
|
+
const visibleLayerIds = cachedProfileInfo.cachedLayerGroups
|
|
3418
|
+
.flatMap(group => group.layers)
|
|
3419
|
+
.filter(layer => layer.visible)
|
|
3420
|
+
.map(layer => layer.id);
|
|
3421
|
+
const searcheableLayers = cachedProfileInfo.profile
|
|
3422
|
+
.layerGroups.flatMap(group => group.layers)
|
|
3423
|
+
.filter(layer => layer.wfsSearchable && visibleLayerIds.includes(layer.id))
|
|
3424
|
+
.map(layer => ({ featureType: layer.layers, baseUrl: layer.baseUrl, name: layer.name,
|
|
3425
|
+
headerField: layer.headerField, searchField: layer.searchField, geometryField: layer.geometryField,
|
|
3426
|
+
fieldsToExcludeFromInfoFromInfo: layer.fieldsToExcludeFromInfoFromInfo }));
|
|
3427
|
+
this._wfsSearch.setSearcheableLayers(searcheableLayers);
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
1881
3430
|
}
|
|
1882
3431
|
filterResults() {
|
|
1883
3432
|
if (!this.searchAddress) {
|
|
1884
3433
|
this.filteredResults = [];
|
|
1885
3434
|
return;
|
|
1886
3435
|
}
|
|
1887
|
-
this.
|
|
3436
|
+
this._searchSubject.next(this.searchAddress);
|
|
3437
|
+
// this._wfsSearch.search(this.searchAddress).subscribe(r => {
|
|
3438
|
+
// this.filteredResults = [r];
|
|
3439
|
+
// });
|
|
1888
3440
|
}
|
|
1889
3441
|
toggleSearch() {
|
|
1890
3442
|
this.collapsed = !this.collapsed;
|
|
@@ -1893,6 +3445,10 @@ class MapSearchComponent {
|
|
|
1893
3445
|
this.filterResults();
|
|
1894
3446
|
}
|
|
1895
3447
|
}
|
|
3448
|
+
highlight(wkt, event) {
|
|
3449
|
+
event.stopPropagation();
|
|
3450
|
+
this._highlight.highlight(wkt);
|
|
3451
|
+
}
|
|
1896
3452
|
onDragEnded(event) {
|
|
1897
3453
|
const position = event.source.getFreeDragPosition();
|
|
1898
3454
|
this.dragPosition = position;
|
|
@@ -1912,6 +3468,9 @@ class MapSearchComponent {
|
|
|
1912
3468
|
if (savedPosition) {
|
|
1913
3469
|
this.dragPosition = JSON.parse(savedPosition);
|
|
1914
3470
|
}
|
|
3471
|
+
else if (this.profile) {
|
|
3472
|
+
this.dragPosition = this._layoutService.loadInitialPositionFromProfile(this.POSITION_STORAGE_KEY, this.profile.searchInitialPosition);
|
|
3473
|
+
}
|
|
1915
3474
|
}
|
|
1916
3475
|
catch (error) {
|
|
1917
3476
|
console.error('Error loading position from localStorage:', error);
|
|
@@ -1919,7 +3478,7 @@ class MapSearchComponent {
|
|
|
1919
3478
|
}
|
|
1920
3479
|
}
|
|
1921
3480
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MapSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1922
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: MapSearchComponent, isStandalone: true, selector: "lib-map-search", ngImport: i0, template: "<div class=\"search-container\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n <div class=\"drag-handle\" cdkDragHandle>\n <mat-icon>search</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleSearch()\">{{ collapsed ? 'flip_to_front' : 'remove' }}</mat-icon>\n </div>\n <div class=\"search-content\" *ngIf=\"!collapsed\">\n <mat-form-field appearance=\"outline\" class=\"search-field\">\n <mat-label>S\u00F8ge</mat-label>\n <input\n type=\"text\"\n matInput\n [(ngModel)]=\"searchAddress\"\n [matAutocomplete]=\"auto\"\n (input)=\"filterResults()\"\n />\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let result of filteredResults\" [value]=\"result\">\n {{ result }}\n </mat-option>\n </mat-autocomplete>\n </mat-form-field>\n </div>\n</div>", styles: [".search-container{position:absolute;top:8em;left:1em;z-index:1000;cursor:grab;max-width:400px;min-width:48px;width:auto}.search-container.collapsed{width:48px;min-width:68px;max-width:48px}.search-container.cdk-drag-dragging{opacity:.8;cursor:grab}.drag-handle{display:flex;align-items:center;justify-content:space-between;background:color-mix(in srgb,#000 60%,transparent);padding:4px;cursor:grab}.drag-handle mat-icon:not(.toggle-icon){color:#fff;font-size:20px;width:20px;height:20px}.search-content{display:flex;align-items:center;background:color-mix(in srgb,#000 60%,transparent);padding:5px;transition:all .3s ease;box-sizing:border-box;cursor:default}.toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:20px;width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:6px;flex-shrink:0}.toggle-icon:hover{color:#2196f3;background:#2196f314}.search-field{width:100%;min-width:200px;cursor:pointer;flex:1}.search-field ::ng-deep .mat-mdc-form-field-focus-overlay{background-color:transparent}.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:transparent!important;border-width:1.5px!important;transition:border-color .3s ease,border-width .3s ease}.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:transparent!important}.search-field ::ng-deep .mat-mdc-form-field-label{color:#fff!important;font-weight:500;font-size:15px}.search-field ::ng-deep .mat-mdc-form-field.mat-focused .mat-mdc-form-field-label{color:#2196f3!important}.search-field ::ng-deep .mat-mdc-input-element{font-size:15px;color:#fff;font-weight:400;line-height:1.5}.search-field ::ng-deep .mat-mdc-input-element::placeholder{color:#ccc;font-weight:400;opacity:.8}.search-field ::ng-deep .mdc-floating-label{padding:0 4px;left:40px!important}::ng-deep .mat-mdc-form-field.mat-form-field-animations-enabled .mdc-text-field__input{margin-left:12px;color:#fff!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option .mdc-list-item__primary-text{color:#fff!important}::ng-deep .mat-mdc-option .mat-pseudo-checkbox-minimal{color:#fff!important}::ng-deep .mat-mdc-form-field-flex{height:40px!important}::ng-deep .mat-mdc-autocomplete-panel{border-radius:12px!important;max-height:320px!important;background:color-mix(in srgb,#000 85%,transparent)!important;box-shadow:0 8px 24px #00000026!important;margin-top:8px!important;overflow:hidden!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option{min-height:30px!important;border-radius:8px!important;transition:all .2s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option:hover:not(.mdc-list-item--disabled){background-color:#0000004d!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px;font-weight:400;color:inherit;line-height:1.5}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar{width:6px}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-track{background:#f1f1f1;border-radius:0 12px 12px 0}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-thumb{background:#c1c1c1;border-radius:3px;transition:background .3s ease}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-thumb:hover{background:#a8a8a8}::ng-deep .mat-mdc-text-field-wrapper{background:color-mix(in srgb,#000 60%,transparent);border-radius:8px;box-shadow:#0000004d 0 1px 4px -1px;transition:all .3s cubic-bezier(.4,0,.2,1)}::ng-deep .mat-mdc-text-field-wrapper:hover{box-shadow:0 4px 16px #00000026}::ng-deep .mat-mdc-form-field:not(.mat-form-field-disabled) .mat-mdc-floating-label.mdc-floating-label{color:#fff!important}::ng-deep .mdc-text-field{border-radius:8px!important}@media (max-width: 768px){.search-container{left:2em;top:1.5em;max-width:350px}.search-container.collapsed{width:44px;min-width:44px;max-width:44px}.search-field{min-width:180px}.toggle-icon{font-size:18px;width:18px;height:18px}}@media (max-width: 480px){.search-container{left:1.5em;right:1.5em;max-width:calc(100vw - 3em)}.search-container.collapsed{width:40px;min-width:40px;max-width:40px;right:auto}.search-field{min-width:150px}.search-field ::ng-deep .mat-mdc-input-element{font-size:14px}::ng-deep .mat-mdc-autocomplete-panel{max-height:240px!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option{min-height:48px!important;padding:10px 16px!important}.toggle-icon{font-size:16px;width:16px;height:16px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i5$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i4$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i5$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i4.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i4.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }] });
|
|
3481
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.15", type: MapSearchComponent, isStandalone: true, selector: "lib-map-search", inputs: { profile: "profile" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"search-container\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n <div class=\"drag-handle\" cdkDragHandle>\n <mat-icon class=\"icon-left\">search</mat-icon>\n <div class=\"right-icons\">\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleSearch()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n </div>\n\n <div class=\"search-content\" *ngIf=\"!collapsed\">\n <mat-form-field appearance=\"outline\" class=\"search-field\">\n <mat-label>S\u00F8ge</mat-label>\n <input\n type=\"text\"\n matInput\n [(ngModel)]=\"searchAddress\"\n [matAutocomplete]=\"auto\"\n (input)=\"filterResults()\"\n />\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let result of filteredResults\" [value]=\"result\" class=\"search-result-option\">\n <span class=\"result-title\">\n {{ result.title }} ({{result.items.length}} af {{ result.total }})\n </span>\n <div *ngFor=\"let item of result.items\" class=\"search-result-item\">\n <span class=\"item-header\">\n {{item.header}}\n </span>\n <mat-icon (click)=\"highlight(item.wkt, $event)\">power_settings_new </mat-icon>\n </div>\n </mat-option>\n </mat-autocomplete>\n </mat-form-field>\n </div>\n</div>", styles: [".search-container{position:absolute;top:8em;left:1em;z-index:2;cursor:grab;max-width:400px;min-width:48px;width:auto}.search-container.cdk-drag-dragging{opacity:.8;cursor:grab}.compact-icon.custom-image-icon{padding:4px;background:none;border:1px solid rgba(255,255,255,.2)}.compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:filter .2s ease}.compact-icon.custom-image-icon.active{background:linear-gradient(147.38deg,#0ea5e9,#075985);border-color:transparent;box-shadow:0 4px 12px #0ea5e966}.compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1)}.compact-icon.custom-image-icon.active:hover{box-shadow:0 6px 20px #0ea5e980}.compact-icon.custom-image-icon:hover:not(.active){background:color-mix(in srgb,#000 70%,transparent);border-color:#0ea5e9;box-shadow:0 2px 8px #0ea5e94d}.compact-icon.custom-image-icon:hover:not(.active) img{filter:brightness(0) invert(.8)}.drag-handle{display:flex;align-items:center;justify-content:space-between;background:#292a2d;padding:2px 8px;cursor:grab;border-radius:5px 5px 0 0;color:#fff}.right-icons{display:flex;align-items:center;gap:6px}.right-icons .drag-indicator-right{font-size:18px!important;width:18px!important;height:18px!important}.search-content{display:flex;flex-direction:column;background:#292a2d;padding:6px;transition:all .3s ease;box-sizing:border-box;cursor:default;border-radius:0 0 5px 5px}.compact-icon{transition:all .3s cubic-bezier(.4,0,.2,1)}.compact-icon.custom-image-icon{background:none;border:1px solid rgba(255,255,255,.2);border-radius:4px;cursor:pointer}.toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.toggle-icon:hover{color:#fff;background:#ffffff26}.search-field{width:100%;min-width:200px;cursor:pointer;flex:1}.search-field ::ng-deep .mat-mdc-form-field-focus-overlay{background-color:transparent}.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:transparent!important;border-width:1.5px!important;transition:border-color .3s ease,border-width .3s ease}.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:transparent!important}.search-field ::ng-deep .mat-mdc-form-field-label{color:#fff!important;font-weight:500;font-size:15px}.search-field ::ng-deep .mat-mdc-form-field.mat-focused .mat-mdc-form-field-label{color:#2196f3!important}.search-field ::ng-deep .mat-mdc-input-element{font-size:15px;color:#fff;font-weight:400;line-height:1.5}.search-field ::ng-deep .mat-mdc-input-element::placeholder{color:#ccc;font-weight:400;opacity:.8}.search-field ::ng-deep .mdc-floating-label{padding:0 4px;left:40px!important}::ng-deep .mat-mdc-form-field.mat-form-field-animations-enabled .mdc-text-field__input{margin-left:12px;color:#fff!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option .mdc-list-item__primary-text{color:#fff!important}::ng-deep .mat-mdc-option .mat-pseudo-checkbox-minimal{color:#fff!important}::ng-deep .mat-mdc-form-field-flex{height:40px!important}::ng-deep .mat-mdc-autocomplete-panel{border-radius:5px!important;max-height:320px!important;background:color-mix(in srgb,#000 85%,transparent)!important;box-shadow:0 8px 24px #00000026!important;margin-top:64px;overflow-y:auto!important;padding:8px!important}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar{width:12px}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option{min-height:30px!important;border-radius:5px!important;transition:all .2s cubic-bezier(.4,0,.2,1);position:relative;overflow:auto;margin-bottom:6px!important;padding:8px 0!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px;font-weight:400;color:inherit;line-height:1.5}.search-result-option{display:flex;flex-direction:column;gap:8px}.result-title{font-weight:600;font-size:13px;color:#bdc1c3cc!important;display:block;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px}.search-result-item{display:flex;align-items:center;justify-content:space-between;padding:6px 4px;border-radius:5px;margin-left:4px;transition:all .6s ease}.search-result-item:hover{color:#f4f4f5;background:#ffffff1a}.search-result-item .item-header{font-size:14px;color:#fff!important;flex:1;font-weight:500}.search-result-item mat-icon{color:#fff!important;font-size:20px;width:20px;height:20px;cursor:pointer;transition:all .2s ease}.search-result-item mat-icon:hover{color:#f7f7f7!important}::ng-deep .mat-mdc-text-field-wrapper{background:color-mix(in srgb,#000 60%,transparent);border-radius:5px;box-shadow:#0000004d 0 1px 4px -1px;transition:all .3s cubic-bezier(.4,0,.2,1)}::ng-deep .mat-mdc-text-field-wrapper:hover{box-shadow:0 4px 16px #00000026}::ng-deep .mat-mdc-form-field:not(.mat-form-field-disabled) .mat-mdc-floating-label.mdc-floating-label{color:#fff!important}::ng-deep .mdc-text-field{border-radius:5px!important}@media (max-width: 768px){.search-container{left:2em;top:1.5em;max-width:350px}.search-container.collapsed{width:44px;min-width:88px;max-width:44px}.search-field{min-width:180px}.toggle-icon{font-size:18px;width:18px;height:18px}}@media (max-width: 480px){.search-container{left:1.5em;right:1.5em;max-width:calc(100vw - 3em)}.search-container.collapsed{width:40px;min-width:40px;max-width:40px;right:auto}.search-field{min-width:150px}.search-field ::ng-deep .mat-mdc-input-element{font-size:14px}::ng-deep .mat-mdc-autocomplete-panel{max-height:240px!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option{min-height:48px!important;padding:10px 16px!important}.toggle-icon{font-size:16px;width:16px;height:16px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i5$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i4.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i5$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i5.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i5.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }] });
|
|
1923
3482
|
}
|
|
1924
3483
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: MapSearchComponent, decorators: [{
|
|
1925
3484
|
type: Component,
|
|
@@ -1932,8 +3491,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
1932
3491
|
MatOptionModule,
|
|
1933
3492
|
MatIconModule,
|
|
1934
3493
|
DragDropModule
|
|
1935
|
-
], template: "<div class=\"search-container\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n <div class=\"drag-handle\" cdkDragHandle>\n <mat-icon>search</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleSearch()\"
|
|
1936
|
-
}]
|
|
3494
|
+
], template: "<div class=\"search-container\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n <div class=\"drag-handle\" cdkDragHandle>\n <mat-icon class=\"icon-left\">search</mat-icon>\n <div class=\"right-icons\">\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleSearch()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n </div>\n\n <div class=\"search-content\" *ngIf=\"!collapsed\">\n <mat-form-field appearance=\"outline\" class=\"search-field\">\n <mat-label>S\u00F8ge</mat-label>\n <input\n type=\"text\"\n matInput\n [(ngModel)]=\"searchAddress\"\n [matAutocomplete]=\"auto\"\n (input)=\"filterResults()\"\n />\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let result of filteredResults\" [value]=\"result\" class=\"search-result-option\">\n <span class=\"result-title\">\n {{ result.title }} ({{result.items.length}} af {{ result.total }})\n </span>\n <div *ngFor=\"let item of result.items\" class=\"search-result-item\">\n <span class=\"item-header\">\n {{item.header}}\n </span>\n <mat-icon (click)=\"highlight(item.wkt, $event)\">power_settings_new </mat-icon>\n </div>\n </mat-option>\n </mat-autocomplete>\n </mat-form-field>\n </div>\n</div>", styles: [".search-container{position:absolute;top:8em;left:1em;z-index:2;cursor:grab;max-width:400px;min-width:48px;width:auto}.search-container.cdk-drag-dragging{opacity:.8;cursor:grab}.compact-icon.custom-image-icon{padding:4px;background:none;border:1px solid rgba(255,255,255,.2)}.compact-icon.custom-image-icon img{width:100%;height:100%;object-fit:contain;transition:filter .2s ease}.compact-icon.custom-image-icon.active{background:linear-gradient(147.38deg,#0ea5e9,#075985);border-color:transparent;box-shadow:0 4px 12px #0ea5e966}.compact-icon.custom-image-icon.active img{filter:brightness(0) invert(1)}.compact-icon.custom-image-icon.active:hover{box-shadow:0 6px 20px #0ea5e980}.compact-icon.custom-image-icon:hover:not(.active){background:color-mix(in srgb,#000 70%,transparent);border-color:#0ea5e9;box-shadow:0 2px 8px #0ea5e94d}.compact-icon.custom-image-icon:hover:not(.active) img{filter:brightness(0) invert(.8)}.drag-handle{display:flex;align-items:center;justify-content:space-between;background:#292a2d;padding:2px 8px;cursor:grab;border-radius:5px 5px 0 0;color:#fff}.right-icons{display:flex;align-items:center;gap:6px}.right-icons .drag-indicator-right{font-size:18px!important;width:18px!important;height:18px!important}.search-content{display:flex;flex-direction:column;background:#292a2d;padding:6px;transition:all .3s ease;box-sizing:border-box;cursor:default;border-radius:0 0 5px 5px}.compact-icon{transition:all .3s cubic-bezier(.4,0,.2,1)}.compact-icon.custom-image-icon{background:none;border:1px solid rgba(255,255,255,.2);border-radius:4px;cursor:pointer}.toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.toggle-icon:hover{color:#fff;background:#ffffff26}.search-field{width:100%;min-width:200px;cursor:pointer;flex:1}.search-field ::ng-deep .mat-mdc-form-field-focus-overlay{background-color:transparent}.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.search-field ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:transparent!important;border-width:1.5px!important;transition:border-color .3s ease,border-width .3s ease}.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__leading,.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__notch,.search-field:not(.mat-focused):hover ::ng-deep .mdc-notched-outline .mdc-notched-outline__trailing{border-color:transparent!important}.search-field ::ng-deep .mat-mdc-form-field-label{color:#fff!important;font-weight:500;font-size:15px}.search-field ::ng-deep .mat-mdc-form-field.mat-focused .mat-mdc-form-field-label{color:#2196f3!important}.search-field ::ng-deep .mat-mdc-input-element{font-size:15px;color:#fff;font-weight:400;line-height:1.5}.search-field ::ng-deep .mat-mdc-input-element::placeholder{color:#ccc;font-weight:400;opacity:.8}.search-field ::ng-deep .mdc-floating-label{padding:0 4px;left:40px!important}::ng-deep .mat-mdc-form-field.mat-form-field-animations-enabled .mdc-text-field__input{margin-left:12px;color:#fff!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option .mdc-list-item__primary-text{color:#fff!important}::ng-deep .mat-mdc-option .mat-pseudo-checkbox-minimal{color:#fff!important}::ng-deep .mat-mdc-form-field-flex{height:40px!important}::ng-deep .mat-mdc-autocomplete-panel{border-radius:5px!important;max-height:320px!important;background:color-mix(in srgb,#000 85%,transparent)!important;box-shadow:0 8px 24px #00000026!important;margin-top:64px;overflow-y:auto!important;padding:8px!important}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar{width:12px}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .mat-mdc-autocomplete-panel::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option{min-height:30px!important;border-radius:5px!important;transition:all .2s cubic-bezier(.4,0,.2,1);position:relative;overflow:auto;margin-bottom:6px!important;padding:8px 0!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option .mdc-list-item__primary-text{font-size:14px;font-weight:400;color:inherit;line-height:1.5}.search-result-option{display:flex;flex-direction:column;gap:8px}.result-title{font-weight:600;font-size:13px;color:#bdc1c3cc!important;display:block;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px}.search-result-item{display:flex;align-items:center;justify-content:space-between;padding:6px 4px;border-radius:5px;margin-left:4px;transition:all .6s ease}.search-result-item:hover{color:#f4f4f5;background:#ffffff1a}.search-result-item .item-header{font-size:14px;color:#fff!important;flex:1;font-weight:500}.search-result-item mat-icon{color:#fff!important;font-size:20px;width:20px;height:20px;cursor:pointer;transition:all .2s ease}.search-result-item mat-icon:hover{color:#f7f7f7!important}::ng-deep .mat-mdc-text-field-wrapper{background:color-mix(in srgb,#000 60%,transparent);border-radius:5px;box-shadow:#0000004d 0 1px 4px -1px;transition:all .3s cubic-bezier(.4,0,.2,1)}::ng-deep .mat-mdc-text-field-wrapper:hover{box-shadow:0 4px 16px #00000026}::ng-deep .mat-mdc-form-field:not(.mat-form-field-disabled) .mat-mdc-floating-label.mdc-floating-label{color:#fff!important}::ng-deep .mdc-text-field{border-radius:5px!important}@media (max-width: 768px){.search-container{left:2em;top:1.5em;max-width:350px}.search-container.collapsed{width:44px;min-width:88px;max-width:44px}.search-field{min-width:180px}.toggle-icon{font-size:18px;width:18px;height:18px}}@media (max-width: 480px){.search-container{left:1.5em;right:1.5em;max-width:calc(100vw - 3em)}.search-container.collapsed{width:40px;min-width:40px;max-width:40px;right:auto}.search-field{min-width:150px}.search-field ::ng-deep .mat-mdc-input-element{font-size:14px}::ng-deep .mat-mdc-autocomplete-panel{max-height:240px!important}::ng-deep .mat-mdc-autocomplete-panel .mat-mdc-option{min-height:48px!important;padding:10px 16px!important}.toggle-icon{font-size:16px;width:16px;height:16px}}\n"] }]
|
|
3495
|
+
}], propDecorators: { profile: [{
|
|
3496
|
+
type: Input
|
|
3497
|
+
}] } });
|
|
1937
3498
|
|
|
1938
3499
|
class LayerService {
|
|
1939
3500
|
config = inject(GISKOMPONENT_CONFIG);
|
|
@@ -1954,69 +3515,81 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
1954
3515
|
|
|
1955
3516
|
class LegendsListComponent {
|
|
1956
3517
|
_http = inject(HttpClient);
|
|
3518
|
+
_layerService = inject(LayerService);
|
|
3519
|
+
_layerHelperService = inject(LayerHelperService);
|
|
3520
|
+
_layoutService = inject(LayoutService);
|
|
3521
|
+
config = inject(GISKOMPONENT_CONFIG);
|
|
3522
|
+
map;
|
|
3523
|
+
profile;
|
|
3524
|
+
filteredLayersDetailed = [];
|
|
3525
|
+
collapsed = true;
|
|
3526
|
+
dragPosition = { x: 0, y: 0 };
|
|
3527
|
+
_baseUrl = this.config.apiBaseUrl;
|
|
3528
|
+
_legendsListBodyControl;
|
|
3529
|
+
_mapFilteredLayerGroupsKeyName = 'mapFilteredLayerGroups';
|
|
3530
|
+
POSITION_STORAGE_KEY = 'legendsListPosition';
|
|
1957
3531
|
ngOnInit() {
|
|
1958
|
-
this.
|
|
3532
|
+
this._loadPosition();
|
|
1959
3533
|
this._layerHelperService.activeLayersChanged.subscribe(() => this._setFilteredLegends().subscribe(result => this.filteredLayersDetailed = result));
|
|
1960
3534
|
}
|
|
1961
3535
|
ngOnChanges(changes) {
|
|
1962
|
-
if (changes['profile'] && this.profile)
|
|
3536
|
+
if (changes['profile'] && this.profile) {
|
|
3537
|
+
this._loadPosition();
|
|
1963
3538
|
this._setFilteredLegends().subscribe(result => this.filteredLayersDetailed = result);
|
|
3539
|
+
}
|
|
1964
3540
|
}
|
|
1965
|
-
|
|
1966
|
-
this.
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
this._legendsListBody = content;
|
|
3541
|
+
ngOnDestroy() {
|
|
3542
|
+
if (this._legendsListBodyControl) {
|
|
3543
|
+
this.map.removeControl(this._legendsListBodyControl);
|
|
3544
|
+
}
|
|
1970
3545
|
}
|
|
1971
|
-
map;
|
|
1972
|
-
profile;
|
|
1973
|
-
searchText = '';
|
|
1974
|
-
filteredLayersDetailed = [];
|
|
1975
|
-
showList = false;
|
|
1976
|
-
config = inject(GISKOMPONENT_CONFIG);
|
|
1977
|
-
_baseUrl = this.config.apiBaseUrl;
|
|
1978
|
-
_legendsListIcon;
|
|
1979
|
-
_legendsListIconControl;
|
|
1980
|
-
_legendsListBody;
|
|
1981
|
-
_legendsListBodyControl;
|
|
1982
|
-
_layerIdsToDisplayInMapKeyName = 'layerIdsToDisplayInMap';
|
|
1983
|
-
_layerService = inject(LayerService);
|
|
1984
|
-
_layerHelperService = inject(LayerHelperService);
|
|
1985
3546
|
toggleLegendsList() {
|
|
1986
|
-
this.
|
|
1987
|
-
if (this.showList) {
|
|
1988
|
-
this._addMapBodyControl();
|
|
1989
|
-
}
|
|
1990
|
-
else {
|
|
1991
|
-
this._removeMapBodyControl();
|
|
1992
|
-
}
|
|
3547
|
+
this.collapsed = !this.collapsed;
|
|
1993
3548
|
}
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
this._legendsListIconControl = new ol_control_Control({ element: element });
|
|
1999
|
-
this.map.addControl(this._legendsListIconControl);
|
|
2000
|
-
}
|
|
3549
|
+
onDragEnded(event) {
|
|
3550
|
+
const position = event.source.getFreeDragPosition();
|
|
3551
|
+
this.dragPosition = position;
|
|
3552
|
+
this._savePosition(position);
|
|
2001
3553
|
}
|
|
2002
3554
|
_getImageUrl(fileName) {
|
|
2003
3555
|
return `${this._baseUrl}/api/image/${fileName}`;
|
|
2004
3556
|
}
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
3557
|
+
_savePosition(position) {
|
|
3558
|
+
try {
|
|
3559
|
+
localStorage.setItem(this.POSITION_STORAGE_KEY, JSON.stringify(position));
|
|
3560
|
+
}
|
|
3561
|
+
catch (error) {
|
|
3562
|
+
console.error('Error saving legends list position to localStorage:', error);
|
|
3563
|
+
}
|
|
2010
3564
|
}
|
|
2011
|
-
|
|
2012
|
-
|
|
3565
|
+
_loadPosition() {
|
|
3566
|
+
try {
|
|
3567
|
+
const savedPosition = localStorage.getItem(this.POSITION_STORAGE_KEY);
|
|
3568
|
+
if (savedPosition) {
|
|
3569
|
+
this.dragPosition = JSON.parse(savedPosition);
|
|
3570
|
+
}
|
|
3571
|
+
else if (this.profile) {
|
|
3572
|
+
this.dragPosition = this._layoutService.loadInitialPositionFromProfile(this.POSITION_STORAGE_KEY, this.profile.legendsListInitialPosition);
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
catch (error) {
|
|
3576
|
+
console.error('Error loading legends list position from localStorage:', error);
|
|
3577
|
+
this.dragPosition = { x: 0, y: 0 };
|
|
3578
|
+
}
|
|
2013
3579
|
}
|
|
2014
3580
|
_setFilteredLegends() {
|
|
2015
3581
|
if (!this.profile?.id) {
|
|
2016
3582
|
return of([]);
|
|
2017
3583
|
}
|
|
2018
|
-
const
|
|
2019
|
-
if (!
|
|
3584
|
+
const cacheValue = localStorage.getItem(`${this._mapFilteredLayerGroupsKeyName}_${this.profile?.id}`);
|
|
3585
|
+
if (!cacheValue) {
|
|
3586
|
+
return of([]);
|
|
3587
|
+
}
|
|
3588
|
+
const layerIdsCachedToDisplay = JSON.parse(cacheValue).cachedLayerGroups
|
|
3589
|
+
.flatMap((lg) => lg.layers)
|
|
3590
|
+
.filter((l) => l.visible)
|
|
3591
|
+
.map((l) => l.id);
|
|
3592
|
+
if (!layerIdsCachedToDisplay || layerIdsCachedToDisplay.length === 0) {
|
|
2020
3593
|
return of([]);
|
|
2021
3594
|
}
|
|
2022
3595
|
return this._layerService.getByIds(layerIdsCachedToDisplay)
|
|
@@ -2053,19 +3626,13 @@ class LegendsListComponent {
|
|
|
2053
3626
|
})));
|
|
2054
3627
|
}
|
|
2055
3628
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LegendsListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2056
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: LegendsListComponent, isStandalone: true, selector: "lib-legends-list", inputs: { map: "map", profile: "profile" },
|
|
3629
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: LegendsListComponent, isStandalone: true, selector: "lib-legends-list", inputs: { map: "map", profile: "profile" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"legends-list-body-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n\n <div class=\"drag-handle-legends\" cdkDragHandle>\n <mat-icon class=\"legend-icon\" (click)=\"toggleLegendsList()\">area_chart</mat-icon>\n\n <div class=\"right-icons\">\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleLegendsList()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n</div>\n\n<div class=\"legends-list-container\">\n @if(!collapsed) {\n <div class=\"ol-unselectable ol-control legends-list-body\">\n <div class=\"item-list\">\n @for (layer of filteredLayersDetailed; track layer.id; let i = $index) {\n @if (layer.imageUrl) {\n <mat-expansion-panel [expanded]=\"i === 0\"> \n <mat-expansion-panel-header>\n <span class=\"panel-title\">\n {{ layer.name }}\n </span>\n </mat-expansion-panel-header>\n <div class=\"legend\">\n <img [src]=\"layer.imageUrl\" class=\"legend-thumbnail\"/>\n </div>\n </mat-expansion-panel>\n }\n }\n </div>\n </div>\n}\n</div>\n</div>", styles: [".legends-list-body-wrapper{position:absolute;left:1em;top:10em;z-index:1000;cursor:grab;box-shadow:0 2px 10px #0000001a;background:#292a2d;width:250px;max-width:250px;transition:width .3s ease,max-width .3s ease;border-radius:5px 5px 0 0}.legends-list-body-wrapper.collapsed{width:90px}.legends-list-body-wrapper.cdk-drag-dragging{opacity:.8;cursor:grabbing;z-index:1001}@media (max-width: 1024px){.legends-list-body-wrapper{width:240px;max-width:240px}}@media (max-width: 768px){.legends-list-body-wrapper{position:fixed;right:1em;bottom:5em;width:calc(100% - 2em);max-width:280px}.legends-list-body-wrapper.collapsed{width:90px}}@media (max-width: 480px){.legends-list-body-wrapper{bottom:4em}}.drag-handle-legends{display:flex;align-items:center;justify-content:space-between;background:#292a2d;padding:2px 8px;cursor:grab;color:#fff;border-radius:5px 5px 0 0}.drag-handle-legends .legend-icon{color:#fff;font-size:18px;width:18px;height:18px;cursor:pointer;transition:all .2s ease}.drag-handle-legends .legend-icon:hover{color:#4caf50}.drag-handle-legends .toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.drag-handle-legends .toggle-icon:hover{color:#fff;background:#ffffff26}.right-icons{display:flex;align-items:center;gap:6px}.right-icons .drag-indicator-right{font-size:18px!important;width:18px!important;height:18px!important;color:#fff}.legends-list-container{display:flex;flex-direction:column;align-items:center;width:100%;transition:all .3s ease;cursor:default;box-sizing:border-box}::ng-deep .legends-list-body{position:relative;left:auto;right:auto;bottom:auto;z-index:auto;background:#000;width:100%;max-height:317px;min-height:80px;overflow:hidden;display:flex;flex-direction:column}@media (max-width: 1024px){::ng-deep .legends-list-body{max-height:450px;min-height:70px}}@media (max-width: 768px){::ng-deep .legends-list-body{max-height:60vh;max-height:calc(var(--vh, 1vh) * 60);min-height:100px}}@media (max-width: 480px){::ng-deep .legends-list-body{max-height:70vh;max-height:calc(var(--vh, 1vh) * 70);min-height:90px}}::ng-deep .legends-list-body .item-list{flex:1 1 auto;overflow-y:auto;padding:4px;min-height:0;background:#000;max-height:500px}@media (max-width: 768px){::ng-deep .legends-list-body .item-list{padding:6px;max-height:400px}}::ng-deep .legends-list-body .item-list mat-expansion-panel{border-radius:0!important;box-shadow:none!important;width:100%;margin-bottom:4px}::ng-deep .legends-list-body .item-list mat-expansion-panel:last-child{border-bottom:none}::ng-deep .legends-list-body .item-list mat-expansion-panel .mat-expansion-panel-header{padding:0 8px;height:40px!important;min-height:40px!important}::ng-deep .legends-list-body .item-list mat-expansion-panel .mat-expansion-panel-header .mat-content{display:flex;align-items:center}::ng-deep .legends-list-body .item-list mat-expansion-panel .mat-expansion-panel-header .panel-title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px;line-height:1.3;font-weight:600;color:#bdc1c3cc;font-size:17px}@media (max-width: 768px){::ng-deep .legends-list-body .item-list mat-expansion-panel .mat-expansion-panel-header .panel-title{max-width:180px;font-size:15px}}::ng-deep .legends-list-body .item-list .mat-expansion-panel-body{padding:4px 8px 8px!important}::ng-deep .legends-list-body .item-list .legend{overflow:hidden;padding:4px;box-shadow:0 -2px 2px #4868b20a,0 2px 2px #6a6f7517,0 1px 2px #4868b214}::ng-deep .legends-list-body .item-list .legend span{color:#fff}.legend-thumbnail{max-width:100%;width:auto;height:auto;max-height:150px;border:1px solid #dee2e6;border-radius:4px;padding:4px;display:block}@media (max-width: 768px){.legend-thumbnail{max-height:120px;padding:3px}}::ng-deep .legends-list-body .item-list::-webkit-scrollbar{width:12px}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}@media (max-width: 768px){.legends-list-body-wrapper{right:.5em;bottom:5em;max-width:280px}}@media (max-width: 480px){.legends-list-body-wrapper{right:.5em;left:.5em;max-width:calc(100vw - 1em);width:auto}.legends-list-body-wrapper.collapsed{width:90px;left:auto}::ng-deep .legends-list-body .item-list{max-height:300px}}\n"], dependencies: [{ kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i5.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i5.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i6.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i6.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "ngmodule", type: MatInputModule }] });
|
|
2057
3630
|
}
|
|
2058
3631
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: LegendsListComponent, decorators: [{
|
|
2059
3632
|
type: Component,
|
|
2060
3633
|
args: [{ selector: 'lib-legends-list', imports: [MatFormFieldModule, CommonModule, MatIconModule, FormsModule, DragDropModule,
|
|
2061
|
-
MatExpansionModule, MatInputModule], template: "<div
|
|
2062
|
-
}], propDecorators: {
|
|
2063
|
-
type: ViewChild,
|
|
2064
|
-
args: ['legendsListIcon', { static: false }]
|
|
2065
|
-
}], contentBody: [{
|
|
2066
|
-
type: ViewChild,
|
|
2067
|
-
args: ['legendsListBody', { static: false }]
|
|
2068
|
-
}], map: [{
|
|
3634
|
+
MatExpansionModule, MatInputModule], template: "<div class=\"legends-list-body-wrapper\" \n cdkDrag \n cdkDragBoundary=\".map-container\" \n [cdkDragFreeDragPosition]=\"dragPosition\"\n (cdkDragEnded)=\"onDragEnded($event)\"\n [class.collapsed]=\"collapsed\">\n\n <div class=\"drag-handle-legends\" cdkDragHandle>\n <mat-icon class=\"legend-icon\" (click)=\"toggleLegendsList()\">area_chart</mat-icon>\n\n <div class=\"right-icons\">\n <mat-icon class=\"drag-indicator-right\">open_with</mat-icon>\n <mat-icon class=\"toggle-icon\" (click)=\"toggleLegendsList()\">\n {{ collapsed ? 'flip_to_front' : 'remove' }}\n </mat-icon>\n </div>\n</div>\n\n<div class=\"legends-list-container\">\n @if(!collapsed) {\n <div class=\"ol-unselectable ol-control legends-list-body\">\n <div class=\"item-list\">\n @for (layer of filteredLayersDetailed; track layer.id; let i = $index) {\n @if (layer.imageUrl) {\n <mat-expansion-panel [expanded]=\"i === 0\"> \n <mat-expansion-panel-header>\n <span class=\"panel-title\">\n {{ layer.name }}\n </span>\n </mat-expansion-panel-header>\n <div class=\"legend\">\n <img [src]=\"layer.imageUrl\" class=\"legend-thumbnail\"/>\n </div>\n </mat-expansion-panel>\n }\n }\n </div>\n </div>\n}\n</div>\n</div>", styles: [".legends-list-body-wrapper{position:absolute;left:1em;top:10em;z-index:1000;cursor:grab;box-shadow:0 2px 10px #0000001a;background:#292a2d;width:250px;max-width:250px;transition:width .3s ease,max-width .3s ease;border-radius:5px 5px 0 0}.legends-list-body-wrapper.collapsed{width:90px}.legends-list-body-wrapper.cdk-drag-dragging{opacity:.8;cursor:grabbing;z-index:1001}@media (max-width: 1024px){.legends-list-body-wrapper{width:240px;max-width:240px}}@media (max-width: 768px){.legends-list-body-wrapper{position:fixed;right:1em;bottom:5em;width:calc(100% - 2em);max-width:280px}.legends-list-body-wrapper.collapsed{width:90px}}@media (max-width: 480px){.legends-list-body-wrapper{bottom:4em}}.drag-handle-legends{display:flex;align-items:center;justify-content:space-between;background:#292a2d;padding:2px 8px;cursor:grab;color:#fff;border-radius:5px 5px 0 0}.drag-handle-legends .legend-icon{color:#fff;font-size:18px;width:18px;height:18px;cursor:pointer;transition:all .2s ease}.drag-handle-legends .legend-icon:hover{color:#4caf50}.drag-handle-legends .toggle-icon{cursor:pointer;color:#fff;transition:all .2s ease;-webkit-user-select:none;user-select:none;font-size:18px!important;width:18px!important;height:18px!important;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:2px;flex-shrink:0}.drag-handle-legends .toggle-icon:hover{color:#fff;background:#ffffff26}.right-icons{display:flex;align-items:center;gap:6px}.right-icons .drag-indicator-right{font-size:18px!important;width:18px!important;height:18px!important;color:#fff}.legends-list-container{display:flex;flex-direction:column;align-items:center;width:100%;transition:all .3s ease;cursor:default;box-sizing:border-box}::ng-deep .legends-list-body{position:relative;left:auto;right:auto;bottom:auto;z-index:auto;background:#000;width:100%;max-height:317px;min-height:80px;overflow:hidden;display:flex;flex-direction:column}@media (max-width: 1024px){::ng-deep .legends-list-body{max-height:450px;min-height:70px}}@media (max-width: 768px){::ng-deep .legends-list-body{max-height:60vh;max-height:calc(var(--vh, 1vh) * 60);min-height:100px}}@media (max-width: 480px){::ng-deep .legends-list-body{max-height:70vh;max-height:calc(var(--vh, 1vh) * 70);min-height:90px}}::ng-deep .legends-list-body .item-list{flex:1 1 auto;overflow-y:auto;padding:4px;min-height:0;background:#000;max-height:500px}@media (max-width: 768px){::ng-deep .legends-list-body .item-list{padding:6px;max-height:400px}}::ng-deep .legends-list-body .item-list mat-expansion-panel{border-radius:0!important;box-shadow:none!important;width:100%;margin-bottom:4px}::ng-deep .legends-list-body .item-list mat-expansion-panel:last-child{border-bottom:none}::ng-deep .legends-list-body .item-list mat-expansion-panel .mat-expansion-panel-header{padding:0 8px;height:40px!important;min-height:40px!important}::ng-deep .legends-list-body .item-list mat-expansion-panel .mat-expansion-panel-header .mat-content{display:flex;align-items:center}::ng-deep .legends-list-body .item-list mat-expansion-panel .mat-expansion-panel-header .panel-title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:200px;line-height:1.3;font-weight:600;color:#bdc1c3cc;font-size:17px}@media (max-width: 768px){::ng-deep .legends-list-body .item-list mat-expansion-panel .mat-expansion-panel-header .panel-title{max-width:180px;font-size:15px}}::ng-deep .legends-list-body .item-list .mat-expansion-panel-body{padding:4px 8px 8px!important}::ng-deep .legends-list-body .item-list .legend{overflow:hidden;padding:4px;box-shadow:0 -2px 2px #4868b20a,0 2px 2px #6a6f7517,0 1px 2px #4868b214}::ng-deep .legends-list-body .item-list .legend span{color:#fff}.legend-thumbnail{max-width:100%;width:auto;height:auto;max-height:150px;border:1px solid #dee2e6;border-radius:4px;padding:4px;display:block}@media (max-width: 768px){.legend-thumbnail{max-height:120px;padding:3px}}::ng-deep .legends-list-body .item-list::-webkit-scrollbar{width:12px}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .legends-list-body .item-list::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}@media (max-width: 768px){.legends-list-body-wrapper{right:.5em;bottom:5em;max-width:280px}}@media (max-width: 480px){.legends-list-body-wrapper{right:.5em;left:.5em;max-width:calc(100vw - 1em);width:auto}.legends-list-body-wrapper.collapsed{width:90px;left:auto}::ng-deep .legends-list-body .item-list{max-height:300px}}\n"] }]
|
|
3635
|
+
}], propDecorators: { map: [{
|
|
2069
3636
|
type: Input
|
|
2070
3637
|
}], profile: [{
|
|
2071
3638
|
type: Input
|
|
@@ -2084,19 +3651,49 @@ class FeatureLoaderService {
|
|
|
2084
3651
|
return;
|
|
2085
3652
|
}
|
|
2086
3653
|
const profile = this._current.profile;
|
|
3654
|
+
if (!settings || !settings.geometryTypeSettings)
|
|
3655
|
+
return;
|
|
2087
3656
|
const allTheFeatures = settings.geometryTypeSettings.filter(gt => gt.features).map(gt => {
|
|
2088
3657
|
const rawFeatures = this.fomatter.readFeatures(gt.features);
|
|
2089
3658
|
rawFeatures.forEach(f => {
|
|
2090
3659
|
this._featureHelper.setId(f);
|
|
2091
3660
|
this._featureHelper.setTypeId(f, gt.typeId);
|
|
3661
|
+
if (gt.disableEditFeatures) {
|
|
3662
|
+
this._featureHelper.lock(f);
|
|
3663
|
+
}
|
|
2092
3664
|
f.set('STYLENAME', gt.style);
|
|
3665
|
+
if (gt.showLabelFromProperty) {
|
|
3666
|
+
f.set('showlabelfrom', gt.showLabelFromProperty);
|
|
3667
|
+
}
|
|
2093
3668
|
});
|
|
2094
3669
|
return rawFeatures;
|
|
2095
3670
|
}).flatMap(f => f);
|
|
2096
3671
|
const getAllStyles$ = allTheFeatures.map(f => this._settingsHelper.getStyle(f.get('STYLENAME'), profile?.styleRepositoryWorkspace, profile?.styleRepositoryGeoserver, f.getGeometry().getType()));
|
|
3672
|
+
if (getAllStyles$.length === 0) {
|
|
3673
|
+
this._undoRedo.init();
|
|
3674
|
+
return;
|
|
3675
|
+
}
|
|
2097
3676
|
combineLatest(getAllStyles$).subscribe({
|
|
2098
3677
|
next: styles => {
|
|
2099
|
-
styles.forEach((s, i) =>
|
|
3678
|
+
styles.forEach((s, i) => {
|
|
3679
|
+
const feature = allTheFeatures[i];
|
|
3680
|
+
if (feature.get('showlabelfrom')) {
|
|
3681
|
+
const styles = Array.isArray(s) ? s : [s];
|
|
3682
|
+
const textStyle = new Text({
|
|
3683
|
+
font: '14px Calibri,sans-serif',
|
|
3684
|
+
fill: new Fill({ color: '#000' }),
|
|
3685
|
+
stroke: new Stroke({ color: '#fff', width: 3 }),
|
|
3686
|
+
textAlign: 'center',
|
|
3687
|
+
text: feature.get(feature.get('showlabelfrom'))
|
|
3688
|
+
});
|
|
3689
|
+
const styleText = new Style({ text: textStyle });
|
|
3690
|
+
styles.push(styleText);
|
|
3691
|
+
feature.setStyle(styles);
|
|
3692
|
+
}
|
|
3693
|
+
else {
|
|
3694
|
+
feature.setStyle(s);
|
|
3695
|
+
}
|
|
3696
|
+
});
|
|
2100
3697
|
this._drawHelperService.setFeatures(allTheFeatures);
|
|
2101
3698
|
this._zoom.zoomToFeatures(allTheFeatures);
|
|
2102
3699
|
this._undoRedo.init();
|
|
@@ -2104,22 +3701,157 @@ class FeatureLoaderService {
|
|
|
2104
3701
|
});
|
|
2105
3702
|
}
|
|
2106
3703
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FeatureLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
2107
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FeatureLoaderService
|
|
3704
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FeatureLoaderService });
|
|
2108
3705
|
}
|
|
2109
3706
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: FeatureLoaderService, decorators: [{
|
|
2110
|
-
type: Injectable
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
3707
|
+
type: Injectable
|
|
3708
|
+
}] });
|
|
3709
|
+
|
|
3710
|
+
class SelectedFeatureInfoComponent {
|
|
3711
|
+
_infoService = inject(ShowInfoService);
|
|
3712
|
+
features = null;
|
|
3713
|
+
collapsedStates = {};
|
|
3714
|
+
ngOnInit() {
|
|
3715
|
+
this._infoService.features$.subscribe({
|
|
3716
|
+
next: f => {
|
|
3717
|
+
this.features = f ? [...f] : null;
|
|
3718
|
+
if (this.features) {
|
|
3719
|
+
this.features.forEach(item => {
|
|
3720
|
+
if (this.collapsedStates[item.layerName] === undefined) {
|
|
3721
|
+
this.collapsedStates[item.layerName] = true;
|
|
3722
|
+
}
|
|
3723
|
+
});
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
});
|
|
3727
|
+
}
|
|
3728
|
+
toggleCollapse(layerName) {
|
|
3729
|
+
this.collapsedStates[layerName] = !this.collapsedStates[layerName];
|
|
3730
|
+
}
|
|
3731
|
+
isCollapsed(layerName) {
|
|
3732
|
+
return this.collapsedStates[layerName] || false;
|
|
3733
|
+
}
|
|
3734
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SelectedFeatureInfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3735
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: SelectedFeatureInfoComponent, isStandalone: true, selector: "selected-feature-info", ngImport: i0, template: "\n@if(features) {\n <div class=\"selected-features-wrapper\"> \n\n @for(item of features; track item.layerName) { \n <div class=\"feature-section\">\n <h4 (click)=\"toggleCollapse(item.layerName)\" class=\"collapsible-header\">\n <mat-icon class=\"collapse-icon\">\n {{ isCollapsed(item.layerName) ? 'keyboard_arrow_up' : 'expand_more' }}\n </mat-icon>\n {{item.layerName}}\n </h4>\n \n <div class=\"feature-content\" [class.collapsed]=\"isCollapsed(item.layerName)\">\n @for(feature of item.values; track feature) {\n <div class=\"feature-item\">\n <div *ngFor=\"let kv of (feature | keyvalue)\">\n {{ kv.value.name }}:\n <ng-container [ngSwitch]=\"kv.value.kind\">\n <img *ngSwitchCase=\"'img'\" [src]=\"kv.value.data\" alt=\"{{ kv.key }}\" style=\"max-width:240px;\" />\n <a *ngSwitchCase=\"'url'\" [href]=\"kv.value.data\" target=\"_blank\" rel=\"noopener noreferrer\">\n {{ kv.key }}\n <mat-icon class=\"link-icon\">open_in_new</mat-icon>\n </a>\n <span *ngSwitchDefault>{{ kv.value.data }}</span>\n </ng-container>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n}\n", styles: ["::ng-deep .selected-features-wrapper{background:#292a2d;border-radius:5px;box-shadow:0 4px 6px #00000012,0 10px 20px #0000001a;max-width:420px;max-height:450px;overflow-y:auto;position:relative;font-family:Avenir Next W01,Lato,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.8)}::ng-deep .selected-features-wrapper::-webkit-scrollbar{width:12px}::ng-deep .selected-features-wrapper::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .selected-features-wrapper::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .selected-features-wrapper::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}::ng-deep .selected-features-wrapper .feature-section{padding:20px 24px;position:relative}::ng-deep .selected-features-wrapper .feature-section:after{content:\"\";position:absolute;bottom:0;left:24px;right:24px;height:1px;background:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.08) 20%,rgba(0,0,0,.08) 80%,transparent 100%)}::ng-deep .selected-features-wrapper .feature-section:last-child:after{display:none}::ng-deep .selected-features-wrapper .feature-section h4.collapsible-header{margin:0 0 16px;font-size:18px;font-weight:700;color:#bdc1c3cc;letter-spacing:-.3px;position:relative;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease;display:flex;align-items:center}::ng-deep .selected-features-wrapper .feature-section h4.collapsible-header:hover{color:#d4d8dacc}::ng-deep .selected-features-wrapper .feature-section h4.collapsible-header .collapse-icon{position:absolute;right:0;top:50%;transform:translateY(-50%);font-size:24px;width:24px;height:24px;transition:transform .3s ease;color:#fff}::ng-deep .selected-features-wrapper .feature-section .feature-content{max-height:2000px;overflow:hidden;transition:max-height .4s cubic-bezier(.4,0,.2,1),opacity .3s ease,margin-top .3s ease;opacity:1}::ng-deep .selected-features-wrapper .feature-section .feature-content.collapsed{max-height:0;opacity:0;margin-top:0}::ng-deep .selected-features-wrapper .feature-section .feature-item{margin-top:14px;background:#000;border-radius:10px;padding:16px;box-shadow:0 2px 4px #0000000a,0 1px 2px #0000000f;border:1px solid rgba(0,0,0,.06);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden;color:#fff}::ng-deep .selected-features-wrapper .feature-section .feature-item:hover{box-shadow:0 4px 12px #2196f326,0 2px 4px #00000014;border-color:#2196f333}::ng-deep .selected-features-wrapper .feature-section .feature-item:hover:before{opacity:1}::ng-deep .selected-features-wrapper .feature-section .feature-item:first-of-type{margin-top:0}::ng-deep .selected-features-wrapper div[ng-reflect-ng-for-of]{display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:start;margin-bottom:12px;font-size:14px;line-height:1.6;padding:6px 0;color:#546e7a;font-weight:600;white-space:nowrap;display:flex;align-items:center}::ng-deep .selected-features-wrapper div[ng-reflect-ng-for-of]:last-child{margin-bottom:0}::ng-deep .selected-features-wrapper div[ng-reflect-ng-for-of]:after{content:\"\";display:inline-block;width:4px;height:4px;background:#2196f3;border-radius:50%;margin-left:6px;opacity:.5}::ng-deep .selected-features-wrapper div[ng-reflect-ng-for-of] span{color:#1a1a1a;font-weight:500;word-break:break-word;background:linear-gradient(135deg,#f5f5f5,#fafafa);padding:4px 10px;border-radius:6px;border:1px solid rgba(0,0,0,.05)}::ng-deep .selected-features-wrapper img{margin-top:8px;border-radius:8px;border:2px solid #e3f2fd;max-width:100%;max-height:200px;display:block;box-shadow:0 4px 12px #0000001a;transition:transform .3s ease,box-shadow .3s ease}::ng-deep .selected-features-wrapper img:hover{box-shadow:0 8px 20px #00000026}::ng-deep .selected-features-wrapper a{color:#89bbeb!important;font-weight:600;transition:all .3s ease;text-decoration:underline;position:relative;padding:2px 4px;border-radius:3px}::ng-deep .selected-features-wrapper a:hover{color:#0d78ca!important;background-color:transparent;text-decoration:underline;transform:translateY(-1px)}::ng-deep .selected-features-wrapper a:active{transform:translateY(0)}::ng-deep .selected-features-wrapper a:after{content:\"\";position:absolute;width:100%;height:1px;bottom:-1px;left:0;background-color:#0d78ca;transform:scaleX(0);transition:transform .3s ease}::ng-deep .selected-features-wrapper a:hover:after{transform:scaleX(1)}@media (max-width: 768px){.selected-features-wrapper{max-width:100%;border-radius:12px 12px 0 0}.selected-features-wrapper .feature-section{padding:16px 20px}.selected-features-wrapper .feature-section:after{left:20px;right:20px}.selected-features-wrapper .feature-section h4.collapsible-header{font-size:16px}.selected-features-wrapper .feature-section .feature-item>div{grid-template-columns:1fr;font-size:13px;gap:4px}.selected-features-wrapper .feature-section .feature-item>div:after{display:none}.selected-features-wrapper .feature-section .feature-item>div span,.selected-features-wrapper .feature-section .feature-item>div a{margin-left:0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "pipe", type: i1$1.KeyValuePipe, name: "keyvalue" }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] });
|
|
3736
|
+
}
|
|
3737
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: SelectedFeatureInfoComponent, decorators: [{
|
|
3738
|
+
type: Component,
|
|
3739
|
+
args: [{ selector: 'selected-feature-info', imports: [CommonModule, FormsModule, AsyncPipe, JsonPipe, MatButtonModule, MatIconModule], template: "\n@if(features) {\n <div class=\"selected-features-wrapper\"> \n\n @for(item of features; track item.layerName) { \n <div class=\"feature-section\">\n <h4 (click)=\"toggleCollapse(item.layerName)\" class=\"collapsible-header\">\n <mat-icon class=\"collapse-icon\">\n {{ isCollapsed(item.layerName) ? 'keyboard_arrow_up' : 'expand_more' }}\n </mat-icon>\n {{item.layerName}}\n </h4>\n \n <div class=\"feature-content\" [class.collapsed]=\"isCollapsed(item.layerName)\">\n @for(feature of item.values; track feature) {\n <div class=\"feature-item\">\n <div *ngFor=\"let kv of (feature | keyvalue)\">\n {{ kv.value.name }}:\n <ng-container [ngSwitch]=\"kv.value.kind\">\n <img *ngSwitchCase=\"'img'\" [src]=\"kv.value.data\" alt=\"{{ kv.key }}\" style=\"max-width:240px;\" />\n <a *ngSwitchCase=\"'url'\" [href]=\"kv.value.data\" target=\"_blank\" rel=\"noopener noreferrer\">\n {{ kv.key }}\n <mat-icon class=\"link-icon\">open_in_new</mat-icon>\n </a>\n <span *ngSwitchDefault>{{ kv.value.data }}</span>\n </ng-container>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n}\n", styles: ["::ng-deep .selected-features-wrapper{background:#292a2d;border-radius:5px;box-shadow:0 4px 6px #00000012,0 10px 20px #0000001a;max-width:420px;max-height:450px;overflow-y:auto;position:relative;font-family:Avenir Next W01,Lato,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,.8)}::ng-deep .selected-features-wrapper::-webkit-scrollbar{width:12px}::ng-deep .selected-features-wrapper::-webkit-scrollbar-track{background:#757474;border-radius:8px}::ng-deep .selected-features-wrapper::-webkit-scrollbar-thumb{background:#1a1c1f;border-radius:8px;border:2px solid #2a2c30}::ng-deep .selected-features-wrapper::-webkit-scrollbar-thumb:hover{background:#0f1012}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button{width:12px;height:16px;background:#2a2c30;border:1px solid #1a1c1f}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button:vertical:decrement{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 4l-4 4h8z'/%3E%3C/svg%3E\") no-repeat center;border-radius:8px 8px 0 0}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button:vertical:decrement:hover{background-color:#1a1c1f}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button:vertical:increment{background:#2a2c30 url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23ffffff' d='M6 8l4-4H2z'/%3E%3C/svg%3E\") no-repeat center;border-radius:0 0 8px 8px}::ng-deep .selected-features-wrapper::-webkit-scrollbar-button:vertical:increment:hover{background-color:#1a1c1f}::ng-deep .selected-features-wrapper .feature-section{padding:20px 24px;position:relative}::ng-deep .selected-features-wrapper .feature-section:after{content:\"\";position:absolute;bottom:0;left:24px;right:24px;height:1px;background:linear-gradient(90deg,transparent 0%,rgba(0,0,0,.08) 20%,rgba(0,0,0,.08) 80%,transparent 100%)}::ng-deep .selected-features-wrapper .feature-section:last-child:after{display:none}::ng-deep .selected-features-wrapper .feature-section h4.collapsible-header{margin:0 0 16px;font-size:18px;font-weight:700;color:#bdc1c3cc;letter-spacing:-.3px;position:relative;cursor:pointer;-webkit-user-select:none;user-select:none;transition:color .2s ease;display:flex;align-items:center}::ng-deep .selected-features-wrapper .feature-section h4.collapsible-header:hover{color:#d4d8dacc}::ng-deep .selected-features-wrapper .feature-section h4.collapsible-header .collapse-icon{position:absolute;right:0;top:50%;transform:translateY(-50%);font-size:24px;width:24px;height:24px;transition:transform .3s ease;color:#fff}::ng-deep .selected-features-wrapper .feature-section .feature-content{max-height:2000px;overflow:hidden;transition:max-height .4s cubic-bezier(.4,0,.2,1),opacity .3s ease,margin-top .3s ease;opacity:1}::ng-deep .selected-features-wrapper .feature-section .feature-content.collapsed{max-height:0;opacity:0;margin-top:0}::ng-deep .selected-features-wrapper .feature-section .feature-item{margin-top:14px;background:#000;border-radius:10px;padding:16px;box-shadow:0 2px 4px #0000000a,0 1px 2px #0000000f;border:1px solid rgba(0,0,0,.06);transition:all .3s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden;color:#fff}::ng-deep .selected-features-wrapper .feature-section .feature-item:hover{box-shadow:0 4px 12px #2196f326,0 2px 4px #00000014;border-color:#2196f333}::ng-deep .selected-features-wrapper .feature-section .feature-item:hover:before{opacity:1}::ng-deep .selected-features-wrapper .feature-section .feature-item:first-of-type{margin-top:0}::ng-deep .selected-features-wrapper div[ng-reflect-ng-for-of]{display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:start;margin-bottom:12px;font-size:14px;line-height:1.6;padding:6px 0;color:#546e7a;font-weight:600;white-space:nowrap;display:flex;align-items:center}::ng-deep .selected-features-wrapper div[ng-reflect-ng-for-of]:last-child{margin-bottom:0}::ng-deep .selected-features-wrapper div[ng-reflect-ng-for-of]:after{content:\"\";display:inline-block;width:4px;height:4px;background:#2196f3;border-radius:50%;margin-left:6px;opacity:.5}::ng-deep .selected-features-wrapper div[ng-reflect-ng-for-of] span{color:#1a1a1a;font-weight:500;word-break:break-word;background:linear-gradient(135deg,#f5f5f5,#fafafa);padding:4px 10px;border-radius:6px;border:1px solid rgba(0,0,0,.05)}::ng-deep .selected-features-wrapper img{margin-top:8px;border-radius:8px;border:2px solid #e3f2fd;max-width:100%;max-height:200px;display:block;box-shadow:0 4px 12px #0000001a;transition:transform .3s ease,box-shadow .3s ease}::ng-deep .selected-features-wrapper img:hover{box-shadow:0 8px 20px #00000026}::ng-deep .selected-features-wrapper a{color:#89bbeb!important;font-weight:600;transition:all .3s ease;text-decoration:underline;position:relative;padding:2px 4px;border-radius:3px}::ng-deep .selected-features-wrapper a:hover{color:#0d78ca!important;background-color:transparent;text-decoration:underline;transform:translateY(-1px)}::ng-deep .selected-features-wrapper a:active{transform:translateY(0)}::ng-deep .selected-features-wrapper a:after{content:\"\";position:absolute;width:100%;height:1px;bottom:-1px;left:0;background-color:#0d78ca;transform:scaleX(0);transition:transform .3s ease}::ng-deep .selected-features-wrapper a:hover:after{transform:scaleX(1)}@media (max-width: 768px){.selected-features-wrapper{max-width:100%;border-radius:12px 12px 0 0}.selected-features-wrapper .feature-section{padding:16px 20px}.selected-features-wrapper .feature-section:after{left:20px;right:20px}.selected-features-wrapper .feature-section h4.collapsible-header{font-size:16px}.selected-features-wrapper .feature-section .feature-item>div{grid-template-columns:1fr;font-size:13px;gap:4px}.selected-features-wrapper .feature-section .feature-item>div:after{display:none}.selected-features-wrapper .feature-section .feature-item>div span,.selected-features-wrapper .feature-section .feature-item>div a{margin-left:0}}\n"] }]
|
|
3740
|
+
}] });
|
|
3741
|
+
|
|
3742
|
+
'ol/format/geojson';
|
|
3743
|
+
class HoverInfoSearchService extends SearchProviderBase {
|
|
3744
|
+
_current = inject(CurrentItemsService);
|
|
3745
|
+
geojsonFormat = new GeoJSON;
|
|
3746
|
+
getSearchableLayers() {
|
|
3747
|
+
return this._current.profile.layerGroups.flatMap(l => l.layers).filter(l => l.showInfoOnHover);
|
|
3748
|
+
}
|
|
3749
|
+
getFilter(searchValue, layer) {
|
|
3750
|
+
const point = new Point(searchValue);
|
|
3751
|
+
return intersects(layer.geometryField, point);
|
|
3752
|
+
}
|
|
3753
|
+
map(l, f) {
|
|
3754
|
+
return {
|
|
3755
|
+
values: f.features.map(f => ({
|
|
3756
|
+
center: this._getCenterPoint(f.geometry),
|
|
3757
|
+
showValue: f.properties ? f.properties[l.propertyToShowOnHover] : ''
|
|
3758
|
+
}))
|
|
3759
|
+
};
|
|
3760
|
+
}
|
|
3761
|
+
_getCenterPoint(geometry) {
|
|
3762
|
+
const geom = this.geojsonFormat.readGeometry(geometry);
|
|
3763
|
+
const geomType = geom.getType();
|
|
3764
|
+
switch (geomType) {
|
|
3765
|
+
case 'Point':
|
|
3766
|
+
return geom;
|
|
3767
|
+
case 'LineString':
|
|
3768
|
+
const ls = geom;
|
|
3769
|
+
return new Point(ls.getCoordinateAt(0.5));
|
|
3770
|
+
case 'Polygon':
|
|
3771
|
+
const poly = geom;
|
|
3772
|
+
return poly.getInteriorPoint();
|
|
3773
|
+
// case 'MultiLineString':
|
|
3774
|
+
// case 'MultiPolygon':
|
|
3775
|
+
// case 'GeometryCollection':
|
|
3776
|
+
// case 'Circle':
|
|
3777
|
+
// return new Point([]);
|
|
3778
|
+
}
|
|
3779
|
+
return new Point([]); //
|
|
3780
|
+
}
|
|
3781
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HoverInfoSearchService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
3782
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HoverInfoSearchService });
|
|
3783
|
+
}
|
|
3784
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: HoverInfoSearchService, decorators: [{
|
|
3785
|
+
type: Injectable
|
|
3786
|
+
}] });
|
|
3787
|
+
|
|
3788
|
+
class ShowInfoHoverService {
|
|
3789
|
+
_current = inject(CurrentItemsService);
|
|
3790
|
+
_search = inject(HoverInfoSearchService);
|
|
3791
|
+
source = new VectorSource();
|
|
3792
|
+
_layer = new VectorLayer({
|
|
3793
|
+
source: this.source,
|
|
3794
|
+
zIndex: 500,
|
|
3795
|
+
});
|
|
3796
|
+
init() {
|
|
3797
|
+
this._current.map$.subscribe({
|
|
3798
|
+
next: map => {
|
|
3799
|
+
let timer;
|
|
3800
|
+
map.addLayer(this._layer);
|
|
3801
|
+
map.on('pointermove', evt => {
|
|
3802
|
+
if (evt.dragging) {
|
|
3803
|
+
return;
|
|
3804
|
+
}
|
|
3805
|
+
clearTimeout(timer); // for every move, restart the timer
|
|
3806
|
+
timer = setTimeout(() => {
|
|
3807
|
+
this.source.clear();
|
|
3808
|
+
this._search.search(evt.coordinate, 2).subscribe({
|
|
3809
|
+
next: features => {
|
|
3810
|
+
const newFeatures = features
|
|
3811
|
+
.flatMap(f => f.values)
|
|
3812
|
+
.map(f => {
|
|
3813
|
+
const styleForFeature = this._getStyle(f.showValue);
|
|
3814
|
+
const newFeature = new Feature({ geometry: f.center });
|
|
3815
|
+
newFeature.setStyle(styleForFeature);
|
|
3816
|
+
return newFeature;
|
|
3817
|
+
});
|
|
3818
|
+
this.source.addFeatures(newFeatures);
|
|
3819
|
+
}
|
|
3820
|
+
});
|
|
3821
|
+
}, 300);
|
|
3822
|
+
});
|
|
3823
|
+
}
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
_getStyle(text) {
|
|
3827
|
+
const style = new Style({
|
|
3828
|
+
text: new Text({
|
|
3829
|
+
text: text,
|
|
3830
|
+
font: '12px Calibri,sans-serif',
|
|
3831
|
+
fill: new Fill({ color: '#000' }),
|
|
3832
|
+
stroke: new Stroke({ color: '#fff', width: 3 }),
|
|
3833
|
+
overflow: true,
|
|
3834
|
+
placement: 'point'
|
|
3835
|
+
})
|
|
3836
|
+
});
|
|
3837
|
+
return style;
|
|
3838
|
+
}
|
|
3839
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ShowInfoHoverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3840
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ShowInfoHoverService });
|
|
3841
|
+
}
|
|
3842
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: ShowInfoHoverService, decorators: [{
|
|
3843
|
+
type: Injectable
|
|
2114
3844
|
}] });
|
|
2115
3845
|
|
|
2116
3846
|
class GisKomponentComponent {
|
|
2117
3847
|
_profileService = inject(ProfileService);
|
|
2118
|
-
// private readonly _undoRedo = inject(UndoRedoService);
|
|
2119
3848
|
_http = inject(HttpClient);
|
|
2120
3849
|
_layerHelper = inject(LayerHelperService);
|
|
2121
3850
|
_layerErrorService = inject(LayerErrorService);
|
|
2122
3851
|
_featureLoader = inject(FeatureLoaderService);
|
|
3852
|
+
_drawLayerService = inject(DrawLayerSourceService);
|
|
3853
|
+
_showHoverInfoService = inject(ShowInfoHoverService);
|
|
3854
|
+
_printHelper = inject(PrintHelperService);
|
|
2123
3855
|
showToolbox = true;
|
|
2124
3856
|
showActiveObjects = true;
|
|
2125
3857
|
showLegendList = true;
|
|
@@ -2127,7 +3859,10 @@ class GisKomponentComponent {
|
|
|
2127
3859
|
identifier;
|
|
2128
3860
|
settings;
|
|
2129
3861
|
toolbarRef;
|
|
2130
|
-
activeObjectsRef;
|
|
3862
|
+
// @ViewChild('activeObjectsRef', {static: true }) activeObjectsRef!: ElementRef;
|
|
3863
|
+
selectedFeatureInfoRef;
|
|
3864
|
+
sessionDone = new EventEmitter();
|
|
3865
|
+
featuresChanged = new EventEmitter();
|
|
2131
3866
|
map;
|
|
2132
3867
|
toolbarCollapsed = false;
|
|
2133
3868
|
layerPanelCollapsed = false;
|
|
@@ -2139,10 +3874,13 @@ class GisKomponentComponent {
|
|
|
2139
3874
|
profiles = [];
|
|
2140
3875
|
selectedProfile;
|
|
2141
3876
|
profileShowToolbox = false;
|
|
2142
|
-
_highlightService = inject(
|
|
3877
|
+
_highlightService = inject(HighlightService);
|
|
2143
3878
|
_currentItems = inject(CurrentItemsService);
|
|
2144
3879
|
layers = [];
|
|
2145
|
-
mousePositionCtrl = new ol_control_mouse({
|
|
3880
|
+
mousePositionCtrl = new ol_control_mouse({
|
|
3881
|
+
projection: 'EPSG:25832',
|
|
3882
|
+
coordinateFormat: createStringXY(2)
|
|
3883
|
+
});
|
|
2146
3884
|
onMoveEndCheckZoomFunction = () => { };
|
|
2147
3885
|
currentZoomLevel = 0;
|
|
2148
3886
|
scaleCtrl = new ol_control_scale({
|
|
@@ -2152,6 +3890,9 @@ class GisKomponentComponent {
|
|
|
2152
3890
|
text: true,
|
|
2153
3891
|
minWidth: 120
|
|
2154
3892
|
});
|
|
3893
|
+
constructor() {
|
|
3894
|
+
this._currentItems.gisKomponentSettings = this.settings;
|
|
3895
|
+
}
|
|
2155
3896
|
profileSelected(profileIdentifier) {
|
|
2156
3897
|
this._profileService.getByIdentifier(profileIdentifier).subscribe({
|
|
2157
3898
|
next: profile => {
|
|
@@ -2173,11 +3914,11 @@ class GisKomponentComponent {
|
|
|
2173
3914
|
layers: lg.layers
|
|
2174
3915
|
.filter(layer => layer.activeInSelector)
|
|
2175
3916
|
.sort((a, b) => a.sortOrder - b.sortOrder)
|
|
2176
|
-
.map((l, index) => this._mapLayer(l, capabilityObject, 'EPSG:25832', lg.id, index)) // for now, we default to EPSG:25832.
|
|
3917
|
+
.map((l, index) => this._mapLayer(l, capabilityObject, 'EPSG:25832', lg.id, index)), // for now, we default to EPSG:25832.
|
|
3918
|
+
properties: { id: lg.id }
|
|
2177
3919
|
}))
|
|
2178
3920
|
];
|
|
2179
3921
|
this.map.setLayers(layers);
|
|
2180
|
-
this.map.addLayer(this._highlightService.highlightLayer);
|
|
2181
3922
|
if (this.settings) {
|
|
2182
3923
|
this._featureLoader.loadFeaturesSettings(this.settings);
|
|
2183
3924
|
}
|
|
@@ -2192,11 +3933,18 @@ class GisKomponentComponent {
|
|
|
2192
3933
|
this.profileShowToolbox = true;
|
|
2193
3934
|
this.map.addControl(toolbarControl);
|
|
2194
3935
|
}
|
|
3936
|
+
this._currentItems.gisKomponentSettings = this.settings;
|
|
2195
3937
|
this.activeObjectsReady = true;
|
|
2196
|
-
|
|
2197
|
-
|
|
3938
|
+
// if (this.activeObjectsRef) {
|
|
3939
|
+
// const activeObjectsControl = new Control({
|
|
3940
|
+
// element: this.activeObjectsRef.nativeElement
|
|
3941
|
+
// });
|
|
3942
|
+
// this.map.addControl(activeObjectsControl);
|
|
3943
|
+
// }
|
|
3944
|
+
const selectedFeatureInfoRefControl = new Control({
|
|
3945
|
+
element: this.selectedFeatureInfoRef.nativeElement
|
|
2198
3946
|
});
|
|
2199
|
-
this.map.addControl(
|
|
3947
|
+
this.map.addControl(selectedFeatureInfoRefControl);
|
|
2200
3948
|
this._handleShowMouseCoordinates(profile.showCoordinates);
|
|
2201
3949
|
this._handleShowScale(profile.showScale);
|
|
2202
3950
|
this._setLogo(profile.logoUrl);
|
|
@@ -2205,11 +3953,33 @@ class GisKomponentComponent {
|
|
|
2205
3953
|
this.onMoveEndCheckZoomFunction = () => {
|
|
2206
3954
|
this._checkZoom(this.map);
|
|
2207
3955
|
};
|
|
3956
|
+
this._drawLayerService.features$.subscribe({
|
|
3957
|
+
next: features => {
|
|
3958
|
+
const geojson = new GeoJSON$1();
|
|
3959
|
+
this.featuresChanged.emit(geojson.writeFeaturesObject(features));
|
|
3960
|
+
}
|
|
3961
|
+
});
|
|
2208
3962
|
this.map.on('moveend', this.onMoveEndCheckZoomFunction);
|
|
2209
|
-
this.
|
|
3963
|
+
this._showHoverInfoService.init();
|
|
2210
3964
|
}
|
|
2211
3965
|
});
|
|
2212
3966
|
}
|
|
3967
|
+
sessionDoneFromActiveObject() {
|
|
3968
|
+
const formatter = new GeoJSON$1();
|
|
3969
|
+
const sessionDone = {
|
|
3970
|
+
doneFrom: 'activeObjects',
|
|
3971
|
+
features: formatter.writeFeaturesObject(this._drawLayerService.allCleanedFeatures)
|
|
3972
|
+
};
|
|
3973
|
+
if (this._currentItems.gisKomponentSettings.printMapSettings && this._currentItems.gisKomponentSettings.printMapSettings.doPrintWhenSessionIsClosed) {
|
|
3974
|
+
this._printHelper.getImgData(this.map, this._currentItems.gisKomponentSettings.printMapSettings.printFormat, this._currentItems.gisKomponentSettings.printMapSettings.printDimensions).then(dataUrl => {
|
|
3975
|
+
sessionDone.imgData = dataUrl;
|
|
3976
|
+
this.sessionDone.emit(sessionDone);
|
|
3977
|
+
});
|
|
3978
|
+
}
|
|
3979
|
+
else {
|
|
3980
|
+
this.sessionDone.emit(sessionDone);
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
2213
3983
|
_checkZoom(map) {
|
|
2214
3984
|
this.currentZoomLevel = map.getView().getZoom() ?? this.currentZoomLevel;
|
|
2215
3985
|
}
|
|
@@ -2326,7 +4096,26 @@ class GisKomponentComponent {
|
|
|
2326
4096
|
this.map = new Map$1({
|
|
2327
4097
|
target: 'map',
|
|
2328
4098
|
});
|
|
4099
|
+
// this._currentItems.gisKomponentSettings = this.settings!;
|
|
2329
4100
|
this.map.addControl(new Rotate({ autoHide: false }));
|
|
4101
|
+
this._addRotateControl();
|
|
4102
|
+
}
|
|
4103
|
+
// Added custom north-arrow with a compass one
|
|
4104
|
+
_addRotateControl() {
|
|
4105
|
+
const iconElement = document.createElement('span');
|
|
4106
|
+
iconElement.innerHTML = `
|
|
4107
|
+
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
4108
|
+
<path d="M12 3 L16 10 L12 8 L8 10 Z" fill="currentColor"/>
|
|
4109
|
+
<path d="M12 21 L8 14 L12 16 L16 14 Z" fill="currentColor"/>
|
|
4110
|
+
<circle cx="12" cy="12" r="1.5" fill="currentColor"/>
|
|
4111
|
+
</svg>
|
|
4112
|
+
`;
|
|
4113
|
+
const rotateControl = new Rotate({
|
|
4114
|
+
label: iconElement,
|
|
4115
|
+
tipLabel: 'Reset to north',
|
|
4116
|
+
autoHide: false
|
|
4117
|
+
});
|
|
4118
|
+
this.map.addControl(rotateControl);
|
|
2330
4119
|
}
|
|
2331
4120
|
toggleShowConflicts() {
|
|
2332
4121
|
this.showConflicts = !this.showConflicts;
|
|
@@ -2344,12 +4133,14 @@ class GisKomponentComponent {
|
|
|
2344
4133
|
this.activeObjectsCollapsed = !this.activeObjectsCollapsed;
|
|
2345
4134
|
}
|
|
2346
4135
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GisKomponentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2347
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: GisKomponentComponent, isStandalone: true, selector: "gis-komponent", inputs: { showToolbox: "showToolbox", showActiveObjects: "showActiveObjects", showLegendList: "showLegendList", showMapSearch: "showMapSearch", identifier: "identifier", settings: "settings" },
|
|
4136
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.15", type: GisKomponentComponent, isStandalone: true, selector: "gis-komponent", inputs: { showToolbox: "showToolbox", showActiveObjects: "showActiveObjects", showLegendList: "showLegendList", showMapSearch: "showMapSearch", identifier: "identifier", settings: "settings" }, outputs: { sessionDone: "sessionDone", featuresChanged: "featuresChanged" }, providers: [CurrentItemsService, FeatureLoaderService, DrawLayerSourceService, ZoomService, UndoRedoService, ShowInfoHoverService, HoverInfoSearchService, CenterPointService, PrintDrawLayerSourceService,
|
|
4137
|
+
HighlightService, ShowInfoService, InfoSearchProvider, InteractionHelperService, ConflictAnalysisSearchProvider, MergeFeaturesService, OverlapService], viewQueries: [{ propertyName: "toolbarRef", first: true, predicate: ["toolbarRef"], descendants: true, static: true }, { propertyName: "selectedFeatureInfoRef", first: true, predicate: ["selectedFeatureInfoRef"], descendants: true, static: true }], ngImport: i0, template: "@if (selectedProfile && selectedProfile.showLayerSelector) {\n <lib-layer-selector [map]=\"map\" [profile]=\"selectedProfile\" [currentZoomLevel]=\"currentZoomLevel\"></lib-layer-selector>\n}\n@if (selectedProfile && selectedProfile.showLegends) {\n <lib-legends-list [map]=\"map\" [profile]=\"selectedProfile\"></lib-legends-list>\n}\n\n<div #selectedFeatureInfoRef>\n <selected-feature-info></selected-feature-info>\n</div>\n\n@if(showActiveObjects && activeObjectsReady && settings && selectedProfile) {\n <activeObjects [settings]=\"settings\" [profile]=\"selectedProfile\" (sessionDone)=\"sessionDoneFromActiveObject()\"></activeObjects>\n}\n<div #toolbarRef class=\"map-toolbar-container\">\n @if(showToolbox && profileShowToolbox && settings) {\n <map-toolbox [map]=\"map\" \n [profile]=\"selectedProfile\"\n [settings]=\"settings\"\n [collapsed]=\"selectedProfile.toolbarCollapsed\" [WKTInputEnabled]=\"settings?.WKTInputEnabled\" [deleteEnabled]=\"settings?.deleteEnabled\" [showMeasureArea]=\"selectedProfile.showAreaMeasurement\" [showMeasureDistance]=\"selectedProfile.showDistanceMeasurement\"></map-toolbox>\n }\n</div>\n\n<div class=\"map-container\">\n <lib-map-search *ngIf=\"showMapSearch\" [profile]=\"selectedProfile\"></lib-map-search>\n\n\n <!-- Konflikter -->\n @if (showConflicts) {\n\n <div class=\"conflict-panel\" [class.collapsed]=\"conflictsCollapsed\">\n <div class=\"header\">\n <span>Konflikter (3)</span>\n <mat-icon>{{ activeObjectsCollapsed ? 'expand_more' : 'expand_less' }}</mat-icon> -->\n </div>\n <mat-list>\n <mat-list-item>\n <span matListItemTitle>Lag #1</span>\n <span matListItemLine><mat-icon>highlight</mat-icon> Objekt #1</span>\n </mat-list-item>\n <mat-list-item>\n <span matListItemTitle>Lag #2 (svarer ikke)</span>\n </mat-list-item>\n <mat-list-item>\n <span matListItemTitle>Lag #3</span>\n <span matListItemLine><mat-icon>highlight</mat-icon> Objekt #1</span>\n <span matListItemLine><mat-icon>highlight</mat-icon> Objekt #2</span>\n </mat-list-item>\n </mat-list>\n </div>\n \n } \n\n <!-- Kort -->\n <div id=\"map\" class=\"map\"></div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%;overflow:hidden}::ng-deep .lib-error-snackbar{background-color:#d32f2f;color:#fff;font-weight:500}::ng-deep .map-container{position:relative;height:81vh;width:100%;overflow:hidden}::ng-deep #map{width:100%;height:100%;position:absolute;inset:0;overflow:hidden}::ng-deep .ol-viewport{overflow:hidden!important}::ng-deep ::ng-deep .ol-logo{position:absolute;left:auto;right:3em;top:6.25em}::ng-deep ::ng-deep .ol-copyright{background-color:transparent;position:absolute;bottom:10px;width:100%;text-align:center}::ng-deep ::ng-deep .toolbar{position:absolute;top:10px;left:10px;background:#fff;padding:4px;border-radius:4px;display:flex;flex-direction:column;transition:width .3s;z-index:1000;overflow:hidden}::ng-deep ::ng-deep .toolbar.collapsed{width:40px;overflow:hidden}::ng-deep .object-panel{position:absolute;bottom:10px;left:10px;background:#fff;padding:8px;border-radius:4px;z-index:1000;max-height:calc(85vh - 20px);overflow-y:auto}::ng-deep .object-panel .header{display:flex;justify-content:space-between;padding:8px;cursor:pointer;background:#f0f0f0}::ng-deep .conflict-panel{position:absolute;bottom:10px;right:10px;background:#fff;padding:8px;border-radius:4px;z-index:1000;max-height:calc(85vh - 20px);overflow-y:auto}::ng-deep .conflict-panel .header{display:flex;justify-content:space-between;padding:8px;cursor:pointer;background:#f0f0f0}::ng-deep ::ng-deep .ol-zoom.ol-unselectable.ol-control{display:flex;flex-direction:column;position:absolute;left:1rem}::ng-deep ::ng-deep button.ol-zoom-in{font-size:2em;width:40px;height:40px;background-color:#292a2d;border:none;box-shadow:none;cursor:pointer;border-radius:5px 5px 0 0!important;color:#fff}::ng-deep ::ng-deep button.ol-zoom-in:hover{color:#e9e3e3;outline:none}::ng-deep ::ng-deep .ol-scale-text{display:flex}::ng-deep button.ol-zoom-out{font-size:2em;width:40px;height:40px;background-color:#292a2d;border:none;box-shadow:none;cursor:pointer;color:#fff;border-radius:0 0 5px 5px!important}::ng-deep button.ol-zoom-out:hover{color:#e9e3e3;outline:none}::ng-deep button.ol-rotate-reset{font-size:2em;width:40px;height:40px;background-color:#292a2d;border:none;box-shadow:none;cursor:pointer;color:#fff;border-radius:5px}::ng-deep button.ol-rotate-reset:hover{color:#e9e3e3;outline:none}::ng-deep .ol-scale-bar.ol-unselectable{position:absolute;bottom:3rem;left:1rem}::ng-deep .ol-mouse-position{top:44em;left:12px;position:absolute;background:color-mix(in srgb,#000 21%,transparent);color:#fffcfc;width:189px;height:30px;padding:2px;border-radius:5px;font-family:Avenir Next W01,Lato,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;text-align:center;display:flex;align-items:center;justify-content:flex-start}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i3$1.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i3$1.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i3$1.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i3$1.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: LayerSelectorComponent, selector: "lib-layer-selector", inputs: ["map", "profile", "currentZoomLevel"] }, { kind: "component", type: MapSearchComponent, selector: "lib-map-search", inputs: ["profile"] }, { kind: "component", type: ToolboxComponent, selector: "map-toolbox", inputs: ["map", "showMeasureDistance", "showMeasureArea", "collapsed", "settings", "profile", "WKTInputEnabled", "deleteEnabled"] }, { kind: "component", type: ActiveObjectsComponent, selector: "activeObjects", inputs: ["settings", "profile"], outputs: ["sessionDone"] }, { kind: "component", type: LegendsListComponent, selector: "lib-legends-list", inputs: ["map", "profile"] }, { kind: "component", type: SelectedFeatureInfoComponent, selector: "selected-feature-info" }] });
|
|
2348
4138
|
}
|
|
2349
4139
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: GisKomponentComponent, decorators: [{
|
|
2350
4140
|
type: Component,
|
|
2351
|
-
args: [{ selector: 'gis-komponent', imports: [CommonModule, MatIconModule, MatListModule, MatSelectModule, LayerSelectorComponent, MapSearchComponent, ToolboxComponent, ActiveObjectsComponent, LegendsListComponent], providers: [
|
|
2352
|
-
|
|
4141
|
+
args: [{ selector: 'gis-komponent', imports: [CommonModule, MatIconModule, MatListModule, MatSelectModule, LayerSelectorComponent, MapSearchComponent, ToolboxComponent, ActiveObjectsComponent, LegendsListComponent, SelectedFeatureInfoComponent], providers: [CurrentItemsService, FeatureLoaderService, DrawLayerSourceService, ZoomService, UndoRedoService, ShowInfoHoverService, HoverInfoSearchService, CenterPointService, PrintDrawLayerSourceService,
|
|
4142
|
+
HighlightService, ShowInfoService, InfoSearchProvider, InteractionHelperService, ConflictAnalysisSearchProvider, MergeFeaturesService, OverlapService], template: "@if (selectedProfile && selectedProfile.showLayerSelector) {\n <lib-layer-selector [map]=\"map\" [profile]=\"selectedProfile\" [currentZoomLevel]=\"currentZoomLevel\"></lib-layer-selector>\n}\n@if (selectedProfile && selectedProfile.showLegends) {\n <lib-legends-list [map]=\"map\" [profile]=\"selectedProfile\"></lib-legends-list>\n}\n\n<div #selectedFeatureInfoRef>\n <selected-feature-info></selected-feature-info>\n</div>\n\n@if(showActiveObjects && activeObjectsReady && settings && selectedProfile) {\n <activeObjects [settings]=\"settings\" [profile]=\"selectedProfile\" (sessionDone)=\"sessionDoneFromActiveObject()\"></activeObjects>\n}\n<div #toolbarRef class=\"map-toolbar-container\">\n @if(showToolbox && profileShowToolbox && settings) {\n <map-toolbox [map]=\"map\" \n [profile]=\"selectedProfile\"\n [settings]=\"settings\"\n [collapsed]=\"selectedProfile.toolbarCollapsed\" [WKTInputEnabled]=\"settings?.WKTInputEnabled\" [deleteEnabled]=\"settings?.deleteEnabled\" [showMeasureArea]=\"selectedProfile.showAreaMeasurement\" [showMeasureDistance]=\"selectedProfile.showDistanceMeasurement\"></map-toolbox>\n }\n</div>\n\n<div class=\"map-container\">\n <lib-map-search *ngIf=\"showMapSearch\" [profile]=\"selectedProfile\"></lib-map-search>\n\n\n <!-- Konflikter -->\n @if (showConflicts) {\n\n <div class=\"conflict-panel\" [class.collapsed]=\"conflictsCollapsed\">\n <div class=\"header\">\n <span>Konflikter (3)</span>\n <mat-icon>{{ activeObjectsCollapsed ? 'expand_more' : 'expand_less' }}</mat-icon> -->\n </div>\n <mat-list>\n <mat-list-item>\n <span matListItemTitle>Lag #1</span>\n <span matListItemLine><mat-icon>highlight</mat-icon> Objekt #1</span>\n </mat-list-item>\n <mat-list-item>\n <span matListItemTitle>Lag #2 (svarer ikke)</span>\n </mat-list-item>\n <mat-list-item>\n <span matListItemTitle>Lag #3</span>\n <span matListItemLine><mat-icon>highlight</mat-icon> Objekt #1</span>\n <span matListItemLine><mat-icon>highlight</mat-icon> Objekt #2</span>\n </mat-list-item>\n </mat-list>\n </div>\n \n } \n\n <!-- Kort -->\n <div id=\"map\" class=\"map\"></div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%;overflow:hidden}::ng-deep .lib-error-snackbar{background-color:#d32f2f;color:#fff;font-weight:500}::ng-deep .map-container{position:relative;height:81vh;width:100%;overflow:hidden}::ng-deep #map{width:100%;height:100%;position:absolute;inset:0;overflow:hidden}::ng-deep .ol-viewport{overflow:hidden!important}::ng-deep ::ng-deep .ol-logo{position:absolute;left:auto;right:3em;top:6.25em}::ng-deep ::ng-deep .ol-copyright{background-color:transparent;position:absolute;bottom:10px;width:100%;text-align:center}::ng-deep ::ng-deep .toolbar{position:absolute;top:10px;left:10px;background:#fff;padding:4px;border-radius:4px;display:flex;flex-direction:column;transition:width .3s;z-index:1000;overflow:hidden}::ng-deep ::ng-deep .toolbar.collapsed{width:40px;overflow:hidden}::ng-deep .object-panel{position:absolute;bottom:10px;left:10px;background:#fff;padding:8px;border-radius:4px;z-index:1000;max-height:calc(85vh - 20px);overflow-y:auto}::ng-deep .object-panel .header{display:flex;justify-content:space-between;padding:8px;cursor:pointer;background:#f0f0f0}::ng-deep .conflict-panel{position:absolute;bottom:10px;right:10px;background:#fff;padding:8px;border-radius:4px;z-index:1000;max-height:calc(85vh - 20px);overflow-y:auto}::ng-deep .conflict-panel .header{display:flex;justify-content:space-between;padding:8px;cursor:pointer;background:#f0f0f0}::ng-deep ::ng-deep .ol-zoom.ol-unselectable.ol-control{display:flex;flex-direction:column;position:absolute;left:1rem}::ng-deep ::ng-deep button.ol-zoom-in{font-size:2em;width:40px;height:40px;background-color:#292a2d;border:none;box-shadow:none;cursor:pointer;border-radius:5px 5px 0 0!important;color:#fff}::ng-deep ::ng-deep button.ol-zoom-in:hover{color:#e9e3e3;outline:none}::ng-deep ::ng-deep .ol-scale-text{display:flex}::ng-deep button.ol-zoom-out{font-size:2em;width:40px;height:40px;background-color:#292a2d;border:none;box-shadow:none;cursor:pointer;color:#fff;border-radius:0 0 5px 5px!important}::ng-deep button.ol-zoom-out:hover{color:#e9e3e3;outline:none}::ng-deep button.ol-rotate-reset{font-size:2em;width:40px;height:40px;background-color:#292a2d;border:none;box-shadow:none;cursor:pointer;color:#fff;border-radius:5px}::ng-deep button.ol-rotate-reset:hover{color:#e9e3e3;outline:none}::ng-deep .ol-scale-bar.ol-unselectable{position:absolute;bottom:3rem;left:1rem}::ng-deep .ol-mouse-position{top:44em;left:12px;position:absolute;background:color-mix(in srgb,#000 21%,transparent);color:#fffcfc;width:189px;height:30px;padding:2px;border-radius:5px;font-family:Avenir Next W01,Lato,-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;text-align:center;display:flex;align-items:center;justify-content:flex-start}\n"] }]
|
|
4143
|
+
}], ctorParameters: () => [], propDecorators: { showToolbox: [{
|
|
2353
4144
|
type: Input
|
|
2354
4145
|
}], showActiveObjects: [{
|
|
2355
4146
|
type: Input
|
|
@@ -2365,9 +4156,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImpo
|
|
|
2365
4156
|
}], toolbarRef: [{
|
|
2366
4157
|
type: ViewChild,
|
|
2367
4158
|
args: ['toolbarRef', { static: true }]
|
|
2368
|
-
}],
|
|
4159
|
+
}], selectedFeatureInfoRef: [{
|
|
2369
4160
|
type: ViewChild,
|
|
2370
|
-
args: ['
|
|
4161
|
+
args: ['selectedFeatureInfoRef', { static: true }]
|
|
4162
|
+
}], sessionDone: [{
|
|
4163
|
+
type: Output
|
|
4164
|
+
}], featuresChanged: [{
|
|
4165
|
+
type: Output
|
|
2371
4166
|
}] } });
|
|
2372
4167
|
class CapabilitiesItem {
|
|
2373
4168
|
url = '';
|