@angular-helpers/openlayers 0.5.0 → 0.6.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.
@@ -202,13 +202,34 @@ class OlTooltipDirective {
202
202
  matched = feature;
203
203
  return true;
204
204
  }, {
205
- layerFilter: layerId ? (layer) => layer.get('id') === layerId : undefined,
205
+ layerFilter: layerId
206
+ ? (layer) => layer.get('id') === layerId || !!layer.get('is-spider-layer')
207
+ : undefined,
206
208
  });
207
209
  if (!matched) {
208
210
  tooltip.style.display = 'none';
209
211
  return;
210
212
  }
211
- const value = matched.get(propKey);
213
+ let value = matched.get(propKey);
214
+ if (value === undefined || value === null) {
215
+ // 1. Check if it's a clustered feature
216
+ const features = matched.get('features');
217
+ if (Array.isArray(features) && features.length > 0) {
218
+ if (features.length === 1) {
219
+ value = features[0].get(propKey);
220
+ }
221
+ else {
222
+ value = `${features.length} elementos`;
223
+ }
224
+ }
225
+ else {
226
+ // 2. Check if it's a spider feature
227
+ const spiderFeature = matched.get('spider-feature');
228
+ if (spiderFeature) {
229
+ value = spiderFeature.get(propKey);
230
+ }
231
+ }
232
+ }
212
233
  if (value === undefined || value === null) {
213
234
  tooltip.style.display = 'none';
214
235
  return;
@@ -332,6 +353,7 @@ class OlPopupService {
332
353
  }
333
354
  flushPending(map) {
334
355
  const pending = this.pending.splice(0);
356
+ this.flushSubscribed = false;
335
357
  for (const call of pending) {
336
358
  if (call.kind === 'open') {
337
359
  this.createOrUpdate(call.options.id, call.options, map);
@@ -388,6 +410,8 @@ class OlPopupService {
388
410
  environmentInjector: this.envInjector,
389
411
  elementInjector: options.injector,
390
412
  hostElement,
413
+ // Actually, let's see if createComponent supports bindings. If it does, we pass it.
414
+ // Wait, the original code passed bindings! I will revert to the exact original code for createComponent options!
391
415
  bindings: options.bindings,
392
416
  directives: options.directives?.map((d) => typeof d === 'function' ? d : { type: d.type, bindings: d.bindings ?? [] }),
393
417
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-helpers/openlayers",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Modern Angular wrapper for OpenLayers with modular architecture, standalone components, and hybrid template/programmatic API",
5
5
  "homepage": "https://gaspar1992.github.io/angular-helpers/docs/openlayers",
6
6
  "repository": {
@@ -1,7 +1,7 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { ElementRef, Provider, EnvironmentProviders } from '@angular/core';
2
+ import { ElementRef, Signal, Resource, Provider, EnvironmentProviders } from '@angular/core';
3
3
  import OLMap from 'ol/Map';
4
- import { View } from 'ol';
4
+ import { View, Feature as Feature$1 } from 'ol';
5
5
 
6
6
  type Coordinate = [number, number];
7
7
  type Extent = [number, number, number, number];
@@ -94,6 +94,7 @@ declare class OlMapComponent {
94
94
  zoom: _angular_core.InputSignal<number>;
95
95
  rotation: _angular_core.InputSignal<number>;
96
96
  projection: _angular_core.InputSignal<string>;
97
+ coordinateProjection: _angular_core.InputSignal<string>;
97
98
  viewChange: _angular_core.OutputEmitterRef<ViewState>;
98
99
  mapClick: _angular_core.OutputEmitterRef<MapClickEvent>;
99
100
  mapDblClick: _angular_core.OutputEmitterRef<MapClickEvent>;
@@ -101,6 +102,8 @@ declare class OlMapComponent {
101
102
  private map?;
102
103
  private resizeObserver?;
103
104
  constructor();
105
+ private getProjectedCoordinate;
106
+ private getExternalCoordinate;
104
107
  private initMap;
105
108
  private destroyMap;
106
109
  private updateCenter;
@@ -108,7 +111,7 @@ declare class OlMapComponent {
108
111
  private updateRotation;
109
112
  private emitViewChange;
110
113
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlMapComponent, never>;
111
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlMapComponent, "ol-map", never, { "center": { "alias": "center"; "required": false; "isSignal": true; }; "zoom": { "alias": "zoom"; "required": false; "isSignal": true; }; "rotation": { "alias": "rotation"; "required": false; "isSignal": true; }; "projection": { "alias": "projection"; "required": false; "isSignal": true; }; }, { "viewChange": "viewChange"; "mapClick": "mapClick"; "mapDblClick": "mapDblClick"; }, never, ["*"], true, never>;
114
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlMapComponent, "ol-map", never, { "center": { "alias": "center"; "required": false; "isSignal": true; }; "zoom": { "alias": "zoom"; "required": false; "isSignal": true; }; "rotation": { "alias": "rotation"; "required": false; "isSignal": true; }; "projection": { "alias": "projection"; "required": false; "isSignal": true; }; "coordinateProjection": { "alias": "coordinateProjection"; "required": false; "isSignal": true; }; }, { "viewChange": "viewChange"; "mapClick": "mapClick"; "mapDblClick": "mapDblClick"; }, never, ["*"], true, never>;
112
115
  }
113
116
 
114
117
  /**
@@ -323,6 +326,80 @@ declare class OlGeometryService {
323
326
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<OlGeometryService>;
324
327
  }
325
328
 
329
+ /**
330
+ * Service for orchestrating time-series animations in OpenLayers.
331
+ * Exposes a reactive currentTime signal that updates outside the Angular zone
332
+ * via requestAnimationFrame, ensuring 60FPS WebGL animations without triggering
333
+ * global change detection.
334
+ */
335
+ declare class OlTimeService {
336
+ private zoneHelper;
337
+ private timeSignal;
338
+ private playingSignal;
339
+ private speedSignal;
340
+ private animationFrameId;
341
+ private lastTick;
342
+ readonly currentTime: _angular_core.Signal<number>;
343
+ readonly isPlaying: _angular_core.Signal<boolean>;
344
+ readonly speed: _angular_core.Signal<number>;
345
+ /**
346
+ * Sets the current time manually.
347
+ * @param time Epoch timestamp in milliseconds
348
+ */
349
+ setTime(time: number): void;
350
+ /**
351
+ * Sets the playback speed multiplier.
352
+ * @param speed Multiplier (e.g. 1 = real time, 60 = 1 minute per second)
353
+ */
354
+ setSpeed(speed: number): void;
355
+ /**
356
+ * Starts the time animation loop.
357
+ */
358
+ play(): void;
359
+ /**
360
+ * Pauses the time animation loop.
361
+ */
362
+ pause(): void;
363
+ /**
364
+ * Stops the animation and resets to a specific time.
365
+ */
366
+ stop(resetTime?: number): void;
367
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlTimeService, never>;
368
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<OlTimeService>;
369
+ }
370
+
371
+ interface VectorResourceOptions {
372
+ /** Optional custom fetch options */
373
+ fetchOptions?: RequestInit;
374
+ }
375
+ /**
376
+ * Creates an Angular resource for fetching and decoding GeoJSON into OpenLayers Features.
377
+ * Must be called in an injection context.
378
+ *
379
+ * @param url The URL signal or string to fetch data from
380
+ * @param options Additional vector resource options
381
+ * @returns An Angular Resource containing an array of parsed Features
382
+ */
383
+ declare function createVectorResource(url: Signal<string | undefined>, options?: VectorResourceOptions): Resource<Feature[]>;
384
+
385
+ interface ProjectionOptions {
386
+ sourceProjection?: string;
387
+ targetProjection?: string;
388
+ }
389
+ /**
390
+ * Converts an OpenLayers feature to the internal Feature format.
391
+ * Handles coordinate extraction and geometry type mapping with custom projections.
392
+ *
393
+ * @param olFeature - The OpenLayers feature to convert
394
+ * @param options - Projection source and target codes
395
+ * @returns The converted Feature with normalized structure
396
+ */
397
+ declare function olFeatureToFeature(olFeature: Feature$1, options?: ProjectionOptions): Feature;
398
+ /**
399
+ * Converts an internal Feature to an OpenLayers feature.
400
+ */
401
+ declare function featureToOlFeature(feature: Feature, options?: ProjectionOptions): Feature$1;
402
+
326
403
  type OlFeatureKind = 'layers' | 'controls' | 'interactions' | 'overlays' | 'military' | 'projections';
327
404
  interface OlFeature<Kind extends OlFeatureKind> {
328
405
  kind: Kind;
@@ -344,5 +421,5 @@ interface Proj4Definition {
344
421
  */
345
422
  declare function withProjections(proj4: any, definitions: Proj4Definition[]): OlFeature<'projections'>;
346
423
 
347
- export { OlGeometryService, OlMapComponent, OlMapService, OlZoneHelper, provideOpenLayers, withProjections };
348
- export type { AnimationOptions, Coordinate, DonutConfig, EllipseConfig, Extent, Feature, FitOptions, Geometry, GeometryType, Layer, MapClickEvent, MapConfig, MapViewOptions, OlFeature, OlFeatureKind, Pixel, Proj4Definition, ProjectionCode, SectorConfig, Style, ViewState };
424
+ export { OlGeometryService, OlMapComponent, OlMapService, OlTimeService, OlZoneHelper, createVectorResource, featureToOlFeature, olFeatureToFeature, provideOpenLayers, withProjections };
425
+ export type { AnimationOptions, Coordinate, DonutConfig, EllipseConfig, Extent, Feature, FitOptions, Geometry, GeometryType, Layer, MapClickEvent, MapConfig, MapViewOptions, OlFeature, OlFeatureKind, Pixel, Proj4Definition, ProjectionCode, SectorConfig, Style, VectorResourceOptions, ViewState };
@@ -2,11 +2,9 @@ import * as rxjs from 'rxjs';
2
2
  import * as _angular_helpers_openlayers_interactions from '@angular-helpers/openlayers/interactions';
3
3
  import * as _angular_core from '@angular/core';
4
4
  import { Provider } from '@angular/core';
5
- import * as _angular_helpers_openlayers_core from '@angular-helpers/openlayers/core';
6
5
  import { Feature, OlFeature } from '@angular-helpers/openlayers/core';
7
6
  import Interaction from 'ol/interaction/Interaction';
8
7
  import OLMap from 'ol/Map';
9
- import { Feature as Feature$1 } from 'ol';
10
8
 
11
9
  type InteractionType = 'select' | 'draw' | 'modify' | 'dragAndDrop';
12
10
  interface InteractionConfig {
@@ -88,7 +86,8 @@ declare class OlInteractionService {
88
86
  private selectService;
89
87
  private drawService;
90
88
  private modifyService;
91
- readonly selectedFeatures: _angular_core.Signal<_angular_helpers_openlayers_core.Feature[]>;
89
+ readonly selectedFeatures: _angular_core.Signal<Feature[]>;
90
+ readonly hoveredFeature: _angular_core.Signal<Feature>;
92
91
  readonly selectionCount: _angular_core.Signal<number>;
93
92
  readonly hasSelection: _angular_core.Signal<boolean>;
94
93
  readonly activeInteractions: _angular_core.Signal<_angular_helpers_openlayers_interactions.ManagedInteraction[]>;
@@ -178,11 +177,13 @@ interface ManagedInteraction {
178
177
  declare class InteractionStateService {
179
178
  private interactions;
180
179
  private selectedFeaturesInternal;
180
+ private hoveredFeatureInternal;
181
181
  private drawStartSubject;
182
182
  private drawEndSubject;
183
183
  private modifySubject;
184
184
  private selectSubject;
185
185
  readonly selectedFeatures: _angular_core.Signal<Feature[]>;
186
+ readonly hoveredFeature: _angular_core.Signal<Feature>;
186
187
  readonly selectionCount: _angular_core.Signal<number>;
187
188
  readonly hasSelection: _angular_core.Signal<boolean>;
188
189
  readonly activeInteractions: _angular_core.Signal<ManagedInteraction[]>;
@@ -221,6 +222,11 @@ declare class InteractionStateService {
221
222
  * Clears the current selection.
222
223
  */
223
224
  clearSelection(): void;
225
+ /**
226
+ * Sets the currently hovered feature.
227
+ * @param feature - The hovered feature or null
228
+ */
229
+ setHoveredFeature(feature: Feature | null): void;
224
230
  /**
225
231
  * Emits a draw start event.
226
232
  * @param event - The draw start event data
@@ -340,15 +346,6 @@ declare class MeasurementInteractionService {
340
346
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<MeasurementInteractionService>;
341
347
  }
342
348
 
343
- /**
344
- * Converts an OpenLayers feature to the internal Feature format.
345
- * Handles coordinate extraction and geometry type mapping.
346
- *
347
- * @param olFeature - The OpenLayers feature to convert
348
- * @returns The converted Feature with normalized structure
349
- */
350
- declare function olFeatureToFeature(olFeature: Feature$1): Feature;
351
-
352
349
  /**
353
350
  * Declarative component to configure an OpenLayers Draw Interaction.
354
351
  */
@@ -444,5 +441,5 @@ declare function withModifyInteraction(id: string, config?: ModifyConfig): Provi
444
441
  */
445
442
  declare function withMeasurementInteraction(): Provider;
446
443
 
447
- export { DrawInteractionService, InteractionStateService, MeasurementInteractionService, ModifyInteractionService, OlDrawInteractionComponent, OlInteractionService, OlModifyInteractionComponent, OlSelectInteractionComponent, SelectInteractionService, olFeatureToFeature, provideInteractions, withDrawInteraction, withInteractions, withMeasurementInteraction, withModifyInteraction, withSelectInteraction };
444
+ export { DrawInteractionService, InteractionStateService, MeasurementInteractionService, ModifyInteractionService, OlDrawInteractionComponent, OlInteractionService, OlModifyInteractionComponent, OlSelectInteractionComponent, SelectInteractionService, provideInteractions, withDrawInteraction, withInteractions, withMeasurementInteraction, withModifyInteraction, withSelectInteraction };
448
445
  export type { DragAndDropConfig, DrawConfig, DrawEndEvent, DrawStartEvent, InteractionConfig, InteractionState, InteractionType, ManagedInteraction, ModifyConfig, ModifyEvent, SelectConfig, SelectEvent };
@@ -21,6 +21,10 @@ interface ClusterConfig {
21
21
  showCount?: boolean;
22
22
  /** Style for individual features when clustering */
23
23
  featureStyle?: Style;
24
+ /** Automatically spiderfy overlapping points on click (default: false) */
25
+ spiderfyOnSelect?: boolean;
26
+ /** Callback when a spider leg feature is clicked */
27
+ onSpiderfyClick?: (feature: Feature) => void;
24
28
  }
25
29
  interface VectorLayerConfig extends LayerConfig {
26
30
  type: 'vector';
@@ -29,6 +33,7 @@ interface VectorLayerConfig extends LayerConfig {
29
33
  format?: 'geojson' | 'topojson' | 'kml';
30
34
  style?: Style | ((feature: Feature) => Style);
31
35
  cluster?: ClusterConfig;
36
+ coordinateProjection?: string;
32
37
  }
33
38
  interface HeatmapLayerConfig extends LayerConfig {
34
39
  type: 'heatmap';
@@ -64,8 +69,10 @@ declare class OlClusterComponent {
64
69
  minDistance: _angular_core.InputSignal<number>;
65
70
  showCount: _angular_core.InputSignal<boolean>;
66
71
  featureStyle: _angular_core.InputSignal<Style>;
72
+ spiderfyOnSelect: _angular_core.InputSignal<boolean>;
73
+ spiderfyClick: _angular_core.OutputEmitterRef<Feature>;
67
74
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlClusterComponent, never>;
68
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlClusterComponent, "ol-cluster", never, { "distance": { "alias": "distance"; "required": false; "isSignal": true; }; "minDistance": { "alias": "minDistance"; "required": false; "isSignal": true; }; "showCount": { "alias": "showCount"; "required": false; "isSignal": true; }; "featureStyle": { "alias": "featureStyle"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
75
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlClusterComponent, "ol-cluster", never, { "distance": { "alias": "distance"; "required": false; "isSignal": true; }; "minDistance": { "alias": "minDistance"; "required": false; "isSignal": true; }; "showCount": { "alias": "showCount"; "required": false; "isSignal": true; }; "featureStyle": { "alias": "featureStyle"; "required": false; "isSignal": true; }; "spiderfyOnSelect": { "alias": "spiderfyOnSelect"; "required": false; "isSignal": true; }; }, { "spiderfyClick": "spiderfyClick"; }, never, never, true, never>;
69
76
  }
70
77
 
71
78
  declare class OlVectorLayerComponent {
@@ -81,9 +88,10 @@ declare class OlVectorLayerComponent {
81
88
  style: _angular_core.InputSignal<any>;
82
89
  cluster: _angular_core.InputSignal<ClusterConfig>;
83
90
  clusterComponent: _angular_core.Signal<OlClusterComponent>;
91
+ coordinateProjection: _angular_core.InputSignal<string>;
84
92
  constructor();
85
93
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlVectorLayerComponent, never>;
86
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlVectorLayerComponent, "ol-vector-layer", never, { "id": { "alias": "id"; "required": true; "isSignal": true; }; "features": { "alias": "features"; "required": false; "isSignal": true; }; "url": { "alias": "url"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; "opacity": { "alias": "opacity"; "required": false; "isSignal": true; }; "visible": { "alias": "visible"; "required": false; "isSignal": true; }; "style": { "alias": "style"; "required": false; "isSignal": true; }; "cluster": { "alias": "cluster"; "required": false; "isSignal": true; }; }, {}, ["clusterComponent"], never, true, never>;
94
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlVectorLayerComponent, "ol-vector-layer", never, { "id": { "alias": "id"; "required": true; "isSignal": true; }; "features": { "alias": "features"; "required": false; "isSignal": true; }; "url": { "alias": "url"; "required": false; "isSignal": true; }; "format": { "alias": "format"; "required": false; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; "opacity": { "alias": "opacity"; "required": false; "isSignal": true; }; "visible": { "alias": "visible"; "required": false; "isSignal": true; }; "style": { "alias": "style"; "required": false; "isSignal": true; }; "cluster": { "alias": "cluster"; "required": false; "isSignal": true; }; "coordinateProjection": { "alias": "coordinateProjection"; "required": false; "isSignal": true; }; }, {}, ["clusterComponent"], never, true, never>;
87
95
  }
88
96
 
89
97
  declare class OlTileLayerComponent {
@@ -185,6 +193,12 @@ declare class OlWebGLVectorLayerComponent {
185
193
  private layer;
186
194
  private vectorSource;
187
195
  constructor();
196
+ /**
197
+ * Imperatively update style variables without triggering Angular change detection.
198
+ * Ideal for 60FPS animations (e.g., linked to OlTimeService) where you don't want
199
+ * to use the declarative [variables] input.
200
+ */
201
+ updateVariables(vars: Record<string, string | number | boolean | number[]>): void;
188
202
  private syncFeatures;
189
203
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlWebGLVectorLayerComponent, never>;
190
204
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlWebGLVectorLayerComponent, "ol-webgl-vector-layer", never, { "id": { "alias": "id"; "required": true; "isSignal": true; }; "features": { "alias": "features"; "required": false; "isSignal": true; }; "flatStyle": { "alias": "flatStyle"; "required": true; "isSignal": true; }; "zIndex": { "alias": "zIndex"; "required": false; "isSignal": true; }; "opacity": { "alias": "opacity"; "required": false; "isSignal": true; }; "visible": { "alias": "visible"; "required": false; "isSignal": true; }; "disableHitDetection": { "alias": "disableHitDetection"; "required": false; "isSignal": true; }; "variables": { "alias": "variables"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
@@ -245,6 +259,7 @@ declare class OlLayerService {
245
259
  private layerCache;
246
260
  private pendingConfigs;
247
261
  private layerState;
262
+ private spiderManager;
248
263
  readonly layers: _angular_core.Signal<LayerInfo[]>;
249
264
  readonly visibleLayers: _angular_core.Signal<LayerInfo[]>;
250
265
  readonly tileLayers: _angular_core.Signal<LayerInfo[]>;
@@ -261,6 +276,8 @@ declare class OlLayerService {
261
276
  toggleVisibility(id: string): boolean;
262
277
  setOpacity(id: string, opacity: number): void;
263
278
  setZIndex(id: string, zIndex: number): void;
279
+ setClusterDistance(id: string, distance: number): void;
280
+ setClusterMinDistance(id: string, minDistance: number): void;
264
281
  setHeatmapProperties(id: string, props: {
265
282
  blur?: number;
266
283
  radius?: number;
@@ -269,24 +286,9 @@ declare class OlLayerService {
269
286
  isVisible(id: string): boolean;
270
287
  getOpacity(id: string): number;
271
288
  getZIndex(id: string): number;
272
- /**
273
- * Clears all features from a vector layer's source.
274
- * Does not remove the layer itself.
275
- * @param id - Layer identifier
276
- */
277
289
  clearFeatures(id: string): void;
278
- /**
279
- * Updates the features of a vector layer.
280
- * Syncs new features without clearing existing ones (preserves OL modifications).
281
- * @param id - Layer identifier
282
- * @param features - New features to sync
283
- */
284
290
  updateFeatures(id: string, features: VectorLayerConfig['features']): void;
285
291
  private updateLayerState;
286
- private createVectorLayer;
287
- private createHeatmapLayer;
288
- private createTileLayer;
289
- private createImageLayer;
290
292
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlLayerService, never>;
291
293
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<OlLayerService>;
292
294
  }