/** * 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; 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; } }