UNPKG

lin3s-front-foundation

Version:

Library that provides a sort of commonly used front-end components in LIN3S projects

398 lines (329 loc) 10.7 kB
/* * This file is part of the Front Foundation package. * * Copyright (c) 2017-present LIN3S <info@lin3s.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. * * @author Mikel Tuesta <mikeltuesta@gmail.com> */ import {OneTimeEventPublisher, LifeTimeEventPublisher} from 'lin3s-event-bus'; import {isIE11} from './../../../../browser'; import GMapMarkerDetail from './../GMapMarkerDetail/GMapMarkerDetail'; import GMapInitializedEvent from './../../../../event-bus/GMap/GMapInitializedEvent'; import GMapMarkerSelectedEvent from './../../../../event-bus/GMap/GMapMarkerSelectedEvent'; import GMapGeocodeEvent from './../../../../event-bus/GMap/GMapGeocodeEvent'; class GMap { domNode; map; geocoder; bounds; mapMarkers = []; mapMarkerClusterer; center; centerOffsetX; centerOffsetY; boundsOffsetX; boundsOffsetY; zoom; markerIcons; markers = []; markerDefaultPath; markerSelectedPath; markerGroupPath; markerWidth; markerHeight; clusterEnabled; clusterTextOffset; clusterTextColor; clusterTextSize; mapStyle; markerDetail; selectedMarker; constructor(domNode, { center, zoom = {initial: 8, max: 12}, markerDefaultPath, markerSelectedPath, markerGroupPath, markerWidth, markerHeight, clusterEnabled, clusterTextOffset, clusterTextColor, clusterTextSize, mapStyle, } = {}) { this.domNode = domNode; this.center = center; this.zoom = zoom; this.markerDefaultPath = markerDefaultPath; this.markerSelectedPath = markerSelectedPath; this.markerGroupPath = markerGroupPath; this.markerWidth = markerWidth; this.markerHeight = markerHeight; this.clusterEnabled = clusterEnabled; this.clusterTextOffset = clusterTextOffset; this.clusterTextColor = clusterTextColor; this.clusterTextSize = clusterTextSize; this.mapStyle = mapStyle; const markerDetailView = this.domNode.querySelector('.gmap-marker-detail'); if (markerDetailView !== null) { this.markerDetail = new GMapMarkerDetail(markerDetailView); } this.markerIcons = this.buildMarkerIcons(); this.initMap(); this.initGeocoder(); this.bindListeners(); const initPromise = new Promise(resolve => { google.maps.event.addListenerOnce(this.map, 'projection_changed', () => { resolve(); }); }); initPromise.then(() => this.publishMapInstanceInitializedEvent()); } buildMarkerIcons() { const extension = isIE11() ? 'png' : 'svg', iconSize = new google.maps.Size(this.markerWidth, this.markerHeight), anchor = new google.maps.Point(this.markerWidth / 2, this.markerHeight), origin = new google.maps.Point(0, 0); return { default: { url: `${this.markerDefaultPath}.${extension}`, anchor, scaledSize: iconSize, optimized: false, origin, }, selected: { url: `${this.markerSelectedPath}.${extension}`, anchor, scaledSize: iconSize, optimized: false, origin, }, group: { url: `${this.markerGroupPath}.${extension}`, anchor, scaledSize: iconSize, optimized: false, origin, }, }; } initMap() { const mapContainer = this.domNode.querySelector('.gmap__map'); this.map = new google.maps.Map(mapContainer, { center: this.center, minZoom: 3, maxZoom: this.zoom.max, zoom: this.zoom.initial, mapTypeId: google.maps.MapTypeId.ROADMAP, styles: this.mapStyle, scrollwheel: false, draggable: true, }); if (!this.clusterEnabled) { return; } this.mapMarkerClusterer = new MarkerClusterer(this.map, [], { // eslint-disable-line no-undef gridSize: 50, maxZoom: 14, styles: [{ width: this.markerWidth, height: this.markerHeight, url: this.markerIcons.group.url, textColor: this.clusterTextColor, textSize: this.clusterTextSize, anchor: this.clusterTextOffset, }], }); } initGeocoder() { this.geocoder = new google.maps.Geocoder(); } bindListeners() { this.map.addListener('click', () => this.onMarkerSelected()); this.map.addListener('dragstart', () => this.onMarkerSelected()); this.map.addListener('zoom_changed', () => this.onMarkerSelected()); } setCenterOffsets({x = 0, y = 0} = {}) { this.centerOffsetX = x; this.centerOffsetY = y; this.centerMap(this.getOffsetedLatLng(this.map.getCenter())); } setBoundsOffsets({x = 0, y = 0} = {}) { this.boundsOffsetX = x; this.boundsOffsetY = y; } setMarkers(markers) { this.clearMarkers(); this.pushMarkers(markers); } clearMarkers() { this.hideMarkerDetailView(); this.bounds = undefined; if (this.clusterEnabled) { this.mapMarkerClusterer.clearMarkers(); } this.mapMarkers.forEach(marker => { google.maps.event.clearListeners(marker, 'click'); marker.setMap(null); }); this.markers = []; this.mapMarkers = []; } pushMarkers(markers) { this.markers = markers; this.bounds = new google.maps.LatLngBounds(); this.markers.forEach(marker => { if (marker.lat === undefined || marker.lng === undefined) { return; } const mapMarker = new google.maps.Marker({ id: marker.id, position: { lat: parseFloat(marker.lat), lng: parseFloat(marker.lng), }, map: this.map, icon: this.markerIcons.default, }); mapMarker.index = this.markers.length; this.bounds.extend(mapMarker.position); this.mapMarkers.push(mapMarker); if (this.clusterEnabled) { this.mapMarkerClusterer.addMarker(mapMarker); } mapMarker.addListener('click', () => this.onMarkerSelected(marker)); }); this.centerMapOnBounds(this.getOffsetedBounds(this.bounds)); } showMarkerDetailView(markerId, markerDetailHtmlContent) { this.hideMarkerDetailView(); this.selectedMarker = this.mapMarkers.find(marker => marker.id === markerId); if (this.selectedMarker === undefined || this.markerDetail === undefined) { return; } const offsetedMarkerLatLng = this.getOffsetedLatLng(this.selectedMarker.getPosition()); this.centerMap(offsetedMarkerLatLng); this.selectedMarker.setIcon(this.markerIcons.selected); this.markerDetail.hide(); this.markerDetail.updateContent(markerDetailHtmlContent); const markerDetailRect = this.markerDetail.getRect(), markerPixelPosition = this.getPixelPositionFromLatLng(this.selectedMarker.getPosition()); this.markerDetail.setPosition({ x: markerPixelPosition.x - markerDetailRect.width / 2, y: markerPixelPosition.y - markerDetailRect.height - this.markerHeight - 20, }); this.markerDetail.show(); } hideMarkerDetailView() { if (this.selectedMarker === undefined || this.markerDetail === undefined) { return; } const markerToHide = this.mapMarkers.find(marker => marker.id === this.selectedMarker.id); if (markerToHide === undefined) { return; } markerToHide.setIcon(this.markerIcons.default); this.markerDetail.hide(); } centerMap(latLng) { this.map.panTo(latLng); } centerMapOnBounds(bounds) { this.map.fitBounds(bounds); this.map.panToBounds(bounds); } getOffsetedLatLng({lat, lng}, {offsetX = this.centerOffsetX, offsetY = this.centerOffsetY} = {}) { const scale = Math.pow(2, this.map.getZoom()), pixelOffset = new google.maps.Point(offsetX / scale || 0, offsetY / scale || 0); const worldCoordinateCenter = this.map.getProjection().fromLatLngToPoint({lat, lng}), worldCoordinateNewCenter = new google.maps.Point( worldCoordinateCenter.x + pixelOffset.x, worldCoordinateCenter.y + pixelOffset.y, ); return this.map.getProjection().fromPointToLatLng(worldCoordinateNewCenter); } getOffsetedBounds(bounds) { const southWest = bounds.getSouthWest(), northEast = bounds.getNorthEast(); return new google.maps.LatLngBounds( this.getOffsetedLatLng( {lat: southWest.lat, lng: southWest.lng}, {offsetX: this.boundsOffsetX, offsetY: this.boundsOffsetY}, ), this.getOffsetedLatLng( {lat: northEast.lat, lng: northEast.lng}, {offsetX: this.boundsOffsetX, offsetY: this.boundsOffsetY,}, ), ); } getPixelPositionFromLatLng({lat, lng}) { const scale = Math.pow(2, this.map.getZoom()), nw = new google.maps.LatLng( this.map.getBounds().getNorthEast().lat(), this.map.getBounds().getSouthWest().lng(), ), worldCoordinateNW = this.map.getProjection().fromLatLngToPoint(nw), worldCoordinate = this.map.getProjection().fromLatLngToPoint({lat, lng}); return new google.maps.Point( Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale), Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale), ); } geocodeAddress(address) { if (address === undefined || address === '') { this.resetMapZoomAndCenterToDefault(); } else { const fullAddress = `${address}, Spain`; this.geocoder.geocode( { address: fullAddress, }, (results, status) => { if (status === google.maps.GeocoderStatus.OK) { const geocodeResult = results[0]; this.centerMap(geocodeResult.geometry.location); this.map.setZoom(14); } else { this.resetMapZoomAndCenterToDefault(); } this.publishGeocodeEvent({status, results}); }, ); } } resetMapZoomAndCenterToDefault() { if (this.bounds !== undefined) { this.centerMapOnBounds(this.getOffsetedBounds(this.bounds)); } else { this.map.setZoom(this.zoom.initial); this.centerMap(this.getOffsetedLatLng(new google.maps.LatLng( this.center.lat, this.center.lng, ))); } } onMarkerSelected(marker) { this.publishMarkerSelectedEvent(marker); } publishMapInstanceInitializedEvent() { OneTimeEventPublisher.publish(new GMapInitializedEvent(this)); } publishMarkerSelectedEvent(marker) { LifeTimeEventPublisher.publish(new GMapMarkerSelectedEvent(this, marker)); } publishGeocodeEvent({status, results}) { LifeTimeEventPublisher.publish(new GMapGeocodeEvent(this, status, results)); } } export default GMap;