@bluehalo/ngx-leaflet 21.2.0 → 21.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.md +6 -0
- package/LICENSE +1 -1
- package/README.md +42 -410
- package/fesm2022/bluehalo-ngx-leaflet.mjs +19 -19
- package/package.json +5 -4
package/CHANGES.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 21.2.1
|
|
4
|
+
- Docs: restructured README — extracted API reference and Recipes to docs/; added Angular component popup pattern to Recipes
|
|
5
|
+
- Tests: expanded unit test coverage to 91 tests across all directives; added Codecov integration
|
|
6
|
+
- CI: upgraded to Node 24, actions/checkout and actions/setup-node to v6
|
|
7
|
+
- Chore: updated copyright to BlueHalo LLC; added npm version badge
|
|
8
|
+
|
|
3
9
|
## 21.2.0
|
|
4
10
|
Add `(leafletOverlayAdd)` and `(leafletOverlayRemove)` output bindings to the `[leafletLayersControl]` directive. These pass through Leaflet's `overlayadd` and `overlayremove` map events, which fire when a user checks or unchecks an overlay in the layers control. Event data is typed as `LayersControlEvent` (provides `layer` and `name`). Closes #285.
|
|
5
11
|
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
# @bluehalo/ngx-leaflet
|
|
2
2
|
|
|
3
|
+
<p align="left">
|
|
4
|
+
<img src="assets/logo.svg" alt="ngx-leaflet" width="200">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
[![NPM version][npm-image]][npm-url]
|
|
3
8
|
[![Build Status][ci-image]][ci-url]
|
|
9
|
+
[![Code Coverage][coverage-image]][coverage-url]
|
|
4
10
|
|
|
11
|
+
[npm-url]: https://www.npmjs.com/package/@bluehalo/ngx-leaflet
|
|
12
|
+
[npm-image]: https://img.shields.io/npm/v/%40bluehalo%2Fngx-leaflet
|
|
5
13
|
[ci-url]: https://github.com/bluehalo/ngx-leaflet/actions/workflows/ci.yml
|
|
6
14
|
[ci-image]: https://github.com/bluehalo/ngx-leaflet/actions/workflows/ci.yml/badge.svg
|
|
15
|
+
[coverage-url]: https://codecov.io/gh/bluehalo/ngx-leaflet
|
|
16
|
+
[coverage-image]: https://codecov.io/gh/bluehalo/ngx-leaflet/graph/badge.svg
|
|
7
17
|
|
|
8
18
|
> Leaflet packages for Angular.io.
|
|
9
19
|
> Provides flexible and extensible components for integrating Leaflet v0.7.x and v1.x into Angular.io projects.
|
|
@@ -11,8 +21,9 @@
|
|
|
11
21
|
## Table of Contents
|
|
12
22
|
- [Install](#install)
|
|
13
23
|
- [Usage](#usage)
|
|
14
|
-
- [API](
|
|
24
|
+
- [API](docs/API.md)
|
|
15
25
|
- [Extensions](#extensions)
|
|
26
|
+
- [Cookbook](docs/cookbook.md)
|
|
16
27
|
- [Getting Help](#help)
|
|
17
28
|
- [Contribute](#contribute)
|
|
18
29
|
- [License](#license)
|
|
@@ -80,39 +91,7 @@ If you are using Angular CLI, you will need to add the Leaflet CSS file to the s
|
|
|
80
91
|
|
|
81
92
|
#### A Note About Markers
|
|
82
93
|
Leaflet marker URLs don't play well with the Angular CLI build pipeline without some special handling.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
1. Include the leaflet marker assets so they are copied intact to the build output.
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
...
|
|
89
|
-
"assets": [
|
|
90
|
-
{
|
|
91
|
-
"glob": "**/*",
|
|
92
|
-
"input": "public"
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
"glob": "**/*",
|
|
96
|
-
"input": "./node_modules/leaflet/dist/images",
|
|
97
|
-
"output": "assets/"
|
|
98
|
-
}
|
|
99
|
-
],
|
|
100
|
-
...
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
1. Configure Leaflet to use the asset URLs as custom marker images.
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
let layer = marker([ 46.879966, -121.726909 ], {
|
|
108
|
-
icon: icon({
|
|
109
|
-
...Icon.Default.prototype.options,
|
|
110
|
-
iconUrl: 'assets/marker-icon.png',
|
|
111
|
-
iconRetinaUrl: 'assets/marker-icon-2x.png',
|
|
112
|
-
shadowUrl: 'assets/marker-shadow.png'
|
|
113
|
-
})
|
|
114
|
-
});
|
|
115
|
-
```
|
|
94
|
+
See [Marker Setup](docs/cookbook.md#marker-setup) in the cookbook for the full configuration steps.
|
|
116
95
|
|
|
117
96
|
|
|
118
97
|
### Import LeafletDirective
|
|
@@ -258,410 +237,63 @@ layer = circle([ 46.95, -122 ], { radius: 5000 });
|
|
|
258
237
|
```
|
|
259
238
|
|
|
260
239
|
|
|
261
|
-
### Dynamically Change Map Layers
|
|
262
|
-
|
|
263
|
-
> **Layer inputs (arrays and maps) are mutable**
|
|
264
|
-
> Previous versions of this plugin treated layers arrays and layer control objects as immutable data structures.
|
|
265
|
-
> We've changed that behavior.
|
|
266
|
-
> Now, mutable changes to the ```leafletLayers```, ```leafletBaseLayers```, and ```leafletLayersControl``` inputs are detected.
|
|
267
|
-
|
|
268
|
-
The plugin is now using internal ngx iterable and key/value differs to detect and track changes to mutable data structures.
|
|
269
|
-
This approach requires a deep compare of the contents of the data structure (which can be slow when the contents are really big).
|
|
270
|
-
For immutable data structures, all that is needed is a top-level instance equality check (which is way faster).
|
|
271
|
-
This change is backwards compatible and was motivated by feedback and confusion.
|
|
272
|
-
While there is a performance impact for some use cases, this approach is more intuitive.
|
|
273
|
-
|
|
274
|
-
There are at least two good approaches to improving performance when there are a lot of layers bound to the map.
|
|
275
|
-
First, you can use the OnPush change detection strategy. There's an example of this in the demo.
|
|
276
|
-
Second, you can wrap a large number of layers into a Leaflet layer group, which will reduce the number of layers the plugin actually has to track during diffs.
|
|
240
|
+
### Dynamically Change Map Layers
|
|
241
|
+
The `[leafletLayers]`, `[leafletBaseLayers]`, and `[leafletLayersControl]` inputs detect mutable changes using Angular's iterable/key-value differs. For details on performance trade-offs and how syncing works, see the [API reference](docs/API.md#dynamically-change-map-layers).
|
|
277
242
|
|
|
278
243
|
|
|
279
244
|
### Working with Leaflet Events
|
|
280
245
|
Often, you'll want to make changes based on a map click or other Leaflet interaction.
|
|
281
|
-
The ngx-leaflet plugin supports several [map events](#map-events) and [layer events](#layer-events) as documented in the API
|
|
246
|
+
The ngx-leaflet plugin supports several [map events](docs/API.md#map-events) and [layer events](docs/API.md#layer-events) as documented in the API reference.
|
|
282
247
|
|
|
283
248
|
You may occasionally need to handle events that aren't exposed through the plugin, however.
|
|
284
249
|
When that happens, you will need to be aware of how Zones and change detection work to ensure your event handling works as expected.
|
|
285
|
-
Take a look at [A Note About Change Detection](#a-note-about-change-detection) for more details.
|
|
250
|
+
Take a look at [A Note About Change Detection](docs/API.md#a-note-about-change-detection) for more details.
|
|
286
251
|
This is by design and a common thing to deal with when using third party libraries and Angular.
|
|
287
252
|
|
|
288
253
|
|
|
289
254
|
## API
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
[leafletOptions]="options"
|
|
298
|
-
[leafletPanOptions]="panOptions"
|
|
299
|
-
[leafletZoomOptions]="zoomOptions"
|
|
300
|
-
[leafletZoomPanOptions]="zoomPanOptions"
|
|
301
|
-
[leafletFitBoundsOptions]="fitBoundsOptions">
|
|
302
|
-
</div>
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
#### [leafletOptions]
|
|
306
|
-
Input binding for the initial leaflet map options (see [Leaflet's](https://leafletjs.com/reference.html#map-option) docs). These options can only be set initially because they are used to create the map. Later changes are ignored.
|
|
307
|
-
|
|
308
|
-
#### [leafletPanOptions]
|
|
309
|
-
Input binding for pan options (see [Leaflet's](https://leafletjs.com/reference.html#pan-options) docs). These options are stored and used whenever pan operations are invoked.
|
|
310
|
-
|
|
311
|
-
#### [leafletZoomOptions]
|
|
312
|
-
Input binding for zoom options (see [Leaflet's](https://leafletjs.com/reference.html#zoom-options) docs). These options are stored and used whenever zoom operations are invoked.
|
|
313
|
-
|
|
314
|
-
#### [leafletZoomPanOptions]
|
|
315
|
-
Input binding for zoom/pan options (see [Leaflet's](https://leafletjs.com/reference.html#zoom/pan-options) docs). These options are stored and used whenever zoom/pan operations are invoked.
|
|
316
|
-
|
|
317
|
-
#### [leafletFitBoundsOptions]
|
|
318
|
-
Input binding for FitBounds options (see [Leaflet's](https://leafletjs.com/reference.html#fitbounds-options) docs). These options are stored and used whenever FitBounds operations are invoked.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
### Dynamically changing zoom level, center, fitBounds, etc.
|
|
322
|
-
```angular181html
|
|
323
|
-
<div leaflet style="height: 300px;"
|
|
324
|
-
[leafletOptions]="options"
|
|
325
|
-
[(leafletZoom)]="zoom"
|
|
326
|
-
[(leafletCenter)]="center"
|
|
327
|
-
[leafletFitBounds]="fitBounds">
|
|
328
|
-
</div>
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
#### [(leafletZoom)]: number
|
|
332
|
-
Input and Output binding for the map zoom level.
|
|
333
|
-
|
|
334
|
-
#### [leafletMaxZoom]: number
|
|
335
|
-
Input binding for the maximum zoom level for the map.
|
|
336
|
-
|
|
337
|
-
#### [leafletMinZoom]: number
|
|
338
|
-
Input binding for the minimum zoom level for the map.
|
|
339
|
-
|
|
340
|
-
#### [(leafletCenter)]: LatLng
|
|
341
|
-
Input and Output binding for the map center position.
|
|
342
|
-
|
|
343
|
-
#### Note: center/zoom operations may interfere with each other
|
|
344
|
-
Zoom/Center operations that are applied in rapid succession may interfere with or cancel each other.
|
|
345
|
-
If both changes are picked up at the same time, the component applies the changes as a map.setView() operation to ensure both are processed.
|
|
346
|
-
Additionally, if a zoom level or center is applied that is not allowed (e.g., beyond max zoom level or outside of max bounds), Leaflet will determine the new value.
|
|
347
|
-
|
|
348
|
-
#### [leafletFitBounds]: LatLngBounds
|
|
349
|
-
Input bind a ```LatLngBounds``` value that will be applied to the map using ```Map.setFitBounds()```.
|
|
350
|
-
This operation has no output binding because the input fitBounds usually results in a slightly different map bounds.
|
|
255
|
+
Full API documentation is in [docs/API.md](docs/API.md). It covers:
|
|
256
|
+
- Advanced map configuration inputs (`[leafletPanOptions]`, `[leafletZoomOptions]`, etc.)
|
|
257
|
+
- Dynamically changing zoom, center, and fitBounds
|
|
258
|
+
- Layer management: `[leafletBaseLayers]`, `[leafletLayers]`, `[leafletLayersControl]`, `[leafletLayer]`
|
|
259
|
+
- Layer events and map events (full list)
|
|
260
|
+
- Getting a reference to the map
|
|
261
|
+
- A note about Angular zones and change detection
|
|
351
262
|
|
|
352
|
-
#### [leafletMaxBounds]: LatLngBounds
|
|
353
|
-
Input bind a ```LatLngBounds``` value that will be applied to the map using ```Map.setMaxBounds()```.
|
|
354
263
|
|
|
264
|
+
## Extensions
|
|
265
|
+
There are several libraries that extend the core functionality of ngx-leaflet:
|
|
266
|
+
* [Leaflet Draw](https://github.com/bluehalo/ngx-leaflet-draw)
|
|
267
|
+
* [Leaflet Markercluster](https://github.com/bluehalo/ngx-leaflet-markercluster)
|
|
268
|
+
* [Leaflet D3 (Hexbins)](https://github.com/bluehalo/ngx-leaflet-d3)
|
|
355
269
|
|
|
356
|
-
### Simple Layer Management: Setting Baselayers
|
|
357
|
-
There is a convenience input binding for setting the baselayers on the map called ```[leafletBaseLayers]```.
|
|
358
|
-
You can also provide ```[leafletLayersControlOptions]``` if you want to show the control on the map that allows you to switch between baselayers.
|
|
359
|
-
If you plan to show more than just baselayers, you should use the more advanced layers controls described in *Advanced Layer Management* below.
|
|
360
|
-
|
|
361
|
-
For an example of the basic map setup, you should check out the *Simple Base Layers* demo.
|
|
362
|
-
|
|
363
|
-
```angular181html
|
|
364
|
-
<div leaflet style="height: 300px;"
|
|
365
|
-
[leafletOptions]="options"
|
|
366
|
-
[leafletBaseLayers]="baseLayers"
|
|
367
|
-
[leafletLayersControlOptions]="layersControlOptions">
|
|
368
|
-
</div>
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
#### [leafletBaseLayers]: Control.LayersObject
|
|
372
|
-
Input bind an ```Control.LayersObject``` to be synced to the map.
|
|
373
|
-
|
|
374
|
-
```typescript
|
|
375
|
-
baseLayers: {
|
|
376
|
-
'layer1': Layer,
|
|
377
|
-
'layer2': Layer
|
|
378
|
-
}
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
On changes, the component syncs the baseLayers on the map with the layers in this object.
|
|
382
|
-
Syncing is performed by tracking the current baselayer and on changes, searching the map to see if any of the current baselayers is added to the map.
|
|
383
|
-
If it finds a baselayer that is still added to the map, it will assume that is still the baselayer and leave it.
|
|
384
|
-
If none of the baselayers can be found on the map, it will add the first layer it finds in the ```Control.LayersObject``` and use that as the new baselayer.
|
|
385
|
-
Layers are compared using instance equality.
|
|
386
|
-
|
|
387
|
-
If you use this directive, you can still manually use the ```[leafletLayers]``` directive, but you will not be able to use the ```[leafletLayersControl]``` directive.
|
|
388
|
-
This directive internally uses the layers control, so if you add both, they'll interfere with each other.
|
|
389
|
-
Because it uses ```control.layers``` under the hood, you can still provide options for the layers control.
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
#### [leafletLayersControlOptions]
|
|
393
|
-
Input binding for Control.Layers options (see [Leaflet's](https://leafletjs.com/reference.html) docs).
|
|
394
|
-
These options are passed into the layers control constructor on creation.
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
### Advanced Layer Management: Layers, and Layers Control
|
|
398
|
-
The ```[leafletLayers]``` and ```[leafletLayersControl]``` input bindings give you direct access to manipulate layers and the layers control.
|
|
399
|
-
When the array bound to ```[leafletLayers]``` is changed, the directive will synchronize the layers on the map to the layers in the array.
|
|
400
|
-
This includes tile layers and any added shapes.
|
|
401
|
-
|
|
402
|
-
The ```[leafletLayersControl]``` input binding allows you to provide a set of base layers and overlay layers that can be managed within leaflet using the layers control.
|
|
403
|
-
When the user manipulates the control via Leaflet, Leaflet will automatically manage the layers, but the input bound layer array isn't going to get updated to reflect those changes.
|
|
404
|
-
|
|
405
|
-
So, use ```[leafletLayers]``` to add a collection of layers to the map.
|
|
406
|
-
And, use ```[leafletLayersControl]``` to allow users to optionally turn layers/overlays on and off.
|
|
407
|
-
|
|
408
|
-
For an example of using the layers controls, you should check out the *Layers and Layer Controls* demo.
|
|
409
|
-
|
|
410
|
-
```angular181html
|
|
411
|
-
<div leaflet style="height: 300px;"
|
|
412
|
-
[leafletOptions]="options"
|
|
413
|
-
[leafletLayers]="layers"
|
|
414
|
-
[leafletLayersControl]="layersControl"
|
|
415
|
-
[leafletLayersControlOptions]="layersControlOptions">
|
|
416
|
-
</div>
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
#### [leafletLayers]: Layer[]
|
|
420
|
-
Input bind an array of all layers to be synced (and made visible) in the map.
|
|
421
|
-
|
|
422
|
-
On changes, the component syncs the layers on the map with the layers in this array.
|
|
423
|
-
Syncing is performed by selectively adding or removing layers.
|
|
424
|
-
Layers are compared using instance equality.
|
|
425
|
-
As a result of how the map is synced, the order of layers is not guaranteed to be consistent as changes are made.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
#### [leafletLayersControl]: Control.Layers
|
|
429
|
-
Input bind a Control.Layers specification. The object contains properties for each of the two constructor arguments for the Control.Layers constructor.
|
|
430
|
-
|
|
431
|
-
```typescript
|
|
432
|
-
layersControl: {
|
|
433
|
-
baseLayers: {
|
|
434
|
-
'layerName': Layer
|
|
435
|
-
},
|
|
436
|
-
overlays: {
|
|
437
|
-
'overlayName': Layer
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
#### [leafletLayersControlOptions]
|
|
443
|
-
Input binding for Control.Layers options (see [Leaflet's](https://leafletjs.com/reference.html) docs).
|
|
444
|
-
These options are passed into the constructor on creation.
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
### Advanced Layer Management: Individual Layers and @for / @if
|
|
448
|
-
The ```[leafletLayer]``` input bindings gives you the ability to add a single layer to the map.
|
|
449
|
-
While this may seem limiting, you can nest elements inside the map element, each with a ```[leafletLayer]``` input.
|
|
450
|
-
The result of this is that each layer will be added to the map.
|
|
451
|
-
If you add a structural directive - ```@for``` or ```@if``` - you can get some added flexibility when controlling layers.
|
|
452
|
-
|
|
453
|
-
```angular181html
|
|
454
|
-
<div leaflet style="height: 300px;"
|
|
455
|
-
[leafletOptions]="options">
|
|
456
|
-
|
|
457
|
-
@for (layer of layers; track layer.id) {
|
|
458
|
-
<div [leafletLayer]="layer"></div>
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
</div>
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
In this example, each layer in the ```layers``` array will create a new child ```div``` element.
|
|
465
|
-
Each element will have a ```[leafletLayer]``` input binding, which will result in the layer being added to the map.
|
|
466
|
-
For more details, you should check out the *Layers and ngFor* demo.
|
|
467
|
-
|
|
468
|
-
There are several layer events that are available when you are using this approach to controlling layers.
|
|
469
|
-
|
|
470
|
-
### Layer Events
|
|
471
|
-
When you are using the ```[leafletLayer]``` directive to add a layer, you can also access output bindings for layer events.
|
|
472
|
-
Two events that are currently exposed include: ```(leafletLayerAdd)``` and ```(leafletLayerRemove)```.
|
|
473
|
-
Each of these emits a ```LeafletEvent``` object.
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
### Map Events
|
|
477
|
-
Leaflet exposes a lot of map events including map zoom, map move, and mouse interactions.
|
|
478
|
-
The plugin exposes several of the most common events.
|
|
479
|
-
For each of these events, the event is emitted in the Angular Zone, so you shouldn't have to do anything extra to get change detection to work.
|
|
480
|
-
For a working example, check out the events section of the demo.
|
|
481
|
-
|
|
482
|
-
#### Mouse Interactions: LeafletMouseEvent
|
|
483
|
-
The following events are provided:
|
|
484
|
-
* ```(leafletClick)```
|
|
485
|
-
* ```(leafletDoubleClick)```
|
|
486
|
-
* ```(leafletMouseDown)```
|
|
487
|
-
* ```(leafletMouseUp)```
|
|
488
|
-
* ```(leafletMouseMove)```
|
|
489
|
-
* ```(leafletMouseOver)```
|
|
490
|
-
* ```(leafletMouseOut)```
|
|
491
|
-
|
|
492
|
-
#### Map Zoom and Move: LeafletEvent
|
|
493
|
-
The following events are provided:
|
|
494
|
-
* ```(leafletMapMove)```
|
|
495
|
-
* ```(leafletMapMoveStart)```
|
|
496
|
-
* ```(leafletMapMoveEnd)```
|
|
497
|
-
* ```(leafletMapZoom)```
|
|
498
|
-
* ```(leafletMapZoomStart)```
|
|
499
|
-
* ```(leafletMapZoomEnd)```
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
### Getting a Reference to the Map
|
|
504
|
-
Occasionally, you may need to directly access the Leaflet map instance.
|
|
505
|
-
For example, to call ```invalidateSize()``` when the map div changes size or is shown/hidden.
|
|
506
|
-
There are a couple of different ways to achieve this depending on what you're trying to do.
|
|
507
|
-
|
|
508
|
-
The easiest and most flexible way is to use the output binding ```leafletMapReady```.
|
|
509
|
-
This output is invoked after the map is created, the argument of the event being the ```Map``` instance.
|
|
510
|
-
|
|
511
|
-
The second is to get a reference to the leaflet directive itself - and there are a couple of ways to do this.
|
|
512
|
-
With a reference to the directive, you can invoke the ```getMap()``` function to get a reference to the ```Map``` instance.
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
#### (leafletMapReady): Map
|
|
516
|
-
This output is emitted when once when the map is initially created inside of the Leaflet directive.
|
|
517
|
-
The event will only fire when the map exists and is ready for manipulation.
|
|
518
|
-
|
|
519
|
-
```angular181html
|
|
520
|
-
<div leaflet
|
|
521
|
-
[leafletOptions]="options"
|
|
522
|
-
(leafletMapReady)="onMapReady($event)">
|
|
523
|
-
</div>
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
```typescript
|
|
527
|
-
onMapReady(map: Map) {
|
|
528
|
-
// Do stuff with map
|
|
529
|
-
}
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
This method of getting the map makes the most sense if you are using the Leaflet directive inside your own component
|
|
533
|
-
and just need to add some limited functionality or register some event handlers.
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
#### Inject LeafletDirective into your Component
|
|
537
|
-
This is the more advanced technique and it won't always work depending on your setup.
|
|
538
|
-
In particular, this will likely not work unless you are writing your own third-party library that extends the functionality of `ngx-leaflet`.
|
|
539
|
-
If this approach does not work for you, try using the `leafletMapReady` event described above.
|
|
540
|
-
|
|
541
|
-
In Angular.io, directives are injectable the same way that Services are.
|
|
542
|
-
This means that you can create your own component or directive and inject the ```LeafletDirective``` into it.
|
|
543
|
-
This will only work if your custom component/directive exists on the same DOM element and is ordered after the injected LeafletDirective, or if it is on a child DOM element.
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
```angular181html
|
|
547
|
-
<!-- On the same DOM element -->
|
|
548
|
-
<div leaflet myCustomDirective></div>
|
|
549
|
-
|
|
550
|
-
<!-- On a child DOM element -->
|
|
551
|
-
<div leaflet>
|
|
552
|
-
<div myCustomDirective></div>
|
|
553
|
-
</div>
|
|
554
|
-
```
|
|
555
|
-
|
|
556
|
-
```typescript
|
|
557
|
-
|
|
558
|
-
@Directive({
|
|
559
|
-
selector: '[myCustomDirective]'
|
|
560
|
-
})
|
|
561
|
-
export class MyCustomDirective {
|
|
562
|
-
readonly #leafletDirective = inject(LeafletDirective);
|
|
563
|
-
|
|
564
|
-
someFunction() {
|
|
565
|
-
if (null !== this.#leafletDirective.getMap()) {
|
|
566
|
-
// Do stuff with the map
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
The benefit of this approach is it's a bit cleaner if you're interested in adding some reusable capability to the existing leaflet map directive.
|
|
573
|
-
As mentioned above, it might not work depending on how you are packaging your component.
|
|
574
|
-
This is how the ```@bluehalo/ngx-leaflet-draw``` and ```@bluehalo/ngx-leaflet-d3``` packages work, so you can use them as references.
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
### A Note About Change Detection
|
|
578
|
-
Change detection is at the core of how Angular works.
|
|
579
|
-
Angular.io uses Zone.js to scope how and when (events, actions, etc.) to trigger change detection.
|
|
580
|
-
It's important to scope it carefully because change detection can be fairly expensive, so you don't want it to happen constantly.
|
|
581
|
-
|
|
582
|
-
Libraries like ngx-leaflet have to decide what to do inside and outside of the Angular zone, balancing convenience and performance.
|
|
583
|
-
Leaflet registers handlers for a lot of mouse events.
|
|
584
|
-
To mitigate the performance impact of constantly running change detection on all mouse events (including mousemove), ngx-leaflet runs most of the Leaflet code outside of the Angular zone.
|
|
585
|
-
The impact of this is that Angular won't automatically detect changes that you make inside of a Leaflet event callback.
|
|
586
|
-
|
|
587
|
-
The solution is to either make sure that Angular relevant changes are made inside of Angular's zone or to manually tell Angular to detect changes.
|
|
588
|
-
|
|
589
|
-
#### Running Inside of Angular's Zone
|
|
590
|
-
Leaflet event handlers run outside of Angular's zone, where changes to input bound fields will not be detected automatically.
|
|
591
|
-
To ensure your changes are detected and applied, you need to make those changed inside of Angular's zone.
|
|
592
|
-
Fortunately, this is extremely easy.
|
|
593
|
-
|
|
594
|
-
```typescript
|
|
595
|
-
fitBounds: any = null;
|
|
596
|
-
circle = circle([ 46.95, -122 ], { radius: 5000 });
|
|
597
|
-
|
|
598
|
-
// Inject the Change Detector into your component
|
|
599
|
-
constructor(private zone: NgZone) {}
|
|
600
|
-
|
|
601
|
-
ngOnInit() {
|
|
602
|
-
|
|
603
|
-
// The 'add' event callback handler happens outside of the Angular zone
|
|
604
|
-
this.circle.on('add', () => {
|
|
605
|
-
|
|
606
|
-
// But, we can run stuff inside of Angular's zone by calling NgZone.run()
|
|
607
|
-
// everything inside the arrow function body happens inside of Angular's zone, where changes will be detected
|
|
608
|
-
this.zone.run(() => {
|
|
609
|
-
this.fitBounds = this.circle.getBounds();
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
#### Manually Triggering Change Detection
|
|
617
|
-
Another option is to manually tell the change detector to detect changes.
|
|
618
|
-
The drawback to this option is that it is less precise.
|
|
619
|
-
This will trigger change detection for this component and all of its children.
|
|
620
|
-
|
|
621
|
-
```typescript
|
|
622
|
-
fitBounds: any = null;
|
|
623
|
-
circle = circle([ 46.95, -122 ], { radius: 5000 });
|
|
624
|
-
|
|
625
|
-
// Inject the Change Detector into your component
|
|
626
|
-
constructor(private changeDetector: ChangeDetectorRef) {}
|
|
627
|
-
|
|
628
|
-
ngOnInit() {
|
|
629
|
-
|
|
630
|
-
// The 'add' event callback happens outside of the Angular zone
|
|
631
|
-
this.circle.on('add', () => {
|
|
632
270
|
|
|
633
|
-
|
|
634
|
-
this.fitBounds = this.circle.getBounds();
|
|
271
|
+
## Cookbook
|
|
635
272
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
}
|
|
641
|
-
```
|
|
642
|
-
|
|
643
|
-
## Extensions
|
|
644
|
-
There are several libraries that extend the core functionality of ngx-leaflet:
|
|
645
|
-
* [Leaflet Draw](https://github.com/BlueHalo/ngx-leaflet-draw)
|
|
646
|
-
* [Leaflet Markercluster](https://github.com/BlueHalo/ngx-leaflet-markercluster)
|
|
647
|
-
* [Leaflet D3 (Hexbins)](https://github.com/BlueHalo/ngx-leaflet-d3)
|
|
273
|
+
Common patterns and examples are in [docs/cookbook.md](docs/cookbook.md), including:
|
|
274
|
+
- [Marker Setup](docs/cookbook.md#marker-setup) — configuring Leaflet markers with the Angular CLI build pipeline
|
|
275
|
+
- [SSR / Server-Side Rendering](docs/cookbook.md#ssr--server-side-rendering) — working around Leaflet's browser-only module initialization
|
|
276
|
+
- [Angular Components in Marker Popups](docs/cookbook.md#angular-components-in-marker-popups) — using `createComponent()` to render Angular components into Leaflet popups
|
|
648
277
|
|
|
649
278
|
|
|
650
279
|
## <a name="help">Getting Help</a>
|
|
651
280
|
Here's a list of articles, tutorials, guides, and help resources:
|
|
652
281
|
* [ngx-leaflet on Stack Overflow](https://stackoverflow.com/questions/tagged/ngx-leaflet)
|
|
653
|
-
* [
|
|
654
|
-
* [
|
|
655
|
-
* [
|
|
282
|
+
* [API Reference](docs/API.md) and [Cookbook](docs/cookbook.md) — up-to-date, version-controlled docs in this repo
|
|
283
|
+
* [High-level intro to @bluehalo/ngx-leaflet](https://github.com/bluehalo/ngx-leaflet/wiki) *(wiki — may be out of date)*
|
|
284
|
+
* [Using @bluehalo/ngx-leaflet in Angular CLI projects](https://github.com/bluehalo/ngx-leaflet/wiki/Getting-Started-Tutorial) *(wiki — may be out of date)*
|
|
285
|
+
* [Integrating 3rd Party Leaflet Libraries with @bluehalo/ngx-leaflet and @angular/cli](https://github.com/bluehalo/ngx-leaflet/wiki/Integrating-Plugins) *(wiki — may be out of date)*
|
|
656
286
|
|
|
657
287
|
|
|
658
288
|
## Contribute
|
|
659
|
-
PRs accepted.
|
|
289
|
+
PRs accepted. Please make contributions on feature branches and open a pull request against `master`.
|
|
660
290
|
|
|
661
291
|
|
|
662
292
|
## License
|
|
663
|
-
See LICENSE
|
|
293
|
+
See [LICENSE](LICENSE) for details.
|
|
664
294
|
|
|
665
295
|
|
|
666
296
|
## Credits
|
|
667
297
|
**[Leaflet](http://leafletjs.com/)** Is an awesome mapping package.
|
|
298
|
+
|
|
299
|
+
**Logo** designed by [@jjmhalew](https://github.com/jjmhalew) ([#371](https://github.com/bluehalo/ngx-leaflet/issues/371)).
|
|
@@ -255,10 +255,10 @@ class LeafletDirective {
|
|
|
255
255
|
this.map.setMaxZoom(zoom);
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
259
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.
|
|
258
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletDirective, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
259
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: LeafletDirective, isStandalone: true, selector: "[leaflet]", inputs: { fitBoundsOptions: ["leafletFitBoundsOptions", "fitBoundsOptions"], panOptions: ["leafletPanOptions", "panOptions"], zoomOptions: ["leafletZoomOptions", "zoomOptions"], zoomPanOptions: ["leafletZoomPanOptions", "zoomPanOptions"], options: ["leafletOptions", "options"], zoom: ["leafletZoom", "zoom"], center: ["leafletCenter", "center"], fitBounds: ["leafletFitBounds", "fitBounds"], maxBounds: ["leafletMaxBounds", "maxBounds"], minZoom: ["leafletMinZoom", "minZoom"], maxZoom: ["leafletMaxZoom", "maxZoom"] }, outputs: { mapReady: "leafletMapReady", zoomChange: "leafletZoomChange", centerChange: "leafletCenterChange", onClick: "leafletClick", onDoubleClick: "leafletDoubleClick", onMouseDown: "leafletMouseDown", onMouseUp: "leafletMouseUp", onMouseMove: "leafletMouseMove", onMouseOver: "leafletMouseOver", onMouseOut: "leafletMouseOut", onMapMove: "leafletMapMove", onMapMoveStart: "leafletMapMoveStart", onMapMoveEnd: "leafletMapMoveEnd", onMapZoom: "leafletMapZoom", onMapZoomStart: "leafletMapZoomStart", onMapZoomEnd: "leafletMapZoomEnd" }, host: { listeners: { "window:resize": "onResize()" } }, usesOnChanges: true, ngImport: i0 }); }
|
|
260
260
|
}
|
|
261
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
261
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletDirective, decorators: [{
|
|
262
262
|
type: Directive,
|
|
263
263
|
args: [{
|
|
264
264
|
selector: '[leaflet]',
|
|
@@ -415,10 +415,10 @@ class LeafletLayerDirective {
|
|
|
415
415
|
l.off('add', this.onAddLayerHandler);
|
|
416
416
|
l.off('remove', this.onRemoveLayerHandler);
|
|
417
417
|
}
|
|
418
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
419
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.
|
|
418
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletLayerDirective, deps: [{ token: LeafletDirective }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
419
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: LeafletLayerDirective, isStandalone: true, selector: "[leafletLayer]", inputs: { layer: ["leafletLayer", "layer"] }, outputs: { onAdd: "leafletLayerAdd", onRemove: "leafletLayerRemove" }, usesOnChanges: true, ngImport: i0 }); }
|
|
420
420
|
}
|
|
421
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
421
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletLayerDirective, decorators: [{
|
|
422
422
|
type: Directive,
|
|
423
423
|
args: [{
|
|
424
424
|
selector: '[leafletLayer]',
|
|
@@ -500,10 +500,10 @@ class LeafletLayersDirective {
|
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
504
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.
|
|
503
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletLayersDirective, deps: [{ token: LeafletDirective }, { token: i0.IterableDiffers }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
504
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: LeafletLayersDirective, isStandalone: true, selector: "[leafletLayers]", inputs: { layers: ["leafletLayers", "layers"] }, ngImport: i0 }); }
|
|
505
505
|
}
|
|
506
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
506
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletLayersDirective, decorators: [{
|
|
507
507
|
type: Directive,
|
|
508
508
|
args: [{
|
|
509
509
|
selector: '[leafletLayers]',
|
|
@@ -676,10 +676,10 @@ class LeafletLayersControlDirective {
|
|
|
676
676
|
}
|
|
677
677
|
}
|
|
678
678
|
}
|
|
679
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
680
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.
|
|
679
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletLayersControlDirective, deps: [{ token: LeafletDirective }, { token: i0.KeyValueDiffers }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
680
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: LeafletLayersControlDirective, isStandalone: true, selector: "[leafletLayersControl]", inputs: { layersControlConfig: ["leafletLayersControl", "layersControlConfig"], layersControlOptions: ["leafletLayersControlOptions", "layersControlOptions"] }, outputs: { layersControlReady: "leafletLayersControlReady", onOverlayAdd: "leafletOverlayAdd", onOverlayRemove: "leafletOverlayRemove" }, ngImport: i0 }); }
|
|
681
681
|
}
|
|
682
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
682
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletLayersControlDirective, decorators: [{
|
|
683
683
|
type: Directive,
|
|
684
684
|
args: [{
|
|
685
685
|
selector: '[leafletLayersControl]',
|
|
@@ -798,10 +798,10 @@ class LeafletBaseLayersDirective {
|
|
|
798
798
|
}
|
|
799
799
|
}
|
|
800
800
|
}
|
|
801
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
802
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.
|
|
801
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletBaseLayersDirective, deps: [{ token: LeafletDirective }, { token: i0.KeyValueDiffers }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
802
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.8", type: LeafletBaseLayersDirective, isStandalone: true, selector: "[leafletBaseLayers]", inputs: { baseLayers: ["leafletBaseLayers", "baseLayers"], layersControlOptions: ["leafletLayersControlOptions", "layersControlOptions"] }, outputs: { layersControlReady: "leafletLayersControlReady" }, ngImport: i0 }); }
|
|
803
803
|
}
|
|
804
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
804
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletBaseLayersDirective, decorators: [{
|
|
805
805
|
type: Directive,
|
|
806
806
|
args: [{
|
|
807
807
|
selector: '[leafletBaseLayers]',
|
|
@@ -818,8 +818,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
818
818
|
}] } });
|
|
819
819
|
|
|
820
820
|
class LeafletModule {
|
|
821
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.
|
|
822
|
-
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.
|
|
821
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
822
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.8", ngImport: i0, type: LeafletModule, imports: [LeafletDirective,
|
|
823
823
|
LeafletLayerDirective,
|
|
824
824
|
LeafletLayersDirective,
|
|
825
825
|
LeafletLayersControlDirective,
|
|
@@ -828,9 +828,9 @@ class LeafletModule {
|
|
|
828
828
|
LeafletLayersDirective,
|
|
829
829
|
LeafletLayersControlDirective,
|
|
830
830
|
LeafletBaseLayersDirective] }); }
|
|
831
|
-
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.
|
|
831
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletModule }); }
|
|
832
832
|
}
|
|
833
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.
|
|
833
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: LeafletModule, decorators: [{
|
|
834
834
|
type: NgModule,
|
|
835
835
|
args: [{
|
|
836
836
|
imports: [
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bluehalo/ngx-leaflet",
|
|
3
3
|
"description": "Angular.io components for Leaflet",
|
|
4
|
-
"version": "21.2.
|
|
5
|
-
"author": "BlueHalo
|
|
6
|
-
"copyright": "Copyright BlueHalo
|
|
4
|
+
"version": "21.2.1",
|
|
5
|
+
"author": "BlueHalo",
|
|
6
|
+
"copyright": "Copyright (c) BlueHalo LLC",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -28,5 +28,6 @@
|
|
|
28
28
|
"default": "./fesm2022/bluehalo-ngx-leaflet.mjs"
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
|
-
"sideEffects": false
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"type": "module"
|
|
32
33
|
}
|