UNPKG

@paperbits/core

Version:
137 lines (111 loc) 5.09 kB
import * as ko from "knockout"; import { Loader, LoaderOptions } from "@googlemaps/js-api-loader"; import { Events } from "@paperbits/common/events"; import { MapRuntimeConfig } from "./runtime/mapRuntimeConfig"; export class GooglmapsBindingHandler { constructor() { const attach = this.attach.bind(this); ko.bindingHandlers["googlemap"] = { update(element: HTMLElement, valueAccessor: () => MapRuntimeConfig): void { const configuration = valueAccessor(); try { attach(element, ko.toJS(configuration)); } catch (error) { console.warn(`Unable to load map.`); } } }; } private async attach(element: HTMLElement, configuration: MapRuntimeConfig): Promise<void> { if (!configuration.apiKey) { return; } const options: Partial<LoaderOptions> = {/* todo */ }; const loader = new Loader({ apiKey: configuration.apiKey, ...options }); loader.deleteScript(); await loader.load(); const markerWidth = 50; const markerHeight = 50; const mapOptions: google.maps.MapOptions = {}; const map = new google.maps.Map(element, mapOptions); if (!configuration.zoom) { configuration.zoom = 17; } else if (typeof configuration.zoom === "string") { configuration.zoom = parseInt(configuration.zoom); } map.setOptions({ streetViewControl: false, mapTypeControl: false, scaleControl: true, rotateControl: false, scrollwheel: false, disableDoubleClickZoom: true, draggable: false, disableDefaultUI: true, mapTypeId: configuration.mapType, zoom: configuration.zoom, styles: configuration.customizations }); class PopupAnchor extends google.maps.OverlayView { private readonly content: HTMLElement; constructor(private readonly position: google.maps.LatLng) { super(); this.content = document.createElement("div"); } /** Called when the popup is added to the map. */ public onAdd(): void { PopupAnchor.preventMapHitsAndGesturesFrom(this.content); this.content.setAttribute("data-toggle", "popup"); this.content.setAttribute("data-target", `#${configuration.markerPopupKey.replace("popups/", "popups")}`); this.content.setAttribute("data-position", "top"); this.getPanes().floatPane.appendChild(this.content); document.dispatchEvent(new CustomEvent(Events.PopupRequest, { detail: configuration.markerPopupKey })); } /** Called each frame when the popup needs to draw itself. */ public draw(): void { const elementPosition = this.getProjection().fromLatLngToDivPixel(this.position); this.content.style.left = elementPosition.x - Math.floor(markerWidth / 2) + "px"; this.content.style.top = elementPosition.y - Math.floor(markerHeight / 2) + "px"; this.content.style.width = markerWidth + "px"; this.content.style.height = markerHeight + "px"; document.dispatchEvent(new CustomEvent("onPopupRepositionRequested", { detail: { element: this.content, placement: "top" // offsetX: // offsetY: } })); } } const position = new google.maps.LatLng({ lat: configuration.location.lat, lng: configuration.location.lng }); const marker: google.maps.Marker = new google.maps.Marker(); marker.setMap(map); if (configuration.markerIcon) { const icon: google.maps.Icon = { url: configuration.markerIcon, scaledSize: new google.maps.Size(markerWidth, markerHeight) }; marker.setIcon(icon); } marker.setPosition(position); map.setCenter(position); if (configuration.markerPopupKey) { const anchor = new PopupAnchor(position); anchor.setMap(map); marker.addListener(Events.Click, () => document.dispatchEvent(new CustomEvent(Events.PopupRequest, { detail: configuration.markerPopupKey }))); } else { const infowindow = new google.maps.InfoWindow(); infowindow.setContent(configuration.caption); if (configuration.caption.length > 0) { infowindow.open(map, marker); } else { infowindow.close(); } } } }