@angular-helpers/openlayers 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # @angular-helpers/openlayers
2
+
3
+ A modern Angular wrapper for OpenLayers with modular architecture, standalone components, and a hybrid template/programmatic API.
4
+
5
+ ## Features
6
+
7
+ - **Standalone Components** - No NgModule boilerplate, use directly in your components
8
+ - **Signals Integration** - Native Angular signals for reactive state management
9
+ - **Modular Loading** - Import only what you need with AgGrid-style sub-entry points
10
+ - **Dual API** - Template for UI, Inputs for data, Services for operations
11
+ - **Tree-shaking** - Unused OpenLayers code is eliminated from your bundle
12
+ - **TypeScript First** - Full type safety with strict mode support
13
+ - **Military Features** - Ellipses, sectors, NATO symbology, and MGRS coordinates
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @angular-helpers/openlayers ol
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ### 1. Configure in your app
24
+
25
+ ```typescript
26
+ // app.config.ts
27
+ import { ApplicationConfig } from '@angular/core';
28
+ import { provideOpenLayers } from '@angular-helpers/openlayers/core';
29
+ import { withLayers } from '@angular-helpers/openlayers/layers';
30
+ import { withControls } from '@angular-helpers/openlayers/controls';
31
+
32
+ export const appConfig: ApplicationConfig = {
33
+ providers: [provideOpenLayers(withLayers(), withControls())],
34
+ };
35
+ ```
36
+
37
+ ### 2. Use in your component
38
+
39
+ ```typescript
40
+ // map.component.ts
41
+ import { Component, inject, signal } from '@angular/core';
42
+ import { OlMapComponent } from '@angular-helpers/openlayers/core';
43
+ import { OlTileLayerComponent } from '@angular-helpers/openlayers/layers';
44
+ import {
45
+ OlZoomControlComponent,
46
+ OlScaleLineControlComponent,
47
+ } from '@angular-helpers/openlayers/controls';
48
+ import { OlMapService } from '@angular-helpers/openlayers/core';
49
+
50
+ @Component({
51
+ selector: 'app-map',
52
+ standalone: true,
53
+ imports: [
54
+ OlMapComponent,
55
+ OlTileLayerComponent,
56
+ OlZoomControlComponent,
57
+ OlScaleLineControlComponent,
58
+ ],
59
+ template: `
60
+ <ol-map
61
+ [center]="center()"
62
+ [zoom]="zoom()"
63
+ (viewChange)="onViewChange($event)"
64
+ (click)="onMapClick($event)"
65
+ style="display: block; height: 400px;"
66
+ >
67
+ <!-- Base Layer -->
68
+ <ol-tile-layer id="osm" source="osm"></ol-tile-layer>
69
+
70
+ <!-- Controls -->
71
+ <ol-zoom-control></ol-zoom-control>
72
+ <ol-scale-line-control unit="metric"></ol-scale-line-control>
73
+ </ol-map>
74
+
75
+ <p>Clicked: {{ lastClick()?.coordinate | json }}</p>
76
+ `,
77
+ })
78
+ export class MapComponent {
79
+ private mapService = inject(OlMapService);
80
+
81
+ center = signal<[number, number]>([2.2945, 48.8584]);
82
+ zoom = signal<number>(12);
83
+ lastClick = signal<{ coordinate: [number, number]; pixel: [number, number] } | null>(null);
84
+
85
+ onViewChange(state: { center: [number, number]; zoom: number }): void {
86
+ this.center.set(state.center);
87
+ this.zoom.set(state.zoom);
88
+ }
89
+
90
+ onMapClick(event: { coordinate: [number, number]; pixel: [number, number] }): void {
91
+ this.lastClick.set(event);
92
+ }
93
+
94
+ flyToEiffel() {
95
+ this.mapService.animateView({ center: [2.2945, 48.8584], zoom: 15, duration: 1000 });
96
+ }
97
+ }
98
+ ```
99
+
100
+ ## Architecture
101
+
102
+ ### Data vs UI Separation
103
+
104
+ | Use Case | Approach | Example |
105
+ | ------------------------------------ | --------------------------- | ------------------------------------------------------------- |
106
+ | **Data** (features, layers, coords) | `@Input()` | `<ol-vector-layer [features]="data">` |
107
+ | **UI** (buttons, popups, toolbars) | Template/content projection | `<ol-custom-control><button>...</button></ol-custom-control>` |
108
+ | **Operations** (animations, queries) | Service via `inject()` | `this.ol.animateView({...})` |
109
+
110
+ ### Sub-Entry Points
111
+
112
+ Import only what you need:
113
+
114
+ ```typescript
115
+ // Core only (~45KB gzipped)
116
+ import { OlMapComponent, OlMapService } from '@angular-helpers/openlayers';
117
+
118
+ // Add layers (~35KB additional)
119
+ import { OlVectorLayerComponent, withLayers } from '@angular-helpers/openlayers/layers';
120
+
121
+ // Add controls (~15KB additional)
122
+ import { OlCustomControlComponent, withControls } from '@angular-helpers/openlayers/controls';
123
+
124
+ // Add interactions (~40KB additional)
125
+ import {
126
+ OlDrawInteractionComponent,
127
+ withInteractions,
128
+ } from '@angular-helpers/openlayers/interactions';
129
+
130
+ // Add military features (~10KB additional)
131
+ import { OlEllipseFeatureComponent, withMilitary } from '@angular-helpers/openlayers/military';
132
+ ```
133
+
134
+ ## API Reference
135
+
136
+ See the [documentation](https://gaspar1992.github.io/angular-helpers/docs/openlayers) for full API reference and examples.
137
+
138
+ ## Comparison with Other Libraries
139
+
140
+ | Feature | ngx-openlayers | ngx-ol-library | IGO2-lib | **This Library** |
141
+ | --------------------- | -------------- | -------------- | -------- | ------------------------ |
142
+ | Angular 21+ | ❌ | ✅ | ❌ | ✅ |
143
+ | Standalone Components | ❌ | ✅ | ❌ | ✅ |
144
+ | Signals | ❌ | ❌ | ❌ | ✅ |
145
+ | Modular Loading | ❌ | Partial | ❌ | ✅ |
146
+ | Programmatic API | ❌ | ❌ | Partial | ✅ |
147
+ | Military Features | ❌ | ❌ | ❌ | ✅ |
148
+ | Bundle Size | ~180KB | ~200KB | ~500KB | **~145KB (all modules)** |
149
+
150
+ ## License
151
+
152
+ MIT
153
+
154
+ ## Contributing
155
+
156
+ See the main repository for contribution guidelines.
@@ -0,0 +1,224 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, NgZone, input, ChangeDetectionStrategy, Component, Injectable } from '@angular/core';
3
+ import { OlMapService } from '@angular-helpers/openlayers/core';
4
+ import Zoom from 'ol/control/Zoom';
5
+ import Attribution from 'ol/control/Attribution';
6
+ import ScaleLine from 'ol/control/ScaleLine';
7
+ import FullScreen from 'ol/control/FullScreen';
8
+
9
+ // OlZoomControlComponent
10
+ class OlZoomControlComponent {
11
+ mapService = inject(OlMapService);
12
+ ngZone = inject(NgZone);
13
+ delta = input(1, ...(ngDevMode ? [{ debugName: "delta" }] : /* istanbul ignore next */ []));
14
+ duration = input(250, ...(ngDevMode ? [{ debugName: "duration" }] : /* istanbul ignore next */ []));
15
+ control;
16
+ ngOnInit() {
17
+ this.tryAddControl();
18
+ }
19
+ tryAddControl(retryCount = 0) {
20
+ const map = this.mapService.getMap();
21
+ if (!map) {
22
+ if (retryCount < 10) {
23
+ setTimeout(() => this.tryAddControl(retryCount + 1), Math.min(50 * (retryCount + 1), 500));
24
+ }
25
+ return;
26
+ }
27
+ this.ngZone.runOutsideAngular(() => {
28
+ this.control = new Zoom({
29
+ delta: this.delta(),
30
+ duration: this.duration(),
31
+ });
32
+ map.addControl(this.control);
33
+ });
34
+ }
35
+ ngOnDestroy() {
36
+ const map = this.mapService.getMap();
37
+ if (!this.control || !map)
38
+ return;
39
+ this.ngZone.runOutsideAngular(() => {
40
+ map.removeControl(this.control);
41
+ });
42
+ }
43
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlZoomControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
44
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: OlZoomControlComponent, isStandalone: true, selector: "ol-zoom-control", inputs: { delta: { classPropertyName: "delta", publicName: "delta", isSignal: true, isRequired: false, transformFunction: null }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
45
+ }
46
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlZoomControlComponent, decorators: [{
47
+ type: Component,
48
+ args: [{
49
+ selector: 'ol-zoom-control',
50
+ template: '',
51
+ changeDetection: ChangeDetectionStrategy.OnPush,
52
+ }]
53
+ }], propDecorators: { delta: [{ type: i0.Input, args: [{ isSignal: true, alias: "delta", required: false }] }], duration: [{ type: i0.Input, args: [{ isSignal: true, alias: "duration", required: false }] }] } });
54
+
55
+ // OlAttributionControlComponent
56
+ class OlAttributionControlComponent {
57
+ mapService = inject(OlMapService);
58
+ ngZone = inject(NgZone);
59
+ collapsible = input(true, ...(ngDevMode ? [{ debugName: "collapsible" }] : /* istanbul ignore next */ []));
60
+ collapsed = input(true, ...(ngDevMode ? [{ debugName: "collapsed" }] : /* istanbul ignore next */ []));
61
+ control;
62
+ ngOnInit() {
63
+ this.tryAddControl();
64
+ }
65
+ tryAddControl(retryCount = 0) {
66
+ const map = this.mapService.getMap();
67
+ if (!map) {
68
+ if (retryCount < 10) {
69
+ setTimeout(() => this.tryAddControl(retryCount + 1), Math.min(50 * (retryCount + 1), 500));
70
+ }
71
+ return;
72
+ }
73
+ this.ngZone.runOutsideAngular(() => {
74
+ this.control = new Attribution({
75
+ collapsible: this.collapsible(),
76
+ collapsed: this.collapsed(),
77
+ });
78
+ map.addControl(this.control);
79
+ });
80
+ }
81
+ ngOnDestroy() {
82
+ const map = this.mapService.getMap();
83
+ if (!this.control || !map)
84
+ return;
85
+ this.ngZone.runOutsideAngular(() => {
86
+ map.removeControl(this.control);
87
+ });
88
+ }
89
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlAttributionControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
90
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: OlAttributionControlComponent, isStandalone: true, selector: "ol-attribution-control", inputs: { collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
91
+ }
92
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlAttributionControlComponent, decorators: [{
93
+ type: Component,
94
+ args: [{
95
+ selector: 'ol-attribution-control',
96
+ template: '',
97
+ changeDetection: ChangeDetectionStrategy.OnPush,
98
+ }]
99
+ }], propDecorators: { collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }] } });
100
+
101
+ // OlScaleLineControlComponent
102
+ class OlScaleLineControlComponent {
103
+ mapService = inject(OlMapService);
104
+ ngZone = inject(NgZone);
105
+ units = input('metric', ...(ngDevMode ? [{ debugName: "units" }] : /* istanbul ignore next */ []));
106
+ bar = input(false, ...(ngDevMode ? [{ debugName: "bar" }] : /* istanbul ignore next */ []));
107
+ steps = input(4, ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
108
+ control;
109
+ ngOnInit() {
110
+ this.tryAddControl();
111
+ }
112
+ tryAddControl(retryCount = 0) {
113
+ const map = this.mapService.getMap();
114
+ if (!map) {
115
+ if (retryCount < 10) {
116
+ setTimeout(() => this.tryAddControl(retryCount + 1), Math.min(50 * (retryCount + 1), 500));
117
+ }
118
+ return;
119
+ }
120
+ this.ngZone.runOutsideAngular(() => {
121
+ this.control = new ScaleLine({
122
+ units: this.units(),
123
+ bar: this.bar(),
124
+ steps: this.steps(),
125
+ });
126
+ map.addControl(this.control);
127
+ });
128
+ }
129
+ ngOnDestroy() {
130
+ const map = this.mapService.getMap();
131
+ if (!this.control || !map)
132
+ return;
133
+ this.ngZone.runOutsideAngular(() => {
134
+ map.removeControl(this.control);
135
+ });
136
+ }
137
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlScaleLineControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
138
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: OlScaleLineControlComponent, isStandalone: true, selector: "ol-scale-line-control", inputs: { units: { classPropertyName: "units", publicName: "units", isSignal: true, isRequired: false, transformFunction: null }, bar: { classPropertyName: "bar", publicName: "bar", isSignal: true, isRequired: false, transformFunction: null }, steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
139
+ }
140
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlScaleLineControlComponent, decorators: [{
141
+ type: Component,
142
+ args: [{
143
+ selector: 'ol-scale-line-control',
144
+ template: '',
145
+ changeDetection: ChangeDetectionStrategy.OnPush,
146
+ }]
147
+ }], propDecorators: { units: [{ type: i0.Input, args: [{ isSignal: true, alias: "units", required: false }] }], bar: [{ type: i0.Input, args: [{ isSignal: true, alias: "bar", required: false }] }], steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: false }] }] } });
148
+
149
+ // OlFullscreenControlComponent
150
+ class OlFullscreenControlComponent {
151
+ mapService = inject(OlMapService);
152
+ ngZone = inject(NgZone);
153
+ source = input(...(ngDevMode ? [undefined, { debugName: "source" }] : /* istanbul ignore next */ []));
154
+ label = input('⤢', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
155
+ labelActive = input('⤡', ...(ngDevMode ? [{ debugName: "labelActive" }] : /* istanbul ignore next */ []));
156
+ tipLabel = input('Toggle full-screen', ...(ngDevMode ? [{ debugName: "tipLabel" }] : /* istanbul ignore next */ []));
157
+ control;
158
+ ngOnInit() {
159
+ this.tryAddControl();
160
+ }
161
+ tryAddControl(retryCount = 0) {
162
+ const map = this.mapService.getMap();
163
+ if (!map) {
164
+ if (retryCount < 10) {
165
+ setTimeout(() => this.tryAddControl(retryCount + 1), Math.min(50 * (retryCount + 1), 500));
166
+ }
167
+ return;
168
+ }
169
+ this.ngZone.runOutsideAngular(() => {
170
+ this.control = new FullScreen({
171
+ source: this.source(),
172
+ label: this.label(),
173
+ labelActive: this.labelActive(),
174
+ tipLabel: this.tipLabel(),
175
+ });
176
+ map.addControl(this.control);
177
+ });
178
+ }
179
+ ngOnDestroy() {
180
+ const map = this.mapService.getMap();
181
+ if (!this.control || !map)
182
+ return;
183
+ this.ngZone.runOutsideAngular(() => {
184
+ map.removeControl(this.control);
185
+ });
186
+ }
187
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlFullscreenControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
188
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: OlFullscreenControlComponent, isStandalone: true, selector: "ol-fullscreen-control", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, labelActive: { classPropertyName: "labelActive", publicName: "labelActive", isSignal: true, isRequired: false, transformFunction: null }, tipLabel: { classPropertyName: "tipLabel", publicName: "tipLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
189
+ }
190
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlFullscreenControlComponent, decorators: [{
191
+ type: Component,
192
+ args: [{
193
+ selector: 'ol-fullscreen-control',
194
+ template: '',
195
+ changeDetection: ChangeDetectionStrategy.OnPush,
196
+ }]
197
+ }], propDecorators: { source: [{ type: i0.Input, args: [{ isSignal: true, alias: "source", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], labelActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelActive", required: false }] }], tipLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tipLabel", required: false }] }] } });
198
+
199
+ // OlControlService
200
+ class OlControlService {
201
+ addCustomControl(element, position) { }
202
+ removeCustomControl(element) { }
203
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlControlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
204
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlControlService });
205
+ }
206
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlControlService, decorators: [{
207
+ type: Injectable
208
+ }] });
209
+
210
+ // Provider functions
211
+ function withControls() {
212
+ return { kind: 'controls', providers: [OlControlService] };
213
+ }
214
+ function provideControls() {
215
+ return withControls();
216
+ }
217
+
218
+ // @angular-helpers/openlayers/controls
219
+
220
+ /**
221
+ * Generated bundle index. Do not edit.
222
+ */
223
+
224
+ export { OlAttributionControlComponent, OlControlService, OlFullscreenControlComponent, OlScaleLineControlComponent, OlZoomControlComponent, provideControls, withControls };
@@ -0,0 +1,184 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, NgZone, Injectable, input, output, viewChild, effect, ChangeDetectionStrategy, Component, makeEnvironmentProviders } from '@angular/core';
3
+ import OLMap from 'ol/Map';
4
+ import View from 'ol/View';
5
+ import { fromLonLat, toLonLat } from 'ol/proj';
6
+
7
+ // OlMapService
8
+ class OlMapService {
9
+ ngZone = inject(NgZone);
10
+ map = null;
11
+ setMap(map) {
12
+ this.map = map;
13
+ }
14
+ getMap() {
15
+ return this.map;
16
+ }
17
+ getView() {
18
+ return this.map?.getView() ?? null;
19
+ }
20
+ setCenter(coordinate) {
21
+ const view = this.getView();
22
+ if (view)
23
+ this.ngZone.runOutsideAngular(() => view.setCenter(coordinate));
24
+ }
25
+ setZoom(level) {
26
+ const view = this.getView();
27
+ if (view)
28
+ this.ngZone.runOutsideAngular(() => view.setZoom(level));
29
+ }
30
+ fitExtent(extent, options) {
31
+ const view = this.getView();
32
+ if (view)
33
+ this.ngZone.runOutsideAngular(() => view.fit(extent, options));
34
+ }
35
+ animateView(options) {
36
+ const view = this.getView();
37
+ if (!view)
38
+ return Promise.resolve();
39
+ return new Promise((resolve) => {
40
+ this.ngZone.runOutsideAngular(() => {
41
+ view.animate({
42
+ center: options.center,
43
+ zoom: options.zoom,
44
+ rotation: options.rotation,
45
+ duration: options.duration ?? 250,
46
+ }, () => this.ngZone.run(() => resolve()));
47
+ });
48
+ });
49
+ }
50
+ getViewState() {
51
+ const view = this.getView();
52
+ if (!view)
53
+ return { center: [0, 0], zoom: 0, rotation: 0 };
54
+ return {
55
+ center: (view.getCenter() ?? [0, 0]),
56
+ zoom: view.getZoom() ?? 0,
57
+ rotation: view.getRotation() ?? 0,
58
+ };
59
+ }
60
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlMapService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
61
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlMapService });
62
+ }
63
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlMapService, decorators: [{
64
+ type: Injectable
65
+ }] });
66
+
67
+ // OlMapComponent
68
+ class OlMapComponent {
69
+ mapService = inject(OlMapService);
70
+ ngZone = inject(NgZone);
71
+ center = input([0, 0], ...(ngDevMode ? [{ debugName: "center" }] : /* istanbul ignore next */ []));
72
+ zoom = input(0, ...(ngDevMode ? [{ debugName: "zoom" }] : /* istanbul ignore next */ []));
73
+ rotation = input(0, ...(ngDevMode ? [{ debugName: "rotation" }] : /* istanbul ignore next */ []));
74
+ projection = input('EPSG:3857', ...(ngDevMode ? [{ debugName: "projection" }] : /* istanbul ignore next */ []));
75
+ viewChange = output();
76
+ mapClick = output();
77
+ mapDblClick = output();
78
+ mapContainerRef = viewChild.required('mapContainer');
79
+ map;
80
+ constructor() {
81
+ effect(() => {
82
+ const center = this.center();
83
+ if (this.map)
84
+ this.updateCenter(center);
85
+ });
86
+ effect(() => {
87
+ const zoom = this.zoom();
88
+ if (this.map)
89
+ this.updateZoom(zoom);
90
+ });
91
+ effect(() => {
92
+ const rotation = this.rotation();
93
+ if (this.map)
94
+ this.updateRotation(rotation);
95
+ });
96
+ }
97
+ ngAfterViewInit() {
98
+ this.initMap();
99
+ }
100
+ ngOnDestroy() {
101
+ this.destroyMap();
102
+ }
103
+ initMap() {
104
+ const container = this.mapContainerRef().nativeElement;
105
+ this.ngZone.runOutsideAngular(() => {
106
+ const view = new View({
107
+ center: fromLonLat(this.center(), this.projection()),
108
+ zoom: this.zoom(),
109
+ rotation: this.rotation(),
110
+ projection: this.projection(),
111
+ });
112
+ this.map = new OLMap({ target: container, view, layers: [] });
113
+ this.mapService.setMap(this.map);
114
+ view.on('change:center', () => this.ngZone.run(() => this.emitViewChange()));
115
+ view.on('change:resolution', () => this.ngZone.run(() => this.emitViewChange()));
116
+ this.map.on('click', (e) => this.ngZone.run(() => this.mapClick.emit({
117
+ coordinate: e.coordinate,
118
+ pixel: e.pixel,
119
+ })));
120
+ this.map.on('dblclick', (e) => this.ngZone.run(() => this.mapDblClick.emit({
121
+ coordinate: e.coordinate,
122
+ pixel: e.pixel,
123
+ })));
124
+ });
125
+ this.emitViewChange();
126
+ }
127
+ destroyMap() {
128
+ if (this.map) {
129
+ this.ngZone.runOutsideAngular(() => {
130
+ this.map.setTarget(undefined);
131
+ this.map.dispose();
132
+ });
133
+ this.map = undefined;
134
+ this.mapService.setMap(null);
135
+ }
136
+ }
137
+ updateCenter(center) {
138
+ if (this.map) {
139
+ const projectedCenter = fromLonLat(center, this.projection());
140
+ this.ngZone.runOutsideAngular(() => this.map.getView().setCenter(projectedCenter));
141
+ }
142
+ }
143
+ updateZoom(zoom) {
144
+ if (this.map)
145
+ this.ngZone.runOutsideAngular(() => this.map.getView().setZoom(zoom));
146
+ }
147
+ updateRotation(rotation) {
148
+ if (this.map)
149
+ this.ngZone.runOutsideAngular(() => this.map.getView().setRotation(rotation));
150
+ }
151
+ emitViewChange() {
152
+ const view = this.map?.getView();
153
+ if (view) {
154
+ const projectedCenter = view.getCenter() ?? [0, 0];
155
+ const lonLatCenter = toLonLat(projectedCenter, this.projection());
156
+ this.viewChange.emit({
157
+ center: lonLatCenter,
158
+ zoom: view.getZoom() ?? 0,
159
+ rotation: view.getRotation() ?? 0,
160
+ });
161
+ }
162
+ }
163
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlMapComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
164
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.4", type: OlMapComponent, isStandalone: true, selector: "ol-map", inputs: { center: { classPropertyName: "center", publicName: "center", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, rotation: { classPropertyName: "rotation", publicName: "rotation", isSignal: true, isRequired: false, transformFunction: null }, projection: { classPropertyName: "projection", publicName: "projection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { viewChange: "viewChange", mapClick: "mapClick", mapDblClick: "mapDblClick" }, viewQueries: [{ propertyName: "mapContainerRef", first: true, predicate: ["mapContainer"], descendants: true, isSignal: true }], ngImport: i0, template: `<div class="ol-map-container" #mapContainer></div>
165
+ <ng-content />`, isInline: true, styles: [":host{display:block;width:100%;height:100%;position:relative}.ol-map-container{width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
166
+ }
167
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlMapComponent, decorators: [{
168
+ type: Component,
169
+ args: [{ selector: 'ol-map', template: `<div class="ol-map-container" #mapContainer></div>
170
+ <ng-content />`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%;height:100%;position:relative}.ol-map-container{width:100%;height:100%}\n"] }]
171
+ }], ctorParameters: () => [], propDecorators: { center: [{ type: i0.Input, args: [{ isSignal: true, alias: "center", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], rotation: [{ type: i0.Input, args: [{ isSignal: true, alias: "rotation", required: false }] }], projection: [{ type: i0.Input, args: [{ isSignal: true, alias: "projection", required: false }] }], viewChange: [{ type: i0.Output, args: ["viewChange"] }], mapClick: [{ type: i0.Output, args: ["mapClick"] }], mapDblClick: [{ type: i0.Output, args: ["mapDblClick"] }], mapContainerRef: [{ type: i0.ViewChild, args: ['mapContainer', { isSignal: true }] }] } });
172
+
173
+ // Provider functions
174
+ function provideOpenLayers(...features) {
175
+ return makeEnvironmentProviders([OlMapService, ...features.flatMap((f) => f.providers)]);
176
+ }
177
+
178
+ // @angular-helpers/openlayers/core
179
+
180
+ /**
181
+ * Generated bundle index. Do not edit.
182
+ */
183
+
184
+ export { OlMapComponent, OlMapService, provideOpenLayers };
@@ -0,0 +1,34 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable } from '@angular/core';
3
+ import { Observable } from 'rxjs';
4
+
5
+ // OlInteractionService
6
+ class OlInteractionService {
7
+ enableInteraction(type, config) {
8
+ return null;
9
+ }
10
+ disableInteraction(id) { }
11
+ startDrawing(type, options) {
12
+ return new Observable();
13
+ }
14
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
15
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlInteractionService });
16
+ }
17
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: OlInteractionService, decorators: [{
18
+ type: Injectable
19
+ }] });
20
+
21
+ function withInteractions() {
22
+ return { kind: 'interactions', providers: [OlInteractionService] };
23
+ }
24
+ function provideInteractions() {
25
+ return withInteractions();
26
+ }
27
+
28
+ // @angular-helpers/openlayers/interactions
29
+
30
+ /**
31
+ * Generated bundle index. Do not edit.
32
+ */
33
+
34
+ export { OlInteractionService, provideInteractions, withInteractions };