@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 +156 -0
- package/fesm2022/angular-helpers-openlayers-controls.mjs +224 -0
- package/fesm2022/angular-helpers-openlayers-core.mjs +184 -0
- package/fesm2022/angular-helpers-openlayers-interactions.mjs +34 -0
- package/fesm2022/angular-helpers-openlayers-layers.mjs +215 -0
- package/fesm2022/angular-helpers-openlayers-military.mjs +38 -0
- package/fesm2022/angular-helpers-openlayers-overlays.mjs +31 -0
- package/fesm2022/angular-helpers-openlayers.mjs +3 -0
- package/package.json +80 -0
- package/types/angular-helpers-openlayers-controls.d.ts +77 -0
- package/types/angular-helpers-openlayers-core.d.ts +144 -0
- package/types/angular-helpers-openlayers-interactions.d.ts +35 -0
- package/types/angular-helpers-openlayers-layers.d.ts +88 -0
- package/types/angular-helpers-openlayers-military.d.ts +33 -0
- package/types/angular-helpers-openlayers-overlays.d.ts +29 -0
- package/types/angular-helpers-openlayers.d.ts +2 -0
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 };
|