@randstad-design/orbit-multitheme
Version:
multitheme Front-end code based on Randstad Human Forward components
287 lines (256 loc) • 7.98 kB
JavaScript
/**
* maps.js
* load google maps with markers and related popups
*/
import { GoogleMapsApi } from './maps/google-maps-api';
import { MapStyle } from './maps/map-style';
import { PopupWrapper } from './maps/popup-wrapper';
import MarkerClusterer from '@googlemaps/markerclustererplus';
/**
* Declare constants
*/
const attributeBase = 'data-rs-maps';
let Popup = null;
export class Maps {
constructor(element) {
this.map = null;
this.element = element;
this.locations = [];
this.marker = null;
this.popup = null;
// get elements
this.googleMapsKey =
this.element.hasAttribute(this.attributes.googleMapsKey) &&
this.element.getAttribute(this.attributes.googleMapsKey);
this.markerUrlPath = this.element.hasAttribute(this.attributes.markerUrl)
? this.element.getAttribute(this.attributes.markerUrl)
: this.variables.defaultMarkerUrl;
this.clusterMarkerUrlPath = this.element.hasAttribute(
this.attributes.clusterMarkerUrl
)
? this.element.getAttribute(this.attributes.clusterMarkerUrl)
: this.variables.defaultClusterMarkerUrl;
this.markerIsNotClickable =
this.element.hasAttribute(this.attributes.markerIsNotClickable) || false;
this.mapPlaceholderElement = this.element.querySelector(
this.attributes.mapsPlaceholderElement
);
this.mapElement = this.mapPlaceholderElement.appendChild(
document.createElement('div')
);
this.clusterEnabled = this.element.getAttribute(this.attributes.cluster);
this.initializeMap();
}
/**
* Declare attribute constants
*/
get attributes() {
return {
clusterMarkerUrl: `${attributeBase}-cluster-marker-url`,
markerUrl: `${attributeBase}-marker-url`,
markerIsNotClickable: `${attributeBase}-marker-is-not-clickable`,
mapsPlaceholderElement: `[${attributeBase}-placeholder]`,
googleMapsKey: `${attributeBase}-google-maps-key`,
cluster: `${attributeBase}-cluster`
};
}
/**
* Declare variable constants
*/
get variables() {
return {
defaultMarkerUrl: '../assets/image/marker.svg',
defaultClusterMarkerUrl: '../assets/image/m'
};
}
/**
* Load google maps API
*/
initializeMap() {
// create map, controls and markers after the API is ready
const gmapApi = new GoogleMapsApi(this.googleMapsKey);
gmapApi
.load()
.then(() => {
this.createMap();
this.customZoomControl(this.mapPlaceholderElement);
this.handleMarkers();
this.addMarker(this.locations);
if (this.clusterEnabled) {
this.setClusterMarkers();
}
})
.catch((reason) => {
console.error(reason);
});
}
createMap() {
//retrieve center location
let zoom = parseInt(this.element.getAttribute('data-rs-maps-zoom'));
if (isNaN(zoom)) {
zoom = 6;
}
// get center of map
const [centerLat, centerLng] = this.element
.getAttribute('data-rs-maps')
.split(',');
// create map
this.map = new google.maps.Map(this.mapPlaceholderElement, {
center: new google.maps.LatLng(centerLat, centerLng),
zoom: zoom,
minZoom: 4,
maxZoom: 17,
disableDefaultUI: true,
panControl: true,
zoomControl: false,
scaleControl: true,
streetViewControl: false,
styles: MapStyle.custom,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
}
/**
* Create Popup class if not already exists
* always AFTER the map is created
*/
createPopup() {
if (Popup === null) {
Popup = PopupWrapper.popupClass;
}
}
/**
* Retrieve markers from html elements with attribute 'data-rs-map-marker'
* and add them to the map
*/
handleMarkers() {
// create the popup class
this.createPopup();
this.locations = [].slice
.call(this.element.querySelectorAll('[data-rs-map-marker]'))
.map((markerElement) => {
//build marker item
let [lat, lng] = markerElement
.getAttribute('data-rs-map-marker')
.split(',');
const item = {};
item.lat = lat.trim();
item.lng = lng.trim();
item.content = document.createElement('div');
item.content.innerHTML = markerElement.innerHTML;
return item;
});
// handle click on map related to popups
google.maps.event.addListener(this.map, 'click', () => {
if (this.marker !== null && typeof this.marker !== 'undefined') {
this.marker.open = false;
this.marker.customPopup.hide();
}
});
}
/**
* Add marker to the map
* @param {any} item Object containing base settings
*/
addMarker(locations) {
// create icon for marker
let icon = {
url: this.markerUrlPath,
size: new google.maps.Size(34, 48)
};
this.markers = locations.map((item) => {
let popup = new Popup(
new google.maps.LatLng(item.lat, item.lng),
item.content
);
const marker = new google.maps.Marker({
position: new google.maps.LatLng(item.lat, item.lng),
icon: icon,
map: this.map,
customPopup: popup
});
popup.marker = marker;
if (!this.markerIsNotClickable) {
google.maps.event.addListener(marker, 'click', () => {
// determine to show or hide the popup
let openMarker = false;
if (marker.open !== true) {
openMarker = true;
}
if (this.marker !== null && marker !== this.marker) {
this.marker.open = false;
this.marker.customPopup.hide();
}
// set active marker
this.marker = marker;
// handle display popup
if (openMarker) {
this.marker.customPopup.setMap(this.marker.map);
this.marker.open = true;
} else {
this.marker.customPopup.hide();
this.marker.open = false;
}
});
}
return marker;
});
}
setClusterMarkers() {
const clusterOptions = {
imagePath: this.clusterMarkerUrlPath,
imageExtension: 'svg',
maxZoom: 15
};
const markerClusterer = new MarkerClusterer(
this.map,
this.markers,
clusterOptions
);
// Change styles after cluster is created
const styles = markerClusterer.getStyles();
for (let i = 0; i < styles.length; i++) {
styles[i].textColor = 'white';
styles[i].textSize = 16;
styles[i].width = 58;
styles[i].height = 66;
styles[i].textLineHeight = 66;
}
}
/**
* Create a custom zoom control
* @param {any} controlContainer
*/
customZoomControl(controlContainer) {
// hide control container
let controlWrapper = controlContainer.appendChild(
document.createElement('div')
);
controlWrapper.classList.add('gmaps__control-container');
controlWrapper.classList.add('gmaps__control-container--loading');
// create element zoom in/out button
let zoomInButton = document.createElement('div');
let zoomOutButton = document.createElement('div');
// create classes for buttons
zoomInButton.classList.add('gmaps__button--zoom');
zoomInButton.classList.add('gmaps__button--zoom-in');
zoomOutButton.classList.add('gmaps__button--zoom');
zoomOutButton.classList.add('gmaps__button--zoom-out');
// append controls
controlWrapper.appendChild(zoomInButton);
controlWrapper.appendChild(zoomOutButton);
// Setup the click event listener - zoomIn
google.maps.event.addDomListener(zoomInButton, 'click', () => {
this.map.setZoom(this.map.getZoom() + 1);
});
// Setup the click event listener - zoomOut
google.maps.event.addDomListener(zoomOutButton, 'click', () => {
this.map.setZoom(this.map.getZoom() - 1);
});
}
/**
* Get selector
*/
static getSelector() {
return `[${attributeBase}]`;
}
}