You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.2 KiB
190 lines
5.2 KiB
/** |
|
* Copyright 2020 Google LLC. All Rights Reserved. |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
import { MarkerWithLabelOptions } from "./marker"; |
|
import { OverlayViewSafe } from "./overlay-view-safe"; |
|
|
|
export type LabelOptions = Partial<MarkerWithLabelOptions>; |
|
|
|
const BLOCK = "block"; |
|
const NONE = "none"; |
|
const ABSOLUTE = "absolute"; |
|
const CURSOR = "pointer"; |
|
const LABEL_CLASS = "marker-label"; |
|
const EVENT_CLASS = "marker-label-event"; |
|
const EVENT_DIV_OPACITY = "0.01"; |
|
|
|
export class Label extends OverlayViewSafe { |
|
public anchor: google.maps.Point; |
|
public position: google.maps.LatLng; |
|
public zIndex: number; |
|
public clickable: boolean; |
|
public draggable: boolean; |
|
private labelDiv: HTMLElement; |
|
private eventDiv: HTMLElement; |
|
private zIndexOffset: number; |
|
private hoverCursor: string; |
|
|
|
constructor({ |
|
clickable = true, |
|
cursor = CURSOR, |
|
draggable = true, |
|
labelAnchor = new google.maps.Point(0, 0), |
|
labelClass = LABEL_CLASS, |
|
labelContent, |
|
position, |
|
opacity = 1, |
|
map, |
|
labelZIndexOffset = 1, |
|
visible = true, |
|
zIndex = 0, |
|
}: LabelOptions) { |
|
super(); |
|
|
|
this.createElements(); |
|
|
|
this.anchor = labelAnchor; |
|
this.content = labelContent; |
|
this.className = labelClass; |
|
this.clickable = clickable; |
|
this.cursor = cursor; |
|
this.draggable = draggable; |
|
|
|
if (position instanceof google.maps.LatLng) { |
|
this.position = position; |
|
} else { |
|
this.position = new google.maps.LatLng(position); |
|
} |
|
|
|
this.opacity = opacity; |
|
this.visible = visible; |
|
this.zIndex = zIndex; |
|
this.zIndexOffset = labelZIndexOffset; |
|
|
|
if (map) { |
|
this.setMap(map); |
|
} |
|
} |
|
|
|
set content(content: string | HTMLElement) { |
|
if (typeof content === "string") { |
|
this.labelDiv.innerHTML = content; |
|
this.eventDiv.innerHTML = content; |
|
} else { |
|
this.labelDiv.innerHTML = ""; |
|
this.labelDiv.appendChild(content); |
|
this.eventDiv.innerHTML = ""; |
|
this.eventDiv.appendChild(content.cloneNode(true)); |
|
} |
|
} |
|
|
|
set className(className: string) { |
|
this.labelDiv.className = className; |
|
this.labelDiv.classList.add(LABEL_CLASS); |
|
this.eventDiv.className = className; |
|
this.eventDiv.classList.add(EVENT_CLASS); |
|
} |
|
|
|
set cursor(cursor: string) { |
|
this.hoverCursor = cursor; |
|
if (this.isInteractive) { |
|
this.eventDiv.style.cursor = cursor; |
|
} |
|
} |
|
|
|
get cursor() { |
|
return this.isInteractive ? this.hoverCursor : "inherit"; |
|
} |
|
|
|
get isInteractive() { |
|
return this.draggable || this.clickable; |
|
} |
|
|
|
set opacity(opacity: number) { |
|
this.labelDiv.style.opacity = String(opacity); |
|
} |
|
|
|
set title(title: string) { |
|
this.eventDiv.title = title; |
|
} |
|
|
|
set visible(visible: boolean) { |
|
if (visible) { |
|
this.labelDiv.style.display = BLOCK; |
|
this.eventDiv.style.display = BLOCK; |
|
} else { |
|
this.labelDiv.style.display = NONE; |
|
this.eventDiv.style.display = NONE; |
|
} |
|
} |
|
|
|
onAdd() { |
|
this.getPanes().markerLayer.appendChild(this.labelDiv); |
|
this.getPanes().overlayMouseTarget.appendChild(this.eventDiv); |
|
} |
|
|
|
draw() { |
|
const coordinates = this.getProjection().fromLatLngToDivPixel( |
|
this.position |
|
); |
|
const x = Math.round(coordinates.x + this.anchor.x); |
|
const y = Math.round(coordinates.y + this.anchor.y); |
|
this.labelDiv.style.left = `${x}px`; |
|
this.labelDiv.style.top = `${y}px`; |
|
this.eventDiv.style.left = this.labelDiv.style.left; |
|
this.eventDiv.style.top = this.labelDiv.style.top; |
|
|
|
// If zIndex is not defined, used vertical position on map. |
|
const zIndex = |
|
(this.zIndex || Math.ceil(coordinates.y)) + this.zIndexOffset; |
|
this.labelDiv.style.zIndex = String(zIndex); |
|
this.eventDiv.style.zIndex = String(zIndex); |
|
|
|
// If not interactive set display none on event div |
|
this.eventDiv.style.display = this.isInteractive |
|
? this.eventDiv.style.display |
|
: NONE; |
|
this.eventDiv.style.cursor = this.cursor; |
|
} |
|
|
|
addDomListener( |
|
event: string, |
|
handler: (event: Event) => void |
|
): google.maps.MapsEventListener { |
|
return google.maps.event.addDomListener(this.eventDiv, event, handler); |
|
} |
|
|
|
onRemove() { |
|
this.labelDiv.parentNode.removeChild(this.labelDiv); |
|
this.eventDiv.parentNode.removeChild(this.eventDiv); |
|
} |
|
|
|
private createElements(): void { |
|
this.labelDiv = document.createElement("div"); |
|
this.eventDiv = document.createElement("div"); |
|
|
|
// default class names |
|
this.labelDiv.classList.add(LABEL_CLASS); |
|
this.labelDiv.classList.add(EVENT_CLASS); |
|
|
|
// default styles for both divs |
|
this.labelDiv.style.position = ABSOLUTE; |
|
this.eventDiv.style.position = ABSOLUTE; |
|
|
|
// default styles for eventDiv |
|
this.eventDiv.style.opacity = EVENT_DIV_OPACITY; |
|
} |
|
}
|
|
|