UNPKG

@progress/kendo-angular-map

Version:
1,598 lines (1,563 loc) 92.5 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import * as i0 from '@angular/core'; import { Injectable, SimpleChange, Directive, TemplateRef, Component, ChangeDetectionStrategy, ContentChild, SecurityContext, Input, forwardRef, ViewChild, ElementRef, EventEmitter, Output, ContentChildren, Optional, NgModule } from '@angular/core'; import * as i3 from '@angular/platform-browser'; import { Subject, BehaviorSubject, combineLatest } from 'rxjs'; import { isDocumentAvailable, hasObservers, ResizeSensorComponent, ResizeBatchService } from '@progress/kendo-angular-common'; import * as i3$1 from '@progress/kendo-angular-l10n'; import { LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n'; import * as i4 from '@progress/kendo-angular-icons'; import { IconsService } from '@progress/kendo-angular-icons'; import { mapMarkerTargetIcon, mapMarkerIcon, plusIcon, minusIcon, caretAltUpIcon, caretAltDownIcon, caretAltLeftIcon, caretAltRightIcon } from '@progress/kendo-svg-icons'; import { InstanceObserver, Map } from '@progress/kendo-charts'; export { Extent, Location } from '@progress/kendo-charts'; import { validatePackage } from '@progress/kendo-licensing'; import { tap } from 'rxjs/operators'; import { NgClass, NgStyle, NgTemplateOutlet } from '@angular/common'; import * as i1 from '@progress/kendo-angular-popup'; import { PopupService, POPUP_CONTAINER } from '@progress/kendo-angular-popup'; /** * @hidden */ class ItemChange { sender; options; constructor(sender, options) { this.sender = sender; this.options = options; } } /** * @hidden */ class CollectionService { itemChanges; source; constructor() { this.source = new Subject(); this.itemChanges = this.source.asObservable(); } notify(change) { this.source.next(change); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CollectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CollectionService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CollectionService, decorators: [{ type: Injectable }], ctorParameters: function () { return []; } }); /** * @hidden */ class Change { key; value; constructor(key, value) { this.key = key; this.value = value; } } /** * @hidden */ class ConfigurationService { ngZone; changes; store = {}; source = new BehaviorSubject({}); constructor(ngZone) { this.ngZone = ngZone; this.initSource(); } initSource() { this.changes = this.source.asObservable(); } push(store) { this.store = store; this.next(); } notify(change) { this.set(change.key, change.value); this.next(); } set(field, value) { let store = this.store; const parts = field.split('.'); let key = parts.shift(); while (parts.length > 0) { store = store[key] = store[key] || {}; key = parts.shift(); } store[key] = value; } next() { this.ngZone.runOutsideAngular(() => { this.source.next(this.store); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConfigurationService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConfigurationService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConfigurationService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.NgZone }]; } }); /** * @hidden */ function copyChanges(changes, options) { for (const propertyName in changes) { if (!changes.hasOwnProperty(propertyName)) { continue; } const value = changes[propertyName].currentValue; if (value === undefined) { delete options[propertyName]; } else { options[propertyName] = value; } } } /** * @hidden */ function toSimpleChanges(changes) { const result = {}; for (const propertyName in changes) { if (!changes.hasOwnProperty(propertyName)) { continue; } result[propertyName] = new SimpleChange(null, changes[propertyName], false); } return result; } /** * @hidden */ class CollectionItemComponent { configurationService; collectionService; subscription; index = -1; options = {}; constructor(configurationService, collectionService) { this.configurationService = configurationService; this.collectionService = collectionService; this.subscription = configurationService.changes.subscribe(store => { this.options = store; this.notify(); }); } ngOnChanges(changes) { const store = this.configurationService.store; copyChanges(changes, store); this.configurationService.push(store); } /** * Updates the component fields with the specified values and refreshes the Chart. * * Use this method when the configuration values cannot be set through the template. * * @example * ```ts-no-run * item.notifyChanges({ visible: true }); * ``` * * @param changes An object containing the updated input fields. */ notifyChanges(changes) { this.ngOnChanges(toSimpleChanges(changes)); } ngOnDestroy() { this.subscription.unsubscribe(); } notify() { if (!this.collectionService) { return; } this.collectionService.notify(new ItemChange(this, this.options)); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CollectionItemComponent, deps: [{ token: ConfigurationService }, { token: CollectionService }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: CollectionItemComponent, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CollectionItemComponent, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: ConfigurationService }, { type: CollectionService }]; } }); /** * @hidden */ class SettingsComponent { configKey; configurationService; store = {}; constructor(configKey, configurationService) { this.configKey = configKey; this.configurationService = configurationService; if (configKey === undefined) { throw new Error('Configuration key not set'); } } ngOnDestroy() { this.store = undefined; this.notify(); } ngOnChanges(changes) { copyChanges(changes, this.store); this.notify(); } /** * Updates the component fields with the specified values and refreshes the component. * * Use this method when the configuration values cannot be set through the template. * * @example * ```ts-no-run * item.notifyChanges({ visible: true }); * ``` * * @param changes An object containing the updated input fields. */ notifyChanges(changes) { this.ngOnChanges(toSimpleChanges(changes)); } markAsVisible() { this.store.visible = true; this.notify(); } notify() { this.configurationService.notify(new Change(this.configKey, this.store)); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SettingsComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: SettingsComponent, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SettingsComponent, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: undefined }, { type: ConfigurationService }]; } }); /** * The configuration options of the Map layer tooltip. * * @hidden */ class LayerTooltipComponent extends SettingsComponent { configurationService; layerTooltipTemplate; constructor(configurationService) { super('tooltip', configurationService); this.configurationService = configurationService; } get layerTooltipTemplateRef() { return this.layerTooltipTemplate; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LayerTooltipComponent, deps: [{ token: ConfigurationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: LayerTooltipComponent, isStandalone: true, selector: "kendo-map-layer-tooltip", queries: [{ propertyName: "layerTooltipTemplate", first: true, predicate: TemplateRef, descendants: true }], usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LayerTooltipComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'kendo-map-layer-tooltip', template: '', standalone: true }] }], ctorParameters: function () { return [{ type: ConfigurationService }]; }, propDecorators: { layerTooltipTemplate: [{ type: ContentChild, args: [TemplateRef, { static: false }] }] } }); /** * @hidden */ class LayerComponent extends CollectionItemComponent { type; configurationService; collectionService; sanitizer; /** * @hidden */ attribution; /** * @hidden */ extent; /** * @hidden */ maxZoom; /** * @hidden */ minZoom; /** * @hidden */ opacity; /** * @hidden */ zIndex; layerTooltip; constructor(type, configurationService, collectionService, sanitizer) { super(configurationService, collectionService); this.type = type; this.configurationService = configurationService; this.collectionService = collectionService; this.sanitizer = sanitizer; } ngOnChanges(changes) { const store = this.configurationService.store; store.type = this.type; const attrChange = changes['attribution']; if (attrChange && this.sanitizer) { attrChange.currentValue = this.sanitizer.sanitize(SecurityContext.HTML, attrChange.currentValue); } super.ngOnChanges(changes); } get layerTooltipTemplateRef() { if (this.layerTooltip) { return this.layerTooltip.layerTooltipTemplateRef; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LayerComponent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: LayerComponent, inputs: { attribution: "attribution", extent: "extent", maxZoom: "maxZoom", minZoom: "minZoom", opacity: "opacity", zIndex: "zIndex" }, queries: [{ propertyName: "layerTooltip", first: true, predicate: LayerTooltipComponent, descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LayerComponent, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: undefined }, { type: ConfigurationService }, { type: CollectionService }, { type: i3.DomSanitizer }]; }, propDecorators: { attribution: [{ type: Input }], extent: [{ type: Input }], maxZoom: [{ type: Input }], minZoom: [{ type: Input }], opacity: [{ type: Input }], zIndex: [{ type: Input }], layerTooltip: [{ type: ContentChild, args: [LayerTooltipComponent, { static: false }] }] } }); /** * Represents the Kendo UI BubbleLayer component for Angular. Displays data as bubbles on vector shape layers for bubble maps. * * @example * ```typescript * @Component({ * selector: 'my-app', * template: ` * <kendo-map> * <kendo-map-bubble-layer * [data]="bubbleData" * locationField="location" * valueField="population" * [maxSize]="50" * [minSize]="10"> * </kendo-map-bubble-layer> * </kendo-map> * ` * }) * export class AppComponent { * public bubbleData = [ * { location: [40.7128, -74.0060], population: 8000000 } * ]; * } * ``` * * @remarks * Supported children components are: {@link BubbleTooltipComponent}. */ class BubbleLayerComponent extends LayerComponent { configurationService; collectionService; sanitizer; /** * Sets the array of data items for this layer. */ data; /** * Sets the data item field which contains the symbol location. * The field should be an array with two numbers &mdash; latitude and longitude in decimal degrees. */ locationField; /** * Sets the value field for the symbols used to determine their relative size. * The data item field should be a number. */ valueField; /** * Sets the symbol to use for bubble layers. */ symbol; /** * Sets the default style for symbols. */ style; /** * Sets the maximum symbol size for bubble layer symbols. * * @default 100 */ maxSize; /** * Sets the minimum symbol size for bubble layer symbols. * Setting a non-zero value will distort the symbol area to value ratio. * * @default 0 */ minSize; constructor(configurationService, collectionService, sanitizer) { super('bubble', configurationService, collectionService, sanitizer); this.configurationService = configurationService; this.collectionService = collectionService; this.sanitizer = sanitizer; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BubbleLayerComponent, deps: [{ token: ConfigurationService }, { token: CollectionService }, { token: i3.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: BubbleLayerComponent, isStandalone: true, selector: "kendo-map-bubble-layer", inputs: { data: "data", locationField: "locationField", valueField: "valueField", symbol: "symbol", style: "style", maxSize: "maxSize", minSize: "minSize" }, providers: [ ConfigurationService, { provide: LayerComponent, useExisting: forwardRef(() => BubbleLayerComponent) } ], usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BubbleLayerComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, providers: [ ConfigurationService, { provide: LayerComponent, useExisting: forwardRef(() => BubbleLayerComponent) } ], selector: 'kendo-map-bubble-layer', template: '', standalone: true }] }], ctorParameters: function () { return [{ type: ConfigurationService }, { type: CollectionService }, { type: i3.DomSanitizer }]; }, propDecorators: { data: [{ type: Input }], locationField: [{ type: Input }], valueField: [{ type: Input }], symbol: [{ type: Input }], style: [{ type: Input }], maxSize: [{ type: Input }], minSize: [{ type: Input }] } }); /** * @hidden */ function hasParent(element, parent) { let current = element; while (current && current !== parent) { current = current.parentNode; } return current ? true : false; } /** * @hidden */ class MapInstanceObserver extends InstanceObserver { handlerMap = { hideTooltip: 'onHideTooltip', init: 'onInit', render: 'onRender', showTooltip: 'onShowTooltip', centerChange: 'onCenterChange', zoomChange: 'onZoomChange' }; constructor(instance) { super(instance); } } /** * @hidden */ class BaseEvent { /** * The `MapComponent` that triggered the event. */ sender; /** * @hidden */ constructor(sender) { this.sender = sender; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BaseEvent, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: BaseEvent, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BaseEvent, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: undefined }]; } }); /** * Arguments for the `beforeReset` event. * Fires immediately before the map resets. Layer implementers typically use this event for cleanup. */ class BeforeResetEvent extends BaseEvent { /** * @hidden */ constructor(_, sender) { super(sender); } } /** * Arguments for the `mapClick` event. * Fires when you click on the map. */ class MapClickEvent extends BaseEvent { /** * The location of the clicked point. */ location; /** * The source DOM event instance. */ originalEvent; /** * @hidden */ constructor(e, sender) { super(sender); this.location = e.location; this.originalEvent = e.originalEvent; } } /** * Arguments for the `markerActivate` event. * Fires when a marker displays and has a DOM element assigned. */ class MarkerActivateEvent extends BaseEvent { /** * The marker instance. */ marker; /** * The marker layer instance. */ layer; /** * @hidden */ constructor(e, sender) { super(sender); this.marker = e.marker; this.layer = e.layer; } } /** * Arguments for the `markerClick` event. * Fires when the user clicks or taps a marker. */ class MarkerClickEvent extends BaseEvent { /** * The marker instance. */ marker; /** * The marker layer instance. */ layer; /** * @hidden */ constructor(e, sender) { super(sender); this.marker = e.marker; this.layer = e.layer; } } /** * @hidden */ class PreventableEvent extends BaseEvent { prevented = false; /** * Prevents the default action for a specified event. * In this way, the source component suppresses * the built-in behavior that follows the event. */ preventDefault() { this.prevented = true; } /** * Returns `true` if the event was prevented * by any of its subscribers. * * @returns `true` if the default action was prevented. * Otherwise, returns `false`. */ isDefaultPrevented() { return this.prevented; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PreventableEvent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: PreventableEvent, usesInheritance: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PreventableEvent, decorators: [{ type: Directive }] }); /** * Arguments for the `markerCreated` event. * Fires once the map has created a marker, and just before the map displays it. * * Cancelling the event prevents displaying the marker. */ class MarkerCreatedEvent extends PreventableEvent { /** * The marker instance. */ marker; /** * The marker layer instance. */ layer; /** * @hidden */ constructor(e, sender) { super(sender); this.marker = e.marker; this.layer = e.layer; } } /** * Arguments for the `panEnd` event. * Fires after the map viewport completes panning. */ class PanEndEvent extends BaseEvent { /** * The map origin (top left or NW corner). */ origin; /** * The current map center. */ center; /** * The source DOM event instance. */ originalEvent; /** * @hidden */ constructor(e, sender) { super(sender); this.origin = e.origin; this.center = e.center; this.originalEvent = e.originalEvent; } } /** * Arguments for the `pan` event. * Fires while the map viewport is being moved. */ class PanEvent extends BaseEvent { /** * The map origin (top left or NW corner). */ origin; /** * The current map center. */ center; /** * The source DOM event instance. */ originalEvent; /** * @hidden */ constructor(e, sender) { super(sender); this.origin = e.origin; this.center = e.center; this.originalEvent = e.originalEvent; } } /** * Arguments for the `reset` event. * Fires when the map resets. * * This typically occurs on initial load and after a zoom/center change. */ class ResetEvent extends BaseEvent { /** * @hidden */ constructor(_, sender) { super(sender); } } /** * Arguments for the `shapeClick` event. * Fires when a shape is clicked or tapped. */ class ShapeClickEvent extends BaseEvent { /** * The shape layer instance. */ layer; /** * The shape instance. */ shape; /** * The source DOM event instance. */ originalEvent; /** * @hidden */ constructor(e, sender) { super(sender); this.layer = e.layer; this.shape = e.shape; this.originalEvent = e.originalEvent; } } /** * Arguments for the `shapeCreated` event. * Fires when a shape is created, but is not rendered yet. */ class ShapeCreatedEvent extends BaseEvent { /** * The shape layer instance. */ layer; /** * The shape instance. */ shape; /** * The original data item for this Shape. */ dataItem; /** * The shape location. */ location; /** * @hidden */ constructor(e, sender) { super(sender); this.layer = e.layer; this.shape = e.shape; this.dataItem = e.shape.dataItem; this.location = e.shape.location; } } /** * Arguments for the `shapeFeatureCreated` event. * Fires when a [GeoJSON Feature](https://geojson.org/geojson-spec.html#feature-objects) is created on a shape layer. */ class ShapeFeatureCreatedEvent extends BaseEvent { /** * The original data item for this Feature. Includes `geometries` and `properties` members. */ dataItem; /** * The shape layer instance. */ layer; /** * The group that contains feature shape instances. */ group; /** * A reference to the `dataItem.properties` object. */ properties; /** * @hidden */ constructor(e, sender) { super(sender); this.dataItem = e.dataItem; this.layer = e.layer; this.group = e.group; this.properties = e.properties; } } /** * Arguments for the `shapeMouseEnter` event. * Fires when the mouse enters a shape. * * > This event fires reliably only for shapes that have a set fill color. * > You can still set the opacity to 0 so the shapes appear to have no fill. */ class ShapeMouseEnterEvent extends BaseEvent { /** * The shape layer instance. */ layer; /** * The shape instance. */ shape; /** * The source DOM event instance. */ originalEvent; /** * @hidden */ constructor(e, sender) { super(sender); this.layer = e.layer; this.shape = e.shape; this.originalEvent = e.originalEvent; } } /** * Arguments for the `shapeMouseLeave` event. * Fires when the mouse leaves a shape. * * > This event fires reliably only for shapes that have a set fill color. * > You can still set the opacity to 0 so the shapes appear to have no fill. */ class ShapeMouseLeaveEvent extends BaseEvent { /** * The shape layer instance. */ layer; /** * The shape instance. */ shape; /** * The source DOM event instance. */ originalEvent; /** * @hidden */ constructor(e, sender) { super(sender); this.layer = e.layer; this.shape = e.shape; this.originalEvent = e.originalEvent; } } /** * Arguments for the `zoomEnd` event. * Fires when the map zoom level changes. */ class ZoomEndEvent extends BaseEvent { /** * The source DOM event instance. */ originalEvent; /** * @hidden */ constructor(e, sender) { super(sender); this.originalEvent = e.originalEvent; } } /** * Arguments for the `zoomStart` event. * Fires when the map zoom level is about to change. * Cancel the event to prevent the user action. */ class ZoomStartEvent extends PreventableEvent { /** * The source DOM event instance. */ originalEvent; /** * @hidden */ constructor(e, sender) { super(sender); this.originalEvent = e.originalEvent; } } const EVENT_MAP = { beforeReset: BeforeResetEvent, click: MapClickEvent, markerActivate: MarkerActivateEvent, markerClick: MarkerClickEvent, markerCreated: MarkerCreatedEvent, panEnd: PanEndEvent, pan: PanEvent, reset: ResetEvent, shapeClick: ShapeClickEvent, shapeCreated: ShapeCreatedEvent, shapeFeatureCreated: ShapeFeatureCreatedEvent, shapeMouseEnter: ShapeMouseEnterEvent, shapeMouseLeave: ShapeMouseLeaveEvent, zoomEnd: ZoomEndEvent, zoomStart: ZoomStartEvent }; /** * @hidden */ class InstanceEventService { create(name, args, sender) { if (EVENT_MAP[name]) { return new EVENT_MAP[name](args, sender); } } } /** * @hidden */ const packageMetadata = { name: '@progress/kendo-angular-map', productName: 'Kendo UI for Angular', productCode: 'KENDOUIANGULAR', productCodes: ['KENDOUIANGULAR'], publishDate: 1756993072, version: '20.0.3', licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/' }; const POSITION_MODE = 'absolute'; const COLLISION = { horizontal: "fit", vertical: "fit" }; /** * @hidden */ class BaseTooltip { popupService; localizationService; animate = true; style = { position: 'relative' }; templateRef; popupRef = null; popupSettings; constructor(popupService, localizationService) { this.popupService = popupService; this.localizationService = localizationService; } get active() { return this.popupRef !== null; } show(e) { const offset = this.position(e.anchor); if (!this.popupRef) { this.popupRef = this.popupService.open(Object.assign({ offset: offset, popupAlign: { vertical: 'bottom', horizontal: 'center' }, animate: this.animate, content: this.templateRef, collision: COLLISION, positionMode: POSITION_MODE }, this.popupSettings)); if (this.localizationService.rtl) { this.popupRef.popupElement.setAttribute('dir', 'rtl'); } this.onInit(); } else { const popup = this.popupRef.popup.instance; popup.offset = offset; } } hide() { if (this.popupRef) { this.popupRef.close(); this.popupRef = null; } } onInit() { //calling on init } ngOnDestroy() { this.hide(); } position(offset) { if (!this.popupSettings || !this.popupSettings.appendTo) { return offset; } const appendTo = this.popupSettings.appendTo.element.nativeElement; const bbox = appendTo.getBoundingClientRect(); const { scrollLeft, scrollTop } = this.scrollOffset(appendTo); return { left: offset.left - bbox.left - scrollLeft, top: offset.top - bbox.top - scrollTop }; } scrollOffset(element) { if (!element) { return null; } let scrollLeft = element.scrollLeft; let scrollTop = element.scrollTop; let parent = element.parentElement; while (parent) { scrollLeft += parent.scrollLeft; scrollTop += parent.scrollTop; parent = parent.parentElement; } return { scrollLeft, scrollTop }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BaseTooltip, deps: [{ token: i1.PopupService }, { token: i3$1.LocalizationService }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: BaseTooltip, inputs: { popupSettings: "popupSettings" }, viewQueries: [{ propertyName: "templateRef", first: true, predicate: ["content"], descendants: true, static: true }], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BaseTooltip, decorators: [{ type: Directive }], ctorParameters: function () { return [{ type: i1.PopupService }, { type: i3$1.LocalizationService }]; }, propDecorators: { templateRef: [{ type: ViewChild, args: ['content', { static: true }] }], popupSettings: [{ type: Input }] } }); /** * @hidden */ class TooltipTemplateService { templates = []; registerTemplate(layerIndex, template) { if (layerIndex > -1) { this.templates[layerIndex] = template; } } getTemplate(layerIndex) { if (layerIndex > -1) { return this.templates[layerIndex]; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TooltipTemplateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TooltipTemplateService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TooltipTemplateService, decorators: [{ type: Injectable }] }); /** * @hidden */ function bodyFactory() { if (isDocumentAvailable()) { return new ElementRef(document.body); } } /** * @hidden */ class TooltipPopupComponent extends BaseTooltip { popupService; templateService; localizationService; ngZone; tooltipTemplateRef; tooltipContext = {}; animate = true; classNames; wrapperClass = 'k-tooltip-wrapper'; leave = new EventEmitter(); popupClasses = {}; mouseleaveSubscription; constructor(popupService, templateService, localizationService, ngZone) { super(popupService, localizationService); this.popupService = popupService; this.templateService = templateService; this.localizationService = localizationService; this.ngZone = ngZone; } show(e) { this.tooltipTemplateRef = this.templateService.getTemplate(e.layerIndex); if (!this.tooltipTemplateRef) { return; } this.popupClasses = Object.assign({ 'k-tooltip': true, 'k-map-tooltip': true, [e.className]: Boolean(e.className) }, this.classNames); this.tooltipContext = e; super.show(e); } containsElement(element) { if (this.popupRef) { return hasParent(element, this.popupRef.popupElement); } } onInit() { this.ngZone.runOutsideAngular(() => { this.mouseleaveSubscription = this.popupRef.popupElement.addEventListener('mouseleave', (args) => { this.leave.emit(args); }); }); this.popupRef.popupElement.classList.add(this.wrapperClass); } hide() { if (this.mouseleaveSubscription) { this.mouseleaveSubscription(); this.mouseleaveSubscription = null; } this.tooltipTemplateRef = null; super.hide(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TooltipPopupComponent, deps: [{ token: i1.PopupService }, { token: TooltipTemplateService }, { token: i3$1.LocalizationService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TooltipPopupComponent, isStandalone: true, selector: "kendo-map-tooltip-popup", inputs: { animate: "animate", classNames: "classNames", wrapperClass: "wrapperClass" }, outputs: { leave: "leave" }, providers: [PopupService, { provide: POPUP_CONTAINER, useFactory: bodyFactory }], usesInheritance: true, ngImport: i0, template: ` <ng-template #content> <div [ngClass]="popupClasses" [ngStyle]="style"> <div class="k-tooltip-content"> <ng-template [ngTemplateOutlet]="tooltipTemplateRef" [ngTemplateOutletContext]="tooltipContext"> </ng-template> </div> </div> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TooltipPopupComponent, decorators: [{ type: Component, args: [{ providers: [PopupService, { provide: POPUP_CONTAINER, useFactory: bodyFactory }], selector: 'kendo-map-tooltip-popup', template: ` <ng-template #content> <div [ngClass]="popupClasses" [ngStyle]="style"> <div class="k-tooltip-content"> <ng-template [ngTemplateOutlet]="tooltipTemplateRef" [ngTemplateOutletContext]="tooltipContext"> </ng-template> </div> </div> </ng-template> `, standalone: true, imports: [NgClass, NgStyle, NgTemplateOutlet] }] }], ctorParameters: function () { return [{ type: i1.PopupService }, { type: TooltipTemplateService }, { type: i3$1.LocalizationService }, { type: i0.NgZone }]; }, propDecorators: { animate: [{ type: Input }], classNames: [{ type: Input }], wrapperClass: [{ type: Input }], leave: [{ type: Output }] } }); // Static SVG Icons used by the Map const svgIcons = { mapMarkerTargetIcon, mapMarkerIcon, plusIcon, minusIcon, caretAltUpIcon, caretAltDownIcon, caretAltLeftIcon, caretAltRightIcon }; /** * Represents the [Kendo UI Map component for Angular]({% slug overview_map %}). * * Use this component to display interactive maps with markers, layers, and controls. * Configure zoom levels, center coordinates, and user interactions like panning and zooming. * * @example * ```ts * import { Component } from '@angular/core'; * * @Component({ * selector: 'my-app', * template: ` * <kendo-map [center]="center" [zoom]="15"> * <kendo-map-layers> * <kendo-map-tile-layer * [subdomains]="tileSubdomains" * [urlTemplate]="tileUrl" * attribution="&copy; <a href='https://osm.org/copyright'>OpenStreetMap contributors</a>" * > * </kendo-map-tile-layer> * <kendo-map-marker-layer * [data]="markers" * locationField="latlng" * titleField="name" * > * </kendo-map-marker-layer> * </kendo-map-layers> * </kendo-map> * ` * }) * class AppComponent { * tileSubdomains = ["a", "b", "c"]; * tileUrl = (e: TileUrlTemplateArgs): string => * `https://${e.subdomain}.tile.openstreetmap.org/${e.zoom}/${e.x}/${e.y}.png`; * * center = [30.2675, -97.7409]; * markers = [{ latlng: [30.2675, -97.7409], name: "Zevo Toys" }]; * } * ``` * * @remarks * Supported children components are: {@link LayersComponent}. */ class MapComponent { configurationService; instanceEventService; element; localizationService; changeDetector; ngZone; renderer; iconsService; /** * Limits the automatic resizing of the Map. Sets the maximum number of times per second * that the component redraws its content when the size of its container changes. * To disable the automatic resizing, set it to `0`. * * @default 10 * * @example * ```ts * @Component({ * selector: 'my-app', * template: ` * <kendo-map [resizeRateLimit]="2"> * </kendo-map> * ` * }) * export class AppComponent { * } * ``` */ resizeRateLimit = 10; /** * Specifies the map center coordinates. * Provide coordinates as `[Latitude, Longitude]`. */ center; /** * Specifies the configuration for built-in map controls. */ controls; /** * The minimum zoom level. Typical web maps use zoom levels from 0 (whole world) to 19 (sub-meter features). * * @default 1 */ minZoom; /** * The maximum zoom level. Typical web maps use zoom levels from 0 (whole world) to 19 (sub-meter features). * * @default 19 */ maxZoom; /** * The size of the map in pixels at zoom level 0. * * @default 256 */ minSize; /** * Controls whether the user can pan the map. * * @default true */ pannable; /** * The settings for the tooltip popup. */ popupSettings; /** * Specifies whether the map should wrap around the east-west edges. * * @default true */ wraparound; /** * Specifies the initial zoom level. * Use values from 0 (whole world) to 19 (sub-meter features). * The map size derives from the zoom level and `minScale` options: `size = (2 ^ zoom) * minSize`. * Map zoom rounds floating point numbers to use whole [`zoom levels`](https://wiki.openstreetmap.org/wiki/Zoom_levels) 0 through 19. * * @default 3 */ zoom = 3; /** * Determines whether users can change the map zoom level. * * @default true */ zoomable; /** * Fires immediately before the map resets. This event is typically used for cleanup by layer implementers. */ beforeReset = new EventEmitter(); /** * Fires when the user clicks on the map. */ mapClick = new EventEmitter(); /** * Fires when a marker appears on the map and its DOM element becomes available. */ markerActivate = new EventEmitter(); /** * Fires when the user clicks or taps a marker. */ markerClick = new EventEmitter(); /** * Fires once the map has created a marker, and just before the map displays it. * * Cancelling the event prevents displaying the marker. */ markerCreated = new EventEmitter(); /** * Fires after the map viewport completes panning. */ panEnd = new EventEmitter(); /** * Fires while the map viewport is being moved. */ pan = new EventEmitter(); /** * Fires when the map resets. * * This typically occurs on initial load and after a zoom/center change. */ reset = new EventEmitter(); /** * Fires when a shape is clicked or tapped. */ shapeClick = new EventEmitter(); /** * Fires when a shape is created, but is not rendered yet. */ shapeCreated = new EventEmitter(); /** * Fires when a [GeoJSON Feature](https://geojson.org/geojson-spec.html#feature-objects) is created on a shape layer. */ shapeFeatureCreated = new EventEmitter(); /** * Fires when the mouse enters a shape. * * > This event will fire reliably only for shapes that have set fill color. * > The opacity can still be set to 0 so the shapes appear to have no fill. */ shapeMouseEnter = new EventEmitter(); /** * Fires when the mouse leaves a shape. * * > This event will fire reliably only for shapes that have set fill color. * > The opacity can still be set to 0 so the shapes appear to have no fill. */ shapeMouseLeave = new EventEmitter(); /** * Fires when the map zoom level is about to change. * * Cancelling the event will prevent the user action. */ zoomStart = new EventEmitter(); /** * Fires when the map zoom level changes. */ zoomEnd = new EventEmitter(); /** * Fires when the map center has been changed. */ centerChange = new EventEmitter(); /** * Fires when the map zoom level has been changed. */ zoomChange = new EventEmitter(); tooltipInstance; instance; initResizeSensor = false; options; theme = null; resizeTimeout; redrawTimeout; destroyed; rtl = false; subscriptions; optionsChange; domSubscriptions; iconSettings; constructor(configurationService, instanceEventService, element, localizationService, changeDetector, ngZone, renderer, iconsService) { this.configurationService = configurationService; this.instanceEventService = instanceEventService; this.element = element; this.localizationService = localizationService; this.changeDetector = changeDetector; this.ngZone = ngZone; this.renderer = renderer; this.iconsService = iconsService; validatePackage(packageMetadata); } ngAfterViewInit() { if (this.canRender) { this.ngZone.runOutsideAngular(() => { const mapMouseleave = this.renderer.listen(this.element.nativeElement, 'mouseleave', this.mapMouseleave.bind(this)); this.domSubscriptions = () => { mapMouseleave(); }; }); } this.setDirection(); this.initConfig(); this.subscriptions = this.localizationService.changes.subscribe(() => this.setDirection()); } ngAfterViewChecked() { if (this.instance && this.autoResize) { this.ngZone.runOutsideAngular(() => { clearTimeout(this.resizeTimeout); this.resizeTimeout = setTimeout(() => { this.resize(); }, 0); }); } } ngOnChanges(changes) { if (this.instance) { if (changes['zoom']) { this.instance.zoom(changes['zoom'].currentValue); delete changes['zoom']; } if (changes['center']) { this.instance.center(changes['center'].currentValue); delete changes['center']; } if (Object.keys(changes).length === 0) { return; } } const store = this.configurationService.store; copyChanges(changes, store); store.popupSettings = null; this.configurationService.push(store); } ngOnDestroy() { this.destroyed = true; if (this.optionsChange) { this.optionsChange.unsubscribe(); } if (this.domSubscriptions) { this.domSubscriptions(); this.domSubscriptions = null; } if (this.instance) { this.instance.destroy(); this.instance = null; } if (this.subscriptions) { this.subscriptions.unsubscribe(); } } /** * Gets the marker layers instances. */ get layers() { return this.instance?.layers; } /** * Gets the extent (visible area) of the map. */ get extent() { return this.instance?.extent(); } /** * Sets the extent (visible area) of the map. */ set extent(extent) { this.instance?.extent(extent); } /** * Detects the container size and redraws the Map. * Resizing happens automatically unless you set `resizeRateLimit` to `0`. */ resize() { //this.instance?.resize(); } /** * Gets the size of the visible map area. * * @returns {Object} The width and height of the visible map area. */ viewSize() { return this.instance?.viewSize(); } /** * Gets event coordinates relative to the map element. * Offset coordinates do not sync to a specific map location. * * @param {any} e The mouse event. * @returns {geometry.Point} The event coordinates relative to the map element. */ eventOffset(e) { return this.instance?.eventOffset(e); } /** * Gets projected layer coordinates for this mouse event. * Layer coordinates are absolute and change only when zoom level changes. * * @param {any} e The mouse event. * @returns {geometry.Point} The projected layer coordinates for this event. */ eventToLayer(e) { return this.instance?.eventToLayer(e); } /** * Gets the geographic location for this mouse event. * * @param {any} e The mouse event. * @returns {geometry.Point} The geographic location for this mouse event. */ eventToLocation(e) { return this.instance?.eventToLocation(e); } /** * Gets relative view coordinates for this mouse event. * Layer elements positioned on these coordinates appear under the mouse cursor. * View coordinates become invalid after a map reset. * * @param {any} e The mouse event. * @returns {geometry.Point} The relative view coordinates for this mouse event. */ eventToView(e) { return this.instance?.eventToView(e); } /** * Converts layer coordinates to geographic location. * * @param {geometry.Point | number[]} point The layer coordinates. Arrays use x, y order. * @param {number} zoom Optional. Zoom level to use. Defaults to current zoom level. * @returns {Location} The geographic location for the layer coordinates. */ layerToLocation(point, zoom) { return this.instance?.layerToLocation(point, zoom); } /** * Gets layer coordinates for a geographic location. * * @param {Location | number[]} location The geographic location. Arrays use [Latitude, Longitude] order. * @param {number} zoom Optional. Zoom level to use. Defaults to current zoom level. * @returns {geometry.Point} The layer coordinates. */ locationToLayer(location, zoom) { return this.instance?.locationToLayer(location, zoom); } /** * Gets view coordinates for a geographic location. * * @param {Location | number[]} location The geographic location. Arrays use [Latitude, Longitude] order. * @returns {geometry.Point} The view coordinates for the geographic location. */ locationToView(location) { return this.instance?.locationToView(location); } /** * Gets the geographic location for view coordinates. * * @param {geometry.Point | number[]} point The view