packages/core/src/lib/directives/marker.ts
AgmMarker renders a map marker inside a AgmMap.
```typescript
.agm-map-container {
height: 300px;
}
],
OnDestroy
OnChanges
AfterContentInit
FitBoundsAccessor
Providers |
{ provide: FitBoundsAccessor, useExisting: forwardRef(() => AgmMarker) }
|
Selector | agm-marker |
Properties |
|
Methods |
|
Inputs |
Outputs |
constructor(_markerManager: MarkerManager)
|
||||||
Parameters :
|
animation | |
Which animation to play when marker is added to a map. This can be 'BOUNCE' or 'DROP' |
iconUrl | |
Type : string | google.maps.Icon | google.maps.Symbol
|
|
Icon (the URL of the image) for the foreground. |
label | |
Type : string | google.maps.MarkerLabel
|
|
The label (a single uppercase character) for the marker. |
latitude | |
Type : number
|
|
The latitude position of the marker. |
longitude | |
Type : number
|
|
The longitude position of the marker. |
markerClickable | |
Default value : true
|
|
If true, the marker can be clicked. Default value is true. |
markerDraggable | |
Default value : false
|
|
If true, the marker can be dragged. Default value is false. |
opacity | |
Default value : 1
|
|
The marker's opacity between 0.0 and 1.0. |
openInfoWindow | |
Default value : true
|
|
Whether to automatically open the child info window when the marker is clicked. |
title | |
Type : string
|
|
The title of the marker. |
visible | |
Default value : true
|
|
If true, the marker is visible |
animationChange | |
Type : EventEmitter
|
|
This event is fired when the marker's animation property changes. |
drag | |
Type : EventEmitter<google.maps.MouseEvent>
|
|
This event is repeatedly fired while the user drags the marker. |
dragEnd | |
Type : EventEmitter<google.maps.MouseEvent>
|
|
This event is fired when the user stops dragging the marker. |
dragStart | |
Type : EventEmitter<google.maps.MouseEvent>
|
|
This event is fired when the user starts dragging the marker. |
markerClick | |
Type : EventEmitter<AgmMarker>
|
|
This event emitter gets emitted when the user clicks on the marker. |
markerDblClick | |
Type : EventEmitter<AgmMarker>
|
|
This event emitter gets emitted when the user clicks twice on the marker. |
markerRightClick | |
Type : EventEmitter<void>
|
|
This event is fired when the user rightclicks on the marker. |
mouseOut | |
Type : EventEmitter<google.maps.MouseEvent>
|
|
This event is fired when the user mouses outside the marker. |
mouseOver | |
Type : EventEmitter<google.maps.MouseEvent>
|
|
This event is fired when the user mouses over the marker. |
Private _addEventListeners |
_addEventListeners()
|
Returns :
void
|
Protected _updateFitBoundsDetails |
_updateFitBoundsDetails()
|
Returns :
void
|
getFitBoundsDetails$ |
getFitBoundsDetails$()
|
Returns :
Observable<FitBoundsDetails>
|
Private handleInfoWindowUpdate |
handleInfoWindowUpdate()
|
Returns :
void
|
id |
id()
|
Returns :
string
|
ngAfterContentInit |
ngAfterContentInit()
|
Returns :
void
|
ngOnChanges | ||||||
ngOnChanges(changes: literal type)
|
||||||
Parameters :
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
toString |
toString()
|
Returns :
string
|
Protected Readonly _fitBoundsDetails$ |
Type : ReplaySubject<FitBoundsDetails>
|
Default value : new ReplaySubject<FitBoundsDetails>(1)
|
Private _id |
Type : string
|
Private _markerAddedToManger |
Default value : false
|
Private _observableSubscriptions |
Type : Subscription[]
|
Default value : []
|
infoWindow |
Type : QueryList<AgmInfoWindow>
|
Default value : new QueryList<AgmInfoWindow>()
|
Decorators :
@ContentChildren(AgmInfoWindow)
|
import { AfterContentInit, ContentChildren, Directive, EventEmitter, forwardRef, Input, OnChanges, OnDestroy, Output, QueryList, SimpleChange } from '@angular/core';
import { Observable, ReplaySubject, Subscription } from 'rxjs';
import { FitBoundsAccessor, FitBoundsDetails } from '../services/fit-bounds';
import { MarkerManager } from '../services/managers/marker-manager';
import { AgmInfoWindow } from './info-window';
let markerId = 0;
/**
* AgmMarker renders a map marker inside a {@link AgmMap}.
*
* ### Example
* ```typescript
* import { Component } from '@angular/core';
*
* @Component({
* selector: 'my-map-cmp',
* styles: [`
* .agm-map-container {
* height: 300px;
* }
* `],
* template: `
* <agm-map [latitude]="lat" [longitude]="lng" [zoom]="zoom">
* <agm-marker [latitude]="lat" [longitude]="lng" [label]="'M'">
* </agm-marker>
* </agm-map>
* `
* })
* ```
*/
@Directive({
selector: 'agm-marker',
providers: [
{ provide: FitBoundsAccessor, useExisting: forwardRef(() => AgmMarker) },
],
})
export class AgmMarker implements OnDestroy, OnChanges, AfterContentInit, FitBoundsAccessor {
/**
* The latitude position of the marker.
*/
@Input() latitude: number;
/**
* The longitude position of the marker.
*/
@Input() longitude: number;
/**
* The title of the marker.
*/
@Input() title: string;
/**
* The label (a single uppercase character) for the marker.
*/
@Input() label: string | google.maps.MarkerLabel;
/**
* If true, the marker can be dragged. Default value is false.
*/
// tslint:disable-next-line:no-input-rename
@Input('markerDraggable') draggable = false;
/**
* Icon (the URL of the image) for the foreground.
*/
@Input() iconUrl: string | google.maps.Icon | google.maps.Symbol;
/**
* If true, the marker is visible
*/
@Input() visible = true;
/**
* Whether to automatically open the child info window when the marker is clicked.
*/
@Input() openInfoWindow = true;
/**
* The marker's opacity between 0.0 and 1.0.
*/
@Input() opacity = 1;
/**
* All markers are displayed on the map in order of their zIndex, with higher values displaying in
* front of markers with lower values. By default, markers are displayed according to their
* vertical position on screen, with lower markers appearing in front of markers further up the
* screen.
*/
@Input() zIndex = 1;
/**
* If true, the marker can be clicked. Default value is true.
*/
// tslint:disable-next-line:no-input-rename
@Input('markerClickable') clickable = true;
/**
* Which animation to play when marker is added to a map.
* This can be 'BOUNCE' or 'DROP'
*/
@Input() animation: keyof typeof google.maps.Animation;
/**
* This event is fired when the marker's animation property changes.
*/
@Output() animationChange = new EventEmitter<keyof typeof google.maps.Animation>();
/**
* This event emitter gets emitted when the user clicks on the marker.
*/
@Output() markerClick: EventEmitter<AgmMarker> = new EventEmitter<AgmMarker>();
/**
* This event emitter gets emitted when the user clicks twice on the marker.
*/
@Output() markerDblClick: EventEmitter<AgmMarker> = new EventEmitter<AgmMarker>();
/**
* This event is fired when the user rightclicks on the marker.
*/
@Output() markerRightClick: EventEmitter<void> = new EventEmitter<void>();
/**
* This event is fired when the user starts dragging the marker.
*/
@Output() dragStart: EventEmitter<google.maps.MouseEvent> = new EventEmitter<google.maps.MouseEvent>();
/**
* This event is repeatedly fired while the user drags the marker.
*/
// tslint:disable-next-line: no-output-native
@Output() drag: EventEmitter<google.maps.MouseEvent> = new EventEmitter<google.maps.MouseEvent>();
/**
* This event is fired when the user stops dragging the marker.
*/
@Output() dragEnd: EventEmitter<google.maps.MouseEvent> = new EventEmitter<google.maps.MouseEvent>();
/**
* This event is fired when the user mouses over the marker.
*/
@Output() mouseOver: EventEmitter<google.maps.MouseEvent> = new EventEmitter<google.maps.MouseEvent>();
/**
* This event is fired when the user mouses outside the marker.
*/
@Output() mouseOut: EventEmitter<google.maps.MouseEvent> = new EventEmitter<google.maps.MouseEvent>();
/** @internal */
@ContentChildren(AgmInfoWindow) infoWindow: QueryList<AgmInfoWindow> = new QueryList<AgmInfoWindow>();
private _markerAddedToManger = false;
private _id: string;
private _observableSubscriptions: Subscription[] = [];
protected readonly _fitBoundsDetails$: ReplaySubject<FitBoundsDetails> = new ReplaySubject<FitBoundsDetails>(1);
constructor(private _markerManager: MarkerManager) { this._id = (markerId++).toString(); }
/* @internal */
ngAfterContentInit() {
this.handleInfoWindowUpdate();
this.infoWindow.changes.subscribe(() => this.handleInfoWindowUpdate());
}
private handleInfoWindowUpdate() {
if (this.infoWindow.length > 1) {
throw new Error('Expected no more than one info window.');
}
this.infoWindow.forEach(marker => {
marker.hostMarker = this;
});
}
/** @internal */
ngOnChanges(changes: { [key: string]: SimpleChange }) {
if (typeof this.latitude === 'string') {
this.latitude = Number(this.latitude);
}
if (typeof this.longitude === 'string') {
this.longitude = Number(this.longitude);
}
if (typeof this.latitude !== 'number' || typeof this.longitude !== 'number') {
return;
}
if (!this._markerAddedToManger) {
this._markerManager.addMarker(this);
this._updateFitBoundsDetails();
this._markerAddedToManger = true;
this._addEventListeners();
return;
}
// tslint:disable: no-string-literal
if (changes['latitude'] || changes['longitude']) {
this._markerManager.updateMarkerPosition(this);
this._updateFitBoundsDetails();
}
if (changes['title']) {
this._markerManager.updateTitle(this);
}
if (changes['label']) {
this._markerManager.updateLabel(this);
}
if (changes['draggable']) {
this._markerManager.updateDraggable(this);
}
if (changes['iconUrl']) {
this._markerManager.updateIcon(this);
}
if (changes['opacity']) {
this._markerManager.updateOpacity(this);
}
if (changes['visible']) {
this._markerManager.updateVisible(this);
}
if (changes['zIndex']) {
this._markerManager.updateZIndex(this);
}
if (changes['clickable']) {
this._markerManager.updateClickable(this);
}
if (changes['animation']) {
this._markerManager.updateAnimation(this);
}
// tslint:enable: no-string-literal
}
/** @internal */
getFitBoundsDetails$(): Observable<FitBoundsDetails> {
return this._fitBoundsDetails$.asObservable();
}
protected _updateFitBoundsDetails() {
this._fitBoundsDetails$.next({ latLng: { lat: this.latitude, lng: this.longitude } });
}
private _addEventListeners() {
const cs = this._markerManager.createEventObservable('click', this).subscribe(() => {
if (this.openInfoWindow) {
this.infoWindow.forEach(infoWindow => infoWindow.open());
}
this.markerClick.emit(this);
});
this._observableSubscriptions.push(cs);
const dcs = this._markerManager.createEventObservable('dblclick', this).subscribe(() => {
this.markerDblClick.emit(null);
});
this._observableSubscriptions.push(dcs);
const rc = this._markerManager.createEventObservable('rightclick', this).subscribe(() => {
this.markerRightClick.emit(null);
});
this._observableSubscriptions.push(rc);
const ds =
this._markerManager.createEventObservable<google.maps.MouseEvent>('dragstart', this)
.subscribe(e => this.dragStart.emit(e));
this._observableSubscriptions.push(ds);
const d =
this._markerManager.createEventObservable<google.maps.MouseEvent>('drag', this)
.subscribe(e => this.drag.emit(e));
this._observableSubscriptions.push(d);
const de =
this._markerManager.createEventObservable<google.maps.MouseEvent>('dragend', this)
.subscribe(e => this.dragEnd.emit(e));
this._observableSubscriptions.push(de);
const mover =
this._markerManager.createEventObservable<google.maps.MouseEvent>('mouseover', this)
.subscribe(e => this.mouseOver.emit(e));
this._observableSubscriptions.push(mover);
const mout =
this._markerManager.createEventObservable<google.maps.MouseEvent>('mouseout', this)
.subscribe(e => this.mouseOut.emit(e));
this._observableSubscriptions.push(mout);
const anChng =
this._markerManager.createEventObservable<void>('animation_changed', this)
.subscribe(() => {
this.animationChange.emit(this.animation);
});
this._observableSubscriptions.push(anChng);
}
/** @internal */
id(): string { return this._id; }
/** @internal */
toString(): string { return 'AgmMarker-' + this._id.toString(); }
/** @internal */
ngOnDestroy() {
this._markerManager.deleteMarker(this);
// unsubscribe all registered observable subscriptions
this._observableSubscriptions.forEach((s) => s.unsubscribe());
}
}