@angular-helpers/openlayers 0.4.0 → 0.5.1
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 +131 -38
- package/core/README.md +43 -0
- package/fesm2022/angular-helpers-openlayers-controls.mjs +289 -36
- package/fesm2022/angular-helpers-openlayers-core.mjs +410 -16
- package/fesm2022/angular-helpers-openlayers-interactions.mjs +529 -71
- package/fesm2022/angular-helpers-openlayers-layers.mjs +947 -311
- package/fesm2022/angular-helpers-openlayers-military.mjs +244 -144
- package/fesm2022/angular-helpers-openlayers-overlays.mjs +35 -11
- package/package.json +2 -2
- package/types/angular-helpers-openlayers-controls.d.ts +24 -4
- package/types/angular-helpers-openlayers-core.d.ts +197 -6
- package/types/angular-helpers-openlayers-interactions.d.ts +125 -31
- package/types/angular-helpers-openlayers-layers.d.ts +166 -21
- package/types/angular-helpers-openlayers-military.d.ts +84 -94
|
@@ -1,35 +1,357 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, computed, Injectable,
|
|
2
|
+
import { inject, signal, computed, Injectable, input, output, 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 OLFeature from 'ol/Feature';
|
|
8
|
-
import { Point, LineString, Polygon, Circle } from 'ol/geom';
|
|
9
|
-
import { fromLonLat } from 'ol/proj';
|
|
10
|
-
import { getCenter } from 'ol/extent';
|
|
11
|
-
import { Style, Circle as Circle$1, Stroke, Fill, Icon } from 'ol/style';
|
|
12
|
-
import Text from 'ol/style/Text';
|
|
13
8
|
import ClusterSource from 'ol/source/Cluster';
|
|
9
|
+
import GeoJSON from 'ol/format/GeoJSON';
|
|
10
|
+
import TopoJSON from 'ol/format/TopoJSON';
|
|
11
|
+
import KML from 'ol/format/KML';
|
|
12
|
+
import { getCenter } from 'ol/extent';
|
|
13
|
+
import { Point, LineString, Polygon, Circle as Circle$1 } from 'ol/geom';
|
|
14
|
+
import { featureToOlFeature, olFeatureToFeature, OlMapService } from '@angular-helpers/openlayers/core';
|
|
14
15
|
import OSM from 'ol/source/OSM';
|
|
15
16
|
import XYZ from 'ol/source/XYZ';
|
|
16
17
|
import TileWMS from 'ol/source/TileWMS';
|
|
17
18
|
import ImageWMS from 'ol/source/ImageWMS';
|
|
18
19
|
import ImageStatic from 'ol/source/ImageStatic';
|
|
19
|
-
import {
|
|
20
|
+
import { Style, Text, Fill, Circle, Stroke, Icon } from 'ol/style';
|
|
21
|
+
import OLFeature from 'ol/Feature';
|
|
22
|
+
import { fromLonLat } from 'ol/proj';
|
|
23
|
+
import WebGLVectorLayer from 'ol/layer/WebGLVector';
|
|
24
|
+
import WebGLTileLayer from 'ol/layer/WebGLTile';
|
|
25
|
+
import WebGLVectorTileLayer from 'ol/layer/WebGLVectorTile';
|
|
26
|
+
import VectorTileSource from 'ol/source/VectorTile';
|
|
27
|
+
import MVT from 'ol/format/MVT';
|
|
28
|
+
|
|
29
|
+
function buildTileSource(config) {
|
|
30
|
+
switch (config.type) {
|
|
31
|
+
case 'osm':
|
|
32
|
+
return new OSM({ attributions: config.attributions });
|
|
33
|
+
case 'xyz':
|
|
34
|
+
return new XYZ({ url: config.url, attributions: config.attributions });
|
|
35
|
+
case 'wms':
|
|
36
|
+
return new TileWMS({
|
|
37
|
+
url: config.url,
|
|
38
|
+
params: config.params ?? {},
|
|
39
|
+
attributions: config.attributions,
|
|
40
|
+
});
|
|
41
|
+
default:
|
|
42
|
+
return new OSM();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function buildImageSource(config) {
|
|
46
|
+
if (config.type === 'static') {
|
|
47
|
+
return new ImageStatic({
|
|
48
|
+
url: config.url,
|
|
49
|
+
imageExtent: config.imageExtent ?? [0, 0, 1, 1],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return new ImageWMS({ url: config.url, params: config.params });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function createClusterStyleFn(clusterCfg, styleFn, defaultStyle) {
|
|
56
|
+
return (olFeature, resolution) => {
|
|
57
|
+
const features = olFeature.get('features');
|
|
58
|
+
const size = features ? features.length : 0;
|
|
59
|
+
// Render cluster badge
|
|
60
|
+
if (size > 1) {
|
|
61
|
+
const showCount = clusterCfg?.showCount ?? true;
|
|
62
|
+
return new Style({
|
|
63
|
+
image: new Circle({
|
|
64
|
+
radius: 15 + Math.min(size * 2, 15),
|
|
65
|
+
fill: new Fill({ color: 'rgba(255, 100, 100, 0.8)' }),
|
|
66
|
+
stroke: new Stroke({ color: '#fff', width: 2 }),
|
|
67
|
+
}),
|
|
68
|
+
text: showCount
|
|
69
|
+
? new Text({
|
|
70
|
+
text: String(size),
|
|
71
|
+
fill: new Fill({ color: '#fff' }),
|
|
72
|
+
})
|
|
73
|
+
: undefined,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// Single feature in cluster: unwrap and call styleFn
|
|
77
|
+
const originalFeature = features?.[0];
|
|
78
|
+
if (originalFeature) {
|
|
79
|
+
// 1. Feature level override
|
|
80
|
+
if (clusterCfg?.featureStyle) {
|
|
81
|
+
// OpenLayers styles are mutable. Clone before modifying geometry to prevent global breakage.
|
|
82
|
+
const style = clusterCfg.featureStyle; // Cast since it might be abstract
|
|
83
|
+
if (style instanceof Style) {
|
|
84
|
+
const origGeom = originalFeature.getGeometry();
|
|
85
|
+
if (origGeom) {
|
|
86
|
+
const clonedStyle = style.clone();
|
|
87
|
+
clonedStyle.setGeometry(origGeom);
|
|
88
|
+
return clonedStyle;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return style;
|
|
92
|
+
}
|
|
93
|
+
// 2. Original Layer style
|
|
94
|
+
if (styleFn) {
|
|
95
|
+
const style = styleFn(originalFeature, resolution);
|
|
96
|
+
if (style instanceof Style) {
|
|
97
|
+
const origGeom = originalFeature.getGeometry();
|
|
98
|
+
if (origGeom) {
|
|
99
|
+
const clonedStyle = style.clone();
|
|
100
|
+
clonedStyle.setGeometry(origGeom);
|
|
101
|
+
return clonedStyle;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return style;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// 3. Fallback to styleFn or default
|
|
108
|
+
return styleFn ? styleFn(olFeature, resolution) : defaultStyle;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const STYLE_PROP$1 = '__angular_helpers_style__';
|
|
113
|
+
const defaultStyle = new Style({
|
|
114
|
+
image: new Circle({
|
|
115
|
+
radius: 6,
|
|
116
|
+
fill: new Fill({ color: '#3399CC' }),
|
|
117
|
+
stroke: new Stroke({ color: '#fff', width: 2 }),
|
|
118
|
+
}),
|
|
119
|
+
});
|
|
120
|
+
function buildVectorLayer(config, source) {
|
|
121
|
+
const clusterCfg = config.cluster;
|
|
122
|
+
const userStyle = config.style;
|
|
123
|
+
const styleFn = (olFeature, resolution) => {
|
|
124
|
+
const abstractStyle = olFeature.get(STYLE_PROP$1);
|
|
125
|
+
if (abstractStyle) {
|
|
126
|
+
const style = new Style();
|
|
127
|
+
const { icon, fill, stroke } = abstractStyle;
|
|
128
|
+
if (icon?.src) {
|
|
129
|
+
style.setImage(new Icon({
|
|
130
|
+
src: icon.src,
|
|
131
|
+
...(icon.size ? { size: icon.size } : {}),
|
|
132
|
+
...(icon.anchor ? { anchor: icon.anchor } : {}),
|
|
133
|
+
}));
|
|
134
|
+
}
|
|
135
|
+
if (fill)
|
|
136
|
+
style.setFill(new Fill({ color: fill.color }));
|
|
137
|
+
if (stroke)
|
|
138
|
+
style.setStroke(new Stroke({ color: stroke.color, width: stroke.width }));
|
|
139
|
+
if (icon?.src || fill || stroke)
|
|
140
|
+
return style;
|
|
141
|
+
}
|
|
142
|
+
if (userStyle) {
|
|
143
|
+
if (typeof userStyle === 'function') {
|
|
144
|
+
const feature = {
|
|
145
|
+
id: String(olFeature.getId() ?? ''),
|
|
146
|
+
geometry: {
|
|
147
|
+
type: olFeature.getGeometry()?.getType(),
|
|
148
|
+
coordinates: [],
|
|
149
|
+
},
|
|
150
|
+
properties: olFeature.getProperties(),
|
|
151
|
+
};
|
|
152
|
+
return userStyle(feature, resolution);
|
|
153
|
+
}
|
|
154
|
+
return userStyle;
|
|
155
|
+
}
|
|
156
|
+
return defaultStyle;
|
|
157
|
+
};
|
|
158
|
+
const clusterStyleFn = createClusterStyleFn(clusterCfg, styleFn, defaultStyle);
|
|
159
|
+
const layer = new VectorLayer({
|
|
160
|
+
source,
|
|
161
|
+
visible: config.visible ?? true,
|
|
162
|
+
opacity: config.opacity ?? 1,
|
|
163
|
+
zIndex: config.zIndex,
|
|
164
|
+
style: clusterCfg?.enabled ? clusterStyleFn : styleFn,
|
|
165
|
+
});
|
|
166
|
+
layer.set('id', config.id);
|
|
167
|
+
layer.set('cluster-config', clusterCfg);
|
|
168
|
+
layer.set('style-fn', styleFn);
|
|
169
|
+
return layer;
|
|
170
|
+
}
|
|
171
|
+
function buildHeatmapLayer(config) {
|
|
172
|
+
const vectorSource = new VectorSource();
|
|
173
|
+
if (config.features && config.features.length > 0) {
|
|
174
|
+
const olFeatures = config.features.map(featureToOlFeature);
|
|
175
|
+
vectorSource.addFeatures(olFeatures);
|
|
176
|
+
}
|
|
177
|
+
const layer = new HeatmapLayer({
|
|
178
|
+
source: vectorSource,
|
|
179
|
+
visible: config.visible ?? true,
|
|
180
|
+
opacity: config.opacity ?? 1,
|
|
181
|
+
zIndex: config.zIndex,
|
|
182
|
+
...(config.blur !== undefined && { blur: config.blur }),
|
|
183
|
+
...(config.radius !== undefined && { radius: config.radius }),
|
|
184
|
+
...(config.weight !== undefined && {
|
|
185
|
+
weight: config.weight,
|
|
186
|
+
}),
|
|
187
|
+
});
|
|
188
|
+
layer.set('id', config.id);
|
|
189
|
+
return layer;
|
|
190
|
+
}
|
|
191
|
+
function buildTileLayer(config, source) {
|
|
192
|
+
const layer = new TileLayer({
|
|
193
|
+
source,
|
|
194
|
+
visible: config.visible ?? true,
|
|
195
|
+
opacity: config.opacity ?? 1,
|
|
196
|
+
zIndex: config.zIndex,
|
|
197
|
+
});
|
|
198
|
+
layer.set('id', config.id);
|
|
199
|
+
return layer;
|
|
200
|
+
}
|
|
201
|
+
function buildImageLayer(config, source) {
|
|
202
|
+
const layer = new ImageLayer({
|
|
203
|
+
source,
|
|
204
|
+
visible: config.visible ?? true,
|
|
205
|
+
opacity: config.opacity ?? 1,
|
|
206
|
+
zIndex: config.zIndex,
|
|
207
|
+
});
|
|
208
|
+
layer.set('id', config.id);
|
|
209
|
+
return layer;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
class SpiderficationManager {
|
|
213
|
+
spiderSource = new VectorSource();
|
|
214
|
+
spiderLayer = new VectorLayer({
|
|
215
|
+
source: this.spiderSource,
|
|
216
|
+
zIndex: 9999,
|
|
217
|
+
properties: { 'is-spider-layer': true },
|
|
218
|
+
});
|
|
219
|
+
mapClickListenerRegistered = false;
|
|
220
|
+
map = null;
|
|
221
|
+
layerCache;
|
|
222
|
+
constructor(layerCache) {
|
|
223
|
+
this.layerCache = layerCache;
|
|
224
|
+
}
|
|
225
|
+
register(map) {
|
|
226
|
+
if (this.mapClickListenerRegistered)
|
|
227
|
+
return;
|
|
228
|
+
this.mapClickListenerRegistered = true;
|
|
229
|
+
this.map = map;
|
|
230
|
+
map.addLayer(this.spiderLayer);
|
|
231
|
+
// Unspiderfy on map movement or zoom
|
|
232
|
+
map.on('movestart', () => this.unspiderfy());
|
|
233
|
+
map.on('singleclick', (e) => {
|
|
234
|
+
let handled = false;
|
|
235
|
+
let keepSpiderOpen = false;
|
|
236
|
+
map.forEachFeatureAtPixel(e.pixel, (f, l) => {
|
|
237
|
+
if (handled)
|
|
238
|
+
return;
|
|
239
|
+
// Check if we clicked a spider item
|
|
240
|
+
if (l === this.spiderLayer) {
|
|
241
|
+
const originalOlFeature = f.get('spider-feature');
|
|
242
|
+
if (originalOlFeature) {
|
|
243
|
+
const layerId = f.get('cluster-layer-id');
|
|
244
|
+
const layerObj = this.layerCache.get(layerId);
|
|
245
|
+
if (layerObj) {
|
|
246
|
+
const clusterCfg = layerObj.get('cluster-config');
|
|
247
|
+
if (clusterCfg?.onSpiderfyClick) {
|
|
248
|
+
// Use olFeatureToFeature so coordinates are properly extracted!
|
|
249
|
+
const feat = olFeatureToFeature(originalOlFeature);
|
|
250
|
+
clusterCfg.onSpiderfyClick(feat);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
handled = true;
|
|
255
|
+
keepSpiderOpen = true; // Keep spider open when clicking a leg
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
// Check if we clicked a cluster
|
|
259
|
+
if (!l)
|
|
260
|
+
return;
|
|
261
|
+
const features = f.get('features');
|
|
262
|
+
if (features && features.length > 1) {
|
|
263
|
+
const clusterCfg = l.get('cluster-config');
|
|
264
|
+
if (clusterCfg?.spiderfyOnSelect) {
|
|
265
|
+
keepSpiderOpen = true;
|
|
266
|
+
handled = true;
|
|
267
|
+
// Execute layer manipulations outside the synchronous event loop
|
|
268
|
+
setTimeout(() => {
|
|
269
|
+
this.spiderfy(map, f, features, l, clusterCfg);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
// Cleanup existing spider layer if we clicked anything else
|
|
275
|
+
if (!keepSpiderOpen) {
|
|
276
|
+
this.unspiderfy();
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
unspiderfy() {
|
|
281
|
+
this.spiderSource.clear();
|
|
282
|
+
}
|
|
283
|
+
spiderfy(map, clusterFeature, features, parentLayer, cfg) {
|
|
284
|
+
this.unspiderfy();
|
|
285
|
+
const count = features.length;
|
|
286
|
+
const centerGeom = clusterFeature.getGeometry();
|
|
287
|
+
if (!centerGeom || centerGeom.getType() !== 'Point')
|
|
288
|
+
return;
|
|
289
|
+
const centerCoords = centerGeom.getCoordinates();
|
|
290
|
+
const resolution = map.getView().getResolution() ?? 1;
|
|
291
|
+
const baseRadius = 30; // 30 pixels
|
|
292
|
+
const radius = baseRadius + count * 2;
|
|
293
|
+
const angleStep = (2 * Math.PI) / count;
|
|
294
|
+
const spiderFeatures = [];
|
|
295
|
+
const styleFn = parentLayer.get('style-fn');
|
|
296
|
+
features.forEach((f, i) => {
|
|
297
|
+
let x, y;
|
|
298
|
+
if (count <= 8) {
|
|
299
|
+
// Circle layout for small number of features
|
|
300
|
+
const angle = i * angleStep;
|
|
301
|
+
x = centerCoords[0] + radius * Math.cos(angle) * resolution;
|
|
302
|
+
y = centerCoords[1] + radius * Math.sin(angle) * resolution;
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
// Spiral layout (caracol) for many features
|
|
306
|
+
const initialRadius = 20;
|
|
307
|
+
const legLength = 15;
|
|
308
|
+
const spiralAngleStep = 0.5;
|
|
309
|
+
const angle = i * spiralAngleStep;
|
|
310
|
+
const r = initialRadius + legLength * (angle / Math.PI);
|
|
311
|
+
x = centerCoords[0] + r * Math.cos(angle) * resolution;
|
|
312
|
+
y = centerCoords[1] + r * Math.sin(angle) * resolution;
|
|
313
|
+
}
|
|
314
|
+
const legGeom = new Point([x, y]);
|
|
315
|
+
// Create leg line
|
|
316
|
+
const lineFeature = new OLFeature(new LineString([centerCoords, [x, y]]));
|
|
317
|
+
lineFeature.setStyle(new Style({ stroke: new Stroke({ color: 'rgba(0,0,0,0.5)', width: 2 }) }));
|
|
318
|
+
spiderFeatures.push(lineFeature);
|
|
319
|
+
// Create point feature
|
|
320
|
+
const pointFeature = new OLFeature(legGeom);
|
|
321
|
+
// Determine style for the spider leg point
|
|
322
|
+
let pointStyle = undefined;
|
|
323
|
+
if (cfg?.featureStyle) {
|
|
324
|
+
pointStyle = cfg.featureStyle;
|
|
325
|
+
}
|
|
326
|
+
else if (styleFn) {
|
|
327
|
+
pointStyle = styleFn(f, resolution);
|
|
328
|
+
}
|
|
329
|
+
// Ensure we always have a visible style even if the original feature has none
|
|
330
|
+
if (!pointStyle || (Array.isArray(pointStyle) && pointStyle.length === 0)) {
|
|
331
|
+
pointStyle = new Style({
|
|
332
|
+
image: new Circle({
|
|
333
|
+
radius: 6,
|
|
334
|
+
fill: new Fill({ color: '#3399CC' }),
|
|
335
|
+
stroke: new Stroke({ color: '#fff', width: 2 }),
|
|
336
|
+
}),
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
pointFeature.setStyle(pointStyle);
|
|
340
|
+
pointFeature.set('spider-feature', f);
|
|
341
|
+
pointFeature.set('cluster-layer-id', parentLayer.get('id'));
|
|
342
|
+
spiderFeatures.push(pointFeature);
|
|
343
|
+
});
|
|
344
|
+
this.spiderSource.addFeatures(spiderFeatures);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
20
347
|
|
|
21
|
-
// OlLayerService
|
|
22
|
-
/**
|
|
23
|
-
* Internal property key used to stash the abstract style metadata on the
|
|
24
|
-
* underlying `ol/Feature` so the layer style function can resolve a
|
|
25
|
-
* per-feature visual without colliding with user `properties`.
|
|
26
|
-
*/
|
|
27
348
|
const STYLE_PROP = '__angular_helpers_style__';
|
|
28
349
|
class OlLayerService {
|
|
29
350
|
mapService = inject(OlMapService);
|
|
30
351
|
layerCache = new Map();
|
|
31
352
|
pendingConfigs = [];
|
|
32
353
|
layerState = signal([], ...(ngDevMode ? [{ debugName: "layerState" }] : /* istanbul ignore next */ []));
|
|
354
|
+
spiderManager = new SpiderficationManager(this.layerCache);
|
|
33
355
|
layers = computed(() => this.layerState(), ...(ngDevMode ? [{ debugName: "layers" }] : /* istanbul ignore next */ []));
|
|
34
356
|
visibleLayers = computed(() => this.layerState().filter((l) => l.visible), ...(ngDevMode ? [{ debugName: "visibleLayers" }] : /* istanbul ignore next */ []));
|
|
35
357
|
tileLayers = computed(() => this.layerState().filter((l) => l.type === 'tile'), ...(ngDevMode ? [{ debugName: "tileLayers" }] : /* istanbul ignore next */ []));
|
|
@@ -55,16 +377,74 @@ class OlLayerService {
|
|
|
55
377
|
}
|
|
56
378
|
}
|
|
57
379
|
createLayer(config, map) {
|
|
380
|
+
let layer;
|
|
58
381
|
switch (config.type) {
|
|
59
|
-
case 'vector':
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
382
|
+
case 'vector': {
|
|
383
|
+
const vConfig = config;
|
|
384
|
+
const sourceOptions = {};
|
|
385
|
+
if (vConfig.url && vConfig.format) {
|
|
386
|
+
sourceOptions.url = vConfig.url;
|
|
387
|
+
if (vConfig.format === 'geojson')
|
|
388
|
+
sourceOptions.format = new GeoJSON();
|
|
389
|
+
else if (vConfig.format === 'topojson')
|
|
390
|
+
sourceOptions.format = new TopoJSON();
|
|
391
|
+
else if (vConfig.format === 'kml')
|
|
392
|
+
sourceOptions.format = new KML();
|
|
393
|
+
}
|
|
394
|
+
const vectorSource = new VectorSource(sourceOptions);
|
|
395
|
+
if (vConfig.features && vConfig.features.length > 0) {
|
|
396
|
+
const olFeatures = vConfig.features.map((f) => {
|
|
397
|
+
const olf = featureToOlFeature(f);
|
|
398
|
+
if (f.style)
|
|
399
|
+
olf.set(STYLE_PROP, f.style);
|
|
400
|
+
return olf;
|
|
401
|
+
});
|
|
402
|
+
vectorSource.addFeatures(olFeatures);
|
|
403
|
+
}
|
|
404
|
+
const clusterCfg = vConfig.cluster;
|
|
405
|
+
const source = clusterCfg?.enabled
|
|
406
|
+
? new ClusterSource({
|
|
407
|
+
source: vectorSource,
|
|
408
|
+
distance: clusterCfg.distance ?? 40,
|
|
409
|
+
minDistance: clusterCfg.minDistance ?? 20,
|
|
410
|
+
geometryFunction: (feature) => {
|
|
411
|
+
const geometry = feature.getGeometry();
|
|
412
|
+
if (!geometry)
|
|
413
|
+
return null;
|
|
414
|
+
if (geometry.getType() === 'Point')
|
|
415
|
+
return geometry;
|
|
416
|
+
return new Point(getCenter(geometry.getExtent()));
|
|
417
|
+
},
|
|
418
|
+
})
|
|
419
|
+
: vectorSource;
|
|
420
|
+
layer = buildVectorLayer(vConfig, source);
|
|
421
|
+
if (clusterCfg?.spiderfyOnSelect) {
|
|
422
|
+
this.spiderManager.register(map);
|
|
423
|
+
}
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
case 'heatmap':
|
|
427
|
+
layer = buildHeatmapLayer(config);
|
|
428
|
+
break;
|
|
429
|
+
case 'tile': {
|
|
430
|
+
const tConfig = config;
|
|
431
|
+
const source = buildTileSource(tConfig.source);
|
|
432
|
+
layer = buildTileLayer(tConfig, source);
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
case 'image': {
|
|
436
|
+
const iConfig = config;
|
|
437
|
+
const source = buildImageSource(iConfig.source);
|
|
438
|
+
layer = buildImageLayer(iConfig, source);
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
65
441
|
default:
|
|
66
442
|
return { id: config.id };
|
|
67
443
|
}
|
|
444
|
+
map.addLayer(layer);
|
|
445
|
+
this.layerCache.set(config.id, layer);
|
|
446
|
+
this.updateLayerState();
|
|
447
|
+
return { id: config.id };
|
|
68
448
|
}
|
|
69
449
|
getLayer(id) {
|
|
70
450
|
return this.layerCache.get(id);
|
|
@@ -73,7 +453,6 @@ class OlLayerService {
|
|
|
73
453
|
return this.layerCache.has(id);
|
|
74
454
|
}
|
|
75
455
|
removeLayer(id) {
|
|
76
|
-
// Cancel if it's still pending (map not ready yet)
|
|
77
456
|
const pendingIdx = this.pendingConfigs.findIndex((c) => c.id === id);
|
|
78
457
|
if (pendingIdx !== -1) {
|
|
79
458
|
this.pendingConfigs.splice(pendingIdx, 1);
|
|
@@ -83,6 +462,7 @@ class OlLayerService {
|
|
|
83
462
|
const layer = this.layerCache.get(id);
|
|
84
463
|
if (map && layer) {
|
|
85
464
|
map.removeLayer(layer);
|
|
465
|
+
layer.dispose();
|
|
86
466
|
this.layerCache.delete(id);
|
|
87
467
|
this.updateLayerState();
|
|
88
468
|
}
|
|
@@ -93,6 +473,11 @@ class OlLayerService {
|
|
|
93
473
|
layer.setVisible(visible);
|
|
94
474
|
this.updateLayerState();
|
|
95
475
|
}
|
|
476
|
+
else {
|
|
477
|
+
const pending = this.pendingConfigs.find((c) => c.id === id);
|
|
478
|
+
if (pending)
|
|
479
|
+
pending.visible = visible;
|
|
480
|
+
}
|
|
96
481
|
}
|
|
97
482
|
toggleVisibility(id) {
|
|
98
483
|
const layer = this.layerCache.get(id);
|
|
@@ -110,6 +495,11 @@ class OlLayerService {
|
|
|
110
495
|
layer.setOpacity(opacity);
|
|
111
496
|
this.updateLayerState();
|
|
112
497
|
}
|
|
498
|
+
else {
|
|
499
|
+
const pending = this.pendingConfigs.find((c) => c.id === id);
|
|
500
|
+
if (pending)
|
|
501
|
+
pending.opacity = opacity;
|
|
502
|
+
}
|
|
113
503
|
}
|
|
114
504
|
setZIndex(id, zIndex) {
|
|
115
505
|
const layer = this.layerCache.get(id);
|
|
@@ -117,6 +507,52 @@ class OlLayerService {
|
|
|
117
507
|
layer.setZIndex(zIndex);
|
|
118
508
|
this.updateLayerState();
|
|
119
509
|
}
|
|
510
|
+
else {
|
|
511
|
+
const pending = this.pendingConfigs.find((c) => c.id === id);
|
|
512
|
+
if (pending)
|
|
513
|
+
pending.zIndex = zIndex;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
setClusterDistance(id, distance) {
|
|
517
|
+
const layer = this.layerCache.get(id);
|
|
518
|
+
if (layer instanceof VectorLayer) {
|
|
519
|
+
const source = layer.getSource();
|
|
520
|
+
if (source && 'setDistance' in source) {
|
|
521
|
+
source.setDistance(distance);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
setClusterMinDistance(id, minDistance) {
|
|
526
|
+
const layer = this.layerCache.get(id);
|
|
527
|
+
if (layer instanceof VectorLayer) {
|
|
528
|
+
const source = layer.getSource();
|
|
529
|
+
if (source && 'setMinDistance' in source) {
|
|
530
|
+
source.setMinDistance(minDistance);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
setHeatmapProperties(id, props) {
|
|
535
|
+
const layer = this.layerCache.get(id);
|
|
536
|
+
if (layer instanceof HeatmapLayer) {
|
|
537
|
+
if (props.blur !== undefined)
|
|
538
|
+
layer.setBlur(props.blur);
|
|
539
|
+
if (props.radius !== undefined)
|
|
540
|
+
layer.setRadius(props.radius);
|
|
541
|
+
if (props.weight !== undefined)
|
|
542
|
+
layer.setWeight(props.weight);
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
const pending = this.pendingConfigs.find((c) => c.id === id);
|
|
546
|
+
if (pending && pending.type === 'heatmap') {
|
|
547
|
+
const heatmapConfig = pending;
|
|
548
|
+
if (props.blur !== undefined)
|
|
549
|
+
heatmapConfig.blur = props.blur;
|
|
550
|
+
if (props.radius !== undefined)
|
|
551
|
+
heatmapConfig.radius = props.radius;
|
|
552
|
+
if (props.weight !== undefined)
|
|
553
|
+
heatmapConfig.weight = props.weight;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
120
556
|
}
|
|
121
557
|
isVisible(id) {
|
|
122
558
|
return this.layerCache.get(id)?.getVisible() ?? false;
|
|
@@ -127,11 +563,6 @@ class OlLayerService {
|
|
|
127
563
|
getZIndex(id) {
|
|
128
564
|
return this.layerCache.get(id)?.getZIndex() ?? 0;
|
|
129
565
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Clears all features from a vector layer's source.
|
|
132
|
-
* Does not remove the layer itself.
|
|
133
|
-
* @param id - Layer identifier
|
|
134
|
-
*/
|
|
135
566
|
clearFeatures(id) {
|
|
136
567
|
const layer = this.layerCache.get(id);
|
|
137
568
|
if (!(layer instanceof VectorLayer))
|
|
@@ -139,19 +570,12 @@ class OlLayerService {
|
|
|
139
570
|
const source = layer.getSource();
|
|
140
571
|
if (!source)
|
|
141
572
|
return;
|
|
142
|
-
// Handle Cluster source: clear the underlying VectorSource
|
|
143
573
|
const clusterSource = source;
|
|
144
574
|
const vectorSource = clusterSource.getSource
|
|
145
575
|
? clusterSource.getSource()
|
|
146
576
|
: source;
|
|
147
577
|
vectorSource?.clear();
|
|
148
578
|
}
|
|
149
|
-
/**
|
|
150
|
-
* Updates the features of a vector layer.
|
|
151
|
-
* Syncs new features without clearing existing ones (preserves OL modifications).
|
|
152
|
-
* @param id - Layer identifier
|
|
153
|
-
* @param features - New features to sync
|
|
154
|
-
*/
|
|
155
579
|
updateFeatures(id, features) {
|
|
156
580
|
const layer = this.layerCache.get(id);
|
|
157
581
|
if (!(layer instanceof VectorLayer))
|
|
@@ -159,58 +583,32 @@ class OlLayerService {
|
|
|
159
583
|
const source = layer.getSource();
|
|
160
584
|
if (!source)
|
|
161
585
|
return;
|
|
162
|
-
// Handle Cluster source: get the underlying VectorSource
|
|
163
586
|
const clusterSource = source;
|
|
164
587
|
const vectorSource = clusterSource.getSource
|
|
165
588
|
? clusterSource.getSource()
|
|
166
589
|
: source;
|
|
167
590
|
if (!(vectorSource instanceof VectorSource))
|
|
168
591
|
return;
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
.getFeatures()
|
|
172
|
-
.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
else if (geom.type === 'LineString') {
|
|
190
|
-
const coords = geom.coordinates.map((c) => fromLonLat(c));
|
|
191
|
-
geometry = new LineString(coords);
|
|
192
|
-
}
|
|
193
|
-
else if (geom.type === 'Polygon') {
|
|
194
|
-
const rings = geom.coordinates.map((ring) => ring.map((c) => fromLonLat(c)));
|
|
195
|
-
geometry = new Polygon(rings);
|
|
196
|
-
}
|
|
197
|
-
else if (geom.type === 'Circle') {
|
|
198
|
-
const center = fromLonLat(geom.coordinates);
|
|
199
|
-
// Approximate radius in meters - use 1000m as default if not specified
|
|
200
|
-
geometry = new Circle(center, geom.radius ?? 1000);
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
geometry = new Point([0, 0]);
|
|
204
|
-
}
|
|
205
|
-
const olFeature = new OLFeature({
|
|
206
|
-
geometry,
|
|
207
|
-
...feature.properties,
|
|
208
|
-
});
|
|
209
|
-
if (feature.style) {
|
|
210
|
-
olFeature.set(STYLE_PROP, feature.style);
|
|
211
|
-
}
|
|
212
|
-
olFeature.setId(feature.id);
|
|
213
|
-
return olFeature;
|
|
592
|
+
if (features) {
|
|
593
|
+
const newFeatureIds = new Set(features.map((f) => f.id));
|
|
594
|
+
const sourceFeatures = vectorSource.getFeatures();
|
|
595
|
+
sourceFeatures.forEach((f) => {
|
|
596
|
+
const fId = f.getId();
|
|
597
|
+
if (fId !== undefined && !newFeatureIds.has(fId)) {
|
|
598
|
+
vectorSource.removeFeature(f);
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
const existingIds = new Set(vectorSource
|
|
602
|
+
.getFeatures()
|
|
603
|
+
.map((f) => f.getId())
|
|
604
|
+
.filter((fId) => fId !== undefined));
|
|
605
|
+
const featuresToAdd = features.filter((f) => !existingIds.has(f.id));
|
|
606
|
+
if (featuresToAdd.length > 0) {
|
|
607
|
+
const olFeatures = featuresToAdd.map((f) => {
|
|
608
|
+
const olf = featureToOlFeature(f);
|
|
609
|
+
if (f.style)
|
|
610
|
+
olf.set(STYLE_PROP, f.style);
|
|
611
|
+
return olf;
|
|
214
612
|
});
|
|
215
613
|
vectorSource.addFeatures(olFeatures);
|
|
216
614
|
}
|
|
@@ -219,7 +617,13 @@ class OlLayerService {
|
|
|
219
617
|
updateLayerState() {
|
|
220
618
|
const layers = [];
|
|
221
619
|
this.layerCache.forEach((layer, id) => {
|
|
222
|
-
|
|
620
|
+
let type = 'vector';
|
|
621
|
+
if (layer instanceof HeatmapLayer)
|
|
622
|
+
type = 'heatmap';
|
|
623
|
+
else if (layer instanceof TileLayer)
|
|
624
|
+
type = 'tile';
|
|
625
|
+
else if (layer instanceof ImageLayer)
|
|
626
|
+
type = 'image';
|
|
223
627
|
layers.push({
|
|
224
628
|
id,
|
|
225
629
|
type: type,
|
|
@@ -230,252 +634,73 @@ class OlLayerService {
|
|
|
230
634
|
});
|
|
231
635
|
this.layerState.set(layers.sort((a, b) => a.zIndex - b.zIndex));
|
|
232
636
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
// Add features if provided
|
|
236
|
-
if (config.features && config.features.length > 0) {
|
|
237
|
-
const olFeatures = config.features.map((feature) => {
|
|
238
|
-
const geom = feature.geometry;
|
|
239
|
-
let geometry;
|
|
240
|
-
// Validate coordinates exist before processing
|
|
241
|
-
if (!geom.coordinates) {
|
|
242
|
-
geometry = new Point([0, 0]);
|
|
243
|
-
}
|
|
244
|
-
else if (geom.type === 'Point') {
|
|
245
|
-
// Transform from EPSG:4326 (lon/lat) to EPSG:3857 (map projection)
|
|
246
|
-
const coords = geom.coordinates;
|
|
247
|
-
geometry = new Point(fromLonLat(coords));
|
|
248
|
-
}
|
|
249
|
-
else if (geom.type === 'LineString') {
|
|
250
|
-
const coords = geom.coordinates.map((c) => fromLonLat(c));
|
|
251
|
-
geometry = new LineString(coords);
|
|
252
|
-
}
|
|
253
|
-
else if (geom.type === 'Polygon') {
|
|
254
|
-
const rings = geom.coordinates.map((ring) => ring.map((c) => fromLonLat(c)));
|
|
255
|
-
geometry = new Polygon(rings);
|
|
256
|
-
}
|
|
257
|
-
else if (geom.type === 'Circle') {
|
|
258
|
-
const center = fromLonLat(geom.coordinates);
|
|
259
|
-
geometry = new Circle(center, geom.radius ?? 1000);
|
|
260
|
-
}
|
|
261
|
-
else {
|
|
262
|
-
geometry = new Point([0, 0]);
|
|
263
|
-
}
|
|
264
|
-
const olFeature = new OLFeature({
|
|
265
|
-
geometry,
|
|
266
|
-
...feature.properties,
|
|
267
|
-
});
|
|
268
|
-
if (feature.style) {
|
|
269
|
-
olFeature.set(STYLE_PROP, feature.style);
|
|
270
|
-
}
|
|
271
|
-
olFeature.setId(feature.id);
|
|
272
|
-
return olFeature;
|
|
273
|
-
});
|
|
274
|
-
vectorSource.addFeatures(olFeatures);
|
|
275
|
-
}
|
|
276
|
-
// Wrap in cluster source if enabled
|
|
277
|
-
const clusterCfg = config.cluster;
|
|
278
|
-
const source = clusterCfg?.enabled
|
|
279
|
-
? new ClusterSource({
|
|
280
|
-
source: vectorSource,
|
|
281
|
-
distance: clusterCfg.distance ?? 40,
|
|
282
|
-
minDistance: clusterCfg.minDistance ?? 20,
|
|
283
|
-
geometryFunction: (feature) => {
|
|
284
|
-
const geometry = feature.getGeometry();
|
|
285
|
-
if (!geometry)
|
|
286
|
-
return null;
|
|
287
|
-
// For Point geometries, use as-is
|
|
288
|
-
if (geometry.getType() === 'Point') {
|
|
289
|
-
return geometry;
|
|
290
|
-
}
|
|
291
|
-
// For other geometries (Polygon, Circle, etc.), use center point
|
|
292
|
-
const extent = geometry.getExtent();
|
|
293
|
-
const center = getCenter(extent);
|
|
294
|
-
return new Point(center);
|
|
295
|
-
},
|
|
296
|
-
})
|
|
297
|
-
: vectorSource;
|
|
298
|
-
// Default style for all geometry types (points, lines, polygons)
|
|
299
|
-
const defaultStyle = new Style({
|
|
300
|
-
fill: new Fill({ color: 'rgba(25, 118, 210, 0.3)' }),
|
|
301
|
-
stroke: new Stroke({ color: '#1976d2', width: 2 }),
|
|
302
|
-
image: new Circle$1({
|
|
303
|
-
radius: 8,
|
|
304
|
-
fill: new Fill({ color: '#1976d2' }),
|
|
305
|
-
stroke: new Stroke({ color: '#d32f2f', width: 2 }),
|
|
306
|
-
}),
|
|
307
|
-
});
|
|
308
|
-
// Cluster style: shows count badge when features are clustered
|
|
309
|
-
const clusterStyleFn = (olFeature) => {
|
|
310
|
-
const features = olFeature.get('features');
|
|
311
|
-
const size = features?.length ?? 1;
|
|
312
|
-
if (size > 1) {
|
|
313
|
-
const showCount = clusterCfg?.showCount ?? true;
|
|
314
|
-
return new Style({
|
|
315
|
-
image: new Circle$1({
|
|
316
|
-
radius: 15 + Math.min(size * 2, 15),
|
|
317
|
-
fill: new Fill({ color: 'rgba(255, 100, 100, 0.8)' }),
|
|
318
|
-
stroke: new Stroke({ color: '#fff', width: 2 }),
|
|
319
|
-
}),
|
|
320
|
-
text: showCount
|
|
321
|
-
? new Text({
|
|
322
|
-
text: String(size),
|
|
323
|
-
fill: new Fill({ color: '#fff' }),
|
|
324
|
-
})
|
|
325
|
-
: undefined,
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
// Single feature: get the original feature from the cluster and use its style
|
|
329
|
-
const originalFeatures = olFeature.get('features');
|
|
330
|
-
const originalFeature = originalFeatures?.[0];
|
|
331
|
-
if (originalFeature) {
|
|
332
|
-
const abstractStyle = originalFeature.get(STYLE_PROP);
|
|
333
|
-
if (abstractStyle) {
|
|
334
|
-
const style = new Style();
|
|
335
|
-
const { icon, fill, stroke } = abstractStyle;
|
|
336
|
-
if (icon?.src) {
|
|
337
|
-
style.setImage(new Icon({
|
|
338
|
-
src: icon.src,
|
|
339
|
-
...(icon.size ? { size: icon.size } : {}),
|
|
340
|
-
...(icon.anchor ? { anchor: icon.anchor } : {}),
|
|
341
|
-
}));
|
|
342
|
-
}
|
|
343
|
-
if (fill) {
|
|
344
|
-
style.setFill(new Fill({ color: fill.color }));
|
|
345
|
-
}
|
|
346
|
-
if (stroke) {
|
|
347
|
-
style.setStroke(new Stroke({ color: stroke.color, width: stroke.width }));
|
|
348
|
-
}
|
|
349
|
-
// If we mapped at least one property, return it, otherwise fallback
|
|
350
|
-
if (icon?.src || fill || stroke)
|
|
351
|
-
return style;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
return defaultStyle;
|
|
355
|
-
};
|
|
356
|
-
// Per-feature style resolver: features carrying `style` render it.
|
|
357
|
-
// Structural type avoids importing `FeatureLike` from `ol/Feature`;
|
|
358
|
-
// tooling has been observed to auto-remove the unused-looking import.
|
|
359
|
-
const styleFn = (olFeature) => {
|
|
360
|
-
const abstractStyle = olFeature.get(STYLE_PROP);
|
|
361
|
-
if (abstractStyle) {
|
|
362
|
-
const style = new Style();
|
|
363
|
-
const { icon, fill, stroke } = abstractStyle;
|
|
364
|
-
if (icon?.src) {
|
|
365
|
-
style.setImage(new Icon({
|
|
366
|
-
src: icon.src,
|
|
367
|
-
...(icon.size ? { size: icon.size } : {}),
|
|
368
|
-
...(icon.anchor ? { anchor: icon.anchor } : {}),
|
|
369
|
-
}));
|
|
370
|
-
}
|
|
371
|
-
if (fill) {
|
|
372
|
-
style.setFill(new Fill({ color: fill.color }));
|
|
373
|
-
}
|
|
374
|
-
if (stroke) {
|
|
375
|
-
style.setStroke(new Stroke({ color: stroke.color, width: stroke.width }));
|
|
376
|
-
}
|
|
377
|
-
if (icon?.src || fill || stroke)
|
|
378
|
-
return style;
|
|
379
|
-
}
|
|
380
|
-
return defaultStyle;
|
|
381
|
-
};
|
|
382
|
-
const layer = new VectorLayer({
|
|
383
|
-
source,
|
|
384
|
-
visible: config.visible ?? true,
|
|
385
|
-
opacity: config.opacity ?? 1,
|
|
386
|
-
zIndex: config.zIndex,
|
|
387
|
-
style: clusterCfg?.enabled ? clusterStyleFn : styleFn,
|
|
388
|
-
});
|
|
389
|
-
layer.set('id', config.id);
|
|
390
|
-
map.addLayer(layer);
|
|
391
|
-
this.layerCache.set(config.id, layer);
|
|
392
|
-
this.updateLayerState();
|
|
393
|
-
return { id: config.id };
|
|
394
|
-
}
|
|
395
|
-
createTileLayer(config, map) {
|
|
396
|
-
let source;
|
|
397
|
-
switch (config.source.type) {
|
|
398
|
-
case 'osm':
|
|
399
|
-
source = new OSM({ attributions: config.source.attributions });
|
|
400
|
-
break;
|
|
401
|
-
case 'xyz':
|
|
402
|
-
source = new XYZ({ url: config.source.url, attributions: config.source.attributions });
|
|
403
|
-
break;
|
|
404
|
-
case 'wms':
|
|
405
|
-
source = new TileWMS({
|
|
406
|
-
url: config.source.url,
|
|
407
|
-
params: config.source.params,
|
|
408
|
-
attributions: config.source.attributions,
|
|
409
|
-
});
|
|
410
|
-
break;
|
|
411
|
-
default:
|
|
412
|
-
source = new OSM();
|
|
413
|
-
}
|
|
414
|
-
const layer = new TileLayer({
|
|
415
|
-
source,
|
|
416
|
-
visible: config.visible ?? true,
|
|
417
|
-
opacity: config.opacity ?? 1,
|
|
418
|
-
zIndex: config.zIndex,
|
|
419
|
-
});
|
|
420
|
-
layer.set('id', config.id);
|
|
421
|
-
map.addLayer(layer);
|
|
422
|
-
this.layerCache.set(config.id, layer);
|
|
423
|
-
this.updateLayerState();
|
|
424
|
-
return { id: config.id };
|
|
425
|
-
}
|
|
426
|
-
createImageLayer(config, map) {
|
|
427
|
-
let source;
|
|
428
|
-
if (config.source.type === 'static') {
|
|
429
|
-
source = new ImageStatic({
|
|
430
|
-
url: config.source.url,
|
|
431
|
-
imageExtent: config.source.imageExtent ?? [0, 0, 1, 1],
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
source = new ImageWMS({ url: config.source.url, params: config.source.params });
|
|
436
|
-
}
|
|
437
|
-
const layer = new ImageLayer({
|
|
438
|
-
source,
|
|
439
|
-
visible: config.visible ?? true,
|
|
440
|
-
opacity: config.opacity ?? 1,
|
|
441
|
-
zIndex: config.zIndex,
|
|
442
|
-
});
|
|
443
|
-
layer.set('id', config.id);
|
|
444
|
-
map.addLayer(layer);
|
|
445
|
-
this.layerCache.set(config.id, layer);
|
|
446
|
-
this.updateLayerState();
|
|
447
|
-
return { id: config.id };
|
|
448
|
-
}
|
|
449
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlLayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
450
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlLayerService });
|
|
637
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlLayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
638
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlLayerService });
|
|
451
639
|
}
|
|
452
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
640
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlLayerService, decorators: [{
|
|
453
641
|
type: Injectable
|
|
454
642
|
}] });
|
|
455
643
|
|
|
644
|
+
class OlClusterComponent {
|
|
645
|
+
distance = input(40, ...(ngDevMode ? [{ debugName: "distance" }] : /* istanbul ignore next */ []));
|
|
646
|
+
minDistance = input(20, ...(ngDevMode ? [{ debugName: "minDistance" }] : /* istanbul ignore next */ []));
|
|
647
|
+
showCount = input(true, ...(ngDevMode ? [{ debugName: "showCount" }] : /* istanbul ignore next */ []));
|
|
648
|
+
featureStyle = input(...(ngDevMode ? [undefined, { debugName: "featureStyle" }] : /* istanbul ignore next */ []));
|
|
649
|
+
spiderfyOnSelect = input(false, ...(ngDevMode ? [{ debugName: "spiderfyOnSelect" }] : /* istanbul ignore next */ []));
|
|
650
|
+
spiderfyClick = output();
|
|
651
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlClusterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
652
|
+
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 }, spiderfyOnSelect: { classPropertyName: "spiderfyOnSelect", publicName: "spiderfyOnSelect", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { spiderfyClick: "spiderfyClick" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
653
|
+
}
|
|
654
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlClusterComponent, decorators: [{
|
|
655
|
+
type: Component,
|
|
656
|
+
args: [{
|
|
657
|
+
selector: 'ol-cluster',
|
|
658
|
+
template: '',
|
|
659
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
660
|
+
}]
|
|
661
|
+
}], 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 }] }], spiderfyOnSelect: [{ type: i0.Input, args: [{ isSignal: true, alias: "spiderfyOnSelect", required: false }] }], spiderfyClick: [{ type: i0.Output, args: ["spiderfyClick"] }] } });
|
|
662
|
+
|
|
456
663
|
// OlVectorLayerComponent
|
|
457
664
|
class OlVectorLayerComponent {
|
|
458
665
|
layerService = inject(OlLayerService);
|
|
459
666
|
destroyRef = inject(DestroyRef);
|
|
460
667
|
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
461
668
|
features = input([], ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
|
|
669
|
+
url = input(...(ngDevMode ? [undefined, { debugName: "url" }] : /* istanbul ignore next */ []));
|
|
670
|
+
format = input(...(ngDevMode ? [undefined, { debugName: "format" }] : /* istanbul ignore next */ []));
|
|
462
671
|
zIndex = input(0, ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
|
|
463
672
|
opacity = input(1, ...(ngDevMode ? [{ debugName: "opacity" }] : /* istanbul ignore next */ []));
|
|
464
673
|
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
465
674
|
style = input(...(ngDevMode ? [undefined, { debugName: "style" }] : /* istanbul ignore next */ []));
|
|
466
675
|
cluster = input(...(ngDevMode ? [undefined, { debugName: "cluster" }] : /* istanbul ignore next */ []));
|
|
676
|
+
clusterComponent = contentChild(OlClusterComponent, ...(ngDevMode ? [{ debugName: "clusterComponent" }] : /* istanbul ignore next */ []));
|
|
467
677
|
constructor() {
|
|
468
678
|
// Initialize layer after DOM is ready
|
|
469
679
|
afterNextRender(() => {
|
|
680
|
+
const clusterCmp = this.clusterComponent();
|
|
681
|
+
const resolvedClusterConfig = this.cluster() ??
|
|
682
|
+
(clusterCmp
|
|
683
|
+
? {
|
|
684
|
+
enabled: true,
|
|
685
|
+
distance: clusterCmp.distance(),
|
|
686
|
+
minDistance: clusterCmp.minDistance(),
|
|
687
|
+
showCount: clusterCmp.showCount(),
|
|
688
|
+
featureStyle: clusterCmp.featureStyle(),
|
|
689
|
+
spiderfyOnSelect: clusterCmp.spiderfyOnSelect(),
|
|
690
|
+
onSpiderfyClick: (f) => clusterCmp.spiderfyClick.emit(f),
|
|
691
|
+
}
|
|
692
|
+
: undefined);
|
|
470
693
|
this.layerService.addLayer({
|
|
471
694
|
id: this.id(),
|
|
472
695
|
type: 'vector',
|
|
473
696
|
features: this.features(),
|
|
697
|
+
url: this.url(),
|
|
698
|
+
format: this.format(),
|
|
474
699
|
zIndex: this.zIndex(),
|
|
475
700
|
opacity: this.opacity(),
|
|
476
701
|
visible: this.visible(),
|
|
477
702
|
style: this.style(),
|
|
478
|
-
cluster:
|
|
703
|
+
cluster: resolvedClusterConfig,
|
|
479
704
|
});
|
|
480
705
|
});
|
|
481
706
|
// Effect to sync features when input changes
|
|
@@ -486,22 +711,42 @@ class OlVectorLayerComponent {
|
|
|
486
711
|
this.layerService.updateFeatures(this.id(), currentFeatures);
|
|
487
712
|
}
|
|
488
713
|
});
|
|
714
|
+
effect(() => {
|
|
715
|
+
this.layerService.setOpacity(this.id(), this.opacity());
|
|
716
|
+
});
|
|
717
|
+
effect(() => {
|
|
718
|
+
this.layerService.setVisibility(this.id(), this.visible());
|
|
719
|
+
});
|
|
720
|
+
effect(() => {
|
|
721
|
+
this.layerService.setZIndex(this.id(), this.zIndex());
|
|
722
|
+
});
|
|
723
|
+
// Reactive cluster distance updates
|
|
724
|
+
effect(() => {
|
|
725
|
+
const clusterCmp = this.clusterComponent();
|
|
726
|
+
if (clusterCmp) {
|
|
727
|
+
const dist = clusterCmp.distance();
|
|
728
|
+
const minDst = clusterCmp.minDistance();
|
|
729
|
+
// Since we are inside effect, these will trigger when distance changes
|
|
730
|
+
this.layerService.setClusterDistance(this.id(), dist);
|
|
731
|
+
this.layerService.setClusterMinDistance(this.id(), minDst);
|
|
732
|
+
}
|
|
733
|
+
});
|
|
489
734
|
// Cleanup when component is destroyed
|
|
490
735
|
this.destroyRef.onDestroy(() => {
|
|
491
736
|
this.layerService.removeLayer(this.id());
|
|
492
737
|
});
|
|
493
738
|
}
|
|
494
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
495
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
739
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlVectorLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
740
|
+
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 });
|
|
496
741
|
}
|
|
497
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
742
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlVectorLayerComponent, decorators: [{
|
|
498
743
|
type: Component,
|
|
499
744
|
args: [{
|
|
500
745
|
selector: 'ol-vector-layer',
|
|
501
746
|
template: '',
|
|
502
747
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
503
748
|
}]
|
|
504
|
-
}], 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 }] }], cluster: [{ type: i0.Input, args: [{ isSignal: true, alias: "cluster", required: false }] }] } });
|
|
749
|
+
}], 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 }] }] } });
|
|
505
750
|
|
|
506
751
|
// OlTileLayerComponent
|
|
507
752
|
class OlTileLayerComponent {
|
|
@@ -532,15 +777,24 @@ class OlTileLayerComponent {
|
|
|
532
777
|
visible: this.visible(),
|
|
533
778
|
});
|
|
534
779
|
});
|
|
780
|
+
effect(() => {
|
|
781
|
+
this.layerService.setOpacity(this.id(), this.opacity());
|
|
782
|
+
});
|
|
783
|
+
effect(() => {
|
|
784
|
+
this.layerService.setVisibility(this.id(), this.visible());
|
|
785
|
+
});
|
|
786
|
+
effect(() => {
|
|
787
|
+
this.layerService.setZIndex(this.id(), this.zIndex());
|
|
788
|
+
});
|
|
535
789
|
// Cleanup when component is destroyed
|
|
536
790
|
this.destroyRef.onDestroy(() => {
|
|
537
791
|
this.layerService.removeLayer(this.id());
|
|
538
792
|
});
|
|
539
793
|
}
|
|
540
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
541
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
794
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTileLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
795
|
+
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 });
|
|
542
796
|
}
|
|
543
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
797
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTileLayerComponent, decorators: [{
|
|
544
798
|
type: Component,
|
|
545
799
|
args: [{
|
|
546
800
|
selector: 'ol-tile-layer',
|
|
@@ -583,10 +837,10 @@ class OlImageLayerComponent {
|
|
|
583
837
|
this.layerService.removeLayer(this.id());
|
|
584
838
|
});
|
|
585
839
|
}
|
|
586
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
587
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
840
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlImageLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
841
|
+
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 });
|
|
588
842
|
}
|
|
589
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
843
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlImageLayerComponent, decorators: [{
|
|
590
844
|
type: Component,
|
|
591
845
|
args: [{
|
|
592
846
|
selector: 'ol-image-layer',
|
|
@@ -595,6 +849,388 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImpor
|
|
|
595
849
|
}]
|
|
596
850
|
}], 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 }] }] } });
|
|
597
851
|
|
|
852
|
+
class OlHeatmapLayerComponent {
|
|
853
|
+
layerService = inject(OlLayerService);
|
|
854
|
+
mapService = inject(OlMapService);
|
|
855
|
+
destroyRef = inject(DestroyRef);
|
|
856
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
857
|
+
features = input([], ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
|
|
858
|
+
zIndex = input(0, ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
|
|
859
|
+
opacity = input(1, ...(ngDevMode ? [{ debugName: "opacity" }] : /* istanbul ignore next */ []));
|
|
860
|
+
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
861
|
+
blur = input(15, ...(ngDevMode ? [{ debugName: "blur" }] : /* istanbul ignore next */ []));
|
|
862
|
+
radius = input(8, ...(ngDevMode ? [{ debugName: "radius" }] : /* istanbul ignore next */ []));
|
|
863
|
+
/** Unit for radius and blur: 'pixels' (default) or 'meters' */
|
|
864
|
+
radiusUnit = input('pixels', ...(ngDevMode ? [{ debugName: "radiusUnit" }] : /* istanbul ignore next */ []));
|
|
865
|
+
weight = input(...(ngDevMode ? [undefined, { debugName: "weight" }] : /* istanbul ignore next */ []));
|
|
866
|
+
/** Computed radius in pixels based on current resolution if unit is 'meters' */
|
|
867
|
+
scaledRadius = computed(() => {
|
|
868
|
+
const r = this.radius();
|
|
869
|
+
if (this.radiusUnit() === 'pixels')
|
|
870
|
+
return r;
|
|
871
|
+
return r / this.mapService.resolution();
|
|
872
|
+
}, ...(ngDevMode ? [{ debugName: "scaledRadius" }] : /* istanbul ignore next */ []));
|
|
873
|
+
/** Computed blur in pixels based on current resolution if unit is 'meters' */
|
|
874
|
+
scaledBlur = computed(() => {
|
|
875
|
+
const b = this.blur();
|
|
876
|
+
if (this.radiusUnit() === 'pixels')
|
|
877
|
+
return b;
|
|
878
|
+
return b / this.mapService.resolution();
|
|
879
|
+
}, ...(ngDevMode ? [{ debugName: "scaledBlur" }] : /* istanbul ignore next */ []));
|
|
880
|
+
constructor() {
|
|
881
|
+
afterNextRender(() => {
|
|
882
|
+
this.layerService.addLayer({
|
|
883
|
+
id: this.id(),
|
|
884
|
+
type: 'heatmap',
|
|
885
|
+
features: this.features(),
|
|
886
|
+
zIndex: this.zIndex(),
|
|
887
|
+
opacity: this.opacity(),
|
|
888
|
+
visible: this.visible(),
|
|
889
|
+
blur: this.scaledBlur(),
|
|
890
|
+
radius: this.scaledRadius(),
|
|
891
|
+
weight: this.weight(),
|
|
892
|
+
});
|
|
893
|
+
});
|
|
894
|
+
effect(() => {
|
|
895
|
+
const currentFeatures = this.features();
|
|
896
|
+
if (this.layerService.getLayer(this.id())) {
|
|
897
|
+
this.layerService.updateFeatures(this.id(), currentFeatures);
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
effect(() => {
|
|
901
|
+
this.layerService.setOpacity(this.id(), this.opacity());
|
|
902
|
+
});
|
|
903
|
+
effect(() => {
|
|
904
|
+
this.layerService.setVisibility(this.id(), this.visible());
|
|
905
|
+
});
|
|
906
|
+
effect(() => {
|
|
907
|
+
this.layerService.setZIndex(this.id(), this.zIndex());
|
|
908
|
+
});
|
|
909
|
+
effect(() => {
|
|
910
|
+
this.layerService.setHeatmapProperties(this.id(), {
|
|
911
|
+
blur: this.scaledBlur(),
|
|
912
|
+
radius: this.scaledRadius(),
|
|
913
|
+
weight: this.weight(),
|
|
914
|
+
});
|
|
915
|
+
});
|
|
916
|
+
this.destroyRef.onDestroy(() => {
|
|
917
|
+
this.layerService.removeLayer(this.id());
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlHeatmapLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
921
|
+
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 });
|
|
922
|
+
}
|
|
923
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlHeatmapLayerComponent, decorators: [{
|
|
924
|
+
type: Component,
|
|
925
|
+
args: [{
|
|
926
|
+
selector: 'ol-heatmap-layer',
|
|
927
|
+
template: '',
|
|
928
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
929
|
+
}]
|
|
930
|
+
}], 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 }] }] } });
|
|
931
|
+
|
|
932
|
+
// OlWebGLVectorLayerComponent
|
|
933
|
+
// GPU-accelerated vector layer for large datasets (10k+ features).
|
|
934
|
+
// Uses FlatStyleLike instead of ol/style/Style. Must be manually disposed.
|
|
935
|
+
/**
|
|
936
|
+
* GPU-accelerated vector layer for rendering large datasets.
|
|
937
|
+
*
|
|
938
|
+
* Important: Uses WebGL 2 for rendering. Styles must be provided as
|
|
939
|
+
* `FlatStyleLike` objects (not `ol/style/Style` instances).
|
|
940
|
+
* Hit detection is disabled by default for performance.
|
|
941
|
+
*
|
|
942
|
+
* @usageNotes
|
|
943
|
+
* ```html
|
|
944
|
+
* <ol-webgl-vector-layer
|
|
945
|
+
* id="big-dataset"
|
|
946
|
+
* [features]="largeDataset()"
|
|
947
|
+
* [flatStyle]="{
|
|
948
|
+
* 'circle-radius': 6,
|
|
949
|
+
* 'circle-fill-color': ['match', ['get', 'type'], 'alert', 'red', 'blue'],
|
|
950
|
+
* 'stroke-color': '#333',
|
|
951
|
+
* 'stroke-width': 1
|
|
952
|
+
* }"
|
|
953
|
+
* [disableHitDetection]="true">
|
|
954
|
+
* </ol-webgl-vector-layer>
|
|
955
|
+
* ```
|
|
956
|
+
*/
|
|
957
|
+
class OlWebGLVectorLayerComponent {
|
|
958
|
+
mapService = inject(OlMapService);
|
|
959
|
+
destroyRef = inject(DestroyRef);
|
|
960
|
+
/** Unique layer identifier */
|
|
961
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
962
|
+
/** Features to render */
|
|
963
|
+
features = input([], ...(ngDevMode ? [{ debugName: "features" }] : /* istanbul ignore next */ []));
|
|
964
|
+
/** WebGL flat style (required — no default provided) */
|
|
965
|
+
flatStyle = input.required(...(ngDevMode ? [{ debugName: "flatStyle" }] : /* istanbul ignore next */ []));
|
|
966
|
+
/** Z-index for layer ordering */
|
|
967
|
+
zIndex = input(0, ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
|
|
968
|
+
/** Opacity (0–1) */
|
|
969
|
+
opacity = input(1, ...(ngDevMode ? [{ debugName: "opacity" }] : /* istanbul ignore next */ []));
|
|
970
|
+
/** Layer visibility */
|
|
971
|
+
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
972
|
+
/** Disable hit detection for better performance (default: true) */
|
|
973
|
+
disableHitDetection = input(true, ...(ngDevMode ? [{ debugName: "disableHitDetection" }] : /* istanbul ignore next */ []));
|
|
974
|
+
/** Style variables for dynamic expressions (e.g. `['var', 'threshold']`) */
|
|
975
|
+
variables = input(...(ngDevMode ? [undefined, { debugName: "variables" }] : /* istanbul ignore next */ []));
|
|
976
|
+
layer = null;
|
|
977
|
+
vectorSource = new VectorSource();
|
|
978
|
+
constructor() {
|
|
979
|
+
afterNextRender(() => {
|
|
980
|
+
const map = this.mapService.getMap();
|
|
981
|
+
if (!map)
|
|
982
|
+
return;
|
|
983
|
+
this.syncFeatures(this.features());
|
|
984
|
+
try {
|
|
985
|
+
this.layer = new WebGLVectorLayer({
|
|
986
|
+
source: this.vectorSource,
|
|
987
|
+
style: this.flatStyle(),
|
|
988
|
+
visible: this.visible(),
|
|
989
|
+
opacity: this.opacity(),
|
|
990
|
+
zIndex: this.zIndex(),
|
|
991
|
+
disableHitDetection: this.disableHitDetection(),
|
|
992
|
+
...(this.variables() ? { variables: this.variables() } : {}),
|
|
993
|
+
});
|
|
994
|
+
this.layer.set('id', this.id());
|
|
995
|
+
map.addLayer(this.layer);
|
|
996
|
+
}
|
|
997
|
+
catch (err) {
|
|
998
|
+
// WebGL Vector Layer failed to initialize (e.g., not supported by browser)
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
// Reactive feature sync
|
|
1002
|
+
effect(() => {
|
|
1003
|
+
const currentFeatures = this.features();
|
|
1004
|
+
if (this.layer) {
|
|
1005
|
+
this.syncFeatures(currentFeatures);
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
// Reactive style updates
|
|
1009
|
+
effect(() => {
|
|
1010
|
+
this.layer?.setStyle(this.flatStyle());
|
|
1011
|
+
});
|
|
1012
|
+
effect(() => {
|
|
1013
|
+
this.layer?.setOpacity(this.opacity());
|
|
1014
|
+
});
|
|
1015
|
+
effect(() => {
|
|
1016
|
+
this.layer?.setVisible(this.visible());
|
|
1017
|
+
});
|
|
1018
|
+
effect(() => {
|
|
1019
|
+
this.layer?.setZIndex(this.zIndex());
|
|
1020
|
+
});
|
|
1021
|
+
effect(() => {
|
|
1022
|
+
const vars = this.variables();
|
|
1023
|
+
if (vars && this.layer) {
|
|
1024
|
+
this.layer.updateStyleVariables(vars);
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
1027
|
+
// CRITICAL: WebGL layers must be manually disposed
|
|
1028
|
+
this.destroyRef.onDestroy(() => {
|
|
1029
|
+
const map = this.mapService.getMap();
|
|
1030
|
+
if (map && this.layer) {
|
|
1031
|
+
map.removeLayer(this.layer);
|
|
1032
|
+
try {
|
|
1033
|
+
this.layer.dispose();
|
|
1034
|
+
}
|
|
1035
|
+
catch {
|
|
1036
|
+
// Ignore WebGL layer disposal errors (e.g., reading 'deleteBuffer' if renderer not fully initialized)
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Imperatively update style variables without triggering Angular change detection.
|
|
1043
|
+
* Ideal for 60FPS animations (e.g., linked to OlTimeService) where you don't want
|
|
1044
|
+
* to use the declarative [variables] input.
|
|
1045
|
+
*/
|
|
1046
|
+
updateVariables(vars) {
|
|
1047
|
+
if (this.layer) {
|
|
1048
|
+
this.layer.updateStyleVariables(vars);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
syncFeatures(features) {
|
|
1052
|
+
this.vectorSource.clear();
|
|
1053
|
+
if (!features?.length)
|
|
1054
|
+
return;
|
|
1055
|
+
const olFeatures = features.map((feature) => {
|
|
1056
|
+
const geom = feature.geometry;
|
|
1057
|
+
let geometry;
|
|
1058
|
+
if (!geom.coordinates) {
|
|
1059
|
+
geometry = new Point([0, 0]);
|
|
1060
|
+
}
|
|
1061
|
+
else if (geom.type === 'Point') {
|
|
1062
|
+
geometry = new Point(fromLonLat(geom.coordinates));
|
|
1063
|
+
}
|
|
1064
|
+
else if (geom.type === 'LineString') {
|
|
1065
|
+
geometry = new LineString(geom.coordinates.map((c) => fromLonLat(c)));
|
|
1066
|
+
}
|
|
1067
|
+
else if (geom.type === 'Polygon') {
|
|
1068
|
+
geometry = new Polygon(geom.coordinates.map((ring) => ring.map((c) => fromLonLat(c))));
|
|
1069
|
+
}
|
|
1070
|
+
else if (geom.type === 'Circle') {
|
|
1071
|
+
const center = fromLonLat(geom.coordinates);
|
|
1072
|
+
geometry = new Circle$1(center, geom.radius ?? 1000);
|
|
1073
|
+
}
|
|
1074
|
+
else {
|
|
1075
|
+
geometry = new Point([0, 0]);
|
|
1076
|
+
}
|
|
1077
|
+
const olFeature = new OLFeature({
|
|
1078
|
+
geometry,
|
|
1079
|
+
...feature.properties,
|
|
1080
|
+
});
|
|
1081
|
+
olFeature.setId(feature.id);
|
|
1082
|
+
return olFeature;
|
|
1083
|
+
});
|
|
1084
|
+
this.vectorSource.addFeatures(olFeatures);
|
|
1085
|
+
}
|
|
1086
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlWebGLVectorLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1087
|
+
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 });
|
|
1088
|
+
}
|
|
1089
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlWebGLVectorLayerComponent, decorators: [{
|
|
1090
|
+
type: Component,
|
|
1091
|
+
args: [{
|
|
1092
|
+
selector: 'ol-webgl-vector-layer',
|
|
1093
|
+
template: '',
|
|
1094
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1095
|
+
}]
|
|
1096
|
+
}], 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 }] }] } });
|
|
1097
|
+
|
|
1098
|
+
// OlWebGLTileLayerComponent
|
|
1099
|
+
// GPU-accelerated tile layer with style expressions for color manipulation.
|
|
1100
|
+
/**
|
|
1101
|
+
* GPU-accelerated tile layer with color/brightness/contrast expressions.
|
|
1102
|
+
*
|
|
1103
|
+
* Supports the same tile sources as `ol-tile-layer` but renders via WebGL,
|
|
1104
|
+
* enabling GPU-powered color manipulation (brightness, contrast, saturation, gamma).
|
|
1105
|
+
*
|
|
1106
|
+
* @usageNotes
|
|
1107
|
+
* ```html
|
|
1108
|
+
* <ol-webgl-tile-layer
|
|
1109
|
+
* id="satellite-webgl"
|
|
1110
|
+
* source="xyz"
|
|
1111
|
+
* [url]="'https://server.arcgisonline.com/.../{z}/{y}/{x}'"
|
|
1112
|
+
* [tileStyle]="{ brightness: 0.1, contrast: 0.2 }">
|
|
1113
|
+
* </ol-webgl-tile-layer>
|
|
1114
|
+
* ```
|
|
1115
|
+
*/
|
|
1116
|
+
class OlWebGLTileLayerComponent {
|
|
1117
|
+
mapService = inject(OlMapService);
|
|
1118
|
+
destroyRef = inject(DestroyRef);
|
|
1119
|
+
/** Unique layer identifier */
|
|
1120
|
+
id = input.required(...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
|
|
1121
|
+
/** Tile source type */
|
|
1122
|
+
source = input.required(...(ngDevMode ? [{ debugName: "source" }] : /* istanbul ignore next */ []));
|
|
1123
|
+
/** Tile URL template (required for 'xyz' and 'mvt') */
|
|
1124
|
+
url = input(...(ngDevMode ? [undefined, { debugName: "url" }] : /* istanbul ignore next */ []));
|
|
1125
|
+
/** Attribution text */
|
|
1126
|
+
attributions = input(...(ngDevMode ? [undefined, { debugName: "attributions" }] : /* istanbul ignore next */ []));
|
|
1127
|
+
/** WebGL tile style (raster expressions) or flat style (MVT) */
|
|
1128
|
+
tileStyle = input(...(ngDevMode ? [undefined, { debugName: "tileStyle" }] : /* istanbul ignore next */ []));
|
|
1129
|
+
/** Z-index for layer ordering */
|
|
1130
|
+
zIndex = input(0, ...(ngDevMode ? [{ debugName: "zIndex" }] : /* istanbul ignore next */ []));
|
|
1131
|
+
/** Opacity (0–1) */
|
|
1132
|
+
opacity = input(1, ...(ngDevMode ? [{ debugName: "opacity" }] : /* istanbul ignore next */ []));
|
|
1133
|
+
/** Layer visibility */
|
|
1134
|
+
visible = input(true, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
|
|
1135
|
+
/** Preload low-res tiles up to this many zoom levels */
|
|
1136
|
+
preload = input(0, ...(ngDevMode ? [{ debugName: "preload" }] : /* istanbul ignore next */ []));
|
|
1137
|
+
layer = null;
|
|
1138
|
+
constructor() {
|
|
1139
|
+
afterNextRender(() => {
|
|
1140
|
+
const map = this.mapService.getMap();
|
|
1141
|
+
if (!map)
|
|
1142
|
+
return;
|
|
1143
|
+
let tileSource;
|
|
1144
|
+
switch (this.source()) {
|
|
1145
|
+
case 'mvt':
|
|
1146
|
+
tileSource = new VectorTileSource({
|
|
1147
|
+
format: new MVT(),
|
|
1148
|
+
url: this.url(),
|
|
1149
|
+
attributions: this.attributions(),
|
|
1150
|
+
});
|
|
1151
|
+
this.layer = new WebGLVectorTileLayer({
|
|
1152
|
+
source: tileSource,
|
|
1153
|
+
visible: this.visible(),
|
|
1154
|
+
opacity: this.opacity(),
|
|
1155
|
+
zIndex: this.zIndex(),
|
|
1156
|
+
style: this.tileStyle() || {},
|
|
1157
|
+
});
|
|
1158
|
+
break;
|
|
1159
|
+
case 'xyz':
|
|
1160
|
+
tileSource = new XYZ({
|
|
1161
|
+
url: this.url(),
|
|
1162
|
+
attributions: this.attributions(),
|
|
1163
|
+
});
|
|
1164
|
+
this.layer = new WebGLTileLayer({
|
|
1165
|
+
source: tileSource,
|
|
1166
|
+
visible: this.visible(),
|
|
1167
|
+
opacity: this.opacity(),
|
|
1168
|
+
zIndex: this.zIndex(),
|
|
1169
|
+
preload: this.preload(),
|
|
1170
|
+
...(this.tileStyle() ? { style: this.tileStyle() } : {}),
|
|
1171
|
+
});
|
|
1172
|
+
break;
|
|
1173
|
+
case 'osm':
|
|
1174
|
+
default:
|
|
1175
|
+
tileSource = new OSM({
|
|
1176
|
+
attributions: this.attributions(),
|
|
1177
|
+
});
|
|
1178
|
+
this.layer = new WebGLTileLayer({
|
|
1179
|
+
source: tileSource,
|
|
1180
|
+
visible: this.visible(),
|
|
1181
|
+
opacity: this.opacity(),
|
|
1182
|
+
zIndex: this.zIndex(),
|
|
1183
|
+
preload: this.preload(),
|
|
1184
|
+
...(this.tileStyle() ? { style: this.tileStyle() } : {}),
|
|
1185
|
+
});
|
|
1186
|
+
break;
|
|
1187
|
+
}
|
|
1188
|
+
if (this.layer) {
|
|
1189
|
+
this.layer.set('id', this.id());
|
|
1190
|
+
map.addLayer(this.layer);
|
|
1191
|
+
}
|
|
1192
|
+
});
|
|
1193
|
+
effect(() => {
|
|
1194
|
+
this.layer?.setOpacity(this.opacity());
|
|
1195
|
+
});
|
|
1196
|
+
effect(() => {
|
|
1197
|
+
this.layer?.setVisible(this.visible());
|
|
1198
|
+
});
|
|
1199
|
+
effect(() => {
|
|
1200
|
+
this.layer?.setZIndex(this.zIndex());
|
|
1201
|
+
});
|
|
1202
|
+
effect(() => {
|
|
1203
|
+
const style = this.tileStyle();
|
|
1204
|
+
if (style && this.layer) {
|
|
1205
|
+
if (this.source() === 'mvt') {
|
|
1206
|
+
this.layer.setStyle(style);
|
|
1207
|
+
}
|
|
1208
|
+
else {
|
|
1209
|
+
this.layer.setStyle(style);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
});
|
|
1213
|
+
// WebGL tile layers also need manual dispose
|
|
1214
|
+
this.destroyRef.onDestroy(() => {
|
|
1215
|
+
const map = this.mapService.getMap();
|
|
1216
|
+
if (map && this.layer) {
|
|
1217
|
+
map.removeLayer(this.layer);
|
|
1218
|
+
this.layer.dispose();
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlWebGLTileLayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1223
|
+
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 });
|
|
1224
|
+
}
|
|
1225
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlWebGLTileLayerComponent, decorators: [{
|
|
1226
|
+
type: Component,
|
|
1227
|
+
args: [{
|
|
1228
|
+
selector: 'ol-webgl-tile-layer',
|
|
1229
|
+
template: '',
|
|
1230
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1231
|
+
}]
|
|
1232
|
+
}], 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 }] }] } });
|
|
1233
|
+
|
|
598
1234
|
// Provider functions
|
|
599
1235
|
function withLayers() {
|
|
600
1236
|
return { kind: 'layers', providers: [OlLayerService] };
|
|
@@ -609,4 +1245,4 @@ function provideLayers() {
|
|
|
609
1245
|
* Generated bundle index. Do not edit.
|
|
610
1246
|
*/
|
|
611
1247
|
|
|
612
|
-
export { OlImageLayerComponent, OlLayerService, OlTileLayerComponent, OlVectorLayerComponent, provideLayers, withLayers };
|
|
1248
|
+
export { OlClusterComponent, OlHeatmapLayerComponent, OlImageLayerComponent, OlLayerService, OlTileLayerComponent, OlVectorLayerComponent, OlWebGLTileLayerComponent, OlWebGLVectorLayerComponent, provideLayers, withLayers };
|