@angular-helpers/openlayers 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -6
- package/fesm2022/angular-helpers-openlayers-controls.mjs +289 -36
- package/fesm2022/angular-helpers-openlayers-core.mjs +215 -16
- package/fesm2022/angular-helpers-openlayers-interactions.mjs +426 -23
- package/fesm2022/angular-helpers-openlayers-layers.mjs +717 -38
- package/fesm2022/angular-helpers-openlayers-military.mjs +329 -12
- package/fesm2022/angular-helpers-openlayers-overlays.mjs +11 -10
- package/package.json +6 -2
- package/types/angular-helpers-openlayers-controls.d.ts +24 -4
- package/types/angular-helpers-openlayers-core.d.ts +143 -4
- package/types/angular-helpers-openlayers-interactions.d.ts +127 -23
- package/types/angular-helpers-openlayers-layers.d.ts +194 -35
- package/types/angular-helpers-openlayers-military.d.ts +160 -16
|
@@ -1,21 +1,39 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, computed, Injectable,
|
|
2
|
+
import { inject, signal, computed, Injectable, input, ChangeDetectionStrategy, Component, DestroyRef, contentChild, afterNextRender, effect } from '@angular/core';
|
|
3
3
|
import VectorLayer from 'ol/layer/Vector';
|
|
4
|
+
import HeatmapLayer from 'ol/layer/Heatmap';
|
|
4
5
|
import TileLayer from 'ol/layer/Tile';
|
|
5
6
|
import ImageLayer from 'ol/layer/Image';
|
|
6
7
|
import VectorSource from 'ol/source/Vector';
|
|
7
|
-
import
|
|
8
|
+
import OLFeature from 'ol/Feature';
|
|
8
9
|
import { Point, LineString, Polygon, Circle } from 'ol/geom';
|
|
9
10
|
import { fromLonLat } from 'ol/proj';
|
|
10
|
-
import {
|
|
11
|
+
import { getCenter } from 'ol/extent';
|
|
12
|
+
import { Style, Circle as Circle$1, Stroke, Fill, Icon } from 'ol/style';
|
|
13
|
+
import Text from 'ol/style/Text';
|
|
14
|
+
import ClusterSource from 'ol/source/Cluster';
|
|
11
15
|
import OSM from 'ol/source/OSM';
|
|
12
16
|
import XYZ from 'ol/source/XYZ';
|
|
13
17
|
import TileWMS from 'ol/source/TileWMS';
|
|
14
18
|
import ImageWMS from 'ol/source/ImageWMS';
|
|
15
19
|
import ImageStatic from 'ol/source/ImageStatic';
|
|
20
|
+
import GeoJSON from 'ol/format/GeoJSON';
|
|
21
|
+
import TopoJSON from 'ol/format/TopoJSON';
|
|
22
|
+
import KML from 'ol/format/KML';
|
|
16
23
|
import { OlMapService } from '@angular-helpers/openlayers/core';
|
|
24
|
+
import WebGLVectorLayer from 'ol/layer/WebGLVector';
|
|
25
|
+
import WebGLTileLayer from 'ol/layer/WebGLTile';
|
|
26
|
+
import WebGLVectorTileLayer from 'ol/layer/WebGLVectorTile';
|
|
27
|
+
import VectorTileSource from 'ol/source/VectorTile';
|
|
28
|
+
import MVT from 'ol/format/MVT';
|
|
17
29
|
|
|
18
30
|
// OlLayerService
|
|
31
|
+
/**
|
|
32
|
+
* Internal property key used to stash the abstract style metadata on the
|
|
33
|
+
* underlying `ol/Feature` so the layer style function can resolve a
|
|
34
|
+
* per-feature visual without colliding with user `properties`.
|
|
35
|
+
*/
|
|
36
|
+
const STYLE_PROP = '__angular_helpers_style__';
|
|
19
37
|
class OlLayerService {
|
|
20
38
|
mapService = inject(OlMapService);
|
|
21
39
|
layerCache = new Map();
|
|
@@ -49,6 +67,8 @@ class OlLayerService {
|
|
|
49
67
|
switch (config.type) {
|
|
50
68
|
case 'vector':
|
|
51
69
|
return this.createVectorLayer(config, map);
|
|
70
|
+
case 'heatmap':
|
|
71
|
+
return this.createHeatmapLayer(config, map);
|
|
52
72
|
case 'tile':
|
|
53
73
|
return this.createTileLayer(config, map);
|
|
54
74
|
case 'image':
|
|
@@ -84,6 +104,12 @@ class OlLayerService {
|
|
|
84
104
|
layer.setVisible(visible);
|
|
85
105
|
this.updateLayerState();
|
|
86
106
|
}
|
|
107
|
+
else {
|
|
108
|
+
const pending = this.pendingConfigs.find((c) => c.id === id);
|
|
109
|
+
if (pending) {
|
|
110
|
+
pending.visible = visible;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
87
113
|
}
|
|
88
114
|
toggleVisibility(id) {
|
|
89
115
|
const layer = this.layerCache.get(id);
|
|
@@ -101,6 +127,12 @@ class OlLayerService {
|
|
|
101
127
|
layer.setOpacity(opacity);
|
|
102
128
|
this.updateLayerState();
|
|
103
129
|
}
|
|
130
|
+
else {
|
|
131
|
+
const pending = this.pendingConfigs.find((c) => c.id === id);
|
|
132
|
+
if (pending) {
|
|
133
|
+
pending.opacity = opacity;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
104
136
|
}
|
|
105
137
|
setZIndex(id, zIndex) {
|
|
106
138
|
const layer = this.layerCache.get(id);
|
|
@@ -108,6 +140,35 @@ class OlLayerService {
|
|
|
108
140
|
layer.setZIndex(zIndex);
|
|
109
141
|
this.updateLayerState();
|
|
110
142
|
}
|
|
143
|
+
else {
|
|
144
|
+
const pending = this.pendingConfigs.find((c) => c.id === id);
|
|
145
|
+
if (pending) {
|
|
146
|
+
pending.zIndex = zIndex;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
setHeatmapProperties(id, props) {
|
|
151
|
+
const layer = this.layerCache.get(id);
|
|
152
|
+
if (layer instanceof HeatmapLayer) {
|
|
153
|
+
if (props.blur !== undefined)
|
|
154
|
+
layer.setBlur(props.blur);
|
|
155
|
+
if (props.radius !== undefined)
|
|
156
|
+
layer.setRadius(props.radius);
|
|
157
|
+
if (props.weight !== undefined)
|
|
158
|
+
layer.setWeight(props.weight);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const pending = this.pendingConfigs.find((c) => c.id === id);
|
|
162
|
+
if (pending && pending.type === 'heatmap') {
|
|
163
|
+
const heatmapConfig = pending;
|
|
164
|
+
if (props.blur !== undefined)
|
|
165
|
+
heatmapConfig.blur = props.blur;
|
|
166
|
+
if (props.radius !== undefined)
|
|
167
|
+
heatmapConfig.radius = props.radius;
|
|
168
|
+
if (props.weight !== undefined)
|
|
169
|
+
heatmapConfig.weight = props.weight;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
111
172
|
}
|
|
112
173
|
isVisible(id) {
|
|
113
174
|
return this.layerCache.get(id)?.getVisible() ?? false;
|
|
@@ -127,7 +188,15 @@ class OlLayerService {
|
|
|
127
188
|
const layer = this.layerCache.get(id);
|
|
128
189
|
if (!(layer instanceof VectorLayer))
|
|
129
190
|
return;
|
|
130
|
-
layer.getSource()
|
|
191
|
+
const source = layer.getSource();
|
|
192
|
+
if (!source)
|
|
193
|
+
return;
|
|
194
|
+
// Handle Cluster source: clear the underlying VectorSource
|
|
195
|
+
const clusterSource = source;
|
|
196
|
+
const vectorSource = clusterSource.getSource
|
|
197
|
+
? clusterSource.getSource()
|
|
198
|
+
: source;
|
|
199
|
+
vectorSource?.clear();
|
|
131
200
|
}
|
|
132
201
|
/**
|
|
133
202
|
* Updates the features of a vector layer.
|
|
@@ -142,19 +211,34 @@ class OlLayerService {
|
|
|
142
211
|
const source = layer.getSource();
|
|
143
212
|
if (!source)
|
|
144
213
|
return;
|
|
145
|
-
//
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
214
|
+
// Handle Cluster source: get the underlying VectorSource
|
|
215
|
+
const clusterSource = source;
|
|
216
|
+
const vectorSource = clusterSource.getSource
|
|
217
|
+
? clusterSource.getSource()
|
|
218
|
+
: source;
|
|
219
|
+
if (!(vectorSource instanceof VectorSource))
|
|
220
|
+
return;
|
|
221
|
+
// Sync features: remove old ones, update existing ones, add new ones
|
|
222
|
+
if (features) {
|
|
223
|
+
const newFeatureIds = new Set(features.map((f) => f.id));
|
|
224
|
+
const sourceFeatures = vectorSource.getFeatures();
|
|
225
|
+
// 1. Remove features that are no longer in the input
|
|
226
|
+
sourceFeatures.forEach((f) => {
|
|
227
|
+
const id = f.getId();
|
|
228
|
+
if (id !== undefined && !newFeatureIds.has(id)) {
|
|
229
|
+
vectorSource.removeFeature(f);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
// 2. Only add features that don't already exist in the source
|
|
233
|
+
const existingIds = new Set(vectorSource
|
|
234
|
+
.getFeatures()
|
|
235
|
+
.map((f) => f.getId())
|
|
236
|
+
.filter((id) => id !== undefined));
|
|
237
|
+
const featuresToAdd = features.filter((f) => !existingIds.has(f.id));
|
|
238
|
+
if (featuresToAdd.length > 0) {
|
|
239
|
+
const olFeatures = featuresToAdd.map((feature) => {
|
|
155
240
|
const geom = feature.geometry;
|
|
156
241
|
let geometry;
|
|
157
|
-
// Validate coordinates exist before processing
|
|
158
242
|
if (!geom.coordinates) {
|
|
159
243
|
geometry = new Point([0, 0]);
|
|
160
244
|
}
|
|
@@ -172,27 +256,35 @@ class OlLayerService {
|
|
|
172
256
|
}
|
|
173
257
|
else if (geom.type === 'Circle') {
|
|
174
258
|
const center = fromLonLat(geom.coordinates);
|
|
175
|
-
// Approximate radius in meters - use 1000m as default if not specified
|
|
176
259
|
geometry = new Circle(center, geom.radius ?? 1000);
|
|
177
260
|
}
|
|
178
261
|
else {
|
|
179
262
|
geometry = new Point([0, 0]);
|
|
180
263
|
}
|
|
181
|
-
const olFeature = new
|
|
264
|
+
const olFeature = new OLFeature({
|
|
182
265
|
geometry,
|
|
183
266
|
...feature.properties,
|
|
184
267
|
});
|
|
268
|
+
if (feature.style) {
|
|
269
|
+
olFeature.set(STYLE_PROP, feature.style);
|
|
270
|
+
}
|
|
185
271
|
olFeature.setId(feature.id);
|
|
186
272
|
return olFeature;
|
|
187
273
|
});
|
|
188
|
-
|
|
274
|
+
vectorSource.addFeatures(olFeatures);
|
|
189
275
|
}
|
|
190
276
|
}
|
|
191
277
|
}
|
|
192
278
|
updateLayerState() {
|
|
193
279
|
const layers = [];
|
|
194
280
|
this.layerCache.forEach((layer, id) => {
|
|
195
|
-
|
|
281
|
+
let type = 'vector';
|
|
282
|
+
if (layer instanceof HeatmapLayer)
|
|
283
|
+
type = 'heatmap';
|
|
284
|
+
else if (layer instanceof TileLayer)
|
|
285
|
+
type = 'tile';
|
|
286
|
+
else if (layer instanceof ImageLayer)
|
|
287
|
+
type = 'image';
|
|
196
288
|
layers.push({
|
|
197
289
|
id,
|
|
198
290
|
type: type,
|
|
@@ -204,7 +296,17 @@ class OlLayerService {
|
|
|
204
296
|
this.layerState.set(layers.sort((a, b) => a.zIndex - b.zIndex));
|
|
205
297
|
}
|
|
206
298
|
createVectorLayer(config, map) {
|
|
207
|
-
const
|
|
299
|
+
const sourceOptions = {};
|
|
300
|
+
if (config.url && config.format) {
|
|
301
|
+
sourceOptions.url = config.url;
|
|
302
|
+
if (config.format === 'geojson')
|
|
303
|
+
sourceOptions.format = new GeoJSON();
|
|
304
|
+
else if (config.format === 'topojson')
|
|
305
|
+
sourceOptions.format = new TopoJSON();
|
|
306
|
+
else if (config.format === 'kml')
|
|
307
|
+
sourceOptions.format = new KML();
|
|
308
|
+
}
|
|
309
|
+
const vectorSource = new VectorSource(sourceOptions);
|
|
208
310
|
// Add features if provided
|
|
209
311
|
if (config.features && config.features.length > 0) {
|
|
210
312
|
const olFeatures = config.features.map((feature) => {
|
|
@@ -234,15 +336,40 @@ class OlLayerService {
|
|
|
234
336
|
else {
|
|
235
337
|
geometry = new Point([0, 0]);
|
|
236
338
|
}
|
|
237
|
-
const olFeature = new
|
|
339
|
+
const olFeature = new OLFeature({
|
|
238
340
|
geometry,
|
|
239
341
|
...feature.properties,
|
|
240
342
|
});
|
|
343
|
+
if (feature.style) {
|
|
344
|
+
olFeature.set(STYLE_PROP, feature.style);
|
|
345
|
+
}
|
|
241
346
|
olFeature.setId(feature.id);
|
|
242
347
|
return olFeature;
|
|
243
348
|
});
|
|
244
|
-
|
|
349
|
+
vectorSource.addFeatures(olFeatures);
|
|
245
350
|
}
|
|
351
|
+
// Wrap in cluster source if enabled
|
|
352
|
+
const clusterCfg = config.cluster;
|
|
353
|
+
const source = clusterCfg?.enabled
|
|
354
|
+
? new ClusterSource({
|
|
355
|
+
source: vectorSource,
|
|
356
|
+
distance: clusterCfg.distance ?? 40,
|
|
357
|
+
minDistance: clusterCfg.minDistance ?? 20,
|
|
358
|
+
geometryFunction: (feature) => {
|
|
359
|
+
const geometry = feature.getGeometry();
|
|
360
|
+
if (!geometry)
|
|
361
|
+
return null;
|
|
362
|
+
// For Point geometries, use as-is
|
|
363
|
+
if (geometry.getType() === 'Point') {
|
|
364
|
+
return geometry;
|
|
365
|
+
}
|
|
366
|
+
// For other geometries (Polygon, Circle, etc.), use center point
|
|
367
|
+
const extent = geometry.getExtent();
|
|
368
|
+
const center = getCenter(extent);
|
|
369
|
+
return new Point(center);
|
|
370
|
+
},
|
|
371
|
+
})
|
|
372
|
+
: vectorSource;
|
|
246
373
|
// Default style for all geometry types (points, lines, polygons)
|
|
247
374
|
const defaultStyle = new Style({
|
|
248
375
|
fill: new Fill({ color: 'rgba(25, 118, 210, 0.3)' }),
|
|
@@ -253,12 +380,139 @@ class OlLayerService {
|
|
|
253
380
|
stroke: new Stroke({ color: '#d32f2f', width: 2 }),
|
|
254
381
|
}),
|
|
255
382
|
});
|
|
383
|
+
// Resolved style: priority to stashed metadata, then config-level style, then default.
|
|
384
|
+
const userStyle = config.style;
|
|
385
|
+
const styleFn = (olFeature, resolution) => {
|
|
386
|
+
// 1. Per-feature style metadata (stashed via STYLE_PROP)
|
|
387
|
+
const abstractStyle = olFeature.get(STYLE_PROP);
|
|
388
|
+
if (abstractStyle) {
|
|
389
|
+
const style = new Style();
|
|
390
|
+
const { icon, fill, stroke } = abstractStyle;
|
|
391
|
+
if (icon?.src) {
|
|
392
|
+
style.setImage(new Icon({
|
|
393
|
+
src: icon.src,
|
|
394
|
+
...(icon.size ? { size: icon.size } : {}),
|
|
395
|
+
...(icon.anchor ? { anchor: icon.anchor } : {}),
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
if (fill) {
|
|
399
|
+
style.setFill(new Fill({ color: fill.color }));
|
|
400
|
+
}
|
|
401
|
+
if (stroke) {
|
|
402
|
+
style.setStroke(new Stroke({ color: stroke.color, width: stroke.width }));
|
|
403
|
+
}
|
|
404
|
+
if (icon?.src || fill || stroke)
|
|
405
|
+
return style;
|
|
406
|
+
}
|
|
407
|
+
// 2. Layer-level style from config (supports functions or static styles)
|
|
408
|
+
if (userStyle) {
|
|
409
|
+
if (typeof userStyle === 'function') {
|
|
410
|
+
// Check if it's already an OL native feature or wrap if needed
|
|
411
|
+
// For simplicity in the demo, we pass the feature as-is or mapped
|
|
412
|
+
const feature = {
|
|
413
|
+
id: String(olFeature.getId() ?? ''),
|
|
414
|
+
geometry: {
|
|
415
|
+
type: olFeature.getGeometry()?.getType(),
|
|
416
|
+
coordinates: [], // coordinates not easily reversible without extra work
|
|
417
|
+
},
|
|
418
|
+
properties: olFeature.getProperties(),
|
|
419
|
+
};
|
|
420
|
+
return userStyle(feature, resolution);
|
|
421
|
+
}
|
|
422
|
+
return userStyle;
|
|
423
|
+
}
|
|
424
|
+
return defaultStyle;
|
|
425
|
+
};
|
|
426
|
+
// Cluster style: shows count badge when features are clustered, else delegates to styleFn
|
|
427
|
+
const clusterStyleFn = (olFeature, resolution) => {
|
|
428
|
+
const features = olFeature.get('features');
|
|
429
|
+
const size = features?.length ?? 1;
|
|
430
|
+
if (size > 1) {
|
|
431
|
+
const showCount = clusterCfg?.showCount ?? true;
|
|
432
|
+
return new Style({
|
|
433
|
+
image: new Circle$1({
|
|
434
|
+
radius: 15 + Math.min(size * 2, 15),
|
|
435
|
+
fill: new Fill({ color: 'rgba(255, 100, 100, 0.8)' }),
|
|
436
|
+
stroke: new Stroke({ color: '#fff', width: 2 }),
|
|
437
|
+
}),
|
|
438
|
+
text: showCount
|
|
439
|
+
? new Text({
|
|
440
|
+
text: String(size),
|
|
441
|
+
fill: new Fill({ color: '#fff' }),
|
|
442
|
+
})
|
|
443
|
+
: undefined,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
// Single feature in cluster: unwrap and call styleFn
|
|
447
|
+
const originalFeature = features?.[0];
|
|
448
|
+
if (originalFeature) {
|
|
449
|
+
// We MUST preserve the original geometry if it's a non-point ( spiderfication etc)
|
|
450
|
+
const style = styleFn(originalFeature, resolution);
|
|
451
|
+
if (style instanceof Style) {
|
|
452
|
+
const origGeom = originalFeature.getGeometry();
|
|
453
|
+
if (origGeom)
|
|
454
|
+
style.setGeometry(origGeom);
|
|
455
|
+
}
|
|
456
|
+
return style;
|
|
457
|
+
}
|
|
458
|
+
return styleFn(olFeature, resolution);
|
|
459
|
+
};
|
|
256
460
|
const layer = new VectorLayer({
|
|
257
461
|
source,
|
|
258
462
|
visible: config.visible ?? true,
|
|
259
463
|
opacity: config.opacity ?? 1,
|
|
260
464
|
zIndex: config.zIndex,
|
|
261
|
-
style:
|
|
465
|
+
style: clusterCfg?.enabled ? clusterStyleFn : styleFn,
|
|
466
|
+
});
|
|
467
|
+
layer.set('id', config.id);
|
|
468
|
+
map.addLayer(layer);
|
|
469
|
+
this.layerCache.set(config.id, layer);
|
|
470
|
+
this.updateLayerState();
|
|
471
|
+
return { id: config.id };
|
|
472
|
+
}
|
|
473
|
+
createHeatmapLayer(config, map) {
|
|
474
|
+
const vectorSource = new VectorSource();
|
|
475
|
+
if (config.features && config.features.length > 0) {
|
|
476
|
+
const olFeatures = config.features.map((feature) => {
|
|
477
|
+
const geom = feature.geometry;
|
|
478
|
+
let geometry;
|
|
479
|
+
if (!geom.coordinates) {
|
|
480
|
+
geometry = new Point([0, 0]);
|
|
481
|
+
}
|
|
482
|
+
else if (geom.type === 'Point') {
|
|
483
|
+
const coords = geom.coordinates;
|
|
484
|
+
geometry = new Point(fromLonLat(coords));
|
|
485
|
+
}
|
|
486
|
+
else if (geom.type === 'LineString') {
|
|
487
|
+
const coords = geom.coordinates.map((c) => fromLonLat(c));
|
|
488
|
+
geometry = new LineString(coords);
|
|
489
|
+
}
|
|
490
|
+
else if (geom.type === 'Polygon') {
|
|
491
|
+
const rings = geom.coordinates.map((ring) => ring.map((c) => fromLonLat(c)));
|
|
492
|
+
geometry = new Polygon(rings);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
geometry = new Point([0, 0]);
|
|
496
|
+
}
|
|
497
|
+
const olFeature = new OLFeature({
|
|
498
|
+
geometry,
|
|
499
|
+
...feature.properties,
|
|
500
|
+
});
|
|
501
|
+
olFeature.setId(feature.id);
|
|
502
|
+
return olFeature;
|
|
503
|
+
});
|
|
504
|
+
vectorSource.addFeatures(olFeatures);
|
|
505
|
+
}
|
|
506
|
+
const layer = new HeatmapLayer({
|
|
507
|
+
source: vectorSource,
|
|
508
|
+
visible: config.visible ?? true,
|
|
509
|
+
opacity: config.opacity ?? 1,
|
|
510
|
+
zIndex: config.zIndex,
|
|
511
|
+
...(config.blur !== undefined && { blur: config.blur }),
|
|
512
|
+
...(config.radius !== undefined && { radius: config.radius }),
|
|
513
|
+
...(config.weight !== undefined && {
|
|
514
|
+
weight: config.weight,
|
|
515
|
+
}),
|
|
262
516
|
});
|
|
263
517
|
layer.set('id', config.id);
|
|
264
518
|
map.addLayer(layer);
|
|
@@ -278,7 +532,7 @@ class OlLayerService {
|
|
|
278
532
|
case 'wms':
|
|
279
533
|
source = new TileWMS({
|
|
280
534
|
url: config.source.url,
|
|
281
|
-
params: config.source.params,
|
|
535
|
+
params: config.source.params ?? {},
|
|
282
536
|
attributions: config.source.attributions,
|
|
283
537
|
});
|
|
284
538
|
break;
|
|
@@ -320,34 +574,69 @@ class OlLayerService {
|
|
|
320
574
|
this.updateLayerState();
|
|
321
575
|
return { id: config.id };
|
|
322
576
|
}
|
|
323
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
324
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
577
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlLayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
578
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlLayerService });
|
|
325
579
|
}
|
|
326
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
580
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlLayerService, decorators: [{
|
|
327
581
|
type: Injectable
|
|
328
582
|
}] });
|
|
329
583
|
|
|
584
|
+
class OlClusterComponent {
|
|
585
|
+
distance = input(40, ...(ngDevMode ? [{ debugName: "distance" }] : /* istanbul ignore next */ []));
|
|
586
|
+
minDistance = input(20, ...(ngDevMode ? [{ debugName: "minDistance" }] : /* istanbul ignore next */ []));
|
|
587
|
+
showCount = input(true, ...(ngDevMode ? [{ debugName: "showCount" }] : /* istanbul ignore next */ []));
|
|
588
|
+
featureStyle = input(...(ngDevMode ? [undefined, { debugName: "featureStyle" }] : /* istanbul ignore next */ []));
|
|
589
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlClusterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
590
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlClusterComponent, isStandalone: true, selector: "ol-cluster", inputs: { distance: { classPropertyName: "distance", publicName: "distance", isSignal: true, isRequired: false, transformFunction: null }, minDistance: { classPropertyName: "minDistance", publicName: "minDistance", isSignal: true, isRequired: false, transformFunction: null }, showCount: { classPropertyName: "showCount", publicName: "showCount", isSignal: true, isRequired: false, transformFunction: null }, featureStyle: { classPropertyName: "featureStyle", publicName: "featureStyle", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
591
|
+
}
|
|
592
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlClusterComponent, decorators: [{
|
|
593
|
+
type: Component,
|
|
594
|
+
args: [{
|
|
595
|
+
selector: 'ol-cluster',
|
|
596
|
+
template: '',
|
|
597
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
598
|
+
}]
|
|
599
|
+
}], propDecorators: { distance: [{ type: i0.Input, args: [{ isSignal: true, alias: "distance", required: false }] }], minDistance: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDistance", required: false }] }], showCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCount", required: false }] }], featureStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "featureStyle", required: false }] }] } });
|
|
600
|
+
|
|
330
601
|
// OlVectorLayerComponent
|
|
331
602
|
class OlVectorLayerComponent {
|
|
332
603
|
layerService = inject(OlLayerService);
|
|
333
604
|
destroyRef = inject(DestroyRef);
|
|
334
605
|
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
335
606
|
features = input([], ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
|
|
607
|
+
url = input(...(ngDevMode ? [undefined, { debugName: "url" }] : /* istanbul ignore next */ []));
|
|
608
|
+
format = input(...(ngDevMode ? [undefined, { debugName: "format" }] : /* istanbul ignore next */ []));
|
|
336
609
|
zIndex = input(0, ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
|
|
337
610
|
opacity = input(1, ...(ngDevMode ? [{ debugName: "opacity" }] : /* istanbul ignore next */ []));
|
|
338
611
|
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
339
612
|
style = input(...(ngDevMode ? [undefined, { debugName: "style" }] : /* istanbul ignore next */ []));
|
|
613
|
+
cluster = input(...(ngDevMode ? [undefined, { debugName: "cluster" }] : /* istanbul ignore next */ []));
|
|
614
|
+
clusterComponent = contentChild(OlClusterComponent, ...(ngDevMode ? [{ debugName: "clusterComponent" }] : /* istanbul ignore next */ []));
|
|
340
615
|
constructor() {
|
|
341
616
|
// Initialize layer after DOM is ready
|
|
342
617
|
afterNextRender(() => {
|
|
618
|
+
const clusterCmp = this.clusterComponent();
|
|
619
|
+
const resolvedClusterConfig = this.cluster() ??
|
|
620
|
+
(clusterCmp
|
|
621
|
+
? {
|
|
622
|
+
enabled: true,
|
|
623
|
+
distance: clusterCmp.distance(),
|
|
624
|
+
minDistance: clusterCmp.minDistance(),
|
|
625
|
+
showCount: clusterCmp.showCount(),
|
|
626
|
+
featureStyle: clusterCmp.featureStyle(),
|
|
627
|
+
}
|
|
628
|
+
: undefined);
|
|
343
629
|
this.layerService.addLayer({
|
|
344
630
|
id: this.id(),
|
|
345
631
|
type: 'vector',
|
|
346
632
|
features: this.features(),
|
|
633
|
+
url: this.url(),
|
|
634
|
+
format: this.format(),
|
|
347
635
|
zIndex: this.zIndex(),
|
|
348
636
|
opacity: this.opacity(),
|
|
349
637
|
visible: this.visible(),
|
|
350
638
|
style: this.style(),
|
|
639
|
+
cluster: resolvedClusterConfig,
|
|
351
640
|
});
|
|
352
641
|
});
|
|
353
642
|
// Effect to sync features when input changes
|
|
@@ -358,22 +647,31 @@ class OlVectorLayerComponent {
|
|
|
358
647
|
this.layerService.updateFeatures(this.id(), currentFeatures);
|
|
359
648
|
}
|
|
360
649
|
});
|
|
650
|
+
effect(() => {
|
|
651
|
+
this.layerService.setOpacity(this.id(), this.opacity());
|
|
652
|
+
});
|
|
653
|
+
effect(() => {
|
|
654
|
+
this.layerService.setVisibility(this.id(), this.visible());
|
|
655
|
+
});
|
|
656
|
+
effect(() => {
|
|
657
|
+
this.layerService.setZIndex(this.id(), this.zIndex());
|
|
658
|
+
});
|
|
361
659
|
// Cleanup when component is destroyed
|
|
362
660
|
this.destroyRef.onDestroy(() => {
|
|
363
661
|
this.layerService.removeLayer(this.id());
|
|
364
662
|
});
|
|
365
663
|
}
|
|
366
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
367
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
664
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlVectorLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
665
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.13", type: OlVectorLayerComponent, isStandalone: true, selector: "ol-vector-layer", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, features: { classPropertyName: "features", publicName: "features", isSignal: true, isRequired: false, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: false, transformFunction: null }, cluster: { classPropertyName: "cluster", publicName: "cluster", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "clusterComponent", first: true, predicate: OlClusterComponent, descendants: true, isSignal: true }], ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
368
666
|
}
|
|
369
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
667
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlVectorLayerComponent, decorators: [{
|
|
370
668
|
type: Component,
|
|
371
669
|
args: [{
|
|
372
670
|
selector: 'ol-vector-layer',
|
|
373
671
|
template: '',
|
|
374
672
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
375
673
|
}]
|
|
376
|
-
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], features: [{ type: i0.Input, args: [{ isSignal: true, alias: "features", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], opacity: [{ type: i0.Input, args: [{ isSignal: true, alias: "opacity", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], style: [{ type: i0.Input, args: [{ isSignal: true, alias: "style", required: false }] }] } });
|
|
674
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], features: [{ type: i0.Input, args: [{ isSignal: true, alias: "features", required: false }] }], url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], opacity: [{ type: i0.Input, args: [{ isSignal: true, alias: "opacity", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], style: [{ type: i0.Input, args: [{ isSignal: true, alias: "style", required: false }] }], cluster: [{ type: i0.Input, args: [{ isSignal: true, alias: "cluster", required: false }] }], clusterComponent: [{ type: i0.ContentChild, args: [i0.forwardRef(() => OlClusterComponent), { isSignal: true }] }] } });
|
|
377
675
|
|
|
378
676
|
// OlTileLayerComponent
|
|
379
677
|
class OlTileLayerComponent {
|
|
@@ -404,15 +702,24 @@ class OlTileLayerComponent {
|
|
|
404
702
|
visible: this.visible(),
|
|
405
703
|
});
|
|
406
704
|
});
|
|
705
|
+
effect(() => {
|
|
706
|
+
this.layerService.setOpacity(this.id(), this.opacity());
|
|
707
|
+
});
|
|
708
|
+
effect(() => {
|
|
709
|
+
this.layerService.setVisibility(this.id(), this.visible());
|
|
710
|
+
});
|
|
711
|
+
effect(() => {
|
|
712
|
+
this.layerService.setZIndex(this.id(), this.zIndex());
|
|
713
|
+
});
|
|
407
714
|
// Cleanup when component is destroyed
|
|
408
715
|
this.destroyRef.onDestroy(() => {
|
|
409
716
|
this.layerService.removeLayer(this.id());
|
|
410
717
|
});
|
|
411
718
|
}
|
|
412
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
413
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
719
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTileLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
720
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlTileLayerComponent, isStandalone: true, selector: "ol-tile-layer", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: true, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, attributions: { classPropertyName: "attributions", publicName: "attributions", isSignal: true, isRequired: false, transformFunction: null }, params: { classPropertyName: "params", publicName: "params", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
414
721
|
}
|
|
415
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
722
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTileLayerComponent, decorators: [{
|
|
416
723
|
type: Component,
|
|
417
724
|
args: [{
|
|
418
725
|
selector: 'ol-tile-layer',
|
|
@@ -455,10 +762,10 @@ class OlImageLayerComponent {
|
|
|
455
762
|
this.layerService.removeLayer(this.id());
|
|
456
763
|
});
|
|
457
764
|
}
|
|
458
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
459
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
765
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlImageLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
766
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlImageLayerComponent, isStandalone: true, selector: "ol-image-layer", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, sourceType: { classPropertyName: "sourceType", publicName: "sourceType", isSignal: true, isRequired: true, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, params: { classPropertyName: "params", publicName: "params", isSignal: true, isRequired: false, transformFunction: null }, imageExtent: { classPropertyName: "imageExtent", publicName: "imageExtent", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
460
767
|
}
|
|
461
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
768
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlImageLayerComponent, decorators: [{
|
|
462
769
|
type: Component,
|
|
463
770
|
args: [{
|
|
464
771
|
selector: 'ol-image-layer',
|
|
@@ -467,6 +774,378 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
467
774
|
}]
|
|
468
775
|
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], sourceType: [{ type: i0.Input, args: [{ isSignal: true, alias: "sourceType", required: true }] }], url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: true }] }], params: [{ type: i0.Input, args: [{ isSignal: true, alias: "params", required: false }] }], imageExtent: [{ type: i0.Input, args: [{ isSignal: true, alias: "imageExtent", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], opacity: [{ type: i0.Input, args: [{ isSignal: true, alias: "opacity", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }] } });
|
|
469
776
|
|
|
777
|
+
class OlHeatmapLayerComponent {
|
|
778
|
+
layerService = inject(OlLayerService);
|
|
779
|
+
mapService = inject(OlMapService);
|
|
780
|
+
destroyRef = inject(DestroyRef);
|
|
781
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
782
|
+
features = input([], ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
|
|
783
|
+
zIndex = input(0, ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
|
|
784
|
+
opacity = input(1, ...(ngDevMode ? [{ debugName: "opacity" }] : /* istanbul ignore next */ []));
|
|
785
|
+
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
786
|
+
blur = input(15, ...(ngDevMode ? [{ debugName: "blur" }] : /* istanbul ignore next */ []));
|
|
787
|
+
radius = input(8, ...(ngDevMode ? [{ debugName: "radius" }] : /* istanbul ignore next */ []));
|
|
788
|
+
/** Unit for radius and blur: 'pixels' (default) or 'meters' */
|
|
789
|
+
radiusUnit = input('pixels', ...(ngDevMode ? [{ debugName: "radiusUnit" }] : /* istanbul ignore next */ []));
|
|
790
|
+
weight = input(...(ngDevMode ? [undefined, { debugName: "weight" }] : /* istanbul ignore next */ []));
|
|
791
|
+
/** Computed radius in pixels based on current resolution if unit is 'meters' */
|
|
792
|
+
scaledRadius = computed(() => {
|
|
793
|
+
const r = this.radius();
|
|
794
|
+
if (this.radiusUnit() === 'pixels')
|
|
795
|
+
return r;
|
|
796
|
+
return r / this.mapService.resolution();
|
|
797
|
+
}, ...(ngDevMode ? [{ debugName: "scaledRadius" }] : /* istanbul ignore next */ []));
|
|
798
|
+
/** Computed blur in pixels based on current resolution if unit is 'meters' */
|
|
799
|
+
scaledBlur = computed(() => {
|
|
800
|
+
const b = this.blur();
|
|
801
|
+
if (this.radiusUnit() === 'pixels')
|
|
802
|
+
return b;
|
|
803
|
+
return b / this.mapService.resolution();
|
|
804
|
+
}, ...(ngDevMode ? [{ debugName: "scaledBlur" }] : /* istanbul ignore next */ []));
|
|
805
|
+
constructor() {
|
|
806
|
+
afterNextRender(() => {
|
|
807
|
+
this.layerService.addLayer({
|
|
808
|
+
id: this.id(),
|
|
809
|
+
type: 'heatmap',
|
|
810
|
+
features: this.features(),
|
|
811
|
+
zIndex: this.zIndex(),
|
|
812
|
+
opacity: this.opacity(),
|
|
813
|
+
visible: this.visible(),
|
|
814
|
+
blur: this.scaledBlur(),
|
|
815
|
+
radius: this.scaledRadius(),
|
|
816
|
+
weight: this.weight(),
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
effect(() => {
|
|
820
|
+
const currentFeatures = this.features();
|
|
821
|
+
if (this.layerService.getLayer(this.id())) {
|
|
822
|
+
this.layerService.updateFeatures(this.id(), currentFeatures);
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
effect(() => {
|
|
826
|
+
this.layerService.setOpacity(this.id(), this.opacity());
|
|
827
|
+
});
|
|
828
|
+
effect(() => {
|
|
829
|
+
this.layerService.setVisibility(this.id(), this.visible());
|
|
830
|
+
});
|
|
831
|
+
effect(() => {
|
|
832
|
+
this.layerService.setZIndex(this.id(), this.zIndex());
|
|
833
|
+
});
|
|
834
|
+
effect(() => {
|
|
835
|
+
this.layerService.setHeatmapProperties(this.id(), {
|
|
836
|
+
blur: this.scaledBlur(),
|
|
837
|
+
radius: this.scaledRadius(),
|
|
838
|
+
weight: this.weight(),
|
|
839
|
+
});
|
|
840
|
+
});
|
|
841
|
+
this.destroyRef.onDestroy(() => {
|
|
842
|
+
this.layerService.removeLayer(this.id());
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlHeatmapLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
846
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlHeatmapLayerComponent, isStandalone: true, selector: "ol-heatmap-layer", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, features: { classPropertyName: "features", publicName: "features", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, blur: { classPropertyName: "blur", publicName: "blur", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, radiusUnit: { classPropertyName: "radiusUnit", publicName: "radiusUnit", isSignal: true, isRequired: false, transformFunction: null }, weight: { classPropertyName: "weight", publicName: "weight", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
847
|
+
}
|
|
848
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlHeatmapLayerComponent, decorators: [{
|
|
849
|
+
type: Component,
|
|
850
|
+
args: [{
|
|
851
|
+
selector: 'ol-heatmap-layer',
|
|
852
|
+
template: '',
|
|
853
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
854
|
+
}]
|
|
855
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], features: [{ type: i0.Input, args: [{ isSignal: true, alias: "features", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], opacity: [{ type: i0.Input, args: [{ isSignal: true, alias: "opacity", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], blur: [{ type: i0.Input, args: [{ isSignal: true, alias: "blur", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], radiusUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "radiusUnit", required: false }] }], weight: [{ type: i0.Input, args: [{ isSignal: true, alias: "weight", required: false }] }] } });
|
|
856
|
+
|
|
857
|
+
// OlWebGLVectorLayerComponent
|
|
858
|
+
// GPU-accelerated vector layer for large datasets (10k+ features).
|
|
859
|
+
// Uses FlatStyleLike instead of ol/style/Style. Must be manually disposed.
|
|
860
|
+
/**
|
|
861
|
+
* GPU-accelerated vector layer for rendering large datasets.
|
|
862
|
+
*
|
|
863
|
+
* Important: Uses WebGL 2 for rendering. Styles must be provided as
|
|
864
|
+
* `FlatStyleLike` objects (not `ol/style/Style` instances).
|
|
865
|
+
* Hit detection is disabled by default for performance.
|
|
866
|
+
*
|
|
867
|
+
* @usageNotes
|
|
868
|
+
* ```html
|
|
869
|
+
* <ol-webgl-vector-layer
|
|
870
|
+
* id="big-dataset"
|
|
871
|
+
* [features]="largeDataset()"
|
|
872
|
+
* [flatStyle]="{
|
|
873
|
+
* 'circle-radius': 6,
|
|
874
|
+
* 'circle-fill-color': ['match', ['get', 'type'], 'alert', 'red', 'blue'],
|
|
875
|
+
* 'stroke-color': '#333',
|
|
876
|
+
* 'stroke-width': 1
|
|
877
|
+
* }"
|
|
878
|
+
* [disableHitDetection]="true">
|
|
879
|
+
* </ol-webgl-vector-layer>
|
|
880
|
+
* ```
|
|
881
|
+
*/
|
|
882
|
+
class OlWebGLVectorLayerComponent {
|
|
883
|
+
mapService = inject(OlMapService);
|
|
884
|
+
destroyRef = inject(DestroyRef);
|
|
885
|
+
/** Unique layer identifier */
|
|
886
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
887
|
+
/** Features to render */
|
|
888
|
+
features = input([], ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
|
|
889
|
+
/** WebGL flat style (required — no default provided) */
|
|
890
|
+
flatStyle = input.required(...(ngDevMode ? [{ debugName: "flatStyle" }] : /* istanbul ignore next */ []));
|
|
891
|
+
/** Z-index for layer ordering */
|
|
892
|
+
zIndex = input(0, ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
|
|
893
|
+
/** Opacity (0–1) */
|
|
894
|
+
opacity = input(1, ...(ngDevMode ? [{ debugName: "opacity" }] : /* istanbul ignore next */ []));
|
|
895
|
+
/** Layer visibility */
|
|
896
|
+
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
897
|
+
/** Disable hit detection for better performance (default: true) */
|
|
898
|
+
disableHitDetection = input(true, ...(ngDevMode ? [{ debugName: "disableHitDetection" }] : /* istanbul ignore next */ []));
|
|
899
|
+
/** Style variables for dynamic expressions (e.g. `['var', 'threshold']`) */
|
|
900
|
+
variables = input(...(ngDevMode ? [undefined, { debugName: "variables" }] : /* istanbul ignore next */ []));
|
|
901
|
+
layer = null;
|
|
902
|
+
vectorSource = new VectorSource();
|
|
903
|
+
constructor() {
|
|
904
|
+
afterNextRender(() => {
|
|
905
|
+
const map = this.mapService.getMap();
|
|
906
|
+
if (!map)
|
|
907
|
+
return;
|
|
908
|
+
this.syncFeatures(this.features());
|
|
909
|
+
try {
|
|
910
|
+
this.layer = new WebGLVectorLayer({
|
|
911
|
+
source: this.vectorSource,
|
|
912
|
+
style: this.flatStyle(),
|
|
913
|
+
visible: this.visible(),
|
|
914
|
+
opacity: this.opacity(),
|
|
915
|
+
zIndex: this.zIndex(),
|
|
916
|
+
disableHitDetection: this.disableHitDetection(),
|
|
917
|
+
...(this.variables() ? { variables: this.variables() } : {}),
|
|
918
|
+
});
|
|
919
|
+
this.layer.set('id', this.id());
|
|
920
|
+
map.addLayer(this.layer);
|
|
921
|
+
}
|
|
922
|
+
catch (err) {
|
|
923
|
+
// WebGL Vector Layer failed to initialize (e.g., not supported by browser)
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
// Reactive feature sync
|
|
927
|
+
effect(() => {
|
|
928
|
+
const currentFeatures = this.features();
|
|
929
|
+
if (this.layer) {
|
|
930
|
+
this.syncFeatures(currentFeatures);
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
// Reactive style updates
|
|
934
|
+
effect(() => {
|
|
935
|
+
this.layer?.setStyle(this.flatStyle());
|
|
936
|
+
});
|
|
937
|
+
effect(() => {
|
|
938
|
+
this.layer?.setOpacity(this.opacity());
|
|
939
|
+
});
|
|
940
|
+
effect(() => {
|
|
941
|
+
this.layer?.setVisible(this.visible());
|
|
942
|
+
});
|
|
943
|
+
effect(() => {
|
|
944
|
+
this.layer?.setZIndex(this.zIndex());
|
|
945
|
+
});
|
|
946
|
+
effect(() => {
|
|
947
|
+
const vars = this.variables();
|
|
948
|
+
if (vars && this.layer) {
|
|
949
|
+
this.layer.updateStyleVariables(vars);
|
|
950
|
+
}
|
|
951
|
+
});
|
|
952
|
+
// CRITICAL: WebGL layers must be manually disposed
|
|
953
|
+
this.destroyRef.onDestroy(() => {
|
|
954
|
+
const map = this.mapService.getMap();
|
|
955
|
+
if (map && this.layer) {
|
|
956
|
+
map.removeLayer(this.layer);
|
|
957
|
+
try {
|
|
958
|
+
this.layer.dispose();
|
|
959
|
+
}
|
|
960
|
+
catch {
|
|
961
|
+
// Ignore WebGL layer disposal errors (e.g., reading 'deleteBuffer' if renderer not fully initialized)
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
syncFeatures(features) {
|
|
967
|
+
this.vectorSource.clear();
|
|
968
|
+
if (!features?.length)
|
|
969
|
+
return;
|
|
970
|
+
const olFeatures = features.map((feature) => {
|
|
971
|
+
const geom = feature.geometry;
|
|
972
|
+
let geometry;
|
|
973
|
+
if (!geom.coordinates) {
|
|
974
|
+
geometry = new Point([0, 0]);
|
|
975
|
+
}
|
|
976
|
+
else if (geom.type === 'Point') {
|
|
977
|
+
geometry = new Point(fromLonLat(geom.coordinates));
|
|
978
|
+
}
|
|
979
|
+
else if (geom.type === 'LineString') {
|
|
980
|
+
geometry = new LineString(geom.coordinates.map((c) => fromLonLat(c)));
|
|
981
|
+
}
|
|
982
|
+
else if (geom.type === 'Polygon') {
|
|
983
|
+
geometry = new Polygon(geom.coordinates.map((ring) => ring.map((c) => fromLonLat(c))));
|
|
984
|
+
}
|
|
985
|
+
else if (geom.type === 'Circle') {
|
|
986
|
+
const center = fromLonLat(geom.coordinates);
|
|
987
|
+
geometry = new Circle(center, geom.radius ?? 1000);
|
|
988
|
+
}
|
|
989
|
+
else {
|
|
990
|
+
geometry = new Point([0, 0]);
|
|
991
|
+
}
|
|
992
|
+
const olFeature = new OLFeature({
|
|
993
|
+
geometry,
|
|
994
|
+
...feature.properties,
|
|
995
|
+
});
|
|
996
|
+
olFeature.setId(feature.id);
|
|
997
|
+
return olFeature;
|
|
998
|
+
});
|
|
999
|
+
this.vectorSource.addFeatures(olFeatures);
|
|
1000
|
+
}
|
|
1001
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlWebGLVectorLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1002
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlWebGLVectorLayerComponent, isStandalone: true, selector: "ol-webgl-vector-layer", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, features: { classPropertyName: "features", publicName: "features", isSignal: true, isRequired: false, transformFunction: null }, flatStyle: { classPropertyName: "flatStyle", publicName: "flatStyle", isSignal: true, isRequired: true, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, disableHitDetection: { classPropertyName: "disableHitDetection", publicName: "disableHitDetection", isSignal: true, isRequired: false, transformFunction: null }, variables: { classPropertyName: "variables", publicName: "variables", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1003
|
+
}
|
|
1004
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlWebGLVectorLayerComponent, decorators: [{
|
|
1005
|
+
type: Component,
|
|
1006
|
+
args: [{
|
|
1007
|
+
selector: 'ol-webgl-vector-layer',
|
|
1008
|
+
template: '',
|
|
1009
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1010
|
+
}]
|
|
1011
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], features: [{ type: i0.Input, args: [{ isSignal: true, alias: "features", required: false }] }], flatStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "flatStyle", required: true }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], opacity: [{ type: i0.Input, args: [{ isSignal: true, alias: "opacity", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], disableHitDetection: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableHitDetection", required: false }] }], variables: [{ type: i0.Input, args: [{ isSignal: true, alias: "variables", required: false }] }] } });
|
|
1012
|
+
|
|
1013
|
+
// OlWebGLTileLayerComponent
|
|
1014
|
+
// GPU-accelerated tile layer with style expressions for color manipulation.
|
|
1015
|
+
/**
|
|
1016
|
+
* GPU-accelerated tile layer with color/brightness/contrast expressions.
|
|
1017
|
+
*
|
|
1018
|
+
* Supports the same tile sources as `ol-tile-layer` but renders via WebGL,
|
|
1019
|
+
* enabling GPU-powered color manipulation (brightness, contrast, saturation, gamma).
|
|
1020
|
+
*
|
|
1021
|
+
* @usageNotes
|
|
1022
|
+
* ```html
|
|
1023
|
+
* <ol-webgl-tile-layer
|
|
1024
|
+
* id="satellite-webgl"
|
|
1025
|
+
* source="xyz"
|
|
1026
|
+
* [url]="'https://server.arcgisonline.com/.../{z}/{y}/{x}'"
|
|
1027
|
+
* [tileStyle]="{ brightness: 0.1, contrast: 0.2 }">
|
|
1028
|
+
* </ol-webgl-tile-layer>
|
|
1029
|
+
* ```
|
|
1030
|
+
*/
|
|
1031
|
+
class OlWebGLTileLayerComponent {
|
|
1032
|
+
mapService = inject(OlMapService);
|
|
1033
|
+
destroyRef = inject(DestroyRef);
|
|
1034
|
+
/** Unique layer identifier */
|
|
1035
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
1036
|
+
/** Tile source type */
|
|
1037
|
+
source = input.required(...(ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []));
|
|
1038
|
+
/** Tile URL template (required for 'xyz' and 'mvt') */
|
|
1039
|
+
url = input(...(ngDevMode ? [undefined, { debugName: "url" }] : /* istanbul ignore next */ []));
|
|
1040
|
+
/** Attribution text */
|
|
1041
|
+
attributions = input(...(ngDevMode ? [undefined, { debugName: "attributions" }] : /* istanbul ignore next */ []));
|
|
1042
|
+
/** WebGL tile style (raster expressions) or flat style (MVT) */
|
|
1043
|
+
tileStyle = input(...(ngDevMode ? [undefined, { debugName: "tileStyle" }] : /* istanbul ignore next */ []));
|
|
1044
|
+
/** Z-index for layer ordering */
|
|
1045
|
+
zIndex = input(0, ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
|
|
1046
|
+
/** Opacity (0–1) */
|
|
1047
|
+
opacity = input(1, ...(ngDevMode ? [{ debugName: "opacity" }] : /* istanbul ignore next */ []));
|
|
1048
|
+
/** Layer visibility */
|
|
1049
|
+
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
1050
|
+
/** Preload low-res tiles up to this many zoom levels */
|
|
1051
|
+
preload = input(0, ...(ngDevMode ? [{ debugName: "preload" }] : /* istanbul ignore next */ []));
|
|
1052
|
+
layer = null;
|
|
1053
|
+
constructor() {
|
|
1054
|
+
afterNextRender(() => {
|
|
1055
|
+
const map = this.mapService.getMap();
|
|
1056
|
+
if (!map)
|
|
1057
|
+
return;
|
|
1058
|
+
let tileSource;
|
|
1059
|
+
switch (this.source()) {
|
|
1060
|
+
case 'mvt':
|
|
1061
|
+
tileSource = new VectorTileSource({
|
|
1062
|
+
format: new MVT(),
|
|
1063
|
+
url: this.url(),
|
|
1064
|
+
attributions: this.attributions(),
|
|
1065
|
+
});
|
|
1066
|
+
this.layer = new WebGLVectorTileLayer({
|
|
1067
|
+
source: tileSource,
|
|
1068
|
+
visible: this.visible(),
|
|
1069
|
+
opacity: this.opacity(),
|
|
1070
|
+
zIndex: this.zIndex(),
|
|
1071
|
+
style: this.tileStyle() || {},
|
|
1072
|
+
});
|
|
1073
|
+
break;
|
|
1074
|
+
case 'xyz':
|
|
1075
|
+
tileSource = new XYZ({
|
|
1076
|
+
url: this.url(),
|
|
1077
|
+
attributions: this.attributions(),
|
|
1078
|
+
});
|
|
1079
|
+
this.layer = new WebGLTileLayer({
|
|
1080
|
+
source: tileSource,
|
|
1081
|
+
visible: this.visible(),
|
|
1082
|
+
opacity: this.opacity(),
|
|
1083
|
+
zIndex: this.zIndex(),
|
|
1084
|
+
preload: this.preload(),
|
|
1085
|
+
...(this.tileStyle() ? { style: this.tileStyle() } : {}),
|
|
1086
|
+
});
|
|
1087
|
+
break;
|
|
1088
|
+
case 'osm':
|
|
1089
|
+
default:
|
|
1090
|
+
tileSource = new OSM({
|
|
1091
|
+
attributions: this.attributions(),
|
|
1092
|
+
});
|
|
1093
|
+
this.layer = new WebGLTileLayer({
|
|
1094
|
+
source: tileSource,
|
|
1095
|
+
visible: this.visible(),
|
|
1096
|
+
opacity: this.opacity(),
|
|
1097
|
+
zIndex: this.zIndex(),
|
|
1098
|
+
preload: this.preload(),
|
|
1099
|
+
...(this.tileStyle() ? { style: this.tileStyle() } : {}),
|
|
1100
|
+
});
|
|
1101
|
+
break;
|
|
1102
|
+
}
|
|
1103
|
+
if (this.layer) {
|
|
1104
|
+
this.layer.set('id', this.id());
|
|
1105
|
+
map.addLayer(this.layer);
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
effect(() => {
|
|
1109
|
+
this.layer?.setOpacity(this.opacity());
|
|
1110
|
+
});
|
|
1111
|
+
effect(() => {
|
|
1112
|
+
this.layer?.setVisible(this.visible());
|
|
1113
|
+
});
|
|
1114
|
+
effect(() => {
|
|
1115
|
+
this.layer?.setZIndex(this.zIndex());
|
|
1116
|
+
});
|
|
1117
|
+
effect(() => {
|
|
1118
|
+
const style = this.tileStyle();
|
|
1119
|
+
if (style && this.layer) {
|
|
1120
|
+
if (this.source() === 'mvt') {
|
|
1121
|
+
this.layer.setStyle(style);
|
|
1122
|
+
}
|
|
1123
|
+
else {
|
|
1124
|
+
this.layer.setStyle(style);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
// WebGL tile layers also need manual dispose
|
|
1129
|
+
this.destroyRef.onDestroy(() => {
|
|
1130
|
+
const map = this.mapService.getMap();
|
|
1131
|
+
if (map && this.layer) {
|
|
1132
|
+
map.removeLayer(this.layer);
|
|
1133
|
+
this.layer.dispose();
|
|
1134
|
+
}
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlWebGLTileLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1138
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.13", type: OlWebGLTileLayerComponent, isStandalone: true, selector: "ol-webgl-tile-layer", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: true, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, attributions: { classPropertyName: "attributions", publicName: "attributions", isSignal: true, isRequired: false, transformFunction: null }, tileStyle: { classPropertyName: "tileStyle", publicName: "tileStyle", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: false, transformFunction: null }, preload: { classPropertyName: "preload", publicName: "preload", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1139
|
+
}
|
|
1140
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlWebGLTileLayerComponent, decorators: [{
|
|
1141
|
+
type: Component,
|
|
1142
|
+
args: [{
|
|
1143
|
+
selector: 'ol-webgl-tile-layer',
|
|
1144
|
+
template: '',
|
|
1145
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1146
|
+
}]
|
|
1147
|
+
}], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: true }] }], source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: true }] }], url: [{ type: i0.Input, args: [{ isSignal: true, alias: "url", required: false }] }], attributions: [{ type: i0.Input, args: [{ isSignal: true, alias: "attributions", required: false }] }], tileStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "tileStyle", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], opacity: [{ type: i0.Input, args: [{ isSignal: true, alias: "opacity", required: false }] }], visible: [{ type: i0.Input, args: [{ isSignal: true, alias: "visible", required: false }] }], preload: [{ type: i0.Input, args: [{ isSignal: true, alias: "preload", required: false }] }] } });
|
|
1148
|
+
|
|
470
1149
|
// Provider functions
|
|
471
1150
|
function withLayers() {
|
|
472
1151
|
return { kind: 'layers', providers: [OlLayerService] };
|
|
@@ -481,4 +1160,4 @@ function provideLayers() {
|
|
|
481
1160
|
* Generated bundle index. Do not edit.
|
|
482
1161
|
*/
|
|
483
1162
|
|
|
484
|
-
export { OlImageLayerComponent, OlLayerService, OlTileLayerComponent, OlVectorLayerComponent, provideLayers, withLayers };
|
|
1163
|
+
export { OlClusterComponent, OlHeatmapLayerComponent, OlImageLayerComponent, OlLayerService, OlTileLayerComponent, OlVectorLayerComponent, OlWebGLTileLayerComponent, OlWebGLVectorLayerComponent, provideLayers, withLayers };
|