@progress/kendo-angular-map
Version:
Kendo UI Map for Angular
1,593 lines (1,558 loc) • 85.2 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 }]
}] } });
/**
* A vector shape layer for bubble maps. [See example](slug:bubble_layers_map).
*/
class BubbleLayerComponent extends LayerComponent {
configurationService;
collectionService;
sanitizer;
/**
* The array of data items for this layer.
*/
data;
/**
* 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;
/**
* The value field for the symbols used to determine their relative size.
* The data item field should be a number.
*/
valueField;
/**
* The symbol to use for bubble layers.
*/
symbol;
/**
* The default style for symbols.
*/
style;
/**
* The maximum symbol size for bubble layer symbols.
*
* @default 100
*/
maxSize;
/**
* The minimum symbol size for bubble layer symbols.
* Setting non-zero value will distort 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 }]; } });
/**
* Fired immediately before the map is reset. This event is typically used for cleanup by layer implementers.
*/
class BeforeResetEvent extends BaseEvent {
/**
* @hidden
*/
constructor(_, sender) {
super(sender);
}
}
/**
* Fired when the user clicks 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;
}
}
/**
* Fired when a marker has been displayed 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;
}
}
/**
* Fired when a marker has been clicked or tapped.
*/
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
}] });
/**
* Fired when a marker has been created and is about to be displayed.
*
* Cancelling the event will prevent the marker from being shown.
*/
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;
}
}
/**
* Fires after the map viewport has been moved.
*/
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;
}
}
/**
* Fired 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;
}
}
/**
* Fired when the map is reset.
*
* This typically occurs on initial load and after a zoom/center change.
*/
class ResetEvent extends BaseEvent {
/**
* @hidden
*/
constructor(_, sender) {
super(sender);
}
}
/**
* Fired 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;
}
}
/**
* Fired 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;
}
}
/**
* Fired 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. Members include `geometries` and `properties`.
*/
dataItem;
/**
* The shape layer instance.
*/
layer;
/**
* The group containing 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;
}
}
/**
* Fired 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.
*/
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;
}
}
/**
* Fired 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.
*/
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;
}
}
/**
* Fired when the map zoom level has changed.
*/
class ZoomEndEvent extends BaseEvent {
/**
* The source DOM event instance
*/
originalEvent;
/**
* @hidden
*/
constructor(e, sender) {
super(sender);
this.originalEvent = e.originalEvent;
}
}
/**
* Fired when the map zoom level is about to change.
*
* Cancelling the event will 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: 1749540406,
version: '19.1.1',
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 %}).
*
* @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" }];
* }
*
* ```
*/
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.
* Defaults to `10`. To disable the automatic resizing, set it to `0`.
*
* @example
* ```ts
* _@Component({
* selector: 'my-app',
* template: `
* <kendo-map [resizeRateLimit]="2">
* <!-- ^^^^^^^^^^^^^^^^^^^^^^
* Will update the size of the Map up to two times a second.
* Resize the example pane or window to try it out.
* -->
* </kendo-map>
* `
* })
* export class AppComponent {
* }
* ```
*/
resizeRateLimit = 10;
/**
* The map center. Coordinates are listed as `[Latitude, Longitude]`.
*/
center;
/**
* The configuration of 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;
/**
* The initial zoom level.
*
* Typical web maps use zoom levels from 0 (whole world) to 19 (sub-meter features).
*
* The map size is derived from the zoom level and minScale options: `size = (2 ^ zoom) * minSize`
*
* > Map zoom rounds floating point numbers. This is done so as the majority of web maps use the whole [`zoom levels`](https://wiki.openstreetmap.org/wiki/Zoom_levels) 0 through to 19.
*
* @default 3
*/
zoom = 3;
/**
* Controls whether the map zoom level can be changed by the user.
*
* @default true
*/
zoomable;
/**
* Fired immediately before the map is reset. This event is typically used for cleanup by layer implementers.
*/
beforeReset = new EventEmitter();
/**
* Fired when the user clicks on the map.
*/
mapClick = new EventEmitter();
/**
* Fired when a marker has been displayed and has a DOM element assigned.
*/
markerActivate = new EventEmitter();
/**
* Fired when a marker has been clicked or tapped.
*/
markerClick = new EventEmitter();
/**
* Fired when a marker has been created and is about to be displayed.
*
* Cancelling the event will prevent the marker from being shown.
*/
markerCreated = new EventEmitter();
/**
* Fires after the map viewport has been moved.
*/
panEnd = new EventEmitter();
/**
* Fired while the map viewport is being moved.
*/
pan = new EventEmitter();
/**
* Fired when the map is reset.
*
* This typically occurs on initial load and after a zoom/center change.
*/
reset = new EventEmitter();
/**
* Fired when a shape is clicked or tapped.
*/
shapeClick = new EventEmitter();
/**
* Fired when a shape is created, but is not rendered yet.
*/
shapeCreated = new EventEmitter();
/**
* Fired when a [GeoJSON Feature](https://geojson.org/geojson-spec.html#feature-objects) is created on a shape layer.
*/
shapeFeatureCreated = new EventEmitter();
/**
* Fired 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();
/**
* Fired 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();
/**
* Fired when the map zoom level is about to change.
*
* Cancelling the event will prevent the user action.
*/
zoomStart = new EventEmitter();
/**
* Fired when the map zoom level has changed.
*/
zoomEnd = new EventEmitter();
/**
* Fired when the map center has been changed.
*/
centerChange = new EventEmitter();
/**
* Fired 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();
}
}
/**
* 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 size of the container and redraws the Map.
* Resizing is automatic unless you set the `resizeRateLimit` option to `0`.
*/
resize() {
//this.instance?.resize();
}
/**
* Retrieves the size of the visible portion of the map.
*
* @returns The size (width and height) of the visible portion of the map.
*/
viewSize() {
return this.instance?.viewSize();
}
/**
* Returns the event coordinates relative to the map element. Offset coordinates are not synchronized to a particular location on the map.
*
* @param e The mouse event.
* @returns The event coordinates relative to the map element.
*/
eventOffset(e) {
return this.instance?.eventOffset(e);
}
/**
* Retrieves projected (layer) coordinates that correspond to this mouse event. Layer coordinates are absolute and change only when the zoom level is changed.
*
* @param e The mouse event.
* @returns The projected (layer) coordinates that correspond to this event.
*/
eventToLayer(e) {
return this.instance?.eventToLayer(e);
}
/**
* Retrieves the geographic location that correspond to this mouse event.
*
* @param e The mouse event.
* @returns The geographic location that correspond to this mouse event.
*/
eventToLocation(e) {
return this.instance?.eventToLocation(e);
}
/**
* Retrieves relative (view) coordinates that correspond to this mouse event. Layer elements positioned on these coordinates will appear under the mouse cursor.
* View coordinates are no longer valid after a map reset.
*
* @param e The mouse event.
* @returns The relative (view) coordinates that correspond to this mouse event.
*/
eventToView(e) {
return this.instance?.eventToView(e);
}
/**
* Transforms layer (projected) coordinates to geographical location.
*
* @param point The layer (projected) coordinates. An array argument is assumed to be in x, y order.
* @param zoom Optional. Assumed zoom level. Defaults to the current zoom level.
* @returns The geographic location that corresponds to the layer coordinates.
*/
layerToLocation(point, zoom) {
return this.instance?.layerToLocation(point, zoom);
}
/**
* Returns the layer (projected) coordinates that correspond to a geographical location.
*
* @param location The geographic location. An array argument is assumed to be in [Latitude, Longitude] order.
* @param zoom Optional. Assumed zoom level. Defaults to the current zoom level.
* @returns The layer (projected) coordinates.
*/
locationToLayer(location, zoom) {
return this.instance?.locationToLayer(location, zoom);
}
/**
* Returns the view (relative) coordinates that correspond to a geographical location.
*
* @param location The geographic location. An array argument is assumed to be in [Latitude, Longitude] order.
* @returns The view coordinates that correspond to a geographical location.
*/
locationToView(location) {
return this.instance?.locationToView(location);
}
/**
* Returns the geographical location that correspond to the view (relative) coordinates.
*
* @param point The view coordinates. An array argument is assumed to be in x, y order.
* @param zoom Optional. Assumed zoom level. Defaults to the current zoom level.
* @returns The geographic location that corresponds to the view coordinates.
*/
viewToLocation(point, zoom) {
return this.instance?.viewToLocation(point, zoom);
}
/**
* @hidden
*/
onResize() {
if (this.autoResize) {
this.resize();
}
}
/**
* @hidden
*/
get canRender() {
return isDocumentAvailable() && Boolean(this.element);
}
get autoResize() {
return this.resizeRateLimit > 0;
}
init() {
if (!this.canRender) {
return;
}
const element = this.element.nativeElement;
this.renderer.setStyle(element, 'display', 'block');
const instanceObserver = new MapInstanceObserver(this);
this.createInstance(element, instanceObserver);
}
initConfig() {
if (!isDocumentAvailable()) {
return;
}
this.ngZone.runOutsideAngular(() => {
th