@maplibre/ngx-maplibre-gl
Version:
A Angular binding of maplibre-gl
2,978 lines • 153 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, NgZone, signal, Injectable, input, viewChild, afterNextRender, ChangeDetectionStrategy, Component, Directive, output, DestroyRef, forwardRef, model, ElementRef, afterEveryRender, ViewEncapsulation, contentChild, TemplateRef, NgModule } from '@angular/core';
import { Marker, Popup, Map as Map$1, AttributionControl, FullscreenControl, GeolocateControl, NavigationControl, ScaleControl, TerrainControl, GlobeControl } from 'maplibre-gl';
import { AsyncSubject, Subject, fromEvent, Subscription, firstValueFrom, merge, tap as tap$1 } from 'rxjs';
import { takeUntilDestroyed, outputToObservable } from '@angular/core/rxjs-interop';
import { tap, switchMap, filter, debounceTime, takeUntil, take, startWith, map } from 'rxjs/operators';
import { NgTemplateOutlet } from '@angular/common';
const keepAvailableObjectValues = (object) => {
return Object.keys(object).reduce((acc, curr) => {
const tKey = curr;
if (object[tKey] === undefined) {
return acc;
}
return { ...acc, [tKey]: object[tKey] };
}, {});
};
/**
* @private
*/
class MapService {
constructor() {
this.zone = inject(NgZone);
this.subscriptionsPerInstance = new Map();
this.mapCreated = new AsyncSubject();
this.mapLoaded = new AsyncSubject();
this.markersToRemove = signal([]);
this.popupsToRemove = signal([]);
this.imageIdsToRemove = signal([]);
this.mapCreated$ = this.mapCreated.asObservable();
this.mapLoaded$ = this.mapLoaded.asObservable();
}
setup(options) {
// Workaround rollup issue
this.createMap(options.mapOptions);
this.hookEvents(options.mapEvents);
this.mapEvents = options.mapEvents;
this.mapCreated.next(undefined);
this.mapCreated.complete();
if (options.mapOptions.terrain || options.mapOptions.projection) {
this.mapInstance.on('load', () => {
if (options.mapOptions.projection) {
this.setProjection(options.mapOptions.projection);
}
if (options.mapOptions.terrain) {
this.setTerrain(options.mapOptions.terrain);
}
});
}
}
destroyMap() {
if (this.mapInstance) {
this.mapInstance.remove();
}
}
updateMinZoom(minZoom) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setMinZoom(minZoom);
});
}
updateMaxZoom(maxZoom) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setMaxZoom(maxZoom);
});
}
updateMinPitch(minPitch) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setMinPitch(minPitch);
});
}
updateMaxPitch(maxPitch) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setMaxPitch(maxPitch);
});
}
updateRenderWorldCopies(status) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setRenderWorldCopies(status);
});
}
updateScrollZoom(status) {
return this.zone.runOutsideAngular(() => {
status
? this.mapInstance.scrollZoom.enable()
: this.mapInstance.scrollZoom.disable();
});
}
updateDragRotate(status) {
return this.zone.runOutsideAngular(() => {
status
? this.mapInstance.dragRotate.enable()
: this.mapInstance.dragRotate.disable();
});
}
updateTouchPitch(status) {
return this.zone.runOutsideAngular(() => {
status
? this.mapInstance.touchPitch.enable()
: this.mapInstance.touchPitch.disable();
});
}
updateTouchZoomRotate(status) {
return this.zone.runOutsideAngular(() => {
status
? this.mapInstance.touchZoomRotate.enable()
: this.mapInstance.touchZoomRotate.disable();
});
}
updateDoubleClickZoom(status) {
return this.zone.runOutsideAngular(() => {
status
? this.mapInstance.doubleClickZoom.enable()
: this.mapInstance.doubleClickZoom.disable();
});
}
updateKeyboard(status) {
return this.zone.runOutsideAngular(() => {
status
? this.mapInstance.keyboard.enable()
: this.mapInstance.keyboard.disable();
});
}
updateDragPan(status) {
return this.zone.runOutsideAngular(() => {
status
? this.mapInstance.dragPan.enable()
: this.mapInstance.dragPan.disable();
});
}
updateBoxZoom(status) {
return this.zone.runOutsideAngular(() => {
status
? this.mapInstance.boxZoom.enable()
: this.mapInstance.boxZoom.disable();
});
}
updateStyle(style) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setStyle(style);
});
}
updateMaxBounds(maxBounds) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setMaxBounds(maxBounds);
});
}
setProjection(options) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setProjection(options);
});
}
setTerrain(options) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setTerrain(options);
});
}
getTerrain() {
return this.zone.runOutsideAngular(() => {
return this.mapInstance.getTerrain();
});
}
setCenterElevation(elevation) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setCenterElevation(elevation);
});
}
changeCanvasCursor(cursor) {
const canvas = this.mapInstance.getCanvasContainer();
canvas.style.cursor = cursor;
}
queryRenderedFeatures(pointOrBox, parameters) {
return this.mapInstance.queryRenderedFeatures(pointOrBox, parameters);
}
panTo(center, options) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.panTo(center, options);
});
}
move(movingMethod, movingOptions, zoom, center, bearing, pitch, roll) {
return this.zone.runOutsideAngular(() => {
this.mapInstance[movingMethod]({
...movingOptions,
zoom: zoom != null ? zoom : this.mapInstance.getZoom(),
center: center != null ? center : this.mapInstance.getCenter(),
bearing: bearing != null ? bearing : this.mapInstance.getBearing(),
pitch: pitch != null ? pitch : this.mapInstance.getPitch(),
roll: roll != null ? roll : this.mapInstance.getRoll(),
});
});
}
addLayer(layer, bindEvents, before) {
this.zone.runOutsideAngular(() => {
Object.keys(layer.layerOptions).forEach((key) => {
const tkey = key;
if (layer.layerOptions[tkey] === undefined) {
delete layer.layerOptions[tkey];
}
});
this.mapInstance.addLayer(layer.layerOptions, before);
if (!bindEvents) {
return;
}
const subscriptions = [];
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'click', layer.layerEvents.layerClick));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'dblclick', layer.layerEvents.layerDblClick));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'mousedown', layer.layerEvents.layerMouseDown));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'mouseup', layer.layerEvents.layerMouseUp));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'mouseenter', layer.layerEvents.layerMouseEnter));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'mouseleave', layer.layerEvents.layerMouseLeave));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'mousemove', layer.layerEvents.layerMouseMove));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'mouseover', layer.layerEvents.layerMouseOver));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'mouseout', layer.layerEvents.layerMouseOut));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'contextmenu', layer.layerEvents.layerContextMenu));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'touchstart', layer.layerEvents.layerTouchStart));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'touchend', layer.layerEvents.layerTouchEnd));
subscriptions.push(this.createSubscriptionForLayer(layer.layerOptions.id, 'touchcancel', layer.layerEvents.layerTouchCancel));
const layerInstance = this.mapInstance.getLayer(layer.layerOptions.id);
if (layerInstance) {
this.subscriptionsPerInstance.set(layerInstance, subscriptions);
}
});
}
removeLayer(layerId) {
this.zone.runOutsideAngular(() => {
const layerInstance = this.mapInstance.getLayer(layerId);
if (layerInstance != null) {
const subscriptions = this.subscriptionsPerInstance.get(layerInstance) || [];
for (const subscription of subscriptions) {
subscription.unsubscribe();
}
this.subscriptionsPerInstance.delete(layerInstance);
this.mapInstance.removeLayer(layerId);
}
});
}
addMarker(marker) {
const options = {
offset: marker.markersOptions.offset,
anchor: marker.markersOptions.anchor,
color: marker.markersOptions.color,
scale: marker.markersOptions.scale,
draggable: !!marker.markersOptions.draggable,
rotationAlignment: marker.markersOptions.rotationAlignment,
rotation: marker.markersOptions.rotation,
pitchAlignment: marker.markersOptions.pitchAlignment,
clickTolerance: marker.markersOptions.clickTolerance,
element: marker.markersOptions.element.childNodes.length > 0
? marker.markersOptions.element
: undefined,
opacity: marker.markersOptions.opacity,
opacityWhenCovered: marker.markersOptions.opacityWhenCovered,
subpixelPositioning: marker.markersOptions.subpixelPositioning,
};
const markerInstance = new Marker(options);
markerInstance.on('dragstart', (event) => {
if (event) {
const { target } = event;
this.zone.run(() => {
marker.markersEvents.markerDragStart.emit(target);
});
}
});
markerInstance.on('drag', (event) => {
if (event) {
const { target } = event;
this.zone.run(() => marker.markersEvents.markerDrag.emit(target));
}
});
markerInstance.on('dragend', (event) => {
if (event) {
const { target } = event;
this.zone.run(() => marker.markersEvents.markerDragEnd.emit(target));
}
});
const lngLat = marker.markersOptions.feature
? marker.markersOptions.feature.geometry.coordinates
: marker.markersOptions.lngLat;
markerInstance.setLngLat(lngLat);
return this.zone.runOutsideAngular(() => {
markerInstance.addTo(this.mapInstance);
return markerInstance;
});
}
removeMarker(marker) {
this.markersToRemove.update((markers) => [...markers, marker]);
}
createPopup(popup, element) {
return this.zone.runOutsideAngular(() => {
const popupOptions = keepAvailableObjectValues(popup.popupOptions);
const popupInstance = new Popup(popupOptions);
popupInstance.setDOMContent(element);
const subscriptions = [];
subscriptions.push(this.createSubscriptionForPopup(popupInstance, 'open', popup.popupEvents.popupOpen));
subscriptions.push(this.createSubscriptionForPopup(popupInstance, 'close', popup.popupEvents.popupClose));
this.subscriptionsPerInstance.set(popupInstance, subscriptions);
return popupInstance;
});
}
addPopupToMap(popup, lngLat) {
return this.zone.runOutsideAngular(() => {
popup.setLngLat(lngLat);
popup.addTo(this.mapInstance);
});
}
addPopupToMarker(marker, popup) {
return this.zone.runOutsideAngular(() => {
marker.setPopup(popup);
});
}
removePopupFromMap(popup) {
if (this.subscriptionsPerInstance.has(popup)) {
const subscriptions = this.subscriptionsPerInstance.get(popup) || [];
for (const subscription of subscriptions) {
subscription.unsubscribe();
}
this.subscriptionsPerInstance.delete(popup);
}
this.popupsToRemove.update((popups) => [...popups, popup]);
}
removePopupFromMarker(marker) {
return this.zone.runOutsideAngular(() => {
const popup = marker.getPopup();
if (this.subscriptionsPerInstance.has(popup)) {
const subscriptions = this.subscriptionsPerInstance.get(popup) || [];
for (const subscription of subscriptions) {
subscription.unsubscribe();
}
this.subscriptionsPerInstance.delete(popup);
}
marker.setPopup(undefined);
});
}
addControl(control, position) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.addControl(control, position);
});
}
removeControl(control) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.removeControl(control);
});
}
async loadAndAddImage(imageId, url, options) {
return this.zone.runOutsideAngular(async () => {
const image = await this.mapInstance.loadImage(url);
this.addImage(imageId, image.data, options);
});
}
addImage(imageId, data, options) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.addImage(imageId, data, options);
});
}
removeImage(imageId) {
this.imageIdsToRemove.update((imagesIds) => [...imagesIds, imageId]);
}
addSource(sourceId, source) {
return this.zone.runOutsideAngular(() => {
Object.keys(source).forEach((key) => source[key] === undefined && delete source[key]);
this.mapInstance.addSource(sourceId, source);
});
}
getSource(sourceId) {
return this.mapInstance.getSource(sourceId);
}
removeSource(sourceId) {
this.zone.runOutsideAngular(() => {
this.findLayersBySourceId(sourceId).forEach((layer) => this.removeLayer(layer.id));
this.mapInstance.removeSource(sourceId);
});
}
setAllLayerPaintProperty(layerId, paint) {
return this.zone.runOutsideAngular(() => {
Object.keys(paint).forEach((key) => {
// TODO Check for perf, setPaintProperty only on changed paint props maybe
this.mapInstance.setPaintProperty(layerId, key, paint[key]);
});
});
}
setAllLayerLayoutProperty(layerId, layout) {
return this.zone.runOutsideAngular(() => {
Object.keys(layout).forEach((key) => {
// TODO Check for perf, setPaintProperty only on changed paint props maybe
this.mapInstance.setLayoutProperty(layerId, key, layout[key]);
});
});
}
setLayerFilter(layerId, filter) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setFilter(layerId, filter);
});
}
setLayerBefore(layerId, beforeId) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.moveLayer(layerId, beforeId);
});
}
setLayerZoomRange(layerId, minZoom, maxZoom) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.setLayerZoomRange(layerId, minZoom ? minZoom : 0, maxZoom ? maxZoom : 20);
});
}
fitBounds(bounds, options) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.fitBounds(bounds, options);
});
}
fitScreenCoordinates(points, bearing, options) {
return this.zone.runOutsideAngular(() => {
this.mapInstance.fitScreenCoordinates(points[0], points[1], bearing, options);
});
}
clearMapElements() {
this.zone.runOutsideAngular(() => {
this.removeMarkers();
this.removePopups();
this.removeImages();
});
}
createMap(options) {
NgZone.assertNotInAngularZone();
const mapOptions = keepAvailableObjectValues(options);
this.mapInstance = new Map$1(mapOptions);
const isIEorEdge = window && /msie\s|trident\/|edge\//i.test(window.navigator.userAgent);
if (isIEorEdge) {
this.mapInstance.setStyle(options.style);
}
}
removeMarkers() {
for (const marker of this.markersToRemove()) {
marker.remove();
}
this.markersToRemove.set([]);
}
removePopups() {
for (const popup of this.popupsToRemove()) {
popup.remove();
}
this.popupsToRemove.set([]);
}
removeImages() {
for (const imageId of this.imageIdsToRemove()) {
this.mapInstance.removeImage(imageId);
}
this.imageIdsToRemove.set([]);
}
findLayersBySourceId(sourceId) {
const layers = this.mapInstance.getStyle().layers;
if (layers == null) {
return [];
}
return layers.filter((l) => 'source' in l ? l.source === sourceId : false);
}
hookEvents(events) {
this.mapInstance.on('load', (evt) => {
this.mapLoaded.next(undefined);
this.mapLoaded.complete();
this.zone.run(() => {
events.mapLoad.emit(evt.target);
});
});
this.mapInstance.on('resize', (evt) => this.zone.run(() => {
events.mapResize.emit(evt);
}));
this.mapInstance.on('remove', (evt) => this.zone.run(() => {
events.mapRemove.emit(evt);
}));
this.mapInstance.on('mousedown', (evt) => this.zone.run(() => {
events.mapMouseDown.emit(evt);
}));
this.mapInstance.on('mouseup', (evt) => this.zone.run(() => {
events.mapMouseUp.emit(evt);
}));
this.mapInstance.on('mousemove', (evt) => this.zone.run(() => {
events.mapMouseMove.emit(evt);
}));
this.mapInstance.on('click', (evt) => this.zone.run(() => {
events.mapClick.emit(evt);
}));
this.mapInstance.on('dblclick', (evt) => this.zone.run(() => {
events.mapDblClick.emit(evt);
}));
this.mapInstance.on('mouseover', (evt) => this.zone.run(() => {
events.mapMouseOver.emit(evt);
}));
this.mapInstance.on('mouseout', (evt) => this.zone.run(() => {
events.mapMouseOut.emit(evt);
}));
this.mapInstance.on('contextmenu', (evt) => this.zone.run(() => {
events.mapContextMenu.emit(evt);
}));
this.mapInstance.on('touchstart', (evt) => this.zone.run(() => {
events.mapTouchStart.emit(evt);
}));
this.mapInstance.on('touchend', (evt) => this.zone.run(() => {
events.mapTouchEnd.emit(evt);
}));
this.mapInstance.on('touchmove', (evt) => this.zone.run(() => {
events.mapTouchMove.emit(evt);
}));
this.mapInstance.on('touchcancel', (evt) => this.zone.run(() => {
events.mapTouchCancel.emit(evt);
}));
this.mapInstance.on('wheel', (evt) => this.zone.run(() => {
events.mapWheel.emit(evt);
}));
this.mapInstance.on('movestart', (evt) => this.zone.run(() => events.moveStart.emit(evt)));
this.mapInstance.on('move', (evt) => this.zone.run(() => events.move.emit(evt)));
this.mapInstance.on('moveend', (evt) => this.zone.run(() => events.moveEnd.emit(evt)));
this.mapInstance.on('dragstart', (evt) => this.zone.run(() => {
events.mapDragStart.emit(evt);
}));
this.mapInstance.on('drag', (evt) => this.zone.run(() => {
events.mapDrag.emit(evt);
}));
this.mapInstance.on('dragend', (evt) => this.zone.run(() => {
events.mapDragEnd.emit(evt);
}));
this.mapInstance.on('zoomstart', (evt) => this.zone.run(() => events.zoomStart.emit(evt)));
this.mapInstance.on('zoom', (evt) => this.zone.run(() => events.zoomEvt.emit(evt)));
this.mapInstance.on('zoomend', (evt) => this.zone.run(() => events.zoomEnd.emit(evt)));
this.mapInstance.on('rotatestart', (evt) => this.zone.run(() => events.rotateStart.emit(evt)));
this.mapInstance.on('rotate', (evt) => this.zone.run(() => events.rotate.emit(evt)));
this.mapInstance.on('rotateend', (evt) => this.zone.run(() => events.rotateEnd.emit(evt)));
this.mapInstance.on('pitchstart', (evt) => this.zone.run(() => events.pitchStart.emit(evt)));
this.mapInstance.on('pitch', (evt) => this.zone.run(() => events.pitchEvt.emit(evt)));
this.mapInstance.on('pitchend', (evt) => this.zone.run(() => events.pitchEnd.emit(evt)));
this.mapInstance.on('boxzoomstart', (evt) => this.zone.run(() => events.boxZoomStart.emit(evt)));
this.mapInstance.on('boxzoomend', (evt) => this.zone.run(() => events.boxZoomEnd.emit(evt)));
this.mapInstance.on('boxzoomcancel', (evt) => this.zone.run(() => events.boxZoomCancel.emit(evt)));
this.mapInstance.on('webglcontextlost', (evt) => this.zone.run(() => events.webGlContextLost.emit(evt)));
this.mapInstance.on('webglcontextrestored', (evt) => this.zone.run(() => events.webGlContextRestored.emit(evt)));
this.mapInstance.on('render', (evt) => this.zone.run(() => events.render.emit(evt)));
this.mapInstance.on('error', (evt) => this.zone.run(() => {
events.mapError.emit(evt);
}));
this.mapInstance.on('data', (evt) => this.zone.run(() => events.data.emit(evt)));
this.mapInstance.on('styledata', (evt) => this.zone.run(() => events.styleData.emit(evt)));
this.mapInstance.on('sourcedata', (evt) => this.zone.run(() => events.sourceData.emit(evt)));
this.mapInstance.on('dataloading', (evt) => this.zone.run(() => events.dataLoading.emit(evt)));
this.mapInstance.on('styledataloading', (evt) => this.zone.run(() => events.styleDataLoading.emit(evt)));
this.mapInstance.on('sourcedataloading', (evt) => this.zone.run(() => events.sourceDataLoading.emit(evt)));
this.mapInstance.on('styleimagemissing', (evt) => this.zone.run(() => events.styleImageMissing.emit(evt)));
this.mapInstance.on('idle', (evt) => this.zone.run(() => events.idle.emit(evt)));
}
createSubscriptionForLayer(layerId, event, emitter) {
const handler = (evt) => {
this.zone.run(() => {
emitter.emit(evt);
});
};
this.mapInstance.on(event, layerId, handler);
return {
unsubscribe: () => {
this.mapInstance.off(event, layerId, handler);
},
};
}
createSubscriptionForPopup(popup, event, emitter) {
const handler = (evt) => {
this.zone.run(() => {
emitter.emit(evt);
});
};
popup.on(event, handler);
return {
unsubscribe: () => {
popup.off(event, handler);
},
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MapService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MapService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MapService, decorators: [{
type: Injectable
}] });
class CustomControl {
constructor(container) {
this.container = container;
}
/** @inheritdoc */
onAdd() {
return this.container;
}
/** @inheritdoc */
onRemove() {
return this.container.parentNode.removeChild(this.container);
}
/** @inheritdoc */
getDefaultPosition() {
return 'top-right';
}
}
/**
* `mgl-control` - a custom control component
* @see [Controls](https://maplibre.org/maplibre-gl-js/docs/API/interfaces/IControl/)
*
* @category Components
*
* @example
* ```html
* ...
* <mgl-map ...>
* <mgl-control> Hello </mgl-control>
* ...
* <mgl-control mglNavigation></mgl-control>
* ...
* <mgl-control mglScale unit="imperial" position="top-right"></mgl-control>
* ...
* <mgl-control
* mglTerrain
* source="rasterDemSource"
* exaggeration="3.1"
* ></mgl-control>
* </mgl-map>
* ```
*/
class ControlComponent {
constructor() {
/** Init injection */
this.mapService = inject(MapService);
/** Init input */
this.position = input();
/** @hidden */
this.content = viewChild.required('content');
afterNextRender(() => {
if (this.content().nativeElement.childNodes.length) {
this.control = new CustomControl(this.content().nativeElement);
this.mapService.mapCreated$.subscribe(() => {
this.mapService.addControl(this.control, this.position());
});
}
});
}
ngOnDestroy() {
if (this.mapService?.mapInstance?.hasControl(this.control)) {
this.mapService.removeControl(this.control);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: ControlComponent, isStandalone: true, selector: "mgl-control", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: `
<div class="maplibregl-ctrl" #content>
<ng-content></ng-content>
</div>
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ControlComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-control',
template: `
<div class="maplibregl-ctrl" #content>
<ng-content></ng-content>
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}], ctorParameters: () => [] });
/**
* `mglAttribution` - an attribution control directive
*
* @category Directives
*
* @see [Add custom attribution](https://maplibre.org/ngx-maplibre-gl/demo/custom-attribution)
* @see [AttributionControl](https://maplibre.org/maplibre-gl-js/docs/API/classes/AttributionControl)
*/
class AttributionControlDirective {
constructor() {
/* Init injection */
this.mapService = inject(MapService);
this.controlComponent = inject(ControlComponent, { host: true });
/** Init input */
this.compact = input();
/** Init input */
this.customAttribution = input();
afterNextRender(() => {
this.mapService.mapCreated$.subscribe(() => {
if (this.controlComponent.control) {
throw new Error('Another control is already set for this control');
}
const options = keepAvailableObjectValues({
compact: this.compact(),
customAttribution: this.customAttribution(),
});
this.controlComponent.control = new AttributionControl(options);
this.mapService.addControl(this.controlComponent.control, this.controlComponent.position());
});
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AttributionControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: AttributionControlDirective, isStandalone: true, selector: "[mglAttribution]", inputs: { compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, customAttribution: { classPropertyName: "customAttribution", publicName: "customAttribution", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: AttributionControlDirective, decorators: [{
type: Directive,
args: [{
selector: '[mglAttribution]',
}]
}], ctorParameters: () => [] });
/**
* `mglFullscreen` - a fullscreen control directive
*
* @category Directives
*/
class FullscreenControlDirective {
constructor() {
/* Init injection */
this.mapService = inject(MapService);
this.controlComponent = inject(ControlComponent, { host: true });
/* Init inputs */
this.container = input();
afterNextRender(() => {
this.mapService.mapCreated$.subscribe(() => {
if (this.controlComponent.control) {
throw new Error('Another control is already set for this control');
}
this.controlComponent.control = new FullscreenControl({
container: this.container(),
});
this.mapService.addControl(this.controlComponent.control, this.controlComponent.position());
});
});
}
onFullscreen() {
this.mapService.mapInstance.resize();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FullscreenControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: FullscreenControlDirective, isStandalone: true, selector: "[mglFullscreen]", inputs: { container: { classPropertyName: "container", publicName: "container", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:webkitfullscreenchange": "onFullscreen()" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FullscreenControlDirective, decorators: [{
type: Directive,
args: [{
selector: '[mglFullscreen]',
host: {
// eslint-disable-next-line @typescript-eslint/naming-convention
'(window:webkitfullscreenchange)': 'onFullscreen()',
},
}]
}], ctorParameters: () => [] });
/**
* `mglGeolocate` - a geolocate control directive
*
* @category Directives
*
* @see [Locate user](https://maplibre.org/ngx-maplibre-gl/demo/locate-user)
* @see [GeolocateControl](https://maplibre.org/maplibre-gl-js/docs/API/classes/GeolocateControl)
*/
class GeolocateControlDirective {
constructor() {
/* Init injection */
this.mapService = inject(MapService);
this.controlComponent = inject(ControlComponent, { host: true });
/* Init inputs */
this.positionOptions = input();
/* Init inputs */
this.fitBoundsOptions = input();
/* Init inputs */
this.trackUserLocation = input();
/* Init inputs */
this.showUserLocation = input();
this.geolocate = output();
afterNextRender(() => {
this.mapService.mapCreated$.subscribe(() => {
if (this.controlComponent.control) {
throw new Error('Another control is already set for this control');
}
const options = keepAvailableObjectValues({
positionOptions: this.positionOptions(),
fitBoundsOptions: this.fitBoundsOptions(),
trackUserLocation: this.trackUserLocation(),
showUserLocation: this.showUserLocation(),
});
this.controlComponent.control = new GeolocateControl(options);
this.controlComponent.control.on('geolocate', (data) => {
this.geolocate.emit(data);
});
this.mapService.addControl(this.controlComponent.control, this.controlComponent.position());
});
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GeolocateControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: GeolocateControlDirective, isStandalone: true, selector: "[mglGeolocate]", inputs: { positionOptions: { classPropertyName: "positionOptions", publicName: "positionOptions", isSignal: true, isRequired: false, transformFunction: null }, fitBoundsOptions: { classPropertyName: "fitBoundsOptions", publicName: "fitBoundsOptions", isSignal: true, isRequired: false, transformFunction: null }, trackUserLocation: { classPropertyName: "trackUserLocation", publicName: "trackUserLocation", isSignal: true, isRequired: false, transformFunction: null }, showUserLocation: { classPropertyName: "showUserLocation", publicName: "showUserLocation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { geolocate: "geolocate" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GeolocateControlDirective, decorators: [{
type: Directive,
args: [{
selector: '[mglGeolocate]',
}]
}], ctorParameters: () => [] });
/**
* `mglNavigation` - a navigation control directive
*
* @category Directives
*
* @see [Navigation](https://maplibre.org/ngx-maplibre-gl/demo/navigation)
* @see [NavigationControl](https://maplibre.org/maplibre-gl-js/docs/API/classes/NavigationControl)
*/
class NavigationControlDirective {
constructor() {
/* Init injection */
this.mapService = inject(MapService);
this.controlComponent = inject(ControlComponent, { host: true });
/* Init inputs */
this.showCompass = input();
/* Init inputs */
this.showZoom = input();
/* Init inputs */
this.visualizePitch = input();
/* Init inputs */
this.visualizeRoll = input();
afterNextRender(() => {
this.mapService.mapCreated$.subscribe(() => {
if (this.controlComponent.control) {
throw new Error('Another control is already set for this control');
}
const options = keepAvailableObjectValues({
showCompass: this.showCompass(),
showZoom: this.showZoom(),
visualizePitch: this.visualizePitch(),
visualizeRoll: this.visualizeRoll(),
});
this.controlComponent.control = new NavigationControl(options);
this.mapService.addControl(this.controlComponent.control, this.controlComponent.position());
});
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NavigationControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: NavigationControlDirective, isStandalone: true, selector: "[mglNavigation]", inputs: { showCompass: { classPropertyName: "showCompass", publicName: "showCompass", isSignal: true, isRequired: false, transformFunction: null }, showZoom: { classPropertyName: "showZoom", publicName: "showZoom", isSignal: true, isRequired: false, transformFunction: null }, visualizePitch: { classPropertyName: "visualizePitch", publicName: "visualizePitch", isSignal: true, isRequired: false, transformFunction: null }, visualizeRoll: { classPropertyName: "visualizeRoll", publicName: "visualizeRoll", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NavigationControlDirective, decorators: [{
type: Directive,
args: [{
selector: '[mglNavigation]',
}]
}], ctorParameters: () => [] });
/**
* `mglScale` - a scale control directive
*
* @category Directives
*
* @see [Scale](https://maplibre.org/ngx-maplibre-gl/demo/ngx-scale-control)
* @see [ScaleControl](https://maplibre.org/maplibre-gl-js/docs/API/classes/ScaleControl)
*/
class ScaleControlDirective {
constructor() {
/* Init injection */
this.mapService = inject(MapService);
this.controlComponent = inject(ControlComponent, { host: true });
/* Init inputs */
this.maxWidth = input();
/* Dynamic inputs */
this.unit = input();
afterNextRender(() => {
this.mapService.mapCreated$.subscribe(() => {
if (this.controlComponent.control) {
throw new Error('Another control is already set for this control');
}
const options = keepAvailableObjectValues({
maxWidth: this.maxWidth(),
unit: this.unit(),
});
this.controlComponent.control = new ScaleControl(options);
this.mapService.addControl(this.controlComponent.control, this.controlComponent.position());
});
});
}
ngOnChanges(changes) {
if (changes.unit && !changes.unit.isFirstChange()) {
this.controlComponent.control.setUnit(changes.unit.currentValue);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ScaleControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: ScaleControlDirective, isStandalone: true, selector: "[mglScale]", inputs: { maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, unit: { classPropertyName: "unit", publicName: "unit", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ScaleControlDirective, decorators: [{
type: Directive,
args: [{
selector: '[mglScale]',
}]
}], ctorParameters: () => [] });
/**
* `mglTerrain` - a terrain control directive
*
* @category Directives
*
* @see [Terrain](https://maplibre.org/ngx-maplibre-gl/demo/terrain-control)
* @see [TerrainControl](https://maplibre.org/maplibre-gl-js/docs/API/classes/TerrainControl)
*/
class TerrainControlDirective {
constructor() {
/* Init injection */
this.mapService = inject(MapService);
this.controlComponent = inject(ControlComponent, { host: true });
/* Init inputs */
this.source = input.required();
this.exaggeration = input();
afterNextRender(() => {
this.mapService.mapCreated$.subscribe(() => {
if (this.controlComponent.control) {
throw new Error('Another control is already set for this control');
}
const options = {
source: this.source(),
exaggeration: this.exaggeration() ?? 1,
};
this.controlComponent.control = new TerrainControl(options);
this.mapService.addControl(this.controlComponent.control, this.controlComponent.position());
});
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: TerrainControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: TerrainControlDirective, isStandalone: true, selector: "[mglTerrain]", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: true, transformFunction: null }, exaggeration: { classPropertyName: "exaggeration", publicName: "exaggeration", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: TerrainControlDirective, decorators: [{
type: Directive,
args: [{
selector: '[mglTerrain]',
}]
}], ctorParameters: () => [] });
/**
* @internal
* A composition object for the source components
*/
class SourceDirective {
constructor() {
/** Init injection */
this.mapService = inject(MapService);
this.destroyRef = inject(DestroyRef);
/** Init input */
this.id = input.required();
/**
* @internal
* Used to store the current source id and make sure removeSource is only called once.
*/
this.sourceId = signal(null);
this.loadSourceSubject = new Subject();
this.loadSource$ = this.loadSourceSubject.asObservable();
}
ngOnInit() {
this.mapService.mapLoaded$
.pipe(tap(() => this.loadSourceSubject.next()), switchMap(() => fromEvent(this.mapService.mapInstance, 'styledata').pipe(filter(() => !this.mapService.mapInstance.getSource(this.id())), tap(() => this.loadSourceSubject.next()))), takeUntilDestroyed(this.destroyRef))
.subscribe();
}
ngOnDestroy() {
this.removeSource();
}
refresh() {
this.removeSource();
this.loadSourceSubject.next();
}
removeSource() {
const currentId = this.sourceId();
if (currentId) {
this.mapService.removeSource(currentId);
this.sourceId.set(null);
}
}
addSource(source) {
this.mapService.addSource(this.id(), source);
this.sourceId.set(this.id());
}
getSource() {
return this.mapService.getSource(this.id());
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: SourceDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: SourceDirective, isStandalone: true, inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: SourceDirective, decorators: [{
type: Directive,
args: [{}]
}] });
/**
* `mgl-geojson-source` - a geojson source component
* @see [geojson](https://maplibre.org/maplibre-gl-js/docs/API/classes/maplibregl.GeoJSONSource/)
*
* @category Source Components
*
* @example
* ```html
* ...
* <mgl-map ...>
* <mgl-geojson-source id="symbols-source">
* <mgl-feature
* *ngFor="let geometry of geometries"
* [geometry]="geometry"
* ></mgl-feature>
* </mgl-geojson-source>
* ...
* <mgl-geojson-source
* id="earthquakes"
* [data]="earthquakes"
* [cluster]="true"
* [clusterMaxZoom]="14"
* [clusterRadius]="50"
* ></mgl-geojson-source>
* </mgl-map>
*
* ```
*/
class GeoJSONSourceComponent {
constructor() {
/** Init injections */
this.sourceDirective = inject(SourceDirective);
/** Init injection */
this.ngZone = inject(NgZone);
/** Dynamic input */
this.data = input({
type: 'FeatureCollection',
features: [],
});
/** Dynamic input */
this.maxzoom = input();
/** Dynamic input */
this.attribution = input();
/** Dynamic input */
this.buffer = input();
/** Dynamic input */
this.tolerance = input();
/** Dynamic input */
this.cluster = input();
/** Dynamic input */
this.clusterRadius = input();
/** Dynamic input */
this.clusterMaxZoom = input();
/** Dynamic input */
this.clusterMinPoints = input();
/** Dynamic input */
this.clusterProperties = input();
/** Dynamic input */
this.lineMetrics = input();
/** Dynamic input */
this.generateId = input();
/** Dynamic input */
this.promoteId = input();
/** Dynamic input */
this.filter = input();
this.updateFeatureDataSubject = new Subject();
this.featureIdCounter = signal(0);
this.sourceDirective.loadSource$
.pipe(tap(() => this.sourceDirective.addSource(this.getGeoJSONSourceSpecification())), switchMap(() => this.updateFeature()), takeUntilDestroyed())
.subscribe();
}
ngOnChanges(changes) {
if (!this.sourceDirective.sourceId()) {
return;
}
if ((changes.maxzoom && !changes.maxzoom.isFirstChange()) ||
(changes.attribution && !changes.attribution.isFirstChange()) ||
(changes.buffer && !changes.buffer.isFirstChange()) ||
(changes.tolerance && !changes.tolerance.isFirstChange()) ||
(changes.cluster && !changes.cluster.isFirstChange()) ||
(changes.clusterRadius && !changes.clusterRadius.isFirstChange()) ||
(changes.clusterMaxZoom && !changes.clusterMaxZoom.isFirstChange()) ||
(changes.clusterMinPoints && !changes.clusterMinPoints.isFirstChange()) ||
(changes.clusterProperties &&
!changes.clusterProperties.isFirstChange()) ||
(changes.lineMetrics && !changes.lineMetrics.isFirstChange()) ||
(changes.generateId && !changes.generateId.isFirstChange()) ||
(changes.promoteId && !changes.promoteId.isFirstChange()) ||
(changes.filter && !changes.filter.isFirstChange())) {
this.sourceDirective.refresh();
}
if (changes.data && !changes.data.isFirstChange()) {
const source = this.sourceDirective.getSource();
if (source === undefined) {
return;
}
source.setData(changes.data.currentValue);
}
}
/**
* For clustered sources, fetches the zoom at which the given cluster expands.
* @param clusterId The value of the cluster's cluster_id property.
*/
async getClusterExpansionZoom(clusterId) {
const source = this.sourceDirective.getSource();
return this.ngZone.run(async () => {
return source.getClusterExpansionZoom(clusterId);
});
}
/**
* For clustered sources, fetches the children of the given cluster on the next zoom level (as an array of GeoJSON features).
* @param clusterId The value of the cluster's cluster_id property.
*/
async getClusterChildren(clusterId) {
const source = this.sourceDirective.getSource();
return this.ngZone.run(async () => {
return source.getClusterChildren(clusterId);
});
}
/**
* For clustered sources, fetches the original points that belong to the cluster (as an array of GeoJSON features).
* @param clusterId The value of the cluster's cluster_id property.
* @param limit The maximum number of features to return.
* @param offset The number of features to skip (e.g. for pagination).
*/
async getClusterLeaves(clusterId, limit, offset) {
const source = this.sourceDirective.getSource();
return this.ngZone.run(async () => {
return source.getClusterLeaves(clusterId, limit, offset);
});
}
_addFeature(feature) {
const collection = (this.data());
collection.features.push(feature);
this.updateFeatureDataSubject.next();
}
_removeFeature(feature) {
const collection = (this.data());
const index = collection.features.indexOf(feature);
if (index > -1) {
collection.features.splice(index, 1);
}
this.updateFeatureDataSubject.next();
}
updateFeatureData() {
this.updateFeatureDataSubject.next();
}
_getNewFeatureId() {
this.featureIdCounter.update((featureIdCounter) => ++featureIdCounter);
return this.featureIdCounter();
}
getGeoJSONSourceSpecification() {
return {
type: 'geojson',
data: this.data(),
maxzoom: this.maxzoom(),
attribution: this.attribution(),
buffer: this.buffer(),
tolerance: this.tolerance(),
cluster: this.cluster(),
clusterRadius: this.clusterRadius(),
clusterMaxZoom: this.clusterMaxZoom(),
clusterMinPoints: this.clusterMinPoints(),
clusterProperties: this.clusterProperties(),
lineMetrics: this.lineMetrics(),
generateId: this.generateId(),
promoteId: this.promoteId(),
filter: this.filter(),
};
}
updateFeature() {
return this.updateFeatureDataSubject.pipe(debounceTime(0)).pipe(tap(() => {
const source = this.sourceDirective.getSource();
if (source === undefined) {
return;
}
source.setData(this.data());
}));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GeoJSONSourceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: GeoJSONSourceComponent, isStandalone: true, selector: "mgl-geojson-source", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, maxzoom: { classPropertyName: "maxzoom", publicName: "maxzoom", isSignal: true, isRequired: false, transformFunction: null }, attribution: { classPropertyName: "attribution", publicName: "attribution", isSignal: true, isRequired: false, transformFunction: null }, buffer: { classPropertyName: "buffer", publicName: "buffer", isSignal: true, isRequired: false, transformFunction: null }, tolerance: { classPropertyName: "tolerance", publicName: "tolerance", isSignal: true, isRequired: false, transformFunction: null }, cluster: { classPropertyName: "cluster", publicName: "cluster", isSignal: true, isRequired: false, transformFunction: null }, clusterRadius: { classPropertyName: "clusterRadius", publicName: "clusterRadius", isSignal: true, isRequired: false, transformFunction: null }, clusterMaxZoom: { classPropertyName: "clusterMaxZoom", publicName: "clusterMaxZoom", isSignal: true, isRequired: false, transformFunction: null }, clusterMinPoints: { classPropertyName: "clusterMinPoints", publicName: "clusterMinPoints", isSignal: true, isRequired: false, transformFunction: null }, clusterProperties: { classPropertyName: "clusterProperties", publicName: "clusterProperties", isSignal: true, isRequired: false, transformFunction: null }, lineMetrics: { classPropertyName: "lineMetrics", publicName: "lineMetrics", isSignal: true, isRequired: false, transformFunction: null }, generateId: { classPropertyName: "generateId", publicName: "generateId", isSignal: true, isRequired: false, transformFunction: null }, promoteId: { classPropertyName: "promoteId", publicName: "promoteId", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, hostDirectives: [{ directive: SourceDirective, inputs: ["id", "id"] }], ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GeoJSONSourceComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-geojson-source',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [{ directive: SourceDirective, inputs: ['id'] }],
}]
}], ctorParameters: () => [] });
/**
* `mgl-feature` - a feature component
* [ngx] inside {@link GeoJSONSourceComponent} only
*
* @category Source Components
*/
class FeatureComponent {
constructor() {
/** Init injection */
this.geoJSONSourceComponent = inject(forwardRef(() => GeoJSONSourceComponent));
/** Init input */
this.id = model();
/** Init input */
this.geometry = input.required();
/** Init input */
this.properties = input();
}
ngOnInit() {
const id = this.id();
if (!id) {
this.id.set(this.geoJSONSourceComponent._getNewFeatureId());
}
const properties = this.properties();
this.feature = {
type: 'Feature',
geometry: this.geometry(),
properties: properties ?? {},
};
this.feature.id = this.id();
this.geoJSONSourceComponent._addFeature(this.feature);
}
ngOnDestroy() {
this.geoJSONSourceComponent._removeFeature(this.feature);
}
updateCoordinates(coordinates) {
this.feature.geometry.coordinates = coordinates;
this.geoJSONSourceComponent.updateFeatureData();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FeatureComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: FeatureComponent, isStandalone: true, selector: "mgl-feature", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, geometry: { classPropertyName: "geometry", publicName: "geometry", isSignal: true, isRequired: true, transformFunction: null }, properties: { classPropertyName: "properties", publicName: "properties", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { id: "idChange" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: FeatureComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-feature',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}] });
/**
* `mglDraggable` - a directive for Feature or Marker
*
* @category Directives
*
* @see [Draggable Marker](https://maplibre.org/ng-maplibre-gl/demo/ngx-drag-a-point)
*/
class DraggableDirective {
constructor() {
/** Init injection */
this.mapService = inject(MapService);
this.ngZone = inject(NgZone);
this.featureComponent = inject(FeatureComponent, {
host: true,
optional: true,
});
// eslint-disable-next-line @angular-eslint/no-input-rename
this.layer = input(null, {
alias: 'mglDraggable',
});
this.featureDragStart = output();
this.featureDragEnd = output();
this.featureDrag = output();
this.sub = new Subscription();
}
ngOnInit() {
let enter$;
let leave$;
let updateCoords;
const layer = this.layer();
if (this.featureComponent && layer) {
enter$ = outputToObservable(layer.layerMouseEnter);
leave$ = outputToObservable(layer.layerMouseLeave);
updateCoords = this.featureComponent.updateCoordinates.bind(this.featureComponent);
if (this.featureComponent.geometry().type !== 'Point') {
throw new Error('mglDraggable only support point feature');
}
}
else {
throw new Error('mglDraggable can only be used on Feature (with a layer as input) or Marker');
}
this.handleDraggable(enter$, leave$, updateCoords);
}
ngOnDestroy() {
this.sub.unsubscribe();
}
handleDraggable(enter$, leave$, updateCoords) {
let moving = false;
let inside = false;
this.mapService.mapCreated$.subscribe(() => {
const mouseUp$ = fromEvent(this.mapService.mapInstance, 'mouseup');
const dragStart$ = enter$.pipe(filter(() => !moving), filter((evt) => this.filterFeature(evt)), tap(() => {
inside = true;
this.mapService.changeCanvasCursor('move');
this.mapService.updateDragPan(false);
}), switchMap(() => fromEvent(this.mapService.mapInstance, 'mousedown').pipe(takeUntil(leave$))));
const dragging$ = dragStart$.pipe(switchMap(() => fromEvent(this.mapService.mapInstance, 'mousemove').pipe(takeUntil(mouseUp$))));
const dragEnd$ = dragStart$.pipe(switchMap(() => mouseUp$.pipe(take(1))));
this.sub.add(dragStart$.subscribe((evt) => {
moving = true;
this.ngZone.run(() => {
this.featureDragStart.emit(evt);
});
}));
this.sub.add(dragging$.subscribe((evt) => {
updateCoords([evt.lngLat.lng, evt.lngLat.lat]);
this.ngZone.run(() => {
this.featureDrag.emit(evt);
});
}));
this.sub.add(dragEnd$.subscribe((evt) => {
moving = false;
this.ngZone.run(() => {
this.featureDragEnd.emit(evt);
});
if (!inside) {
// It's possible to dragEnd outside the target (small input lag)
this.mapService.changeCanvasCursor('');
this.mapService.updateDragPan(true);
}
}));
this.sub.add(leave$
.pipe(tap(() => (inside = false)), filter(() => !moving))
.subscribe(() => {
this.mapService.changeCanvasCursor('');
this.mapService.updateDragPan(true);
}));
});
}
filterFeature(evt) {
const layer = this.layer();
if (this.featureComponent && layer) {
const feature = this.mapService.queryRenderedFeatures(evt.point, {
layers: [layer.id()],
filter: [
'all',
['==', '$type', 'Point'],
['==', '$id', this.featureComponent.id()],
],
})[0];
if (!feature) {
return false;
}
}
return true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DraggableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.0.4", type: DraggableDirective, isStandalone: true, selector: "[mglDraggable]", inputs: { layer: { classPropertyName: "layer", publicName: "mglDraggable", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { featureDragStart: "featureDragStart", featureDragEnd: "featureDragEnd", featureDrag: "featureDrag" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: DraggableDirective, decorators: [{
type: Directive,
args: [{
selector: '[mglDraggable]',
}]
}] });
/**
* `mgl-image` - an image component
* @see [addImage](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/#addimage)
*
* @category Components
*
* @example
* ```html
* ...
* <mgl-map
* ...
* >
* <mgl-image
* id="image"
* url="https://..."
* (imageLoaded)="imageLoaded = true"
* >
* ...
* <mgl-image
* id="image2"
* [data]="{
* width: 64,
* height: 64,
* data: imageData
* }"
* >
* </mgl-map>
* ...
* imageData: Uint8Array;
* ```
*/
class ImageComponent {
constructor() {
/** Init injection */
this.mapService = inject(MapService);
this.destroyRef = inject(DestroyRef);
this.zone = inject(NgZone);
/** Init input */
this.id = input.required();
/** Dynamic input */
this.data = input();
/** Dynamic input */
this.options = input();
/** Dynamic input */
this.url = input();
this.imageError = output();
this.imageLoaded = output();
this.isAdded = signal(false);
this.isAdding = signal(false);
}
ngOnInit() {
this.mapService.mapLoaded$
.pipe(switchMap(() => fromEvent(this.mapService.mapInstance, 'styledata').pipe(startWith(undefined), filter(() => !this.isAdding() &&
!this.mapService.mapInstance.hasImage(this.id())))), takeUntilDestroyed(this.destroyRef))
.subscribe(() => this.addImage());
}
ngOnChanges(changes) {
if ((changes.data && !changes.data.isFirstChange()) ||
(changes.options && !changes.options.isFirstChange()) ||
(changes.url && !changes.url.isFirstChange())) {
this.removeImage();
this.ngOnInit();
}
}
ngOnDestroy() {
this.removeImage();
}
removeImage() {
if (this.isAdded()) {
this.mapService.removeImage(this.id());
}
}
async addImage() {
this.isAdding.set(true);
const data = this.data();
const url = this.url();
if (data) {
this.mapService.addImage(this.id(), data, this.options());
this.isAdded.set(true);
this.isAdding.set(false);
}
else if (url) {
try {
await this.mapService.loadAndAddImage(this.id(), url, this.options());
this.isAdded.set(true);
this.isAdding.set(false);
this.zone.run(() => {
this.imageLoaded.emit();
});
}
catch (error) {
this.zone.run(() => {
this.imageError.emit(error);
});
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ImageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: ImageComponent, isStandalone: true, selector: "mgl-image", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageError: "imageError", imageLoaded: "imageLoaded" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ImageComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-image',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}] });
/**
* `mgl-layer` - a layer component
* @see [layers](https://maplibre.org/maplibre-style-spec/layers/)
*
* @category Layer Component
*
* @example
* ```html
* ...
* <mgl-map ...>
* <mgl-layer
* id="state-borders"
* type="line"
* [source]="states"
* [paint]="{
* 'line-color': '#627BC1',
* 'line-width': 2
* }"
* ></mgl-layer>
* </mgl-map>
* ```
*/
class LayerComponent {
constructor() {
/** Init injection */
this.destroyRef = inject(DestroyRef);
this.mapService = inject(MapService);
/** Init input */
this.id = input.required();
this.type = input.required();
this.source = input();
this.metadata = input();
this.sourceLayer = input();
/**
* A flag to enable removeSource clean up functionality
*
* Init input
*/
this.removeSource = input();
this.filter = input();
this.layout = input();
this.paint = input();
this.before = input();
this.minzoom = input();
this.maxzoom = input();
this.layerClick = output();
this.layerDblClick = output();
this.layerMouseDown = output();
this.layerMouseUp = output();
this.layerMouseEnter = output();
this.layerMouseLeave = output();
this.layerMouseMove = output();
this.layerMouseOver = output();
this.layerMouseOut = output();
this.layerContextMenu = output();
this.layerTouchStart = output();
this.layerTouchEnd = output();
this.layerTouchCancel = output();
this.layerAdded = signal(false);
this.sourceIdAdded = signal(null);
}
ngOnInit() {
this.mapService.mapLoaded$
.pipe(switchMap(() => fromEvent(this.mapService.mapInstance, 'styledata').pipe(map(() => false), filter(() => !this.mapService.mapInstance.getLayer(this.id())), startWith(true))), takeUntilDestroyed(this.destroyRef))
.subscribe((bindEvents) => this.init(bindEvents));
}
ngOnChanges(changes) {
if (!this.layerAdded()) {
return;
}
if (changes.paint && !changes.paint.isFirstChange()) {
this.mapService.setAllLayerPaintProperty(this.id(), changes.paint.currentValue);
}
if (changes.layout && !changes.layout.isFirstChange()) {
this.mapService.setAllLayerLayoutProperty(this.id(), changes.layout.currentValue);
}
if (changes.filter && !changes.filter.isFirstChange()) {
this.mapService.setLayerFilter(this.id(), changes.filter.currentValue);
}
if (changes.before && !changes.before.isFirstChange()) {
this.mapService.setLayerBefore(this.id(), changes.before.currentValue);
}
if ((changes.minzoom && !changes.minzoom.isFirstChange()) ||
(changes.maxzoom && !changes.maxzoom.isFirstChange())) {
this.mapService.setLayerZoomRange(this.id(), this.minzoom(), this.maxzoom());
}
}
ngOnDestroy() {
if (this.layerAdded()) {
const sourceIdAdded = this.sourceIdAdded();
this.mapService.removeLayer(this.id());
if (sourceIdAdded !== null) {
// Clean up any automatically created source for this layer
if (this.mapService.getSource(sourceIdAdded)) {
this.mapService.removeSource(sourceIdAdded);
}
}
}
}
init(bindEvents) {
const layer = {
layerOptions: {
id: this.id(),
type: this.type(),
source: this.source(),
metadata: this.metadata(),
// eslint-disable-next-line @typescript-eslint/naming-convention
'source-layer': this.sourceLayer(),
minzoom: this.minzoom(),
maxzoom: this.maxzoom(),
filter: this.filter(),
layout: this.layout(),
paint: this.paint(),
},
layerEvents: {
layerClick: this.layerClick,
layerDblClick: this.layerDblClick,
layerMouseDown: this.layerMouseDown,
layerMouseUp: this.layerMouseUp,
layerMouseEnter: this.layerMouseEnter,
layerMouseLeave: this.layerMouseLeave,
layerMouseMove: this.layerMouseMove,
layerMouseOver: this.layerMouseOver,
layerMouseOut: this.layerMouseOut,
layerContextMenu: this.layerContextMenu,
layerTouchStart: this.layerTouchStart,
layerTouchEnd: this.layerTouchEnd,
layerTouchCancel: this.layerTouchCancel,
},
};
if (this.removeSource() && typeof this.source() !== 'string') {
// There is no id of an existing source bound to this layer
if (this.mapService.getSource(this.id()) === undefined) {
// A source with this layer id doesn't exist so it will be created automatically in the addLayer call below
this.sourceIdAdded.set(this.id());
}
}
this.mapService.addLayer(layer, bindEvents, this.before());
const sourceIdAdded = this.sourceIdAdded();
if (sourceIdAdded !== null) {
const getSource = this.mapService.getSource(sourceIdAdded);
if (getSource === undefined) {
// If it wasn't created for some reason then we don't want to clean it up
this.sourceIdAdded.set(null);
}
}
this.layerAdded.set(true);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: LayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: LayerComponent, isStandalone: true, selector: "mgl-layer", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: false, transformFunction: null }, metadata: { classPropertyName: "metadata", publicName: "metadata", isSignal: true, isRequired: false, transformFunction: null }, sourceLayer: { classPropertyName: "sourceLayer", publicName: "sourceLayer", isSignal: true, isRequired: false, transformFunction: null }, removeSource: { classPropertyName: "removeSource", publicName: "removeSource", isSignal: true, isRequired: false, transformFunction: null }, filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, paint: { classPropertyName: "paint", publicName: "paint", isSignal: true, isRequired: false, transformFunction: null }, before: { classPropertyName: "before", publicName: "before", isSignal: true, isRequired: false, transformFunction: null }, minzoom: { classPropertyName: "minzoom", publicName: "minzoom", isSignal: true, isRequired: false, transformFunction: null }, maxzoom: { classPropertyName: "maxzoom", publicName: "maxzoom", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { layerClick: "layerClick", layerDblClick: "layerDblClick", layerMouseDown: "layerMouseDown", layerMouseUp: "layerMouseUp", layerMouseEnter: "layerMouseEnter", layerMouseLeave: "layerMouseLeave", layerMouseMove: "layerMouseMove", layerMouseOver: "layerMouseOver", layerMouseOut: "layerMouseOut", layerContextMenu: "layerContextMenu", layerTouchStart: "layerTouchStart", layerTouchEnd: "layerTouchEnd", layerTouchCancel: "layerTouchCancel" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: LayerComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-layer',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}] });
/**
* `mgl-map` - The main map component
* @see [Map](https://maplibre.org/maplibre-gl-js/docs/API/classes/Map/)
*
* @category Map Component
*
* @example
* ```typescript
* ...
* @Component({
* template: `
* <mgl-map
* [style]="'https://demotiles.maplibre.org/style.json'"
* [zoom]="[9]"
* [center]="[-74.50, 40]"
* (mapLoad)="map = $event"
* ></mgl-map>
* `,
* ...
* })
* export class DisplayMapComponent {
* map: Map; // MapLibre GL Map object (MapLibre is ran outside angular zone, keep that in mind when binding events from this object)
* ...
* }
* ```
*/
class MapComponent {
get mapInstance() {
return this.mapService.mapInstance;
}
constructor() {
this.mapService = inject(MapService);
this.elementRef = inject(ElementRef);
/** Init input */
this.collectResourceTiming = input();
/** Init input */
this.crossSourceCollisions = input();
/** Init input */
this.customMapboxApiUrl = input();
/** Init input */
this.fadeDuration = input();
/** Init input */
this.hash = input();
/** Init input */
this.refreshExpiredTiles = input();
/** Init input */
this.canvasContextAttributes = input();
/** Init input */
this.bearingSnap = input();
/** Init input */
this.interactive = input();
/** Init input */
this.pitchWithRotate = input();
/** Init input */
this.clickTolerance = input();
/** Init input */
this.attributionControl = input();
/** Init input */
this.logoPosition = input();
/** Init input */
this.maxTileCacheSize = input();
/** Init input */
this.localIdeographFontFamily = input();
/** Init input */
this.trackResize = input();
/** Init input */
this.transformRequest = input();
/** Init input */
this.bounds = input();
/** Init input */
this.locale = input();
/** Init input */
this.cooperativeGestures = input();
/** Init input */
this.cancelPendingTileRequestsWhileZooming = input();
/** Init input */
this.centerClampedToGround = input();
/** Init input */
this.maplibreLogo = input();
/** Init input */
this.maxCanvasSize = input();
/** Init input */
this.maxTileCacheZoomLevels = input();
/** Init input */
this.pixelRatio = input();
/** Init input */
this.rollEnabled = input();
/** Init input */
this.transformCameraUpdate = input();
/** Init input */
this.validateStyle = input();
/** Dynamic input */
this.minZoom = input();
/** Dynamic input */
this.maxZoom = input();
/** Dynamic input */
this.minPitch = input();
/** Dynamic input */
this.maxPitch = input();
/** Dynamic input */
this.scrollZoom = input();
/** Dynamic input */
this.dragRotate = input();
/** Dynamic input */
this.touchPitch = input();
/** Dynamic input */
this.touchZoomRotate = input();
/** Dynamic input */
this.doubleClickZoom = input();
/** Dynamic input */
this.keyboard = input();
/** Dynamic input */
this.dragPan = input();
/** Dynamic input */
this.boxZoom = input();
/** Dynamic input */
this.style = input.required();
/** Dynamic input */
this.center = input();
/** Dynamic input */
this.maxBounds = input();
/** Dynamic input */
this.zoom = input();
/** Dynamic input */
this.bearing = input();
/** Dynamic input */
this.pitch = input();
/** Dynamic input */
this.roll = input();
/** Dynamic input */
this.fitBoundsOptions = input(); // First value goes to options.fitBoundsOptions. Subsequents changes are passed to fitBounds
/** Dynamic input */
this.renderWorldCopies = input();
/** Dynamic input */
this.elevation = input();
/** Dynamic input that is not part of the `MapOptions` object */
this.terrain = input();
/** Dynamic input that is not part of the `MapOptions` object */
this.projection = input();
/** Added by ngx-mapbox-gl */
this.movingMethod = input('flyTo');
this.movingOptions = input();
// => First value is a alias to bounds input (since mapbox 0.53.0). Subsequents changes are passed to fitBounds
this.fitBounds = input();
this.fitScreenCoordinates = input();
this.centerWithPanTo = input();
this.panToOptions = input();
this.cursorStyle = input();
this.mapResize = output();
this.mapRemove = output();
this.mapMouseDown = output();
this.mapMouseUp = output();
this.mapMouseMove = output();
this.mapClick = output();
this.mapDblClick = output();
this.mapMouseOver = output();
this.mapMouseOut = output();
this.mapContextMenu = output();
this.mapTouchStart = output();
this.mapTouchEnd = output();
this.mapTouchMove = output();
this.mapTouchCancel = output();
this.mapWheel = output();
this.moveStart = output();
this.move = output();
this.moveEnd = output();
this.mapDragStart = output();
this.mapDrag = output();
this.mapDragEnd = output();
this.zoomStart = output();
this.zoomEvt = output();
this.zoomEnd = output();
this.rotateStart = output();
this.rotate = output();
this.rotateEnd = output();
this.pitchStart = output();
this.pitchEvt = output();
this.pitchEnd = output();
this.boxZoomStart = output();
this.boxZoomEnd = output();
this.boxZoomCancel = output();
this.webGlContextLost = output();
this.webGlContextRestored = output();
this.mapLoad = output();
this.idle = output();
this.render = output();
this.mapError = output();
this.data = output();
this.styleData = output();
this.sourceData = output();
this.dataLoading = output();
this.styleDataLoading = output();
this.sourceDataLoading = output();
this.styleImageMissing = output();
this.mapContainer = viewChild.required('container');
afterNextRender(() => {
if (this.canvasContextAttributes()?.preserveDrawingBuffer) {
// This is to allow better interaction with the map state
const htmlElement = this.elementRef.nativeElement;
htmlElement.setAttribute('data-cy', 'map');
this.mapLoad.subscribe(() => {
htmlElement.setAttribute('data-loaded', 'true');
});
this.idle.subscribe(() => {
htmlElement.setAttribute('data-idle', 'true');
});
this.render.subscribe(() => {
htmlElement.removeAttribute('data-idle');
});
}
this.mapService.setup({
mapOptions: {
collectResourceTiming: this.collectResourceTiming(),
container: this.mapContainer().nativeElement,
crossSourceCollisions: this.crossSourceCollisions(),
fadeDuration: this.fadeDuration(),
minZoom: this.minZoom(),
maxZoom: this.maxZoom(),
minPitch: this.minPitch(),
maxPitch: this.maxPitch(),
style: this.style(),
hash: this.hash(),
interactive: this.interactive(),
bearingSnap: this.bearingSnap(),
pitchWithRotate: this.pitchWithRotate(),
clickTolerance: this.clickTolerance(),
attributionControl: this.attributionControl(),
logoPosition: this.logoPosition(),
canvasContextAttributes: this.canvasContextAttributes(),
refreshExpiredTiles: this.refreshExpiredTiles(),
maxBounds: this.maxBounds(),
scrollZoom: this.scrollZoom(),
boxZoom: this.boxZoom(),
dragRotate: this.dragRotate(),
dragPan: this.dragPan(),
keyboard: this.keyboard(),
doubleClickZoom: this.doubleClickZoom(),
touchPitch: this.touchPitch(),
touchZoomRotate: this.touchZoomRotate(),
trackResize: this.trackResize(),
center: this.center(),
zoom: this.zoom(),
bearing: this.bearing(),
pitch: this.pitch(),
roll: this.roll(),
renderWorldCopies: this.renderWorldCopies(),
maxTileCacheSize: this.maxTileCacheSize(),
localIdeographFontFamily: this.localIdeographFontFamily(),
transformRequest: this.transformRequest(),
bounds: this.bounds() ? this.bounds() : this.fitBounds(),
fitBoundsOptions: this.fitBoundsOptions(),
locale: this.locale,
cooperativeGestures: this.cooperativeGestures(),
cancelPendingTileRequestsWhileZooming: this.cancelPendingTileRequestsWhileZooming(),
centerClampedToGround: this.centerClampedToGround(),
elevation: this.elevation(),
maplibreLogo: this.maplibreLogo(),
maxCanvasSize: this.maxCanvasSize(),
maxTileCacheZoomLevels: this.maxTileCacheZoomLevels(),
pixelRatio: this.pixelRatio(),
rollEnabled: this.rollEnabled(),
transformCameraUpdate: this.transformCameraUpdate(),
validateStyle: this.validateStyle(),
terrain: this.terrain(),
projection: this.projection(),
},
mapEvents: this,
});
const cursorStyle = this.cursorStyle();
if (cursorStyle) {
this.mapService.changeCanvasCursor(cursorStyle);
}
});
afterEveryRender(() => {
this.mapService.clearMapElements();
});
}
ngOnDestroy() {
this.mapService.destroyMap();
}
async ngOnChanges(changes) {
await firstValueFrom(this.mapService.mapCreated$);
const zoom = this.zoom();
const bearing = this.bearing();
const pitch = this.pitch();
const center = this.center();
if (changes.cursorStyle && !changes.cursorStyle.isFirstChange()) {
this.mapService.changeCanvasCursor(changes.cursorStyle.currentValue);
}
if (changes.minZoom && !changes.minZoom.isFirstChange()) {
this.mapService.updateMinZoom(changes.minZoom.currentValue);
}
if (changes.maxZoom && !changes.maxZoom.isFirstChange()) {
this.mapService.updateMaxZoom(changes.maxZoom.currentValue);
}
if (changes.minPitch && !changes.minPitch.isFirstChange()) {
this.mapService.updateMinPitch(changes.minPitch.currentValue);
}
if (changes.maxPitch && !changes.maxPitch.isFirstChange()) {
this.mapService.updateMaxPitch(changes.maxPitch.currentValue);
}
if (changes.renderWorldCopies &&
!changes.renderWorldCopies.isFirstChange()) {
this.mapService.updateRenderWorldCopies(changes.renderWorldCopies.currentValue);
}
if (changes.scrollZoom && !changes.scrollZoom.isFirstChange()) {
this.mapService.updateScrollZoom(changes.scrollZoom.currentValue);
}
if (changes.dragRotate && !changes.dragRotate.isFirstChange()) {
this.mapService.updateDragRotate(changes.dragRotate.currentValue);
}
if (changes.touchPitch && !changes.touchPitch.isFirstChange()) {
this.mapService.updateTouchPitch(changes.touchPitch.currentValue);
}
if (changes.touchZoomRotate && !changes.touchZoomRotate.isFirstChange()) {
this.mapService.updateTouchZoomRotate(changes.touchZoomRotate.currentValue);
}
if (changes.doubleClickZoom && !changes.doubleClickZoom.isFirstChange()) {
this.mapService.updateDoubleClickZoom(changes.doubleClickZoom.currentValue);
}
if (changes.keyboard && !changes.keyboard.isFirstChange()) {
this.mapService.updateKeyboard(changes.keyboard.currentValue);
}
if (changes.dragPan && !changes.dragPan.isFirstChange()) {
this.mapService.updateDragPan(changes.dragPan.currentValue);
}
if (changes.boxZoom && !changes.boxZoom.isFirstChange()) {
this.mapService.updateBoxZoom(changes.boxZoom.currentValue);
}
if (changes.style && !changes.style.isFirstChange()) {
this.mapService.updateStyle(changes.style.currentValue);
}
if (changes.maxBounds && !changes.maxBounds.isFirstChange()) {
this.mapService.updateMaxBounds(changes.maxBounds.currentValue);
}
if (changes.fitBounds &&
changes.fitBounds.currentValue &&
!changes.fitBounds.isFirstChange()) {
this.mapService.fitBounds(changes.fitBounds.currentValue, this.fitBoundsOptions());
}
if (changes.fitScreenCoordinates &&
changes.fitScreenCoordinates.currentValue) {
if ((center || zoom || pitch || this.fitBounds()) &&
changes.fitScreenCoordinates.isFirstChange()) {
console.warn('[ngx-maplibre-gl] center / zoom / pitch / fitBounds inputs are being overridden by fitScreenCoordinates input');
}
this.mapService.fitScreenCoordinates(changes.fitScreenCoordinates.currentValue, bearing ? bearing[0] : 0, this.movingOptions());
}
if (this.centerWithPanTo() &&
changes.center &&
!changes.center.isFirstChange() &&
!changes.zoom &&
!changes.bearing &&
!changes.pitch &&
!changes.roll) {
this.mapService.panTo(this.center(), this.panToOptions());
}
else if ((changes.center && !changes.center.isFirstChange()) ||
(changes.zoom && !changes.zoom.isFirstChange()) ||
(changes.bearing && !changes.bearing.isFirstChange() && !changes.fitScreenCoordinates) ||
(changes.pitch && !changes.pitch.isFirstChange()) ||
(changes.roll && !changes.roll.isFirstChange())) {
this.mapService.move(this.movingMethod(), this.movingOptions(), changes.zoom && zoom ? zoom[0] : undefined, changes.center ? center : undefined, changes.bearing && bearing ? bearing[0] : undefined, changes.pitch && pitch ? pitch[0] : undefined, changes.roll ? changes.roll.currentValue : undefined);
}
if (changes.terrain && !changes.terrain.isFirstChange()) {
this.mapService.setTerrain(changes.terrain.currentValue);
}
if (changes.projection && !changes.projection.isFirstChange()) {
this.mapService.setProjection(changes.projection.currentValue);
}
if (changes.elevation && !changes.elevation.isFirstChange()) {
this.mapService.setCenterElevation(changes.elevation.currentValue);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MapComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: MapComponent, isStandalone: true, selector: "mgl-map", inputs: { collectResourceTiming: { classPropertyName: "collectResourceTiming", publicName: "collectResourceTiming", isSignal: true, isRequired: false, transformFunction: null }, crossSourceCollisions: { classPropertyName: "crossSourceCollisions", publicName: "crossSourceCollisions", isSignal: true, isRequired: false, transformFunction: null }, customMapboxApiUrl: { classPropertyName: "customMapboxApiUrl", publicName: "customMapboxApiUrl", isSignal: true, isRequired: false, transformFunction: null }, fadeDuration: { classPropertyName: "fadeDuration", publicName: "fadeDuration", isSignal: true, isRequired: false, transformFunction: null }, hash: { classPropertyName: "hash", publicName: "hash", isSignal: true, isRequired: false, transformFunction: null }, refreshExpiredTiles: { classPropertyName: "refreshExpiredTiles", publicName: "refreshExpiredTiles", isSignal: true, isRequired: false, transformFunction: null }, canvasContextAttributes: { classPropertyName: "canvasContextAttributes", publicName: "canvasContextAttributes", isSignal: true, isRequired: false, transformFunction: null }, bearingSnap: { classPropertyName: "bearingSnap", publicName: "bearingSnap", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, pitchWithRotate: { classPropertyName: "pitchWithRotate", publicName: "pitchWithRotate", isSignal: true, isRequired: false, transformFunction: null }, clickTolerance: { classPropertyName: "clickTolerance", publicName: "clickTolerance", isSignal: true, isRequired: false, transformFunction: null }, attributionControl: { classPropertyName: "attributionControl", publicName: "attributionControl", isSignal: true, isRequired: false, transformFunction: null }, logoPosition: { classPropertyName: "logoPosition", publicName: "logoPosition", isSignal: true, isRequired: false, transformFunction: null }, maxTileCacheSize: { classPropertyName: "maxTileCacheSize", publicName: "maxTileCacheSize", isSignal: true, isRequired: false, transformFunction: null }, localIdeographFontFamily: { classPropertyName: "localIdeographFontFamily", publicName: "localIdeographFontFamily", isSignal: true, isRequired: false, transformFunction: null }, trackResize: { classPropertyName: "trackResize", publicName: "trackResize", isSignal: true, isRequired: false, transformFunction: null }, transformRequest: { classPropertyName: "transformRequest", publicName: "transformRequest", isSignal: true, isRequired: false, transformFunction: null }, bounds: { classPropertyName: "bounds", publicName: "bounds", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null }, cooperativeGestures: { classPropertyName: "cooperativeGestures", publicName: "cooperativeGestures", isSignal: true, isRequired: false, transformFunction: null }, cancelPendingTileRequestsWhileZooming: { classPropertyName: "cancelPendingTileRequestsWhileZooming", publicName: "cancelPendingTileRequestsWhileZooming", isSignal: true, isRequired: false, transformFunction: null }, centerClampedToGround: { classPropertyName: "centerClampedToGround", publicName: "centerClampedToGround", isSignal: true, isRequired: false, transformFunction: null }, maplibreLogo: { classPropertyName: "maplibreLogo", publicName: "maplibreLogo", isSignal: true, isRequired: false, transformFunction: null }, maxCanvasSize: { classPropertyName: "maxCanvasSize", publicName: "maxCanvasSize", isSignal: true, isRequired: false, transformFunction: null }, maxTileCacheZoomLevels: { classPropertyName: "maxTileCacheZoomLevels", publicName: "maxTileCacheZoomLevels", isSignal: true, isRequired: false, transformFunction: null }, pixelRatio: { classPropertyName: "pixelRatio", publicName: "pixelRatio", isSignal: true, isRequired: false, transformFunction: null }, rollEnabled: { classPropertyName: "rollEnabled", publicName: "rollEnabled", isSignal: true, isRequired: false, transformFunction: null }, transformCameraUpdate: { classPropertyName: "transformCameraUpdate", publicName: "transformCameraUpdate", isSignal: true, isRequired: false, transformFunction: null }, validateStyle: { classPropertyName: "validateStyle", publicName: "validateStyle", isSignal: true, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: true, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: true, isRequired: false, transformFunction: null }, minPitch: { classPropertyName: "minPitch", publicName: "minPitch", isSignal: true, isRequired: false, transformFunction: null }, maxPitch: { classPropertyName: "maxPitch", publicName: "maxPitch", isSignal: true, isRequired: false, transformFunction: null }, scrollZoom: { classPropertyName: "scrollZoom", publicName: "scrollZoom", isSignal: true, isRequired: false, transformFunction: null }, dragRotate: { classPropertyName: "dragRotate", publicName: "dragRotate", isSignal: true, isRequired: false, transformFunction: null }, touchPitch: { classPropertyName: "touchPitch", publicName: "touchPitch", isSignal: true, isRequired: false, transformFunction: null }, touchZoomRotate: { classPropertyName: "touchZoomRotate", publicName: "touchZoomRotate", isSignal: true, isRequired: false, transformFunction: null }, doubleClickZoom: { classPropertyName: "doubleClickZoom", publicName: "doubleClickZoom", isSignal: true, isRequired: false, transformFunction: null }, keyboard: { classPropertyName: "keyboard", publicName: "keyboard", isSignal: true, isRequired: false, transformFunction: null }, dragPan: { classPropertyName: "dragPan", publicName: "dragPan", isSignal: true, isRequired: false, transformFunction: null }, boxZoom: { classPropertyName: "boxZoom", publicName: "boxZoom", isSignal: true, isRequired: false, transformFunction: null }, style: { classPropertyName: "style", publicName: "style", isSignal: true, isRequired: true, transformFunction: null }, center: { classPropertyName: "center", publicName: "center", isSignal: true, isRequired: false, transformFunction: null }, maxBounds: { classPropertyName: "maxBounds", publicName: "maxBounds", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, bearing: { classPropertyName: "bearing", publicName: "bearing", isSignal: true, isRequired: false, transformFunction: null }, pitch: { classPropertyName: "pitch", publicName: "pitch", isSignal: true, isRequired: false, transformFunction: null }, roll: { classPropertyName: "roll", publicName: "roll", isSignal: true, isRequired: false, transformFunction: null }, fitBoundsOptions: { classPropertyName: "fitBoundsOptions", publicName: "fitBoundsOptions", isSignal: true, isRequired: false, transformFunction: null }, renderWorldCopies: { classPropertyName: "renderWorldCopies", publicName: "renderWorldCopies", isSignal: true, isRequired: false, transformFunction: null }, elevation: { classPropertyName: "elevation", publicName: "elevation", isSignal: true, isRequired: false, transformFunction: null }, terrain: { classPropertyName: "terrain", publicName: "terrain", isSignal: true, isRequired: false, transformFunction: null }, projection: { classPropertyName: "projection", publicName: "projection", isSignal: true, isRequired: false, transformFunction: null }, movingMethod: { classPropertyName: "movingMethod", publicName: "movingMethod", isSignal: true, isRequired: false, transformFunction: null }, movingOptions: { classPropertyName: "movingOptions", publicName: "movingOptions", isSignal: true, isRequired: false, transformFunction: null }, fitBounds: { classPropertyName: "fitBounds", publicName: "fitBounds", isSignal: true, isRequired: false, transformFunction: null }, fitScreenCoordinates: { classPropertyName: "fitScreenCoordinates", publicName: "fitScreenCoordinates", isSignal: true, isRequired: false, transformFunction: null }, centerWithPanTo: { classPropertyName: "centerWithPanTo", publicName: "centerWithPanTo", isSignal: true, isRequired: false, transformFunction: null }, panToOptions: { classPropertyName: "panToOptions", publicName: "panToOptions", isSignal: true, isRequired: false, transformFunction: null }, cursorStyle: { classPropertyName: "cursorStyle", publicName: "cursorStyle", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { mapResize: "mapResize", mapRemove: "mapRemove", mapMouseDown: "mapMouseDown", mapMouseUp: "mapMouseUp", mapMouseMove: "mapMouseMove", mapClick: "mapClick", mapDblClick: "mapDblClick", mapMouseOver: "mapMouseOver", mapMouseOut: "mapMouseOut", mapContextMenu: "mapContextMenu", mapTouchStart: "mapTouchStart", mapTouchEnd: "mapTouchEnd", mapTouchMove: "mapTouchMove", mapTouchCancel: "mapTouchCancel", mapWheel: "mapWheel", moveStart: "moveStart", move: "move", moveEnd: "moveEnd", mapDragStart: "mapDragStart", mapDrag: "mapDrag", mapDragEnd: "mapDragEnd", zoomStart: "zoomStart", zoomEvt: "zoomEvt", zoomEnd: "zoomEnd", rotateStart: "rotateStart", rotate: "rotate", rotateEnd: "rotateEnd", pitchStart: "pitchStart", pitchEvt: "pitchEvt", pitchEnd: "pitchEnd", boxZoomStart: "boxZoomStart", boxZoomEnd: "boxZoomEnd", boxZoomCancel: "boxZoomCancel", webGlContextLost: "webGlContextLost", webGlContextRestored: "webGlContextRestored", mapLoad: "mapLoad", idle: "idle", render: "render", mapError: "mapError", data: "data", styleData: "styleData", sourceData: "sourceData", dataLoading: "dataLoading", styleDataLoading: "styleDataLoading", sourceDataLoading: "sourceDataLoading", styleImageMissing: "styleImageMissing" }, providers: [MapService], viewQueries: [{ propertyName: "mapContainer", first: true, predicate: ["container"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: '<div #container></div>', isInline: true, styles: [":host{display:block}div{height:100%;width:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MapComponent, decorators: [{
type: Component,
args: [{ selector: 'mgl-map', template: '<div #container></div>', providers: [MapService], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}div{height:100%;width:100%}\n"] }]
}], ctorParameters: () => [] });
/**
* `mgl-marker` - a marker component
* @see [Marker](https://maplibre.org/maplibre-gl-js/docs/API/classes/Marker/)
*
* @category Components
*
* @example
* ```html
* ...
* <mgl-map ...>
* <mgl-marker [lngLat]="[-66.324462890625, -16.024695711685304]">
* <div (click)="alert('Foo')" class="marker">Hello</div>
* </mgl-marker>
* </mgl-map>
* ```
*
* Note: Only use this if you **really** need to use HTML/Angular component to render your symbol. These markers are slow compared to a `Layer` of symbol because they're not rendered using WebGL.
*/
class MarkerComponent {
constructor() {
/** Init injection */
this.mapService = inject(MapService);
this.destroyRef = inject(DestroyRef);
/** Init inputs */
this.offset = input();
this.anchor = input();
this.clickTolerance = input();
this.color = input();
this.scale = input();
this.opacity = input();
this.opacityWhenCovered = input();
this.subpixelPositioning = input();
/** Dynamic input */
this.feature = input();
this.lngLat = input();
this.draggable = input();
this.popupShown = input();
this.className = input();
this.pitchAlignment = input();
this.rotationAlignment = input();
this.rotation = input();
this.markerDragStart = output();
this.markerDragEnd = output();
this.markerDrag = output();
this.content = viewChild.required('content');
this.markerInstance = signal(null);
afterNextRender(() => {
this.mapService.mapCreated$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => {
const marker = this.mapService.addMarker({
markersOptions: {
element: this.content().nativeElement,
feature: this.feature(),
lngLat: this.lngLat(),
offset: this.offset(),
anchor: this.anchor(),
color: this.color(),
scale: this.scale(),
draggable: !!this.draggable(),
clickTolerance: this.clickTolerance(),
rotation: this.rotation(),
rotationAlignment: this.rotationAlignment(),
pitchAlignment: this.pitchAlignment(),
opacity: this.opacity(),
opacityWhenCovered: this.opacityWhenCovered(),
subpixelPositioning: this.subpixelPositioning(),
},
markersEvents: {
markerDragStart: this.markerDragStart,
markerDrag: this.markerDrag,
markerDragEnd: this.markerDragEnd,
},
});
this.markerInstance.set(marker);
});
});
}
ngOnDestroy() {
this.removeMarker();
}
ngOnInit() {
if (this.feature() && this.lngLat()) {
throw new Error('feature and lngLat input are mutually exclusive');
}
}
ngOnChanges(changes) {
const markerInstance = this.markerInstance();
if (changes.lngLat && !changes.lngLat.isFirstChange()) {
markerInstance.setLngLat(changes.lngLat.currentValue);
}
if (changes.feature && !changes.feature.isFirstChange()) {
markerInstance.setLngLat(changes.feature.currentValue.geometry.coordinates);
}
if (changes.draggable && !changes.draggable.isFirstChange()) {
markerInstance.setDraggable(!!changes.draggable.currentValue);
}
if (changes.popupShown && !changes.popupShown.isFirstChange()) {
changes.popupShown.currentValue
? markerInstance.getPopup().addTo(this.mapService.mapInstance)
: markerInstance.getPopup().remove();
}
if (changes.pitchAlignment && !changes.pitchAlignment.isFirstChange()) {
markerInstance.setPitchAlignment(changes.pitchAlignment.currentValue);
}
if (changes.rotationAlignment &&
!changes.rotationAlignment.isFirstChange()) {
markerInstance.setRotationAlignment(changes.rotationAlignment.currentValue);
}
if (changes.rotation && !changes.rotation.isFirstChange()) {
markerInstance.setRotation(changes.rotation.currentValue);
}
}
removeMarker() {
this.mapService.removeMarker(this.markerInstance());
this.markerInstance.set(null);
}
togglePopup() {
this.markerInstance().togglePopup();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MarkerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: MarkerComponent, isStandalone: true, selector: "mgl-marker", inputs: { offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null }, anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: false, transformFunction: null }, clickTolerance: { classPropertyName: "clickTolerance", publicName: "clickTolerance", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, opacity: { classPropertyName: "opacity", publicName: "opacity", isSignal: true, isRequired: false, transformFunction: null }, opacityWhenCovered: { classPropertyName: "opacityWhenCovered", publicName: "opacityWhenCovered", isSignal: true, isRequired: false, transformFunction: null }, subpixelPositioning: { classPropertyName: "subpixelPositioning", publicName: "subpixelPositioning", isSignal: true, isRequired: false, transformFunction: null }, feature: { classPropertyName: "feature", publicName: "feature", isSignal: true, isRequired: false, transformFunction: null }, lngLat: { classPropertyName: "lngLat", publicName: "lngLat", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, popupShown: { classPropertyName: "popupShown", publicName: "popupShown", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, pitchAlignment: { classPropertyName: "pitchAlignment", publicName: "pitchAlignment", isSignal: true, isRequired: false, transformFunction: null }, rotationAlignment: { classPropertyName: "rotationAlignment", publicName: "rotationAlignment", isSignal: true, isRequired: false, transformFunction: null }, rotation: { classPropertyName: "rotation", publicName: "rotation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { markerDragStart: "markerDragStart", markerDragEnd: "markerDragEnd", markerDrag: "markerDrag" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: `<div [class]="className()" #content>
<ng-content></ng-content>
</div>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MarkerComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-marker',
template: `<div [class]="className()" #content>
<ng-content></ng-content>
</div>`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}], ctorParameters: () => [] });
/**
* a template directive for point for {@link MarkersForClustersComponent}
*
* @category Directives
*/
class PointDirective {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: PointDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.4", type: PointDirective, isStandalone: true, selector: "ng-template[mglPoint]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: PointDirective, decorators: [{
type: Directive,
args: [{
selector: 'ng-template[mglPoint]',
}]
}] });
/**
* a template directive for clustered point for {@link MarkersForClustersComponent}
*
* @category Directives
*/
class ClusterPointDirective {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ClusterPointDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.4", type: ClusterPointDirective, isStandalone: true, selector: "ng-template[mglClusterPoint]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ClusterPointDirective, decorators: [{
type: Directive,
args: [{
selector: 'ng-template[mglClusterPoint]',
}]
}] });
let uniqId = 0;
/**
* [ngx] `mgl-markers-for-clusters` - an HTML marker component for clustered points.
* Requires a geojson source that is clustered.
*
* @category Components
*
* @example
* ```html
* ...
* <mgl-map ...>
* <mgl-markers-for-cluster [source]="myGeoJsonclusteredSource">
* <ng-template mglPoint let-feature> Marker! </ng-template>
* <ng-template mglClusterPoint let-feature>
* ClusterId: {{feature.properties?.cluster_id}}, Points:
* {{feature.properties?.point_count}}
* </ng-template>
* </mgl-markers-for-cluster>
* </mgl-map>
* ```
*
* Note: Only use this if you **really** need to use HTML/Angular component to render your symbols. This is **slower** than rendering symbols in WebGL.
*/
class MarkersForClustersComponent {
constructor() {
this.destroyRef = inject(DestroyRef);
this.mapService = inject(MapService);
this.ngZone = inject(NgZone);
/** Init input */
this.source = input.required();
/** @hidden */
this.pointTpl = contentChild(PointDirective, {
read: TemplateRef,
});
/** @hidden */
this.clusterPointTpl = contentChild(ClusterPointDirective, {
read: TemplateRef,
});
/** @hidden */
this.clusterPoints = signal([]);
/** @hidden */
this.layerId = `mgl-markers-for-clusters-${uniqId++}`;
afterNextRender(() => {
const clusterDataUpdate = () => fromEvent(this.mapService.mapInstance, 'data').pipe(filter((e) => e.sourceId === this.source() &&
e.sourceDataType !== 'metadata' &&
this.mapService.mapInstance.isSourceLoaded(this.source())));
this.mapService.mapCreated$
.pipe(switchMap(clusterDataUpdate), switchMap(() => merge(fromEvent(this.mapService.mapInstance, 'move'), fromEvent(this.mapService.mapInstance, 'moveend')).pipe(startWith(undefined))))
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => {
this.ngZone.run(() => {
this.updateCluster();
});
});
});
}
updateCluster() {
const params = this.getClusterParams(this.pointTpl());
this.clusterPoints.set(this.mapService.mapInstance.queryRenderedFeatures(params));
}
getClusterParams(pointTpl) {
if (!pointTpl) {
return { layers: [this.layerId], filter: ['==', 'cluster', true] };
}
return { layers: [this.layerId] };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MarkersForClustersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: MarkersForClustersComponent, isStandalone: true, selector: "mgl-markers-for-clusters", inputs: { source: { classPropertyName: "source", publicName: "source", isSignal: true, isRequired: true, transformFunction: null } }, queries: [{ propertyName: "pointTpl", first: true, predicate: PointDirective, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "clusterPointTpl", first: true, predicate: ClusterPointDirective, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0, template: `
<mgl-layer
[id]="layerId"
[source]="source()"
type="circle"
[paint]="{ 'circle-radius': 0 }"
></mgl-layer>
@for (feature of clusterPoints(); track $index) {
@if (feature.properties.cluster) {
<mgl-marker [feature]="feature">
<ng-container
*ngTemplateOutlet="clusterPointTpl(); context: { $implicit: feature }"
></ng-container>
</mgl-marker>
} @else {
<mgl-marker [feature]="feature">
<ng-container
*ngTemplateOutlet="pointTpl(); context: { $implicit: feature }"
></ng-container>
</mgl-marker>
}
}`, isInline: true, dependencies: [{ kind: "component", type: LayerComponent, selector: "mgl-layer", inputs: ["id", "type", "source", "metadata", "sourceLayer", "removeSource", "filter", "layout", "paint", "before", "minzoom", "maxzoom"], outputs: ["layerClick", "layerDblClick", "layerMouseDown", "layerMouseUp", "layerMouseEnter", "layerMouseLeave", "layerMouseMove", "layerMouseOver", "layerMouseOut", "layerContextMenu", "layerTouchStart", "layerTouchEnd", "layerTouchCancel"] }, { kind: "component", type: MarkerComponent, selector: "mgl-marker", inputs: ["offset", "anchor", "clickTolerance", "color", "scale", "opacity", "opacityWhenCovered", "subpixelPositioning", "feature", "lngLat", "draggable", "popupShown", "className", "pitchAlignment", "rotationAlignment", "rotation"], outputs: ["markerDragStart", "markerDragEnd", "markerDrag"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: MarkersForClustersComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-markers-for-clusters',
template: `
<mgl-layer
[id]="layerId"
[source]="source()"
type="circle"
[paint]="{ 'circle-radius': 0 }"
></mgl-layer>
@for (feature of clusterPoints(); track $index) {
@if (feature.properties.cluster) {
<mgl-marker [feature]="feature">
<ng-container
*ngTemplateOutlet="clusterPointTpl(); context: { $implicit: feature }"
></ng-container>
</mgl-marker>
} @else {
<mgl-marker [feature]="feature">
<ng-container
*ngTemplateOutlet="pointTpl(); context: { $implicit: feature }"
></ng-container>
</mgl-marker>
}
}`,
changeDetection: ChangeDetectionStrategy.OnPush,
preserveWhitespaces: false,
imports: [LayerComponent, MarkerComponent, NgTemplateOutlet],
}]
}], ctorParameters: () => [] });
/**
* `mgl-popup` - a popup component
* @see [Popup](https://maplibre.org/maplibre-gl-js/docs/API/classes/Popup/)
*
* @category Components
*
* @example
* ```html
* ...
* <mgl-map ...>
* <mgl-popup [lngLat]="[-96, 37.8]" [closeOnClick]="false">
* <h1>Hello world !</h1>
* </mgl-popup>
* ...
* <mgl-marker #myMarker ...> ... </mgl-marker>
* <mgl-popup [marker]="myMarker"> Hello from marker ! </mgl-popup>
* </mgl-map>
* ```
*/
class PopupComponent {
constructor() {
/** Init injection */
this.destroyRef = inject(DestroyRef);
this.mapService = inject(MapService);
/** Init input */
this.closeButton = input();
/** Init input */
this.closeOnClick = input();
/** Init input */
this.closeOnMove = input();
/** Init input */
this.focusAfterOpen = input();
/** Init input */
this.anchor = input();
/** Init input */
this.className = input();
/** Init input */
this.maxWidth = input();
/** Init input */
this.subpixelPositioning = input();
/**
* Dynamic input [ngx]
* Mutually exclusive with `lngLat`
*/
this.feature = input();
/** Dynamic input */
this.lngLat = input();
/**
* Dynamic input [ngx]
* The targeted marker
*/
this.marker = input();
/** Dynamic input */
this.offset = input();
this.popupClose = output();
this.popupOpen = output();
/** @hidden */
this.content = viewChild.required('content');
this.popupInstance = null;
afterNextRender(() => {
this.popupInstance = this.createPopup();
this.addPopup(this.popupInstance)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe();
});
}
ngOnInit() {
if ((this.lngLat() && this.marker()) ||
(this.feature() && this.lngLat()) ||
(this.feature() && this.marker())) {
throw new Error('marker, lngLat, feature input are mutually exclusive');
}
}
ngOnChanges(changes) {
if (changes.feature && !changes.feature.isFirstChange()) {
const newlngLat = this.getLngLat(this.lngLat(), this.feature());
this.mapService.removePopupFromMap(this.popupInstance);
const popupInstanceTmp = this.createPopup();
this.mapService.addPopupToMap(popupInstanceTmp, newlngLat);
this.popupInstance = popupInstanceTmp;
}
if (changes.lngLat && !changes.lngLat.isFirstChange()) {
this.popupInstance.setLngLat(changes.lngLat.currentValue);
}
if (changes.marker && !changes.marker.isFirstChange()) {
const previousMarker = changes.marker.previousValue;
const previousMarkerInstance = previousMarker.markerInstance();
if (previousMarkerInstance) {
this.mapService.removePopupFromMarker(previousMarkerInstance);
}
const markerInstance = this.marker()?.markerInstance();
if (markerInstance && this.popupInstance) {
this.mapService.addPopupToMarker(markerInstance, this.popupInstance);
}
}
if (changes.offset &&
!changes.offset.isFirstChange() &&
this.popupInstance) {
this.popupInstance.setOffset(changes.offset.currentValue);
}
}
ngOnDestroy() {
this.removePopupFromMarker();
}
createPopup() {
return this.mapService.createPopup({
popupOptions: {
closeButton: this.closeButton(),
closeOnClick: this.closeOnClick(),
closeOnMove: this.closeOnMove(),
focusAfterOpen: this.focusAfterOpen(),
anchor: this.anchor(),
offset: this.offset(),
className: this.className(),
maxWidth: this.maxWidth(),
subpixelPositioning: this.subpixelPositioning(),
},
popupEvents: {
popupOpen: this.popupOpen,
popupClose: this.popupClose,
},
}, this.content().nativeElement);
}
addPopup(popup) {
return this.mapService.mapCreated$.pipe(tap$1(() => {
const lngLat = this.lngLat();
const feature = this.feature();
const markerInstance = this.marker()?.markerInstance();
if (lngLat || feature) {
this.mapService.addPopupToMap(popup, this.getLngLat(lngLat, feature));
}
else if (markerInstance) {
this.mapService.addPopupToMarker(markerInstance, popup);
}
else {
throw new Error('mgl-popup need either lngLat/marker/feature to be set');
}
}));
}
removePopupFromMarker() {
if (this.popupInstance) {
const markerInstance = this.marker()?.markerInstance();
if (this.lngLat() || this.feature()) {
this.mapService.removePopupFromMap(this.popupInstance);
}
else if (markerInstance) {
this.mapService.removePopupFromMarker(markerInstance);
}
else {
this.mapService.removePopupFromMap(this.popupInstance);
}
}
this.popupInstance = null;
}
getLngLat(lngLat, feature) {
if (lngLat) {
return lngLat;
}
else if (feature) {
return feature.geometry.coordinates;
}
throw new Error('lngLat or feature value is required');
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: PopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.0.4", type: PopupComponent, isStandalone: true, selector: "mgl-popup", inputs: { closeButton: { classPropertyName: "closeButton", publicName: "closeButton", isSignal: true, isRequired: false, transformFunction: null }, closeOnClick: { classPropertyName: "closeOnClick", publicName: "closeOnClick", isSignal: true, isRequired: false, transformFunction: null }, closeOnMove: { classPropertyName: "closeOnMove", publicName: "closeOnMove", isSignal: true, isRequired: false, transformFunction: null }, focusAfterOpen: { classPropertyName: "focusAfterOpen", publicName: "focusAfterOpen", isSignal: true, isRequired: false, transformFunction: null }, anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, subpixelPositioning: { classPropertyName: "subpixelPositioning", publicName: "subpixelPositioning", isSignal: true, isRequired: false, transformFunction: null }, feature: { classPropertyName: "feature", publicName: "feature", isSignal: true, isRequired: false, transformFunction: null }, lngLat: { classPropertyName: "lngLat", publicName: "lngLat", isSignal: true, isRequired: false, transformFunction: null }, marker: { classPropertyName: "marker", publicName: "marker", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { popupClose: "popupClose", popupOpen: "popupOpen" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: '<div #content data-cy="mgl-popup"><ng-content></ng-content></div>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: PopupComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-popup',
template: '<div #content data-cy="mgl-popup"><ng-content></ng-content></div>',
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}], ctorParameters: () => [] });
/**
* `mgl-canvas-source` - a canvas source component
* @see [canvas](https://maplibre.org/maplibre-style-spec/sources/#canvas)
*
* @category Source Components
*/
class CanvasSourceComponent {
constructor() {
/** Init injections */
this.sourceDirective = inject(SourceDirective);
/** Dynamic input */
this.coordinates = input.required();
/** Dynamic input */
this.canvas = input.required();
/** Dynamic input */
this.animate = input();
this.sourceDirective.loadSource$
.pipe(tap$1(() => this.sourceDirective.addSource(this.getCanvasSourceSpecification())), takeUntilDestroyed())
.subscribe();
}
ngOnChanges(changes) {
if (!this.sourceDirective.sourceId()) {
return;
}
if ((changes.canvas && !changes.canvas.isFirstChange()) ||
(changes.animate && !changes.animate.isFirstChange())) {
this.sourceDirective.refresh();
}
else if (changes.coordinates && !changes.coordinates.isFirstChange()) {
const source = this.sourceDirective.getSource();
if (source === undefined) {
return;
}
source.setCoordinates(changes.coordinates.currentValue);
}
}
getCanvasSourceSpecification() {
return {
type: 'canvas',
coordinates: this.coordinates(),
canvas: this.canvas(),
animate: this.animate(),
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: CanvasSourceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: CanvasSourceComponent, isStandalone: true, selector: "mgl-canvas-source", inputs: { coordinates: { classPropertyName: "coordinates", publicName: "coordinates", isSignal: true, isRequired: true, transformFunction: null }, canvas: { classPropertyName: "canvas", publicName: "canvas", isSignal: true, isRequired: true, transformFunction: null }, animate: { classPropertyName: "animate", publicName: "animate", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, hostDirectives: [{ directive: SourceDirective, inputs: ["id", "id"] }], ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: CanvasSourceComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-canvas-source',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [{ directive: SourceDirective, inputs: ['id'] }],
}]
}], ctorParameters: () => [] });
/**
* `mgl-image-source` - an image source component
* @see [image](https://maplibre.org/maplibre-style-spec/sources/#image)
*
* @category Source Components
*/
class ImageSourceComponent {
constructor() {
/** Init injection */
this.destroyRef = inject(DestroyRef);
this.mapService = inject(MapService);
/** Init inputs */
this.id = input.required();
/** Dynamic inputs */
this.url = input.required();
this.coordinates = input.required();
this.type = 'image';
this.sourceId = signal(null);
}
ngOnInit() {
this.mapService.mapLoaded$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(() => this.addSource());
}
ngOnChanges(changes) {
const sourceId = this.sourceId();
if (sourceId === null) {
return;
}
const source = this.mapService.getSource(sourceId);
if (source === undefined) {
return;
}
source.updateImage({
url: changes.url === undefined ? undefined : this.url(),
coordinates: changes.coordinates === undefined ? undefined : this.coordinates(),
});
}
ngOnDestroy() {
const sourceId = this.sourceId();
if (sourceId !== null) {
this.mapService.removeSource(sourceId);
this.sourceId.set(null);
}
}
addSource() {
const imageSource = {
type: 'image',
url: this.url(),
coordinates: this.coordinates(),
};
this.mapService.addSource(this.id(), imageSource);
this.sourceId.set(this.id());
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ImageSourceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: ImageSourceComponent, isStandalone: true, selector: "mgl-image-source", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: true, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: true, transformFunction: null }, coordinates: { classPropertyName: "coordinates", publicName: "coordinates", isSignal: true, isRequired: true, transformFunction: null } }, usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: ImageSourceComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-image-source',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
}]
}] });
/**
* `mgl-raster-dem-source` - a raster DEM source
* @see [raster DEM](https://maplibre.org/maplibre-style-spec/sources/#raster-dem)
*
* @category Source Components
*/
class RasterDemSourceComponent {
constructor() {
/** Init injections */
this.sourceDirective = inject(SourceDirective);
/** Dynamic input */
this.url = input();
/** Dynamic input */
this.tiles = input();
/** Dynamic input */
this.bounds = input();
/** Dynamic input */
this.minzoom = input();
/** Dynamic input */
this.maxzoom = input();
/** Dynamic input */
this.tileSize = input();
/** Dynamic input */
this.attribution = input();
/** Dynamic input */
this.encoding = input();
this.sourceDirective.loadSource$
.pipe(tap(() => this.sourceDirective.addSource(this.getRasterDEMSourceSpecification())), takeUntilDestroyed())
.subscribe();
}
ngOnChanges(changes) {
if (!this.sourceDirective.sourceId()) {
return;
}
if ((changes.url && !changes.url.isFirstChange()) ||
(changes.tiles && !changes.tiles.isFirstChange()) ||
(changes.bounds && !changes.bounds.isFirstChange()) ||
(changes.minzoom && !changes.minzoom.isFirstChange()) ||
(changes.maxzoom && !changes.maxzoom.isFirstChange()) ||
(changes.tileSize && !changes.tileSize.isFirstChange()) ||
(changes.attribution && !changes.attribution.isFirstChange()) ||
(changes.encoding && !changes.encoding.isFirstChange())) {
this.sourceDirective.refresh();
}
}
getRasterDEMSourceSpecification() {
return {
type: 'raster-dem',
url: this.url(),
tiles: this.tiles(),
bounds: this.bounds(),
minzoom: this.minzoom(),
maxzoom: this.maxzoom(),
tileSize: this.tileSize(),
attribution: this.attribution(),
encoding: this.encoding(),
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: RasterDemSourceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: RasterDemSourceComponent, isStandalone: true, selector: "mgl-raster-dem-source", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, tiles: { classPropertyName: "tiles", publicName: "tiles", isSignal: true, isRequired: false, transformFunction: null }, bounds: { classPropertyName: "bounds", publicName: "bounds", isSignal: true, isRequired: false, transformFunction: null }, minzoom: { classPropertyName: "minzoom", publicName: "minzoom", isSignal: true, isRequired: false, transformFunction: null }, maxzoom: { classPropertyName: "maxzoom", publicName: "maxzoom", isSignal: true, isRequired: false, transformFunction: null }, tileSize: { classPropertyName: "tileSize", publicName: "tileSize", isSignal: true, isRequired: false, transformFunction: null }, attribution: { classPropertyName: "attribution", publicName: "attribution", isSignal: true, isRequired: false, transformFunction: null }, encoding: { classPropertyName: "encoding", publicName: "encoding", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, hostDirectives: [{ directive: SourceDirective, inputs: ["id", "id"] }], ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: RasterDemSourceComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-raster-dem-source',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [{ directive: SourceDirective, inputs: ['id'] }],
}]
}], ctorParameters: () => [] });
/**
* `mgl-raster-source` - a raster source component
* @see [raster](https://maplibre.org/maplibre-style-spec/sources/#raster)
*
* @category Source Components
*/
class RasterSourceComponent {
constructor() {
/** Init injections */
this.sourceDirective = inject(SourceDirective);
/** Dynamic input */
this.url = input();
/** Dynamic input */
this.tiles = input();
/** Dynamic input */
this.bounds = input();
/** Dynamic input */
this.scheme = input();
/** Dynamic input */
this.minzoom = input();
/** Dynamic input */
this.maxzoom = input();
/** Dynamic input */
this.tileSize = input();
/** Dynamic input */
this.attribution = input();
this.sourceDirective.loadSource$
.pipe(tap$1(() => this.sourceDirective.addSource(this.getRasterSourceSpecification())), takeUntilDestroyed())
.subscribe();
}
ngOnChanges(changes) {
if (!this.sourceDirective.sourceId()) {
return;
}
if ((changes.url && !changes.url.isFirstChange()) ||
(changes.tiles && !changes.tiles.isFirstChange()) ||
(changes.bounds && !changes.bounds.isFirstChange()) ||
(changes.minzoom && !changes.minzoom.isFirstChange()) ||
(changes.maxzoom && !changes.maxzoom.isFirstChange()) ||
(changes.tileSize && !changes.tileSize.isFirstChange()) ||
(changes.scheme && !changes.scheme.isFirstChange()) ||
(changes.attribution && !changes.attribution.isFirstChange())) {
this.sourceDirective.refresh();
}
}
getRasterSourceSpecification() {
return {
type: 'raster',
url: this.url(),
tiles: this.tiles(),
bounds: this.bounds(),
minzoom: this.minzoom(),
maxzoom: this.maxzoom(),
tileSize: this.tileSize(),
scheme: this.scheme(),
attribution: this.attribution(),
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: RasterSourceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: RasterSourceComponent, isStandalone: true, selector: "mgl-raster-source", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, tiles: { classPropertyName: "tiles", publicName: "tiles", isSignal: true, isRequired: false, transformFunction: null }, bounds: { classPropertyName: "bounds", publicName: "bounds", isSignal: true, isRequired: false, transformFunction: null }, scheme: { classPropertyName: "scheme", publicName: "scheme", isSignal: true, isRequired: false, transformFunction: null }, minzoom: { classPropertyName: "minzoom", publicName: "minzoom", isSignal: true, isRequired: false, transformFunction: null }, maxzoom: { classPropertyName: "maxzoom", publicName: "maxzoom", isSignal: true, isRequired: false, transformFunction: null }, tileSize: { classPropertyName: "tileSize", publicName: "tileSize", isSignal: true, isRequired: false, transformFunction: null }, attribution: { classPropertyName: "attribution", publicName: "attribution", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, hostDirectives: [{ directive: SourceDirective, inputs: ["id", "id"] }], ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: RasterSourceComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-raster-source',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [{ directive: SourceDirective, inputs: ['id'] }],
}]
}], ctorParameters: () => [] });
/**
* `mgl-vector-source` - a vector source component
* @see [vector](https://maplibre.org/maplibre-style-spec/sources/#vector)
*
* @category Source Components
*/
class VectorSourceComponent {
constructor() {
/** Init injections */
this.sourceDirective = inject(SourceDirective);
/** Dynamic inputs */
this.url = input();
this.tiles = input();
this.bounds = input();
this.scheme = input();
this.minzoom = input();
this.maxzoom = input();
this.attribution = input();
this.promoteId = input();
this.sourceDirective.loadSource$
.pipe(tap$1(() => this.sourceDirective.addSource(this.getVectorSourceSpecification())), takeUntilDestroyed())
.subscribe();
}
ngOnChanges(changes) {
if (!this.sourceDirective.sourceId()) {
return;
}
if ((changes.bounds && !changes.bounds.isFirstChange()) ||
(changes.scheme && !changes.scheme.isFirstChange()) ||
(changes.minzoom && !changes.minzoom.isFirstChange()) ||
(changes.maxzoom && !changes.maxzoom.isFirstChange()) ||
(changes.attribution && !changes.attribution.isFirstChange()) ||
(changes.promoteId && !changes.promoteId.isFirstChange())) {
this.sourceDirective.refresh();
}
else if ((changes.url && !changes.url.isFirstChange()) ||
(changes.tiles && !changes.tiles.isFirstChange())) {
const source = this.sourceDirective.getSource();
if (source === undefined) {
return;
}
const url = this.url();
if (changes.url && url) {
source.setUrl(url);
}
const tiles = this.tiles();
if (changes.tiles && tiles) {
source.setTiles(tiles);
}
}
}
getVectorSourceSpecification() {
return {
type: 'vector',
url: this.url(),
tiles: this.tiles(),
bounds: this.bounds(),
scheme: this.scheme(),
minzoom: this.minzoom(),
maxzoom: this.maxzoom(),
attribution: this.attribution(),
promoteId: this.promoteId(),
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: VectorSourceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: VectorSourceComponent, isStandalone: true, selector: "mgl-vector-source", inputs: { url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null }, tiles: { classPropertyName: "tiles", publicName: "tiles", isSignal: true, isRequired: false, transformFunction: null }, bounds: { classPropertyName: "bounds", publicName: "bounds", isSignal: true, isRequired: false, transformFunction: null }, scheme: { classPropertyName: "scheme", publicName: "scheme", isSignal: true, isRequired: false, transformFunction: null }, minzoom: { classPropertyName: "minzoom", publicName: "minzoom", isSignal: true, isRequired: false, transformFunction: null }, maxzoom: { classPropertyName: "maxzoom", publicName: "maxzoom", isSignal: true, isRequired: false, transformFunction: null }, attribution: { classPropertyName: "attribution", publicName: "attribution", isSignal: true, isRequired: false, transformFunction: null }, promoteId: { classPropertyName: "promoteId", publicName: "promoteId", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, hostDirectives: [{ directive: SourceDirective, inputs: ["id", "id"] }], ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: VectorSourceComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-vector-source',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [{ directive: SourceDirective, inputs: ['id'] }],
}]
}], ctorParameters: () => [] });
/**
* `mgl-video-source` - a video source
* @see [video](https://maplibre.org/maplibre-style-spec/sources/#video)
*
* @category Source Components
*/
class VideoSourceComponent {
constructor() {
this.sourceDirective = inject(SourceDirective);
/** Dynamic input */
this.urls = input.required();
/** Dynamic input */
this.coordinates = input.required();
this.sourceDirective.loadSource$.pipe(tap$1(() => this.addSource()), takeUntilDestroyed()).subscribe();
}
ngOnChanges(changes) {
if (!this.sourceDirective.sourceId()) {
return;
}
if (changes.urls && !changes.urls.isFirstChange()) {
this.sourceDirective.refresh();
}
else if (changes.coordinates && !changes.coordinates.isFirstChange()) {
const source = this.sourceDirective.getSource();
if (source === undefined) {
return;
}
source.setCoordinates(changes.coordinates.currentValue);
}
}
addSource() {
const source = {
type: 'video',
urls: this.urls(),
coordinates: this.coordinates(),
};
this.sourceDirective.addSource(source);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: VideoSourceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.0.4", type: VideoSourceComponent, isStandalone: true, selector: "mgl-video-source", inputs: { urls: { classPropertyName: "urls", publicName: "urls", isSignal: true, isRequired: true, transformFunction: null }, coordinates: { classPropertyName: "coordinates", publicName: "coordinates", isSignal: true, isRequired: true, transformFunction: null } }, usesOnChanges: true, hostDirectives: [{ directive: SourceDirective, inputs: ["id", "id"] }], ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: VideoSourceComponent, decorators: [{
type: Component,
args: [{
selector: 'mgl-video-source',
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
hostDirectives: [{ directive: SourceDirective, inputs: ['id'] }],
}]
}], ctorParameters: () => [] });
const componentsAndDirectives = [
MapComponent,
LayerComponent,
DraggableDirective,
ImageComponent,
VectorSourceComponent,
GeoJSONSourceComponent,
RasterDemSourceComponent,
RasterSourceComponent,
ImageSourceComponent,
VideoSourceComponent,
CanvasSourceComponent,
FeatureComponent,
MarkerComponent,
PopupComponent,
ControlComponent,
FullscreenControlDirective,
NavigationControlDirective,
GeolocateControlDirective,
AttributionControlDirective,
ScaleControlDirective,
PointDirective,
ClusterPointDirective,
MarkersForClustersComponent,
TerrainControlDirective,
SourceDirective
];
class NgxMapLibreGLModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgxMapLibreGLModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.0.4", ngImport: i0, type: NgxMapLibreGLModule, imports: [MapComponent,
LayerComponent,
DraggableDirective,
ImageComponent,
VectorSourceComponent,
GeoJSONSourceComponent,
RasterDemSourceComponent,
RasterSourceComponent,
ImageSourceComponent,
VideoSourceComponent,
CanvasSourceComponent,
FeatureComponent,
MarkerComponent,
PopupComponent,
ControlComponent,
FullscreenControlDirective,
NavigationControlDirective,
GeolocateControlDirective,
AttributionControlDirective,
ScaleControlDirective,
PointDirective,
ClusterPointDirective,
MarkersForClustersComponent,
TerrainControlDirective,
SourceDirective], exports: [MapComponent,
LayerComponent,
DraggableDirective,
ImageComponent,
VectorSourceComponent,
GeoJSONSourceComponent,
RasterDemSourceComponent,
RasterSourceComponent,
ImageSourceComponent,
VideoSourceComponent,
CanvasSourceComponent,
FeatureComponent,
MarkerComponent,
PopupComponent,
ControlComponent,
FullscreenControlDirective,
NavigationControlDirective,
GeolocateControlDirective,
AttributionControlDirective,
ScaleControlDirective,
PointDirective,
ClusterPointDirective,
MarkersForClustersComponent,
TerrainControlDirective,
SourceDirective] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgxMapLibreGLModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: NgxMapLibreGLModule, decorators: [{
type: NgModule,
args: [{
imports: [...componentsAndDirectives],
exports: [...componentsAndDirectives],
}]
}] });
/**
* `mglGlobe` - a globe control directive
*
* @category Directives
*
* @see [Globe](https://maplibre.org/ngx-maplibre-gl/demo/globe)
* @see [GlobeControl](https://maplibre.org/maplibre-gl-js/docs/API/classes/GlobeControl)
*/
class GlobeControlDirective {
constructor() {
this.mapService = inject(MapService);
this.controlComponent = inject(ControlComponent, { host: true });
afterNextRender(() => {
this.mapService.mapCreated$.subscribe(() => {
if (this.controlComponent.control) {
throw new Error('Another control is already set for this control');
}
this.controlComponent.control = new GlobeControl();
this.mapService.addControl(this.controlComponent.control, this.controlComponent.position());
});
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GlobeControlDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.0.4", type: GlobeControlDirective, isStandalone: true, selector: "[mglGlobe]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: GlobeControlDirective, decorators: [{
type: Directive,
args: [{
selector: '[mglGlobe]',
}]
}], ctorParameters: () => [] });
/*
* Public API Surface of ngx-maplibre-gl
*/
/**
* Generated bundle index. Do not edit.
*/
export { AttributionControlDirective, CanvasSourceComponent, ClusterPointDirective, ControlComponent, CustomControl, DraggableDirective, FeatureComponent, FullscreenControlDirective, GeoJSONSourceComponent, GeolocateControlDirective, GlobeControlDirective, ImageComponent, ImageSourceComponent, LayerComponent, MapComponent, MapService, MarkerComponent, MarkersForClustersComponent, NavigationControlDirective, NgxMapLibreGLModule, PointDirective, PopupComponent, RasterDemSourceComponent, RasterSourceComponent, ScaleControlDirective, SourceDirective, TerrainControlDirective, VectorSourceComponent, VideoSourceComponent };
//# sourceMappingURL=maplibre-ngx-maplibre-gl.mjs.map