adb-shared 6.2.20 → 6.2.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -6
- package/fesm2022/adb-shared-src-map.mjs +824 -0
- package/fesm2022/adb-shared-src-map.mjs.map +1 -0
- package/fesm2022/adb-shared.mjs +490 -1159
- package/fesm2022/adb-shared.mjs.map +1 -1
- package/package.json +8 -5
- package/types/adb-shared-src-map.d.ts +260 -0
- package/types/adb-shared.d.ts +12 -259
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
import * as i1$1 from '@angular/common';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { forwardRef, Component, InjectionToken, Inject, Injectable, Input, signal, effect, NgModule } from '@angular/core';
|
|
5
|
+
import * as i4 from '@angular/forms';
|
|
6
|
+
import { NG_VALUE_ACCESSOR, FormControl, FormGroup, FormArray, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
7
|
+
import * as i1 from '@ngx-translate/core';
|
|
8
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
9
|
+
import * as Leaflet from 'leaflet';
|
|
10
|
+
import Leaflet__default from 'leaflet';
|
|
11
|
+
import '@geoman-io/leaflet-geoman-free';
|
|
12
|
+
import { Subscription, combineLatest, map, debounceTime } from 'rxjs';
|
|
13
|
+
import * as i3 from '@angular/router';
|
|
14
|
+
import { RouterModule } from '@angular/router';
|
|
15
|
+
import { finalize } from 'rxjs/operators';
|
|
16
|
+
import * as i3$1 from '@angular/common/http';
|
|
17
|
+
import * as i5 from 'adb-shared';
|
|
18
|
+
import { AdbDatePickerModule, AdbPipesModule, AdbFilterSectionModule, AdbPickerModule } from 'adb-shared';
|
|
19
|
+
import { addYears, startOfYear, endOfYear, startOfDay, endOfDay, parseISO } from 'date-fns';
|
|
20
|
+
|
|
21
|
+
class AdbMapUtils {
|
|
22
|
+
static INITIAL_CENTER_LAT = 62;
|
|
23
|
+
static INITIAL_CENTER_LNG = 17;
|
|
24
|
+
static OverlayMaps = {
|
|
25
|
+
'Altitude': new Leaflet.TileLayer.WMS("https://maps.sgu.se/lmv/hojdmodell/v1.1?SERVICE=WMS", { layers: "terrangskuggning", format: "image/png", transparent: true, opacity: 0.3, maxZoom: 16, version: "1.3.0" }),
|
|
26
|
+
'Fjällkarta': new Leaflet.TileLayer.WMS('api/maps/mountain', {
|
|
27
|
+
minZoom: 6,
|
|
28
|
+
maxZoom: 18,
|
|
29
|
+
maxNativeZoom: 14,
|
|
30
|
+
attribution: '© <a href="https://www.lantmateriet.se/">Fjällkart</a>',
|
|
31
|
+
wms: true
|
|
32
|
+
}),
|
|
33
|
+
'Kommuner': new Leaflet.TileLayer.WMS('https://sosgeo.artdata.slu.se/geoserver/GeoRegion/wms?', {
|
|
34
|
+
layers: 'GeoRegion:Municipality',
|
|
35
|
+
version: '1.1.0',
|
|
36
|
+
transparent: true,
|
|
37
|
+
format: 'image/png'
|
|
38
|
+
}),
|
|
39
|
+
'Län': new Leaflet.TileLayer.WMS('https://sosgeo.artdata.slu.se/geoserver/GeoRegion/wms?', {
|
|
40
|
+
layers: 'GeoRegion:County',
|
|
41
|
+
version: '1.1.0',
|
|
42
|
+
transparent: true,
|
|
43
|
+
format: 'image/png'
|
|
44
|
+
}),
|
|
45
|
+
'Ortnamn': new Leaflet.TileLayer.WMS("https://maps.sgu.se/lmv/topowebb-skikt/v1.1?SERVICE=WMS", {
|
|
46
|
+
layers: "text",
|
|
47
|
+
format: "image/png",
|
|
48
|
+
transparent: true,
|
|
49
|
+
version: "1.3.0",
|
|
50
|
+
}),
|
|
51
|
+
'Ekonomisk zon': new Leaflet.TileLayer.WMS("https://sosgeo.artdata.slu.se/geoserver/it.geosolutions/wms?", {
|
|
52
|
+
layers: "it.geosolutions:Ekonomiska_zonens_yttre_avgränsningslinjer_linje",
|
|
53
|
+
format: "image/png",
|
|
54
|
+
transparent: true,
|
|
55
|
+
version: "1.1.0"
|
|
56
|
+
})
|
|
57
|
+
};
|
|
58
|
+
static Providers = [
|
|
59
|
+
{
|
|
60
|
+
name: 'Open Streetmap',
|
|
61
|
+
id: 3,
|
|
62
|
+
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
|
63
|
+
minZoom: 0,
|
|
64
|
+
maxZoom: 18,
|
|
65
|
+
params: {
|
|
66
|
+
maxNativeZoom: 18,
|
|
67
|
+
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
68
|
+
},
|
|
69
|
+
wms: false
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'Sveriges gränser',
|
|
73
|
+
id: 7,
|
|
74
|
+
url: 'https://sosgeo.artdata.slu.se/geoserver/it.geosolutions/wms',
|
|
75
|
+
minZoom: 6,
|
|
76
|
+
maxZoom: 18,
|
|
77
|
+
params: {
|
|
78
|
+
maxNativeZoom: 14,
|
|
79
|
+
attribution: '© <a href="https://www.lantmateriet.se/">Sveriges gränser</a>',
|
|
80
|
+
layers: 'it.geosolutions:Sverige_epsg5845', styles: 'municipality_name_yellow',
|
|
81
|
+
epsg: 5845
|
|
82
|
+
},
|
|
83
|
+
wms: true
|
|
84
|
+
}
|
|
85
|
+
];
|
|
86
|
+
//NOTE: Will be move
|
|
87
|
+
static redListMapper2 = {
|
|
88
|
+
'VU': '228',
|
|
89
|
+
'EN': '229',
|
|
90
|
+
'CR': '230',
|
|
91
|
+
'RE': '231',
|
|
92
|
+
'DD': '232',
|
|
93
|
+
'NT': '233'
|
|
94
|
+
};
|
|
95
|
+
static createMap(elementId, options = {}) {
|
|
96
|
+
const map = Leaflet.map(elementId, {
|
|
97
|
+
zoomAnimation: false,
|
|
98
|
+
fadeAnimation: false,
|
|
99
|
+
markerZoomAnimation: false,
|
|
100
|
+
inertia: false,
|
|
101
|
+
scrollWheelZoom: options.scrollZoom ?? true,
|
|
102
|
+
zoomControl: options.zoom ?? true,
|
|
103
|
+
dragging: options.zoom ?? true,
|
|
104
|
+
minZoom: -1
|
|
105
|
+
});
|
|
106
|
+
map.setView([62, 17], 5);
|
|
107
|
+
Leaflet.control.scale().addTo(map);
|
|
108
|
+
if (options.providers !== false) {
|
|
109
|
+
this.addProviders(map);
|
|
110
|
+
}
|
|
111
|
+
return map;
|
|
112
|
+
}
|
|
113
|
+
static addProviders(map) {
|
|
114
|
+
const backgroundMaps = {};
|
|
115
|
+
for (const value of Object.values(AdbMapUtils.Providers)) {
|
|
116
|
+
backgroundMaps[value.name] = value.wms
|
|
117
|
+
? Leaflet.tileLayer.wms(value.url, value.params)
|
|
118
|
+
: Leaflet.tileLayer(value.url, value.params);
|
|
119
|
+
}
|
|
120
|
+
if (backgroundMaps['Open Streetmap']) {
|
|
121
|
+
map.addLayer(backgroundMaps['Open Streetmap']);
|
|
122
|
+
}
|
|
123
|
+
Leaflet.control.layers(backgroundMaps, AdbMapUtils.OverlayMaps).addTo(map);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
class PolygonDrawerInput {
|
|
128
|
+
subscriptions = new Subscription();
|
|
129
|
+
mapId = "" + Math.floor(Math.random() * Date.now());
|
|
130
|
+
map;
|
|
131
|
+
polygonDraw = false;
|
|
132
|
+
shapeLayer = null;
|
|
133
|
+
geoJson;
|
|
134
|
+
ngAfterViewInit() {
|
|
135
|
+
this.map = AdbMapUtils.createMap(this.mapId, {
|
|
136
|
+
zoom: true,
|
|
137
|
+
scrollZoom: true,
|
|
138
|
+
providers: true
|
|
139
|
+
});
|
|
140
|
+
this.map.whenReady(() => {
|
|
141
|
+
this.initDraw();
|
|
142
|
+
this.renderInitialShape();
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
ngOnInit() { }
|
|
146
|
+
ngOnDestroy() {
|
|
147
|
+
this.subscriptions.unsubscribe();
|
|
148
|
+
}
|
|
149
|
+
initDraw() {
|
|
150
|
+
this.map.pm.removeControls();
|
|
151
|
+
this.map.pm.enableDraw('Polygon', {
|
|
152
|
+
tooltips: false,
|
|
153
|
+
finishOn: 'snap',
|
|
154
|
+
snapDistance: 30,
|
|
155
|
+
snapMiddle: false
|
|
156
|
+
});
|
|
157
|
+
this.map.on("pm:create", (e) => {
|
|
158
|
+
if (e.shape !== "Polygon")
|
|
159
|
+
return;
|
|
160
|
+
this.polygonDraw = false;
|
|
161
|
+
this.map.pm.disableDraw();
|
|
162
|
+
this.clearShape();
|
|
163
|
+
this.shapeLayer = Leaflet__default.geoJSON(e.layer.toGeoJSON(), {
|
|
164
|
+
interactive: false
|
|
165
|
+
});
|
|
166
|
+
this.map.addLayer(this.shapeLayer);
|
|
167
|
+
this.map.fitBounds(this.shapeLayer.getBounds());
|
|
168
|
+
this.onChange(e.layer.toGeoJSON());
|
|
169
|
+
this.map.removeLayer(e.layer);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
renderInitialShape() {
|
|
173
|
+
if (this.geoJson?.type === "Feature") {
|
|
174
|
+
this.shapeLayer = Leaflet__default.geoJSON(this.geoJson, {
|
|
175
|
+
interactive: false
|
|
176
|
+
});
|
|
177
|
+
this.map.addLayer(this.shapeLayer);
|
|
178
|
+
this.map.fitBounds(this.shapeLayer.getBounds());
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
this.map.setView([AdbMapUtils.INITIAL_CENTER_LAT, AdbMapUtils.INITIAL_CENTER_LNG], 5);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
clearShape() {
|
|
185
|
+
if (this.shapeLayer) {
|
|
186
|
+
this.map.removeLayer(this.shapeLayer);
|
|
187
|
+
this.shapeLayer = null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
onDrawPolygon() {
|
|
191
|
+
this.polygonDraw = true;
|
|
192
|
+
this.map.pm.enableDraw("Polygon", {
|
|
193
|
+
allowSelfIntersection: false,
|
|
194
|
+
snappable: false
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
onUndoStep() {
|
|
198
|
+
const draw = this.map.pm.Draw?.Polygon;
|
|
199
|
+
draw?._removeLastVertex();
|
|
200
|
+
}
|
|
201
|
+
onDeleteShape() {
|
|
202
|
+
this.clearShape();
|
|
203
|
+
this.map.pm.disableDraw();
|
|
204
|
+
this.polygonDraw = false;
|
|
205
|
+
this.onChange(null);
|
|
206
|
+
this.map.setView([62, 17], 5);
|
|
207
|
+
}
|
|
208
|
+
// ControlValueAccessor
|
|
209
|
+
onChange = () => { };
|
|
210
|
+
onTouched = () => { };
|
|
211
|
+
writeValue(geoJson) {
|
|
212
|
+
this.geoJson = geoJson;
|
|
213
|
+
}
|
|
214
|
+
registerOnChange(fn) {
|
|
215
|
+
this.onChange = fn;
|
|
216
|
+
}
|
|
217
|
+
registerOnTouched(fn) {
|
|
218
|
+
this.onTouched = fn;
|
|
219
|
+
}
|
|
220
|
+
setDisabledState(isDisabled) { }
|
|
221
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: PolygonDrawerInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
222
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: PolygonDrawerInput, isStandalone: false, selector: "adb-polygon-drawer", providers: [
|
|
223
|
+
{
|
|
224
|
+
provide: NG_VALUE_ACCESSOR,
|
|
225
|
+
useExisting: forwardRef(() => PolygonDrawerInput),
|
|
226
|
+
multi: true
|
|
227
|
+
}
|
|
228
|
+
], ngImport: i0, template: "<div class=\"mb-1 d-flex gap-1 flex-wrap align-items-start\">\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onDrawPolygon()\" title=\"Polygon\">\r\n <span class=\"fas fa-draw-polygon\"></span> {{'OBSERVATION.DRAW'|translate}}\r\n </button>\r\n @if (polygonDraw) {\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onDeleteShape()\" title=\"Ta bort\">\r\n <span class=\"fas fa-times\"></span>\r\n </button>\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onUndoStep()\" title=\"\u00C5ngra\">\r\n <span class=\"fas fa-undo\"></span>\r\n </button>\r\n }\r\n</div>\r\n<div [id]=\"mapId\" class=\"border\" style=\"height:20rem\"></div>", dependencies: [{ kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
229
|
+
}
|
|
230
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: PolygonDrawerInput, decorators: [{
|
|
231
|
+
type: Component,
|
|
232
|
+
args: [{ selector: "adb-polygon-drawer", standalone: false, providers: [
|
|
233
|
+
{
|
|
234
|
+
provide: NG_VALUE_ACCESSOR,
|
|
235
|
+
useExisting: forwardRef(() => PolygonDrawerInput),
|
|
236
|
+
multi: true
|
|
237
|
+
}
|
|
238
|
+
], template: "<div class=\"mb-1 d-flex gap-1 flex-wrap align-items-start\">\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onDrawPolygon()\" title=\"Polygon\">\r\n <span class=\"fas fa-draw-polygon\"></span> {{'OBSERVATION.DRAW'|translate}}\r\n </button>\r\n @if (polygonDraw) {\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onDeleteShape()\" title=\"Ta bort\">\r\n <span class=\"fas fa-times\"></span>\r\n </button>\r\n <button class=\"btn btn-secondary\" type=\"button\" (click)=\"onUndoStep()\" title=\"\u00C5ngra\">\r\n <span class=\"fas fa-undo\"></span>\r\n </button>\r\n }\r\n</div>\r\n<div [id]=\"mapId\" class=\"border\" style=\"height:20rem\"></div>" }]
|
|
239
|
+
}] });
|
|
240
|
+
|
|
241
|
+
var AdbMapFilterType;
|
|
242
|
+
(function (AdbMapFilterType) {
|
|
243
|
+
AdbMapFilterType["Taxon"] = "taxon";
|
|
244
|
+
AdbMapFilterType["Area"] = "area";
|
|
245
|
+
AdbMapFilterType["OwnArea"] = "ownArea";
|
|
246
|
+
AdbMapFilterType["Time"] = "time";
|
|
247
|
+
AdbMapFilterType["RedList"] = "redlist";
|
|
248
|
+
AdbMapFilterType["RiskList"] = "risklist";
|
|
249
|
+
AdbMapFilterType["TaxaLists"] = "taxonLists";
|
|
250
|
+
AdbMapFilterType["Datasources"] = "datasources";
|
|
251
|
+
})(AdbMapFilterType || (AdbMapFilterType = {}));
|
|
252
|
+
class VisibleFilters {
|
|
253
|
+
showTaxon;
|
|
254
|
+
showTime;
|
|
255
|
+
showArea;
|
|
256
|
+
showOwnArea;
|
|
257
|
+
showTaxaLists;
|
|
258
|
+
showDatasets;
|
|
259
|
+
}
|
|
260
|
+
const ADB_MAP_CONFIG = new InjectionToken('ADB_MAP_CONFIG');
|
|
261
|
+
class AdbMapConfigService {
|
|
262
|
+
log;
|
|
263
|
+
artfaktaTaxonLists;
|
|
264
|
+
observationFeatures;
|
|
265
|
+
taxaListsApi;
|
|
266
|
+
filters;
|
|
267
|
+
observationPage;
|
|
268
|
+
constructor(config) {
|
|
269
|
+
this.log = config.log ?? false;
|
|
270
|
+
this.artfaktaTaxonLists = config.artfaktaTaxonLists ?? 'https://artfakta.se/metadata/listor';
|
|
271
|
+
this.taxaListsApi = config.api + '/taxalists';
|
|
272
|
+
this.observationFeatures = config.api + '/observation-features';
|
|
273
|
+
this.observationPage = config.observationPage ?? 'https://mobil.artportalen.se/observationer';
|
|
274
|
+
this.filters = {
|
|
275
|
+
showTaxon: this.hasFilter(AdbMapFilterType.Taxon, config.filters),
|
|
276
|
+
showTime: this.hasFilter(AdbMapFilterType.Time, config.filters),
|
|
277
|
+
showArea: this.hasFilter(AdbMapFilterType.Area, config.filters),
|
|
278
|
+
showOwnArea: this.hasFilter(AdbMapFilterType.OwnArea, config.filters),
|
|
279
|
+
showTaxaLists: this.hasFilter(AdbMapFilterType.TaxaLists, config.filters),
|
|
280
|
+
showDatasets: this.hasFilter(AdbMapFilterType.Datasources, config.filters),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
hasFilter(f, filters) {
|
|
284
|
+
return filters?.includes(f) ?? true;
|
|
285
|
+
}
|
|
286
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbMapConfigService, deps: [{ token: ADB_MAP_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
287
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbMapConfigService });
|
|
288
|
+
}
|
|
289
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbMapConfigService, decorators: [{
|
|
290
|
+
type: Injectable
|
|
291
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
292
|
+
type: Inject,
|
|
293
|
+
args: [ADB_MAP_CONFIG]
|
|
294
|
+
}] }] });
|
|
295
|
+
|
|
296
|
+
class TreeviewComponent {
|
|
297
|
+
nodes = [];
|
|
298
|
+
selectedIds = [];
|
|
299
|
+
onChange = () => { };
|
|
300
|
+
onTouched = () => { };
|
|
301
|
+
writeValue(ids) {
|
|
302
|
+
this.selectedIds = ids ?? [];
|
|
303
|
+
this.applySelection(this.nodes);
|
|
304
|
+
}
|
|
305
|
+
registerOnChange(fn) {
|
|
306
|
+
this.onChange = fn;
|
|
307
|
+
}
|
|
308
|
+
registerOnTouched(fn) {
|
|
309
|
+
this.onTouched = fn;
|
|
310
|
+
}
|
|
311
|
+
setDisabledState(isDisabled) {
|
|
312
|
+
this.setReadOnly(this.nodes, isDisabled);
|
|
313
|
+
}
|
|
314
|
+
onLeafToggle(node) {
|
|
315
|
+
if (node._readOnly)
|
|
316
|
+
return;
|
|
317
|
+
node._selected = !node._selected;
|
|
318
|
+
this.selectedIds = TreeviewComponent.collectSelectedLeafIds(this.nodes);
|
|
319
|
+
this.onChange(this.selectedIds);
|
|
320
|
+
this.onTouched();
|
|
321
|
+
}
|
|
322
|
+
applySelection(nodes) {
|
|
323
|
+
for (const node of nodes) {
|
|
324
|
+
if (node.children?.length) {
|
|
325
|
+
this.applySelection(node.children);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
node._selected = this.selectedIds.includes(node.id);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
setReadOnly(nodes, readOnly) {
|
|
333
|
+
for (const node of nodes) {
|
|
334
|
+
node._readOnly = readOnly;
|
|
335
|
+
if (node.children?.length) {
|
|
336
|
+
this.setReadOnly(node.children, readOnly);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
static collectSelectedLeafIds(nodes) {
|
|
341
|
+
const ids = [];
|
|
342
|
+
for (const node of nodes) {
|
|
343
|
+
if (node.children?.length) {
|
|
344
|
+
ids.push(...this.collectSelectedLeafIds(node.children));
|
|
345
|
+
}
|
|
346
|
+
else if (node._selected) {
|
|
347
|
+
ids.push(node.id);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return ids;
|
|
351
|
+
}
|
|
352
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: TreeviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
353
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: TreeviewComponent, isStandalone: false, selector: "app-treeview", inputs: { nodes: "nodes" }, providers: [
|
|
354
|
+
{
|
|
355
|
+
provide: NG_VALUE_ACCESSOR,
|
|
356
|
+
useExisting: forwardRef(() => TreeviewComponent),
|
|
357
|
+
multi: true
|
|
358
|
+
}
|
|
359
|
+
], ngImport: i0, template: "<ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: nodes }\">\r\n</ng-container>\r\n<ng-template #nodeTpl let-nodes>\r\n @for (node of nodes; track node) {\r\n <div class=\"ms-3\">\r\n @if(!node.children || node.children.length === 0){\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <input id=\"{{node.id}}\" type=\"checkbox\" class=\"form-check-input m-0\" [checked]=\"node._selected\" [disabled]=\"node._readOnly\" (change)=\"onLeafToggle(node)\" />\r\n <label for=\"{{node.id}}\">{{ node.name }}</label>\r\n </div>\r\n }\r\n @else {\r\n {{ node.name }}\r\n <div>\r\n <ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: node.children }\">\r\n </ng-container>\r\n </div>\r\n }\r\n </div>\r\n}\r\n</ng-template>", dependencies: [{ kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
360
|
+
}
|
|
361
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: TreeviewComponent, decorators: [{
|
|
362
|
+
type: Component,
|
|
363
|
+
args: [{ selector: 'app-treeview', standalone: false, providers: [
|
|
364
|
+
{
|
|
365
|
+
provide: NG_VALUE_ACCESSOR,
|
|
366
|
+
useExisting: forwardRef(() => TreeviewComponent),
|
|
367
|
+
multi: true
|
|
368
|
+
}
|
|
369
|
+
], template: "<ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: nodes }\">\r\n</ng-container>\r\n<ng-template #nodeTpl let-nodes>\r\n @for (node of nodes; track node) {\r\n <div class=\"ms-3\">\r\n @if(!node.children || node.children.length === 0){\r\n <div class=\"d-flex align-items-center gap-2\">\r\n <input id=\"{{node.id}}\" type=\"checkbox\" class=\"form-check-input m-0\" [checked]=\"node._selected\" [disabled]=\"node._readOnly\" (change)=\"onLeafToggle(node)\" />\r\n <label for=\"{{node.id}}\">{{ node.name }}</label>\r\n </div>\r\n }\r\n @else {\r\n {{ node.name }}\r\n <div>\r\n <ng-container *ngTemplateOutlet=\"nodeTpl; context: { $implicit: node.children }\">\r\n </ng-container>\r\n </div>\r\n }\r\n </div>\r\n}\r\n</ng-template>" }]
|
|
370
|
+
}], propDecorators: { nodes: [{
|
|
371
|
+
type: Input
|
|
372
|
+
}] } });
|
|
373
|
+
|
|
374
|
+
class AdbObsMapComponent {
|
|
375
|
+
activatedRoute;
|
|
376
|
+
config;
|
|
377
|
+
router;
|
|
378
|
+
http;
|
|
379
|
+
subscriptions = new Subscription();
|
|
380
|
+
error;
|
|
381
|
+
mapLoading = signal(false, ...(ngDevMode ? [{ debugName: "mapLoading" }] : []));
|
|
382
|
+
siteLayer;
|
|
383
|
+
hasBox;
|
|
384
|
+
count;
|
|
385
|
+
mapId = '' + Math.floor(Math.random() * Date.now());
|
|
386
|
+
map = Leaflet.map;
|
|
387
|
+
//Lock start
|
|
388
|
+
mapReady = signal(false, ...(ngDevMode ? [{ debugName: "mapReady" }] : []));
|
|
389
|
+
hasQueryParams = false;
|
|
390
|
+
hasUrlParams = false;
|
|
391
|
+
queryParams;
|
|
392
|
+
urlParams;
|
|
393
|
+
//Lock end
|
|
394
|
+
constructor(activatedRoute, config, router, http) {
|
|
395
|
+
this.activatedRoute = activatedRoute;
|
|
396
|
+
this.config = config;
|
|
397
|
+
this.router = router;
|
|
398
|
+
this.http = http;
|
|
399
|
+
effect(() => {
|
|
400
|
+
// This will re-run whenever mapReady() changes
|
|
401
|
+
if (this.mapReady() && this.hasQueryParams && this.hasUrlParams) {
|
|
402
|
+
this.tryLoad();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
ngAfterViewInit() {
|
|
407
|
+
this.map = AdbMapUtils.createMap(this.mapId, {
|
|
408
|
+
zoom: true,
|
|
409
|
+
scrollZoom: false,
|
|
410
|
+
providers: true
|
|
411
|
+
});
|
|
412
|
+
this.map.whenReady(() => {
|
|
413
|
+
this.mapReady.set(true);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
// Loads data only after:
|
|
417
|
+
// - the Leaflet map is ready
|
|
418
|
+
// - Angular has emitted query params (may be empty)
|
|
419
|
+
// - Angular has emitted route params (may be empty)
|
|
420
|
+
tryLoad() {
|
|
421
|
+
if (!this.mapReady() || !this.hasQueryParams || !this.hasUrlParams) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const params = { ...this.queryParams };
|
|
425
|
+
this.hasBox = params['bbox'] ? true : false;
|
|
426
|
+
if (this.urlParams.has('taxonId')) {
|
|
427
|
+
params['taxonId'] = this.urlParams.get('taxonId');
|
|
428
|
+
}
|
|
429
|
+
this.loadFeature(params);
|
|
430
|
+
}
|
|
431
|
+
ngOnInit() {
|
|
432
|
+
this.subscriptions.add(this.activatedRoute.queryParams.subscribe(q => {
|
|
433
|
+
this.queryParams = q ?? {};
|
|
434
|
+
this.hasQueryParams = true;
|
|
435
|
+
this.tryLoad();
|
|
436
|
+
}));
|
|
437
|
+
this.subscriptions.add(this.activatedRoute.paramMap.subscribe(p => {
|
|
438
|
+
this.urlParams = p;
|
|
439
|
+
this.hasUrlParams = true;
|
|
440
|
+
this.tryLoad();
|
|
441
|
+
}));
|
|
442
|
+
}
|
|
443
|
+
loadFeature(qParams) {
|
|
444
|
+
this.mapLoading.set(true);
|
|
445
|
+
this.error = null;
|
|
446
|
+
const url = this.config.observationFeatures;
|
|
447
|
+
this.subscriptions.add(this.http.get(url, { observe: 'response', params: qParams }).
|
|
448
|
+
pipe(finalize(() => {
|
|
449
|
+
this.mapLoading.set(false);
|
|
450
|
+
})).
|
|
451
|
+
subscribe({
|
|
452
|
+
next: (response) => {
|
|
453
|
+
if (!response.body) {
|
|
454
|
+
throw new Error('No GeoJson body');
|
|
455
|
+
}
|
|
456
|
+
const geo = response.body;
|
|
457
|
+
geo.properties = { count: response.headers.get('X-Observations-TotalCount') };
|
|
458
|
+
this.buildMap(geo);
|
|
459
|
+
}, error: err => {
|
|
460
|
+
this.error = err;
|
|
461
|
+
}
|
|
462
|
+
}));
|
|
463
|
+
}
|
|
464
|
+
buildMap(geojson) {
|
|
465
|
+
if (this.siteLayer) {
|
|
466
|
+
this.map.removeLayer(this.siteLayer);
|
|
467
|
+
}
|
|
468
|
+
this.count = geojson?.properties?.count;
|
|
469
|
+
this.siteLayer = Leaflet.geoJson(geojson, {
|
|
470
|
+
style: (feature) => {
|
|
471
|
+
return {
|
|
472
|
+
className: `svg ${this.getPolygonClassName(feature.properties)}`, // Leaflet applies this class to the SVG path
|
|
473
|
+
weight: 1,
|
|
474
|
+
fillOpacity: 0.8,
|
|
475
|
+
};
|
|
476
|
+
},
|
|
477
|
+
pointToLayer: (feature, latlng) => {
|
|
478
|
+
const marker = Leaflet.marker(latlng, {
|
|
479
|
+
icon: Leaflet.divIcon({
|
|
480
|
+
className: '',
|
|
481
|
+
html: '<div class="adb-map-marker"></div>',
|
|
482
|
+
iconAnchor: [3, 3]
|
|
483
|
+
})
|
|
484
|
+
});
|
|
485
|
+
// if (feature.properties && feature.properties['Occurrence.OccurrenceId']) {
|
|
486
|
+
// marker.on('click', () => {
|
|
487
|
+
// window.location.href = this.config.observationPage + '/' + feature.properties['Occurrence.OccurrenceId'];
|
|
488
|
+
// });
|
|
489
|
+
// }
|
|
490
|
+
return marker;
|
|
491
|
+
}, onEachFeature: (feature, layer) => {
|
|
492
|
+
if (feature.geometry.type === "Polygon" ||
|
|
493
|
+
feature.geometry.type === "MultiPolygon") {
|
|
494
|
+
layer.setStyle({ interactive: false });
|
|
495
|
+
// if (feature.properties.ObservationsCount > 0) {
|
|
496
|
+
// layer.on('click', () => {
|
|
497
|
+
// const boundBox = JSON.stringify(this.getMapBoundsToBbox(layer.getBounds()));
|
|
498
|
+
// this.router.navigate([], { queryParams: { bbox: boundBox }, queryParamsHandling: 'merge' });
|
|
499
|
+
// });
|
|
500
|
+
// layer.on('mouseover', () => {
|
|
501
|
+
// layer.setStyle({ className: 'svg cursor-pointer' });
|
|
502
|
+
// });
|
|
503
|
+
// layer.on('mouseout', () => {
|
|
504
|
+
// layer.setStyle({ className: 'svg' });
|
|
505
|
+
// });
|
|
506
|
+
// }
|
|
507
|
+
// if (feature.properties.FeatureType) { //area
|
|
508
|
+
// layer.setStyle({ interactive: false });
|
|
509
|
+
// }
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
const circleLayer = Leaflet.featureGroup();
|
|
514
|
+
circleLayer.addTo(this.siteLayer);
|
|
515
|
+
this.map.addLayer(this.siteLayer);
|
|
516
|
+
if (geojson.bbox) {
|
|
517
|
+
const [minLon, minLat, maxLon, maxLat] = geojson.bbox;
|
|
518
|
+
const bounds = Leaflet.latLngBounds([[minLat, minLon], [maxLat, maxLon]]);
|
|
519
|
+
if (bounds.isValid()) {
|
|
520
|
+
// Safari sometimes needs extra time after layer adds
|
|
521
|
+
setTimeout(() => {
|
|
522
|
+
this.map.invalidateSize({ animate: false });
|
|
523
|
+
this.map.fitBounds(bounds, { animate: false });
|
|
524
|
+
}, 50); // 30–50ms works best in Safari
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
getPolygonClassName(props) {
|
|
529
|
+
if (props.FeatureType) {
|
|
530
|
+
return 'map-area';
|
|
531
|
+
}
|
|
532
|
+
if (props.ObservationsCount < 10)
|
|
533
|
+
return 'map-heat-low';
|
|
534
|
+
if (props.ObservationsCount < 500)
|
|
535
|
+
return 'map-heat-small';
|
|
536
|
+
return 'map-heat-high';
|
|
537
|
+
}
|
|
538
|
+
getMapBoundsToBbox(bounds) {
|
|
539
|
+
return [bounds.getNorthWest().lat, bounds.getNorthWest().lng, bounds.getSouthEast().lat, bounds.getSouthEast().lng];
|
|
540
|
+
}
|
|
541
|
+
ngOnDestroy() {
|
|
542
|
+
this.subscriptions.unsubscribe();
|
|
543
|
+
}
|
|
544
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbObsMapComponent, deps: [{ token: i3.ActivatedRoute }, { token: AdbMapConfigService }, { token: i3.Router }, { token: i3$1.HttpClient }], target: i0.ɵɵFactoryTarget.Component });
|
|
545
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: AdbObsMapComponent, isStandalone: false, selector: "adb-obs-map", ngImport: i0, template: "<!-- @if(hasBox&&!mapLoading()){\r\n<div class=\"mb-1 d-flex justify-content-between flex-wrap\">\r\n <a [routerLink]=\"[]\" [queryParams]=\"{bbox:null,z:null}\" queryParamsHandling=\"merge\" class=\"d-flex gap-1 align-items-baseline\">\r\n <span class=\"fas fa-chevron-left\"></span>\r\n Tillbaka upp\r\n </a>\r\n</div>\r\n} -->\r\n@if(error){\r\n<div class=\"alert alert-danger\">\r\n {{'ERROR.SERVER_ERROR'|translate}}\r\n</div>\r\n}\r\n<div [class.loading]=\"mapLoading()\">\r\n <div [id]=\"mapId\" class=\"mb-1 map-container\"></div>\r\n</div>\r\n<div class=\"mb-1 d-flex gap-3 justify-content-between flex-wrap\">\r\n @if (!mapLoading()&&count) {\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-low\"></div>\r\n <10\r\n </div>\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-medium\"></div>\r\n 10 - 500\r\n </div>\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-high\"></div>\r\n >500\r\n </div>\r\n <div class=\"ms-auto\">\r\n {{count|adbSpacing}} {{'OBSERVATION.OBSERVATIONS'|translate}}\r\n </div>\r\n }\r\n</div>", dependencies: [{ kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "pipe", type: i5.NumberSpacingPipe, name: "adbSpacing" }] });
|
|
546
|
+
}
|
|
547
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbObsMapComponent, decorators: [{
|
|
548
|
+
type: Component,
|
|
549
|
+
args: [{ selector: 'adb-obs-map', standalone: false, template: "<!-- @if(hasBox&&!mapLoading()){\r\n<div class=\"mb-1 d-flex justify-content-between flex-wrap\">\r\n <a [routerLink]=\"[]\" [queryParams]=\"{bbox:null,z:null}\" queryParamsHandling=\"merge\" class=\"d-flex gap-1 align-items-baseline\">\r\n <span class=\"fas fa-chevron-left\"></span>\r\n Tillbaka upp\r\n </a>\r\n</div>\r\n} -->\r\n@if(error){\r\n<div class=\"alert alert-danger\">\r\n {{'ERROR.SERVER_ERROR'|translate}}\r\n</div>\r\n}\r\n<div [class.loading]=\"mapLoading()\">\r\n <div [id]=\"mapId\" class=\"mb-1 map-container\"></div>\r\n</div>\r\n<div class=\"mb-1 d-flex gap-3 justify-content-between flex-wrap\">\r\n @if (!mapLoading()&&count) {\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-low\"></div>\r\n <10\r\n </div>\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-medium\"></div>\r\n 10 - 500\r\n </div>\r\n <div class=\"d-flex align-items-center gap-1\">\r\n <div class=\"legend map-heat-high\"></div>\r\n >500\r\n </div>\r\n <div class=\"ms-auto\">\r\n {{count|adbSpacing}} {{'OBSERVATION.OBSERVATIONS'|translate}}\r\n </div>\r\n }\r\n</div>" }]
|
|
550
|
+
}], ctorParameters: () => [{ type: i3.ActivatedRoute }, { type: AdbMapConfigService }, { type: i3.Router }, { type: i3$1.HttpClient }] });
|
|
551
|
+
|
|
552
|
+
const DateTypes = {
|
|
553
|
+
THIS_YEAR: '1',
|
|
554
|
+
LAST_YEAR: '2',
|
|
555
|
+
ALL_YEAR: '3',
|
|
556
|
+
LAST_5_YEAR: '4',
|
|
557
|
+
LAST_25_YEAR: '5',
|
|
558
|
+
CUSTOM: '6',
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
class AdbMapFilters {
|
|
562
|
+
cdr;
|
|
563
|
+
config;
|
|
564
|
+
http;
|
|
565
|
+
router;
|
|
566
|
+
activatedRoute;
|
|
567
|
+
inline = false;
|
|
568
|
+
static datasets = ['1', '3', '5', '6', '4', '8'];
|
|
569
|
+
subscriptions = new Subscription();
|
|
570
|
+
form;
|
|
571
|
+
thisYear = new Date();
|
|
572
|
+
lastYear = addYears(new Date(), -1);
|
|
573
|
+
queryParamsMap;
|
|
574
|
+
hasOwnArea;
|
|
575
|
+
geo;
|
|
576
|
+
area;
|
|
577
|
+
areasArray;
|
|
578
|
+
dataSetCount;
|
|
579
|
+
taxonListCount;
|
|
580
|
+
riskListCount;
|
|
581
|
+
redListCount;
|
|
582
|
+
areaCount;
|
|
583
|
+
periodCount;
|
|
584
|
+
listsError;
|
|
585
|
+
filters;
|
|
586
|
+
taxaLists;
|
|
587
|
+
hasTaxonInUrlParameter;
|
|
588
|
+
dsControls;
|
|
589
|
+
dateStartConfig;
|
|
590
|
+
dateEndConfig;
|
|
591
|
+
artfakta;
|
|
592
|
+
constructor(cdr, config, http, router, activatedRoute) {
|
|
593
|
+
this.cdr = cdr;
|
|
594
|
+
this.config = config;
|
|
595
|
+
this.http = http;
|
|
596
|
+
this.router = router;
|
|
597
|
+
this.activatedRoute = activatedRoute;
|
|
598
|
+
this.filters = config.filters;
|
|
599
|
+
this.artfakta = this.config.artfaktaTaxonLists;
|
|
600
|
+
}
|
|
601
|
+
ngOnInit() {
|
|
602
|
+
const lists$ = this.http.get(this.config.taxaListsApi, { params: { limit: -1 } });
|
|
603
|
+
const combined$ = combineLatest([this.activatedRoute.paramMap, this.activatedRoute.queryParamMap, lists$])
|
|
604
|
+
.pipe(map(results => ({ params: results[0], qParams: results[1], lists: results[2] })), debounceTime(0));
|
|
605
|
+
this.subscriptions.add(combined$.subscribe(result => {
|
|
606
|
+
this.form = this.createForm(result.params, result.qParams, result.lists);
|
|
607
|
+
this.cdr.markForCheck();
|
|
608
|
+
}));
|
|
609
|
+
}
|
|
610
|
+
removeArea(index) {
|
|
611
|
+
this.form.get('areas').removeAt(index);
|
|
612
|
+
this.form.markAsDirty();
|
|
613
|
+
}
|
|
614
|
+
addArea() {
|
|
615
|
+
const areas = this.form.get('areas');
|
|
616
|
+
areas.push(new FormControl(null));
|
|
617
|
+
this.form.updateValueAndValidity();
|
|
618
|
+
this.form.markAsDirty();
|
|
619
|
+
}
|
|
620
|
+
onSubmit() {
|
|
621
|
+
const data = this.form.value;
|
|
622
|
+
let params = {};
|
|
623
|
+
params.p = data.period ?? null;
|
|
624
|
+
if (data.period === DateTypes.THIS_YEAR) {
|
|
625
|
+
params.startAt = startOfYear(this.thisYear).toISOString();
|
|
626
|
+
params.endAt = null;
|
|
627
|
+
}
|
|
628
|
+
else if (data.period === DateTypes.LAST_YEAR) {
|
|
629
|
+
params.startAt = startOfYear(this.lastYear).toISOString();
|
|
630
|
+
params.endAt = endOfYear(this.lastYear).toISOString();
|
|
631
|
+
}
|
|
632
|
+
else if (data.period === DateTypes.ALL_YEAR) {
|
|
633
|
+
params.startAt = null;
|
|
634
|
+
params.endAt = null;
|
|
635
|
+
params.p = null;
|
|
636
|
+
}
|
|
637
|
+
else if (data.period === DateTypes.LAST_5_YEAR) {
|
|
638
|
+
params.startAt = startOfYear(addYears(new Date(), -5)).toISOString();
|
|
639
|
+
params.endAt = null;
|
|
640
|
+
}
|
|
641
|
+
else if (data.period === DateTypes.LAST_25_YEAR) {
|
|
642
|
+
params.startAt = startOfYear(addYears(new Date(), -25)).toISOString();
|
|
643
|
+
params.endAt = null;
|
|
644
|
+
}
|
|
645
|
+
else if (data.period === DateTypes.CUSTOM) {
|
|
646
|
+
params.startAt = startOfDay(data.startAt).toISOString();
|
|
647
|
+
params.endAt = endOfDay(data.endAt).toISOString();
|
|
648
|
+
}
|
|
649
|
+
if (this.hasOwnArea && data.geo) {
|
|
650
|
+
params.geo = JSON.stringify(data.geo.geometry?.coordinates[0]);
|
|
651
|
+
}
|
|
652
|
+
const cleaned = data.areas?.filter(v => v != null && v !== '');
|
|
653
|
+
if (cleaned.length > 0) {
|
|
654
|
+
params.area = cleaned;
|
|
655
|
+
}
|
|
656
|
+
if (this.activatedRoute.snapshot.paramMap.has('taxonId')) {
|
|
657
|
+
params.taxonId = this.activatedRoute.snapshot.paramMap.get('taxonId');
|
|
658
|
+
}
|
|
659
|
+
else {
|
|
660
|
+
params.taxonId = data.taxonId ?? null;
|
|
661
|
+
}
|
|
662
|
+
if (data.list?.length > 0) {
|
|
663
|
+
params.list = data.list;
|
|
664
|
+
}
|
|
665
|
+
if (data.ds?.length > 0) {
|
|
666
|
+
const selected = data.ds.filter(f => f.selected).map(m => m.id);
|
|
667
|
+
params.ds = selected.length ? selected : null;
|
|
668
|
+
}
|
|
669
|
+
this.router.navigate([], { queryParams: params, relativeTo: this.activatedRoute });
|
|
670
|
+
}
|
|
671
|
+
createForm(params, qMap, lists) {
|
|
672
|
+
this.hasTaxonInUrlParameter = params['taxonId'];
|
|
673
|
+
this.hasOwnArea = qMap.has('geo') && this.filters.showOwnArea;
|
|
674
|
+
const areas = qMap.getAll('area').filter(a => a != null && a.trim() !== '' && a.includes('-'));
|
|
675
|
+
const form = new FormGroup({
|
|
676
|
+
period: new FormControl(qMap.has('p') ? qMap.get('p') : '3'),
|
|
677
|
+
areas: new FormArray((Array.isArray(areas) && areas.length ? areas : [null]).map(a => new FormControl(a))),
|
|
678
|
+
geo: new FormControl(qMap.has('geo') ? {
|
|
679
|
+
type: 'Feature',
|
|
680
|
+
geometry: { type: 'Polygon', coordinates: [JSON.parse(qMap.get('geo'))] }
|
|
681
|
+
} : null)
|
|
682
|
+
});
|
|
683
|
+
this.areasArray = form.get('areas');
|
|
684
|
+
this.periodCount = qMap.has('p') && qMap.get('p') !== '3' ? 1 : 0;
|
|
685
|
+
this.areaCount = areas?.length;
|
|
686
|
+
if (!this.hasTaxonInUrlParameter) {
|
|
687
|
+
form.addControl('taxonId', new FormControl(qMap.get('taxonId') ?? null));
|
|
688
|
+
const selectedTaxonList = qMap.has('list') ? qMap.getAll('list').map(val => Number(val)).filter(val => !isNaN(val)) : null;
|
|
689
|
+
this.taxaLists = lists;
|
|
690
|
+
this.taxonListCount = selectedTaxonList?.length;
|
|
691
|
+
form.addControl('list', new FormControl(selectedTaxonList));
|
|
692
|
+
let datasets = qMap.has('ds') ? (Array.isArray(qMap.getAll('ds')) ? qMap.getAll('ds') : [qMap.get('ds')]) : null;
|
|
693
|
+
this.dataSetCount = datasets?.length;
|
|
694
|
+
form.addControl('ds', new FormArray(AdbMapFilters.datasets.map(id => new FormGroup({
|
|
695
|
+
id: new FormControl(id),
|
|
696
|
+
selected: new FormControl(datasets?.includes(id))
|
|
697
|
+
}))));
|
|
698
|
+
this.dsControls = form.get('ds').controls;
|
|
699
|
+
}
|
|
700
|
+
this.updateCustomDate(form, qMap.get('p'), qMap);
|
|
701
|
+
this.subscriptions.add(form.get('period').valueChanges.subscribe(period => {
|
|
702
|
+
this.updateCustomDate(form, period, qMap);
|
|
703
|
+
}));
|
|
704
|
+
return form;
|
|
705
|
+
}
|
|
706
|
+
updateCustomDate(form, period, qMap) {
|
|
707
|
+
if (form.contains('startAt')) {
|
|
708
|
+
form.removeControl('startAt');
|
|
709
|
+
}
|
|
710
|
+
if (form.contains('endAt')) {
|
|
711
|
+
form.removeControl('endAt');
|
|
712
|
+
}
|
|
713
|
+
if (period === DateTypes.CUSTOM) {
|
|
714
|
+
let start = qMap.has('startAt') ? parseISO(qMap.get('startAt')) : null;
|
|
715
|
+
let end = qMap.has('endAt') ? parseISO(qMap.get('endAt')) : null;
|
|
716
|
+
if (qMap.get('p') !== DateTypes.CUSTOM) {
|
|
717
|
+
start = new Date();
|
|
718
|
+
end = new Date();
|
|
719
|
+
}
|
|
720
|
+
this.dateStartConfig = { maxDate: end ?? new Date() };
|
|
721
|
+
this.dateEndConfig = { minDate: start ?? null, maxDate: new Date() };
|
|
722
|
+
const startControl = new FormControl(start, Validators.required);
|
|
723
|
+
const endControl = new FormControl(end, Validators.required);
|
|
724
|
+
form.addControl('startAt', startControl);
|
|
725
|
+
form.addControl('endAt', endControl);
|
|
726
|
+
this.subscriptions.add(startControl.valueChanges.subscribe(startAt => {
|
|
727
|
+
this.dateEndConfig = { minDate: startAt ?? null, maxDate: new Date() };
|
|
728
|
+
}));
|
|
729
|
+
this.subscriptions.add(endControl.valueChanges.subscribe(endAt => {
|
|
730
|
+
this.dateStartConfig = { maxDate: endAt ?? new Date() };
|
|
731
|
+
}));
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
ngOnDestroy() {
|
|
735
|
+
this.subscriptions.unsubscribe();
|
|
736
|
+
}
|
|
737
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbMapFilters, deps: [{ token: i0.ChangeDetectorRef }, { token: AdbMapConfigService }, { token: i3$1.HttpClient }, { token: i3.Router }, { token: i3.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
|
|
738
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: AdbMapFilters, isStandalone: false, selector: "adb-map-filters", inputs: { inline: "inline" }, ngImport: i0, template: "@if(form){\r\n<form [formGroup]=\"form\" class=\"form mb-3\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"mb-3\">\r\n <adb-filter-section titleResource=\"TAXON.TAXA\" [expanded]=\"true\">\r\n @if(filters.showTaxon&&!hasTaxonInUrlParameter){\r\n <div class=\"mb-3\">\r\n <label for=\"species\">{{'TAXON.TAXON'|translate}}</label>\r\n <adb-taxon-picker formControlName=\"taxonId\" id=\"species\"></adb-taxon-picker>\r\n </div>\r\n }\r\n </adb-filter-section>\r\n @if(filters.showTime){\r\n <adb-filter-section [count]=\"periodCount\" titleResource=\"OBSERVATION.PERIOD\">\r\n <div class=\"mb-1\">\r\n <select class=\"form-select\" formControlName=\"period\" id=\"period\">\r\n <option value=\"1\">{{thisYear|date:'yyyy'}}</option>\r\n <option value=\"2\">{{lastYear|date:'yyyy'}}</option>\r\n <option value=\"3\">{{'OBSERVATION.ALL_YEAR'|translate}}</option>\r\n <option value=\"4\">{{'OBSERVATION.LAST_5_YEAR'|translate}}</option>\r\n <option value=\"5\">{{'OBSERVATION.LAST_25_YEAR'|translate}}</option>\r\n <option value=\"6\">{{'OBSERVATION.CUSTOMIZED'|translate}}</option>\r\n </select>\r\n </div>\r\n @if (form.value?.period==='6') {\r\n <div class=\"mb-2\">\r\n <label for=\"startAt\">{{'FROM' |translate}}</label>\r\n <input adbDatepicker type=\"text\" class=\"form-control datepicker\" id=\"startAt\" formControlName=\"startAt\" [settings]=\"dateStartConfig\">\r\n </div>\r\n <div class=\"mb-2\">\r\n <label for=\"endAt\">{{'TO' |translate}}</label>\r\n <input adbDatepicker type=\"text\" class=\"form-control datepicker\" id=\"endAt\" formControlName=\"endAt\" [settings]=\"dateEndConfig\">\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n @if(filters.showArea){\r\n <adb-filter-section [count]=\"areaCount\" titleResource=\"GEOGRAPHY\" [lazy]=\"true\">\r\n <ng-template>\r\n @if(filters.showOwnArea){\r\n <div role=\"tablist\" aria-label=\"{{'AREA'|translate}}\" class=\"d-flex gap-2 justify-content-end\">\r\n <button class=\"btn btn-link p-0\" [class.text-dark]=\"!hasOwnArea\" (click)=\"hasOwnArea=false\" role=\"tab\" id=\"tab-select\" aria-selected=\"{{!hasOwnArea}}\" aria-controls=\"panel-select\">\r\n {{'CHOOSE'|translate}}\r\n </button>\r\n <button class=\"btn btn-link p-0\" [class.text-dark]=\"hasOwnArea\" (click)=\"hasOwnArea=true\" role=\"tab\" id=\"tab-draw\" aria-selected=\"false\" aria-controls=\"panel-draw\">\r\n {{'OWN_AREA'|translate}}\r\n </button>\r\n </div>\r\n }\r\n <div class=\"mb-2\">\r\n @if(hasOwnArea&&filters.showOwnArea){\r\n <div class=\"pt-1\" role=\"tabpanel\" id=\"area-draw\" aria-labelledby=\"tab-draw\">\r\n <div>\r\n <adb-polygon-drawer formControlName=\"geo\"></adb-polygon-drawer>\r\n </div>\r\n </div>\r\n }@else{\r\n <div role=\"tabpanel\" id=\"area-select\" aria-labelledby=\"tab-select\">\r\n <div formArrayName=\"areas\">\r\n <div class=\"d-flex align-items-end mb-1\">\r\n <label>{{'AREAS'|translate}}</label>\r\n <button class=\"ms-auto text-dark btn btn-sm btn-secondary\" attr.aria-label=\"{{'OBSERVATION.ADD_AREA'|translate}}\" title=\"{{'OBSERVATION.ADD_AREA'|translate}}\" type=\"button\" (click)=\"addArea()\">\r\n <span class=\"fas fa-plus\"></span>\r\n </button>\r\n </div>\r\n @for (ctrl of areasArray.controls; track ctrl; let i = $index; let last = $last) {\r\n <div class=\"d-flex mb-2\">\r\n <adb-area-picker id=\"area-{{i}}\" [formControlName]=\"i\"></adb-area-picker>\r\n @if(areasArray.length>1){\r\n <button class=\"btn btn-secondary ms-1\" attr.aria-label=\"{{'DELETE'|translate}}\" title=\"{{'DELETE'|translate}}\" type=\"button\" (click)=\"removeArea(i)\">\r\n <span class=\"fas fa-trash\"></span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </adb-filter-section>\r\n }\r\n @if(form.get('taxonId')){\r\n @if(filters.showTaxaLists){\r\n <adb-filter-section [count]=\"taxonListCount\" titleResource=\"LISTS.NATURE_CONSERVATION_LISTS\">\r\n <div class=\"mb-3\">\r\n <app-treeview formControlName=\"list\" [nodes]=\"taxaLists\"></app-treeview>\r\n </div>\r\n {{'LISTS.READ_MORE'|translate}}\r\n <a [href]=\"artfakta\">{{'LISTS.LIST_CONTENT'|translate}}</a>\r\n </adb-filter-section>\r\n }\r\n @if(filters.showDatasets){\r\n <adb-filter-section [count]=\"dataSetCount\" titleResource=\"DATASET.DATASETS\">\r\n @if (form.get('ds')) {\r\n <div formArrayName=\"ds\">\r\n @for (item of dsControls; track item; let i = $index) {\r\n <div [formGroupName]=\"i\" class=\"form-check\">\r\n <input type=\"checkbox\" formControlName=\"selected\" [id]=\"'ds-' + item.value.id\" class=\"form-check-input\">\r\n <label [for]=\"'ds-' + item.value.id\" class=\"form-check-label\">{{ 'PROVIDERS.'+item.value.id |translate }}</label>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n }\r\n </div>\r\n <div class=\"d-flex justify-content-end gap-2\">\r\n @if (inline) {\r\n <a class=\"btn btn-secondary\" [routerLink]=\"[]\">\r\n {{'CANCEL'|translate}}\r\n </a>\r\n }\r\n <button type=\"submit\" class=\"btn btn-primary\" [disabled]=\"form.invalid||form.pristine\">{{'FILTER'|translate}}</button>\r\n </div>\r\n</form>\r\n}", dependencies: [{ kind: "directive", type: i4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i4.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i4.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: i4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i4.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i4.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i4.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: i5.AdbDatePickerDirective, selector: "input[adbDatepicker]", inputs: ["format", "toLeft", "settings"], outputs: ["adbBlur"] }, { kind: "component", type: i5.FilterSectionComponent, selector: "adb-filter-section", inputs: ["titleResource", "helpResource", "count", "expanded", "lazy"] }, { kind: "component", type: i5.AdbAreaPickerComponent, selector: "adb-area-picker", inputs: ["placeholder", "useObject", "prefill"] }, { kind: "component", type: i5.AdbTaxonPickerComponent, selector: "adb-taxon-picker", inputs: ["placeholder", "useObject", "prefill"] }, { kind: "component", type: PolygonDrawerInput, selector: "adb-polygon-drawer" }, { kind: "component", type: TreeviewComponent, selector: "app-treeview", inputs: ["nodes"] }, { kind: "pipe", type: i1$1.DatePipe, name: "date" }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] });
|
|
739
|
+
}
|
|
740
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbMapFilters, decorators: [{
|
|
741
|
+
type: Component,
|
|
742
|
+
args: [{ selector: 'adb-map-filters', standalone: false, template: "@if(form){\r\n<form [formGroup]=\"form\" class=\"form mb-3\" (ngSubmit)=\"onSubmit()\">\r\n <div class=\"mb-3\">\r\n <adb-filter-section titleResource=\"TAXON.TAXA\" [expanded]=\"true\">\r\n @if(filters.showTaxon&&!hasTaxonInUrlParameter){\r\n <div class=\"mb-3\">\r\n <label for=\"species\">{{'TAXON.TAXON'|translate}}</label>\r\n <adb-taxon-picker formControlName=\"taxonId\" id=\"species\"></adb-taxon-picker>\r\n </div>\r\n }\r\n </adb-filter-section>\r\n @if(filters.showTime){\r\n <adb-filter-section [count]=\"periodCount\" titleResource=\"OBSERVATION.PERIOD\">\r\n <div class=\"mb-1\">\r\n <select class=\"form-select\" formControlName=\"period\" id=\"period\">\r\n <option value=\"1\">{{thisYear|date:'yyyy'}}</option>\r\n <option value=\"2\">{{lastYear|date:'yyyy'}}</option>\r\n <option value=\"3\">{{'OBSERVATION.ALL_YEAR'|translate}}</option>\r\n <option value=\"4\">{{'OBSERVATION.LAST_5_YEAR'|translate}}</option>\r\n <option value=\"5\">{{'OBSERVATION.LAST_25_YEAR'|translate}}</option>\r\n <option value=\"6\">{{'OBSERVATION.CUSTOMIZED'|translate}}</option>\r\n </select>\r\n </div>\r\n @if (form.value?.period==='6') {\r\n <div class=\"mb-2\">\r\n <label for=\"startAt\">{{'FROM' |translate}}</label>\r\n <input adbDatepicker type=\"text\" class=\"form-control datepicker\" id=\"startAt\" formControlName=\"startAt\" [settings]=\"dateStartConfig\">\r\n </div>\r\n <div class=\"mb-2\">\r\n <label for=\"endAt\">{{'TO' |translate}}</label>\r\n <input adbDatepicker type=\"text\" class=\"form-control datepicker\" id=\"endAt\" formControlName=\"endAt\" [settings]=\"dateEndConfig\">\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n @if(filters.showArea){\r\n <adb-filter-section [count]=\"areaCount\" titleResource=\"GEOGRAPHY\" [lazy]=\"true\">\r\n <ng-template>\r\n @if(filters.showOwnArea){\r\n <div role=\"tablist\" aria-label=\"{{'AREA'|translate}}\" class=\"d-flex gap-2 justify-content-end\">\r\n <button class=\"btn btn-link p-0\" [class.text-dark]=\"!hasOwnArea\" (click)=\"hasOwnArea=false\" role=\"tab\" id=\"tab-select\" aria-selected=\"{{!hasOwnArea}}\" aria-controls=\"panel-select\">\r\n {{'CHOOSE'|translate}}\r\n </button>\r\n <button class=\"btn btn-link p-0\" [class.text-dark]=\"hasOwnArea\" (click)=\"hasOwnArea=true\" role=\"tab\" id=\"tab-draw\" aria-selected=\"false\" aria-controls=\"panel-draw\">\r\n {{'OWN_AREA'|translate}}\r\n </button>\r\n </div>\r\n }\r\n <div class=\"mb-2\">\r\n @if(hasOwnArea&&filters.showOwnArea){\r\n <div class=\"pt-1\" role=\"tabpanel\" id=\"area-draw\" aria-labelledby=\"tab-draw\">\r\n <div>\r\n <adb-polygon-drawer formControlName=\"geo\"></adb-polygon-drawer>\r\n </div>\r\n </div>\r\n }@else{\r\n <div role=\"tabpanel\" id=\"area-select\" aria-labelledby=\"tab-select\">\r\n <div formArrayName=\"areas\">\r\n <div class=\"d-flex align-items-end mb-1\">\r\n <label>{{'AREAS'|translate}}</label>\r\n <button class=\"ms-auto text-dark btn btn-sm btn-secondary\" attr.aria-label=\"{{'OBSERVATION.ADD_AREA'|translate}}\" title=\"{{'OBSERVATION.ADD_AREA'|translate}}\" type=\"button\" (click)=\"addArea()\">\r\n <span class=\"fas fa-plus\"></span>\r\n </button>\r\n </div>\r\n @for (ctrl of areasArray.controls; track ctrl; let i = $index; let last = $last) {\r\n <div class=\"d-flex mb-2\">\r\n <adb-area-picker id=\"area-{{i}}\" [formControlName]=\"i\"></adb-area-picker>\r\n @if(areasArray.length>1){\r\n <button class=\"btn btn-secondary ms-1\" attr.aria-label=\"{{'DELETE'|translate}}\" title=\"{{'DELETE'|translate}}\" type=\"button\" (click)=\"removeArea(i)\">\r\n <span class=\"fas fa-trash\"></span>\r\n </button>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </ng-template>\r\n </adb-filter-section>\r\n }\r\n @if(form.get('taxonId')){\r\n @if(filters.showTaxaLists){\r\n <adb-filter-section [count]=\"taxonListCount\" titleResource=\"LISTS.NATURE_CONSERVATION_LISTS\">\r\n <div class=\"mb-3\">\r\n <app-treeview formControlName=\"list\" [nodes]=\"taxaLists\"></app-treeview>\r\n </div>\r\n {{'LISTS.READ_MORE'|translate}}\r\n <a [href]=\"artfakta\">{{'LISTS.LIST_CONTENT'|translate}}</a>\r\n </adb-filter-section>\r\n }\r\n @if(filters.showDatasets){\r\n <adb-filter-section [count]=\"dataSetCount\" titleResource=\"DATASET.DATASETS\">\r\n @if (form.get('ds')) {\r\n <div formArrayName=\"ds\">\r\n @for (item of dsControls; track item; let i = $index) {\r\n <div [formGroupName]=\"i\" class=\"form-check\">\r\n <input type=\"checkbox\" formControlName=\"selected\" [id]=\"'ds-' + item.value.id\" class=\"form-check-input\">\r\n <label [for]=\"'ds-' + item.value.id\" class=\"form-check-label\">{{ 'PROVIDERS.'+item.value.id |translate }}</label>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </adb-filter-section>\r\n }\r\n }\r\n </div>\r\n <div class=\"d-flex justify-content-end gap-2\">\r\n @if (inline) {\r\n <a class=\"btn btn-secondary\" [routerLink]=\"[]\">\r\n {{'CANCEL'|translate}}\r\n </a>\r\n }\r\n <button type=\"submit\" class=\"btn btn-primary\" [disabled]=\"form.invalid||form.pristine\">{{'FILTER'|translate}}</button>\r\n </div>\r\n</form>\r\n}" }]
|
|
743
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: AdbMapConfigService }, { type: i3$1.HttpClient }, { type: i3.Router }, { type: i3.ActivatedRoute }], propDecorators: { inline: [{
|
|
744
|
+
type: Input
|
|
745
|
+
}] } });
|
|
746
|
+
|
|
747
|
+
class AdbMapModule {
|
|
748
|
+
static forRoot(config) {
|
|
749
|
+
return {
|
|
750
|
+
ngModule: AdbMapModule,
|
|
751
|
+
providers: [
|
|
752
|
+
{
|
|
753
|
+
provide: ADB_MAP_CONFIG,
|
|
754
|
+
useValue: config
|
|
755
|
+
}
|
|
756
|
+
]
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbMapModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
760
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.0", ngImport: i0, type: AdbMapModule, declarations: [AdbObsMapComponent,
|
|
761
|
+
PolygonDrawerInput,
|
|
762
|
+
AdbMapFilters,
|
|
763
|
+
TreeviewComponent], imports: [CommonModule,
|
|
764
|
+
FormsModule,
|
|
765
|
+
RouterModule,
|
|
766
|
+
ReactiveFormsModule,
|
|
767
|
+
AdbDatePickerModule, i1.TranslateModule, AdbPipesModule,
|
|
768
|
+
AdbFilterSectionModule,
|
|
769
|
+
AdbPickerModule], exports: [AdbObsMapComponent,
|
|
770
|
+
PolygonDrawerInput,
|
|
771
|
+
AdbMapFilters] });
|
|
772
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbMapModule, providers: [
|
|
773
|
+
AdbMapConfigService
|
|
774
|
+
], imports: [CommonModule,
|
|
775
|
+
FormsModule,
|
|
776
|
+
RouterModule,
|
|
777
|
+
ReactiveFormsModule,
|
|
778
|
+
AdbDatePickerModule,
|
|
779
|
+
TranslateModule.forChild(),
|
|
780
|
+
AdbPipesModule,
|
|
781
|
+
AdbFilterSectionModule,
|
|
782
|
+
AdbPickerModule] });
|
|
783
|
+
}
|
|
784
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AdbMapModule, decorators: [{
|
|
785
|
+
type: NgModule,
|
|
786
|
+
args: [{
|
|
787
|
+
imports: [
|
|
788
|
+
CommonModule,
|
|
789
|
+
FormsModule,
|
|
790
|
+
RouterModule,
|
|
791
|
+
ReactiveFormsModule,
|
|
792
|
+
AdbDatePickerModule,
|
|
793
|
+
TranslateModule.forChild(),
|
|
794
|
+
AdbPipesModule,
|
|
795
|
+
AdbFilterSectionModule,
|
|
796
|
+
AdbPickerModule
|
|
797
|
+
],
|
|
798
|
+
declarations: [
|
|
799
|
+
AdbObsMapComponent,
|
|
800
|
+
PolygonDrawerInput,
|
|
801
|
+
AdbMapFilters,
|
|
802
|
+
TreeviewComponent,
|
|
803
|
+
// Stats,
|
|
804
|
+
// AdbGeojsonPolygonDirective
|
|
805
|
+
],
|
|
806
|
+
exports: [
|
|
807
|
+
AdbObsMapComponent,
|
|
808
|
+
PolygonDrawerInput,
|
|
809
|
+
AdbMapFilters,
|
|
810
|
+
// Stats,
|
|
811
|
+
// AdbGeojsonPolygonDirective
|
|
812
|
+
],
|
|
813
|
+
providers: [
|
|
814
|
+
AdbMapConfigService
|
|
815
|
+
]
|
|
816
|
+
}]
|
|
817
|
+
}] });
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Generated bundle index. Do not edit.
|
|
821
|
+
*/
|
|
822
|
+
|
|
823
|
+
export { ADB_MAP_CONFIG, AdbMapConfigService, AdbMapFilterType, AdbMapFilters, AdbMapModule, AdbMapUtils, AdbObsMapComponent, PolygonDrawerInput, VisibleFilters };
|
|
824
|
+
//# sourceMappingURL=adb-shared-src-map.mjs.map
|