@angular-helpers/openlayers 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,29 +1,346 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable } from '@angular/core';
2
+ import { inject, resource, Injectable } from '@angular/core';
3
+ import { OlGeometryService } from '@angular-helpers/openlayers/core';
4
+ import { Style, Icon, Stroke, RegularShape, Fill } from 'ol/style';
5
+ import { LineString, Point } from 'ol/geom';
3
6
 
4
- // OlMilitaryService
7
+ /**
8
+ * Service exposing geometry helpers and MIL-STD-2525 symbology rendering.
9
+ *
10
+ * - `createEllipse`, `createSector`, `createDonut` are **pure math** and
11
+ * delegate to {@link OlGeometryService} in core.
12
+ * - `createMilSymbol` uses the milsymbol library via Angular resource loading.
13
+ */
5
14
  class OlMilitaryService {
15
+ idCounter = 0;
16
+ geometryService = inject(OlGeometryService);
17
+ /**
18
+ * Resource managing the lazy-loading of the milsymbol library.
19
+ * Angular resource provides native signals for value, loading state, and errors.
20
+ */
21
+ msResource = resource({ ...(ngDevMode ? { debugName: "msResource" } : /* istanbul ignore next */ {}), loader: () => import('milsymbol') });
22
+ /** Signal indicating if the milsymbol library is currently being loaded. */
23
+ isLoading = this.msResource.isLoading;
24
+ constructor() { }
25
+ // ---------------------------------------------------------------------------
26
+ // Geometry helpers (delegated to core)
27
+ // ---------------------------------------------------------------------------
28
+ /**
29
+ * Build a `Feature<Polygon>` approximating an ellipse centered at
30
+ * `config.center`. See {@link EllipseConfig} for parameter semantics.
31
+ */
6
32
  createEllipse(config) {
7
- return { id: 'ellipse-1', geometry: { type: 'Polygon', coordinates: [] } };
33
+ return this.geometryService.createEllipse(config);
8
34
  }
35
+ /**
36
+ * Build a `Feature<Polygon>` for a circular sector (pie slice).
37
+ * See {@link SectorConfig} for parameter semantics.
38
+ */
9
39
  createSector(config) {
10
- return { id: 'sector-1', geometry: { type: 'Polygon', coordinates: [] } };
40
+ return this.geometryService.createSector(config);
41
+ }
42
+ /**
43
+ * Build a `Feature<Polygon>` for a donut (annular ring).
44
+ */
45
+ createDonut(config) {
46
+ return this.geometryService.createDonut(config);
47
+ }
48
+ // ---------------------------------------------------------------------------
49
+ // MIL-STD-2525 symbology (lazy `milsymbol` load)
50
+ // ---------------------------------------------------------------------------
51
+ /**
52
+ * Pre-load the optional `milsymbol` peer dependency.
53
+ * Since resource() starts loading immediately, this simply returns a promise
54
+ * that resolves when the resource is ready.
55
+ */
56
+ async preloadMilsymbol() {
57
+ this.assertBrowser();
58
+ // We can just await the dynamic import again; the browser/bundler will
59
+ // return the same module instantly if already loaded by the resource.
60
+ await import('milsymbol');
61
+ }
62
+ /**
63
+ * Build a MIL-STD-2525 symbol feature asynchronously.
64
+ * Waits for the milsymbol resource to resolve.
65
+ */
66
+ async createMilSymbol(config) {
67
+ this.assertBrowser();
68
+ this.assertSidc(config.sidc);
69
+ // Dynamic import ensures we have the module reference even if called
70
+ // before the resource signal has propagated.
71
+ const msModule = await import('milsymbol');
72
+ return this.buildSymbolFeature(config, msModule);
73
+ }
74
+ /**
75
+ * Build a MIL-STD-2525 symbol feature synchronously.
76
+ * Throws if `milsymbol` resource is not ready.
77
+ */
78
+ createMilSymbolSync(config) {
79
+ this.assertBrowser();
80
+ this.assertSidc(config.sidc);
81
+ const msModule = this.msResource.value();
82
+ if (!msModule) {
83
+ throw new Error('milsymbol is not loaded yet. Call preloadMilsymbol() or use the async createMilSymbol().');
84
+ }
85
+ return this.buildSymbolFeature(config, msModule);
86
+ }
87
+ // ---------------------------------------------------------------------------
88
+ // Internals
89
+ // ---------------------------------------------------------------------------
90
+ nextId(kind) {
91
+ return `${kind}-${++this.idCounter}`;
92
+ }
93
+ buildSymbolFeature(config, msModule) {
94
+ const { sidc, position, properties, quantity, ...rest } = config;
95
+ const milOptions = {
96
+ ...rest,
97
+ ...(quantity !== undefined ? { quantity: String(quantity) } : {}),
98
+ };
99
+ const ms = msModule;
100
+ const SymbolClass = ms.default?.Symbol || ms.Symbol;
101
+ const symbol = new SymbolClass(sidc, milOptions);
102
+ const style = this.symbolToStyleResult(symbol);
103
+ const mergedProperties = { sidc, ...milOptions, ...properties };
104
+ return {
105
+ id: this.nextId('symbol'),
106
+ geometry: { type: 'Point', coordinates: position },
107
+ properties: mergedProperties,
108
+ style: { icon: { src: style.src, size: style.size, anchor: style.anchor } },
109
+ };
110
+ }
111
+ symbolToStyleResult(symbol) {
112
+ const svg = symbol.asSVG();
113
+ const { width, height } = symbol.getSize();
114
+ const { x: ax, y: ay } = symbol.getAnchor();
115
+ return {
116
+ src: `data:image/svg+xml;base64,${this.encodeBase64Utf8(svg)}`,
117
+ size: [width, height],
118
+ anchor: [ax / width, ay / height],
119
+ };
120
+ }
121
+ encodeBase64Utf8(input) {
122
+ return btoa(unescape(encodeURIComponent(input)));
123
+ }
124
+ /**
125
+ * Generates a canvas and anchor for a MIL-STD-2525 symbol.
126
+ * Requires milsymbol to be loaded (synchronous).
127
+ */
128
+ createUnitStyle(sidc, selected = false, size = 30) {
129
+ const msModule = this.msResource.value();
130
+ if (!msModule)
131
+ return null;
132
+ const ms = msModule;
133
+ const SymbolClass = ms.default?.Symbol || ms.Symbol;
134
+ const symbol = new SymbolClass(sidc, {
135
+ size,
136
+ strokeWidth: selected ? 6 : 4,
137
+ });
138
+ const canvas = symbol.asCanvas();
139
+ const anchor = symbol.getAnchor();
140
+ return {
141
+ image: {
142
+ img: canvas,
143
+ size: [canvas.width, canvas.height],
144
+ anchor: [anchor.x / canvas.width, anchor.y / canvas.height],
145
+ },
146
+ zIndex: selected ? 100 : 10,
147
+ };
148
+ }
149
+ assertSidc(sidc) {
150
+ if (typeof sidc !== 'string' || sidc.length < 10) {
151
+ throw new TypeError('sidc must be a non-empty MIL-STD-2525 SIDC string');
152
+ }
153
+ }
154
+ assertBrowser() {
155
+ if (typeof window === 'undefined') {
156
+ throw new Error('createMilSymbol requires a browser environment');
157
+ }
158
+ }
159
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlMilitaryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
160
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlMilitaryService });
161
+ }
162
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlMilitaryService, decorators: [{
163
+ type: Injectable
164
+ }], ctorParameters: () => [] });
165
+
166
+ // Tactical Graphics Service — investigation and prototype for military line drawing
167
+ /**
168
+ * Service providing styles and geometry generators for military tactical graphics
169
+ * such as battle fronts, axes of attack, and boundaries.
170
+ *
171
+ * NOTE: For point symbols (units), it delegates to {@link OlMilitaryService}
172
+ * for lazy-loading `milsymbol`.
173
+ */
174
+ class OlTacticalGraphicsService {
175
+ idCounter = 0;
176
+ militaryService = inject(OlMilitaryService);
177
+ /**
178
+ * Creates a LineString feature representing a battle front.
179
+ */
180
+ createFrontLine(coordinates, direction = 'friendly') {
181
+ return {
182
+ id: this.nextId('front-line'),
183
+ geometry: { type: 'LineString', coordinates },
184
+ properties: { tacticalType: 'front-line', direction },
185
+ };
11
186
  }
12
- addMilSymbol(config) {
187
+ /**
188
+ * Creates a LineString feature representing an attack arrow.
189
+ */
190
+ createAttackArrow(coordinates, direction = 'friendly') {
13
191
  return {
14
- id: `symbol-${config.sidc}`,
15
- geometry: { type: 'Point', coordinates: config.position },
192
+ id: this.nextId('attack-arrow'),
193
+ geometry: { type: 'LineString', coordinates },
194
+ properties: { tacticalType: 'attack-arrow', direction },
16
195
  };
17
196
  }
18
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlMilitaryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
19
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlMilitaryService });
197
+ /**
198
+ * Creates a Polygon feature representing a control zone.
199
+ */
200
+ createControlZone(coordinates, direction = 'friendly') {
201
+ return {
202
+ id: this.nextId('control-zone'),
203
+ geometry: { type: 'Polygon', coordinates },
204
+ properties: { tacticalType: 'control-zone', direction },
205
+ };
206
+ }
207
+ /**
208
+ * Creates a Point feature representing a military unit.
209
+ * @param sidc - Symbol Identification Code (MIL-STD-2525 / APP-6)
210
+ */
211
+ createUnit(coordinate, sidc, name) {
212
+ return {
213
+ id: this.nextId('unit'),
214
+ geometry: { type: 'Point', coordinates: coordinate },
215
+ properties: { tacticalType: 'unit', sidc, name },
216
+ };
217
+ }
218
+ nextId(kind) {
219
+ return `${kind}-${++this.idCounter}`;
220
+ }
221
+ /**
222
+ * Style for Troop Units using milsymbol.
223
+ * NOTE: Requires milsymbol to be pre-loaded via OlMilitaryService.
224
+ */
225
+ createUnitStyle(sidc, selected = false) {
226
+ // We delegate the style calculation to militaryService which handles the lazy-load state.
227
+ const styleProperties = this.militaryService.createUnitStyle(sidc, selected);
228
+ if (!styleProperties)
229
+ return null;
230
+ return new Style({
231
+ image: new Icon({
232
+ img: styleProperties.image.img,
233
+ size: styleProperties.image.size,
234
+ anchor: styleProperties.image.anchor,
235
+ }),
236
+ zIndex: styleProperties.zIndex,
237
+ });
238
+ }
239
+ /**
240
+ * Style for Battle Fronts (Complex LineString with teeth).
241
+ */
242
+ createFrontLineStyle(color, direction = 'friendly') {
243
+ return (feature, resolution) => {
244
+ const geometry = feature.getGeometry();
245
+ if (!(geometry instanceof LineString))
246
+ return [];
247
+ const styles = [
248
+ new Style({
249
+ stroke: new Stroke({
250
+ color,
251
+ width: 3,
252
+ lineDash: direction === 'hostile' ? [10, 10] : undefined,
253
+ }),
254
+ }),
255
+ ];
256
+ const coords = geometry.getCoordinates();
257
+ const stride = 40 * resolution; // Spacing between markers
258
+ let distSoFar = 0;
259
+ for (let i = 0; i < coords.length - 1; i++) {
260
+ const p1 = coords[i];
261
+ const p2 = coords[i + 1];
262
+ const dx = p2[0] - p1[0];
263
+ const dy = p2[1] - p1[1];
264
+ const len = Math.sqrt(dx * dx + dy * dy);
265
+ const angle = Math.atan2(dy, dx);
266
+ while (distSoFar < len) {
267
+ const ratio = distSoFar / len;
268
+ const pos = [p1[0] + dx * ratio, p1[1] + dy * ratio];
269
+ // Add "teeth" or spikes along the line
270
+ styles.push(new Style({
271
+ geometry: new Point(pos),
272
+ image: new RegularShape({
273
+ fill: new Fill({ color }),
274
+ points: direction === 'friendly' ? 20 : 3, // Semicircle vs Triangle
275
+ radius: 6,
276
+ rotation: -angle + (direction === 'friendly' ? 0 : Math.PI / 2),
277
+ angle: direction === 'friendly' ? angle + Math.PI / 2 : 0,
278
+ }),
279
+ }));
280
+ distSoFar += stride;
281
+ }
282
+ distSoFar -= len;
283
+ }
284
+ return styles;
285
+ };
286
+ }
287
+ /**
288
+ * Style for Troop Movements (Arrows).
289
+ */
290
+ createAttackArrowStyle(color) {
291
+ return (feature) => {
292
+ const geometry = feature.getGeometry();
293
+ if (!(geometry instanceof LineString))
294
+ return [];
295
+ const coords = geometry.getCoordinates();
296
+ if (coords.length < 2)
297
+ return [];
298
+ const last = coords[coords.length - 1];
299
+ const prev = coords[coords.length - 2];
300
+ const angle = Math.atan2(last[1] - prev[1], last[0] - prev[0]);
301
+ return [
302
+ new Style({
303
+ stroke: new Stroke({ color, width: 4, lineDash: [8, 4] }),
304
+ }),
305
+ new Style({
306
+ geometry: new Point(last),
307
+ image: new RegularShape({
308
+ fill: new Fill({ color }),
309
+ points: 3,
310
+ radius: 14,
311
+ rotation: -angle + Math.PI / 2,
312
+ }),
313
+ }),
314
+ ];
315
+ };
316
+ }
317
+ /**
318
+ * Style for Control Zones (Polygons).
319
+ */
320
+ createZoneStyle(color, opacity = 0.2) {
321
+ return new Style({
322
+ fill: new Fill({ color: this.hexToRgba(color, opacity) }),
323
+ stroke: new Stroke({ color, width: 2 }),
324
+ });
325
+ }
326
+ hexToRgba(hex, alpha) {
327
+ const r = parseInt(hex.slice(1, 3), 16);
328
+ const g = parseInt(hex.slice(3, 5), 16);
329
+ const b = parseInt(hex.slice(5, 7), 16);
330
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
331
+ }
332
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTacticalGraphicsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
333
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTacticalGraphicsService });
20
334
  }
21
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlMilitaryService, decorators: [{
335
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTacticalGraphicsService, decorators: [{
22
336
  type: Injectable
23
337
  }] });
24
338
 
25
339
  function withMilitary() {
26
- return { kind: 'military', providers: [OlMilitaryService] };
340
+ return {
341
+ kind: 'military',
342
+ providers: [OlMilitaryService, OlTacticalGraphicsService],
343
+ };
27
344
  }
28
345
  function provideMilitary() {
29
346
  return withMilitary();
@@ -35,4 +352,4 @@ function provideMilitary() {
35
352
  * Generated bundle index. Do not edit.
36
353
  */
37
354
 
38
- export { OlMilitaryService, provideMilitary, withMilitary };
355
+ export { OlMilitaryService, OlTacticalGraphicsService, provideMilitary, withMilitary };
@@ -2,6 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { inject, ElementRef, input, output, DestroyRef, effect, ChangeDetectionStrategy, Component, Directive, EnvironmentInjector, ApplicationRef, createComponent, Injectable } from '@angular/core';
3
3
  import Overlay from 'ol/Overlay';
4
4
  import { OlMapService, OlZoneHelper } from '@angular-helpers/openlayers/core';
5
+ import { OlLayerService } from '@angular-helpers/openlayers/layers';
5
6
 
6
7
  // OlPopupComponent — declarative popup with content projection.
7
8
  /**
@@ -106,8 +107,8 @@ class OlPopupComponent {
106
107
  this.overlay = null;
107
108
  this.currentMap = null;
108
109
  }
109
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
110
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.4", type: OlPopupComponent, isStandalone: true, selector: "ol-popup", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, positioning: { classPropertyName: "positioning", publicName: "positioning", isSignal: true, isRequired: false, transformFunction: null }, autoPan: { classPropertyName: "autoPan", publicName: "autoPan", isSignal: true, isRequired: false, transformFunction: null }, closeButton: { classPropertyName: "closeButton", publicName: "closeButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { attributes: { "role": "dialog" } }, ngImport: i0, template: `
110
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlPopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
111
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.13", type: OlPopupComponent, isStandalone: true, selector: "ol-popup", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, positioning: { classPropertyName: "positioning", publicName: "positioning", isSignal: true, isRequired: false, transformFunction: null }, autoPan: { classPropertyName: "autoPan", publicName: "autoPan", isSignal: true, isRequired: false, transformFunction: null }, closeButton: { classPropertyName: "closeButton", publicName: "closeButton", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { attributes: { "role": "dialog" } }, ngImport: i0, template: `
111
112
  @if (closeButton()) {
112
113
  <button type="button" class="ol-popup-close" aria-label="Close" (click)="onCloseClick()">
113
114
  ×
@@ -116,7 +117,7 @@ class OlPopupComponent {
116
117
  <ng-content />
117
118
  `, isInline: true, styles: [":host{display:block;position:relative}.ol-popup-close{position:absolute;top:4px;right:4px;width:20px;height:20px;padding:0;border:none;background:transparent;font-size:16px;line-height:1;cursor:pointer;color:inherit}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
118
119
  }
119
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlPopupComponent, decorators: [{
120
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlPopupComponent, decorators: [{
120
121
  type: Component,
121
122
  args: [{ selector: 'ol-popup', changeDetection: ChangeDetectionStrategy.OnPush, template: `
122
123
  @if (closeButton()) {
@@ -231,10 +232,10 @@ class OlTooltipDirective {
231
232
  this.listener = null;
232
233
  this.currentMap = null;
233
234
  }
234
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
235
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.4", type: OlTooltipDirective, isStandalone: true, selector: "[olTooltip]", inputs: { olTooltip: { classPropertyName: "olTooltip", publicName: "olTooltip", isSignal: true, isRequired: true, transformFunction: null }, olTooltipLayer: { classPropertyName: "olTooltipLayer", publicName: "olTooltipLayer", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
235
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
236
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.13", type: OlTooltipDirective, isStandalone: true, selector: "[olTooltip]", inputs: { olTooltip: { classPropertyName: "olTooltip", publicName: "olTooltip", isSignal: true, isRequired: true, transformFunction: null }, olTooltipLayer: { classPropertyName: "olTooltipLayer", publicName: "olTooltipLayer", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
236
237
  }
237
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlTooltipDirective, decorators: [{
238
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlTooltipDirective, decorators: [{
238
239
  type: Directive,
239
240
  args: [{
240
241
  selector: '[olTooltip]',
@@ -409,10 +410,10 @@ class OlPopupService {
409
410
  this.popups.set(id, { id, overlay, componentRef: ref, dispose });
410
411
  });
411
412
  }
412
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlPopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
413
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlPopupService });
413
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlPopupService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
414
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlPopupService });
414
415
  }
415
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlPopupService, decorators: [{
416
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.13", ngImport: i0, type: OlPopupService, decorators: [{
416
417
  type: Injectable
417
418
  }], ctorParameters: () => [] });
418
419
  // -----------------------------------------------------------------------------
@@ -446,7 +447,7 @@ function applyOverlayConfig(overlay, config) {
446
447
  }
447
448
 
448
449
  function withOverlays() {
449
- return { kind: 'overlays', providers: [OlPopupService] };
450
+ return { kind: 'overlays', providers: [OlLayerService, OlPopupService] };
450
451
  }
451
452
  function provideOverlays() {
452
453
  return withOverlays();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-helpers/openlayers",
3
- "version": "0.3.0",
3
+ "version": "0.5.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": {
@@ -32,9 +32,13 @@
32
32
  "peerDependencies": {
33
33
  "@angular/common": "^21.0.0",
34
34
  "@angular/core": "^21.0.0",
35
+ "milsymbol": "^3.0.0",
35
36
  "ol": "^10.0.0"
36
37
  },
37
38
  "peerDependenciesMeta": {
39
+ "milsymbol": {
40
+ "optional": true
41
+ },
38
42
  "ol": {
39
43
  "optional": false
40
44
  }
@@ -78,4 +82,4 @@
78
82
  "dependencies": {
79
83
  "tslib": "^2.3.0"
80
84
  }
81
- }
85
+ }
@@ -1,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { InjectionToken } from '@angular/core';
2
+ import { InjectionToken, OnInit, ElementRef } from '@angular/core';
3
3
  import OLMap from 'ol/Map';
4
4
  import { OlFeature } from '@angular-helpers/openlayers/core';
5
5
 
@@ -87,7 +87,7 @@ interface LayerSwitcherItem {
87
87
  /** Display name for the layer */
88
88
  name: string;
89
89
  /** Type of the layer */
90
- type: 'vector' | 'tile' | 'image';
90
+ type: 'vector' | 'tile' | 'image' | 'heatmap';
91
91
  /** Whether the layer is currently visible */
92
92
  visible: boolean;
93
93
  /** Opacity of the layer (0-1) */
@@ -114,7 +114,7 @@ type LayerSwitcherPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-
114
114
  * </ol-layer-switcher>
115
115
  * ```
116
116
  */
117
- declare class OlLayerSwitcherComponent {
117
+ declare class OlLayerSwitcherComponent implements OnInit {
118
118
  position: _angular_core.InputSignal<"top-left" | "top-right" | "bottom-left" | "bottom-right">;
119
119
  layers: _angular_core.InputSignal<LayerSwitcherItem[]>;
120
120
  collapsible: _angular_core.InputSignal<boolean>;
@@ -129,6 +129,7 @@ declare class OlLayerSwitcherComponent {
129
129
  opacity: number;
130
130
  }>;
131
131
  protected isCollapsed: _angular_core.WritableSignal<boolean>;
132
+ ngOnInit(): void;
132
133
  toggleCollapsed(): void;
133
134
  toggleLayer(id: string): void;
134
135
  setOpacity(id: string, event: Event): void;
@@ -197,6 +198,25 @@ interface ControlConfig {
197
198
  className?: string;
198
199
  }
199
200
 
201
+ declare class OlGeolocationControlComponent {
202
+ private mapService;
203
+ private zoneHelper;
204
+ private destroyRef;
205
+ position: _angular_core.InputSignal<ControlPosition>;
206
+ trackingChange: _angular_core.OutputEmitterRef<boolean>;
207
+ controlElement: ElementRef<HTMLElement>;
208
+ protected tracking: _angular_core.WritableSignal<boolean>;
209
+ private control?;
210
+ private geolocation?;
211
+ private positionFeature?;
212
+ private accuracyFeature?;
213
+ private layer?;
214
+ constructor();
215
+ toggleTracking(): void;
216
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<OlGeolocationControlComponent, never>;
217
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<OlGeolocationControlComponent, "ol-geolocation-control", never, { "position": { "alias": "position"; "required": false; "isSignal": true; }; }, { "trackingChange": "trackingChange"; }, never, never, true, never>;
218
+ }
219
+
200
220
  declare class OlControlService {
201
221
  addCustomControl(element: HTMLElement, position: ControlPosition): void;
202
222
  removeCustomControl(element: HTMLElement): void;
@@ -211,5 +231,5 @@ declare class OlControlService {
211
231
  declare function withControls(): OlFeature<'controls'>;
212
232
  declare function provideControls(): OlFeature<'controls'>;
213
233
 
214
- export { OlAttributionControlComponent, OlBasemapSwitcherComponent, OlControlService, OlFullscreenControlComponent, OlLayerSwitcherComponent, OlRotateControlComponent, OlScaleLineControlComponent, OlZoomControlComponent, ROTATE_CONTROL_MAP_SERVICE, provideControls, withControls };
234
+ export { OlAttributionControlComponent, OlBasemapSwitcherComponent, OlControlService, OlFullscreenControlComponent, OlGeolocationControlComponent, OlLayerSwitcherComponent, OlRotateControlComponent, OlScaleLineControlComponent, OlZoomControlComponent, ROTATE_CONTROL_MAP_SERVICE, provideControls, withControls };
215
235
  export type { BasemapConfig, BasemapSwitcherPosition, ControlConfig, ControlPosition, LayerSwitcherItem, LayerSwitcherPosition, RotateControlMapService };