@progress/kendo-angular-map
Version:
Kendo UI Map for Angular
1,598 lines (1,563 loc) • 92.5 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* 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 — 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="© <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