mirror of
https://github.com/a2nt/webpack-bootstrap-ui-kit.git
synced 2024-10-22 11:05:45 +02:00
Rewrite Maps API to vanilla js
This commit is contained in:
parent
121dd24d5e
commit
a422116f17
@ -2,80 +2,82 @@ import Events from '../_events';
|
|||||||
import Carousel from 'bootstrap/js/src/carousel';
|
import Carousel from 'bootstrap/js/src/carousel';
|
||||||
|
|
||||||
const CarouselUI = ((window) => {
|
const CarouselUI = ((window) => {
|
||||||
const NAME = 'js-carousel';
|
const NAME = 'js-carousel';
|
||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
console.log(`${NAME}: init`);
|
console.log(`${NAME}: init`);
|
||||||
document.querySelectorAll(`.${NAME}`).forEach((el, i) => {
|
|
||||||
const carousel = new Carousel(el);
|
document.querySelectorAll(`.${NAME}`).forEach((el, i) => {
|
||||||
// create next/prev arrows
|
const carousel = new Carousel(el);
|
||||||
if (el.dataset.bsArrows) {
|
// create next/prev arrows
|
||||||
const next = document.createElement('button');
|
if (el.dataset.bsArrows) {
|
||||||
next.classList.add('carousel-control-next');
|
const next = document.createElement('button');
|
||||||
next.setAttribute('type', 'button');
|
next.classList.add('carousel-control-next');
|
||||||
next.setAttribute('data-bs-target', el.getAttribute('id'));
|
next.setAttribute('type', 'button');
|
||||||
next.setAttribute('data-bs-slide', 'next');
|
next.setAttribute('data-bs-target', el.getAttribute('id'));
|
||||||
next.addEventListener('click', (e) => {
|
next.setAttribute('data-bs-slide', 'next');
|
||||||
carousel.next();
|
next.addEventListener('click', (e) => {
|
||||||
|
carousel.next();
|
||||||
|
});
|
||||||
|
next.innerHTML = '<span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Next</span>';
|
||||||
|
el.appendChild(next);
|
||||||
|
|
||||||
|
const prev = document.createElement('button');
|
||||||
|
prev.setAttribute('type', 'button');
|
||||||
|
prev.classList.add('carousel-control-prev');
|
||||||
|
prev.setAttribute('data-bs-target', el.getAttribute('id'));
|
||||||
|
prev.setAttribute('data-bs-slide', 'prev');
|
||||||
|
prev.addEventListener('click', (e) => {
|
||||||
|
carousel.prev();
|
||||||
|
});
|
||||||
|
prev.innerHTML = '<span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span>';
|
||||||
|
el.appendChild(prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el.dataset.bsIndicators) {
|
||||||
|
const indicators = document.createElement('div');
|
||||||
|
indicators.classList.add('carousel-indicators');
|
||||||
|
const items = el.querySelectorAll('.carousel-item');
|
||||||
|
let i = 0;
|
||||||
|
while (i < items.length) {
|
||||||
|
const ind = document.createElement('button');
|
||||||
|
ind.setAttribute('type', 'button');
|
||||||
|
if (i == 0) {
|
||||||
|
ind.classList.add('active');
|
||||||
|
}
|
||||||
|
ind.setAttribute('data-bs-target', el.getAttribute('id'));
|
||||||
|
ind.setAttribute('data-bs-slide-to', i);
|
||||||
|
|
||||||
|
ind.addEventListener('click', (e) => {
|
||||||
|
const target = e.target;
|
||||||
|
carousel.to(target.getAttribute('data-bs-slide-to'));
|
||||||
|
indicators.querySelectorAll('.active').forEach((ind2) => {
|
||||||
|
ind2.classList.remove('active');
|
||||||
|
});
|
||||||
|
target.classList.add('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
indicators.appendChild(ind);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
el.appendChild(indicators);
|
||||||
|
el.addEventListener('slide.bs.carousel', (e) => {
|
||||||
|
el.querySelectorAll('.carousel-indicators .active').forEach((ind2) => {
|
||||||
|
ind2.classList.remove('active');
|
||||||
|
});
|
||||||
|
el.querySelectorAll(`.carousel-indicators [data-bs-slide-to="${ e.to }"]`).forEach((ind2) => {
|
||||||
|
ind2.classList.add('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
el.classList.add(`${NAME}-active`);
|
||||||
});
|
});
|
||||||
next.innerHTML = '<span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Next</span>';
|
};
|
||||||
el.appendChild(next);
|
|
||||||
|
|
||||||
const prev = document.createElement('button');
|
window.addEventListener(`${Events.LODEDANDREADY}`, init);
|
||||||
prev.setAttribute('type', 'button');
|
window.addEventListener(`${Events.AJAX}`, init);
|
||||||
prev.classList.add('carousel-control-prev');
|
|
||||||
prev.setAttribute('data-bs-target', el.getAttribute('id'));
|
|
||||||
prev.setAttribute('data-bs-slide', 'prev');
|
|
||||||
prev.addEventListener('click', (e) => {
|
|
||||||
carousel.prev();
|
|
||||||
});
|
|
||||||
prev.innerHTML = '<span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span>';
|
|
||||||
el.appendChild(prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (el.dataset.bsIndicators) {
|
|
||||||
const indicators = document.createElement('div');
|
|
||||||
indicators.classList.add('carousel-indicators');
|
|
||||||
const items = el.querySelectorAll('.carousel-item');
|
|
||||||
let i = 0;
|
|
||||||
while (i < items.length) {
|
|
||||||
const ind = document.createElement('button');
|
|
||||||
ind.setAttribute('type', 'button');
|
|
||||||
if (i == 0) {
|
|
||||||
ind.classList.add('active');
|
|
||||||
}
|
|
||||||
ind.setAttribute('data-bs-target', el.getAttribute('id'));
|
|
||||||
ind.setAttribute('data-bs-slide-to', i);
|
|
||||||
|
|
||||||
ind.addEventListener('click', (e) => {
|
|
||||||
const target = e.target;
|
|
||||||
carousel.to(target.getAttribute('data-bs-slide-to'));
|
|
||||||
indicators.querySelectorAll('.active').forEach((ind2) => {
|
|
||||||
ind2.classList.remove('active');
|
|
||||||
});
|
|
||||||
target.classList.add('active');
|
|
||||||
});
|
|
||||||
|
|
||||||
indicators.appendChild(ind);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
el.appendChild(indicators);
|
|
||||||
el.addEventListener('slide.bs.carousel', (e) => {
|
|
||||||
el.querySelectorAll('.carousel-indicators .active').forEach((ind2) => {
|
|
||||||
ind2.classList.remove('active');
|
|
||||||
});
|
|
||||||
el.querySelectorAll(`.carousel-indicators [data-bs-slide-to="${ e.to }"]`).forEach((ind2) => {
|
|
||||||
ind2.classList.add('active');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
el.classList.add(`${NAME}-active`);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener(`${Events.LODEDANDREADY}`, init);
|
|
||||||
window.addEventListener(`${Events.AJAX}`, init);
|
|
||||||
})(window);
|
})(window);
|
||||||
|
|
||||||
export default CarouselUI;
|
export default CarouselUI;
|
||||||
|
123
src/js/_ui/map.api.js
Normal file
123
src/js/_ui/map.api.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import Events from '../_events';
|
||||||
|
|
||||||
|
import '../../scss/_ui/map.api.scss';
|
||||||
|
|
||||||
|
import CONSTS from 'js/_consts';
|
||||||
|
|
||||||
|
const MapAPI = ((window) => {
|
||||||
|
// Constants
|
||||||
|
const NAME = 'js-mapapi';
|
||||||
|
const MAP_DRIVER = CONSTS['MAP_DRIVER'];
|
||||||
|
|
||||||
|
class MapAPI {
|
||||||
|
// Constructor
|
||||||
|
constructor(el) {
|
||||||
|
const ui = this;
|
||||||
|
const Drv = new MAP_DRIVER();
|
||||||
|
const BODY = document.querySelector('body');
|
||||||
|
const config = el.dataset;
|
||||||
|
config['center'] = [
|
||||||
|
config['lng'] ? config['lng'] : BODY.dataset['default-lng'],
|
||||||
|
config['lat'] ? config['lat'] : BODY.dataset['default-lat'],
|
||||||
|
];
|
||||||
|
|
||||||
|
/*config['style'] = config['style'] ?
|
||||||
|
jQuery.parseJSON(config['style']) :
|
||||||
|
null;
|
||||||
|
|
||||||
|
config['font-family'] = $BODY.css('font-family');*/
|
||||||
|
|
||||||
|
if (!config['icon']) {
|
||||||
|
config['icon'] = '<i class="fas fa-map-marker-alt"></i>';
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`${NAME}: init ${Drv.getName()}...`);
|
||||||
|
ui.drv = Drv;
|
||||||
|
ui.el = el;
|
||||||
|
ui.config = config;
|
||||||
|
|
||||||
|
Drv.init(el, config);
|
||||||
|
|
||||||
|
el.addEventListener(Events.MAPAPILOADED, () => {
|
||||||
|
ui.addMarkers()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public methods
|
||||||
|
getMap() {
|
||||||
|
return ui.map;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispose() {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
ui.el = null;
|
||||||
|
ui.el.classList.remove(`${NAME}-active`);
|
||||||
|
}
|
||||||
|
|
||||||
|
addMarkers() {
|
||||||
|
console.log(`${NAME}: addMarkers`);
|
||||||
|
const ui = this;
|
||||||
|
const el = ui.el;
|
||||||
|
const Drv = ui.drv;
|
||||||
|
const config = ui.config;
|
||||||
|
|
||||||
|
ui.map = Drv.getMap();
|
||||||
|
|
||||||
|
if (config['geojson']) {
|
||||||
|
console.log(`${NAME}: setting up geocode data`);
|
||||||
|
Drv.addGeoJson(config);
|
||||||
|
} else if (config['address']) {
|
||||||
|
console.log(config['address']);
|
||||||
|
console.log(`${NAME}: setting up address marker`);
|
||||||
|
Drv.geocode(config['address'], (results) => {
|
||||||
|
console.log(results);
|
||||||
|
|
||||||
|
const lat = results[0].geometry.location.lat();
|
||||||
|
const lng = results[0].geometry.location.lng();
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${NAME}: setting up single lat/lng marker lat: ${lat} lng: ${lng}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
Drv.addMarker([lng, lat], config);
|
||||||
|
ui.map.setCenter({
|
||||||
|
lat,
|
||||||
|
lng
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else if (config['lat'] && config['lng']) {
|
||||||
|
const lat = config['lat'];
|
||||||
|
const lng = config['lng'];
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${NAME}: setting up single lat/lng marker lat: ${lat} lng: ${lng}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
Drv.addMarker([lng, lat], config);
|
||||||
|
}
|
||||||
|
|
||||||
|
el.classList.add(`${NAME}-active`);
|
||||||
|
|
||||||
|
el.dispatchEvent(new Event(Events.MAPLOADED));
|
||||||
|
console.log(`${NAME}: Map is loaded`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
console.log(`${NAME}: init`);
|
||||||
|
document.querySelectorAll(`.${NAME}`).forEach((el, i) => {
|
||||||
|
const map = new MapAPI(el);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// auto-apply
|
||||||
|
window.addEventListener(`${Events.LODEDANDREADY}`, init);
|
||||||
|
window.addEventListener(`${Events.AJAX}`, init);
|
||||||
|
|
||||||
|
return MapAPI;
|
||||||
|
})(window);
|
||||||
|
|
||||||
|
export default MapAPI;
|
61
src/js/drivers/_google.track.external.links.js
Normal file
61
src/js/drivers/_google.track.external.links.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
function _gaLt(event) {
|
||||||
|
if (typeof ga !== 'function') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var el = event.srcElement || event.target;
|
||||||
|
|
||||||
|
/* Loop up the DOM tree through parent elements if clicked element is not a link (eg: an image inside a link) */
|
||||||
|
while (
|
||||||
|
el &&
|
||||||
|
(typeof el.tagName == 'undefined' ||
|
||||||
|
el.tagName.toLowerCase() != 'a' ||
|
||||||
|
!el.href)
|
||||||
|
) {
|
||||||
|
el = el.parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el && el.href) {
|
||||||
|
/* link */
|
||||||
|
var link = el.href;
|
||||||
|
if (link.indexOf(location.host) == -1 && !link.match(/^javascript:/i)) {
|
||||||
|
/* external link */
|
||||||
|
/* HitCallback function to either open link in either same or new window */
|
||||||
|
var hitBack = function(link, target) {
|
||||||
|
target ? window.open(link, target) : (window.location.href = link);
|
||||||
|
};
|
||||||
|
/* Is target set and not _(self|parent|top)? */
|
||||||
|
var target =
|
||||||
|
el.target && !el.target.match(/^_(self|parent|top)$/i)
|
||||||
|
? el.target
|
||||||
|
: false;
|
||||||
|
/* send event with callback */
|
||||||
|
ga(
|
||||||
|
'send',
|
||||||
|
'event',
|
||||||
|
'Outgoing Links',
|
||||||
|
link,
|
||||||
|
document.location.pathname + document.location.search,
|
||||||
|
{ hitCallback: hitBack(link, target) },
|
||||||
|
);
|
||||||
|
|
||||||
|
/* Prevent standard click */
|
||||||
|
event.preventDefault ? event.preventDefault() : (event.returnValue = !1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attach the event to all clicks in the document after page has loaded */
|
||||||
|
var w = window;
|
||||||
|
w.addEventListener
|
||||||
|
? w.addEventListener(
|
||||||
|
'load',
|
||||||
|
() => {
|
||||||
|
document.body.addEventListener('click', _gaLt, !1);
|
||||||
|
},
|
||||||
|
!1,
|
||||||
|
)
|
||||||
|
: w.attachEvent &&
|
||||||
|
w.attachEvent('onload', () => {
|
||||||
|
document.body.attachEvent('onclick', _gaLt);
|
||||||
|
});
|
199
src/js/drivers/_map.google.font-icons.js
Normal file
199
src/js/drivers/_map.google.font-icons.js
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Obj = {
|
||||||
|
init: () => {
|
||||||
|
class GoogleMapsHtmlOverlay extends google.maps.OverlayView {
|
||||||
|
constructor(options) {
|
||||||
|
super();
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
ui.setMap(options.map);
|
||||||
|
ui.position = options.position;
|
||||||
|
ui.html =
|
||||||
|
(options.html ?
|
||||||
|
options.html :
|
||||||
|
'<div class="mapboxgl-marker"><i class="marker-icon fas fa-map-marker-alt"></i></div>'
|
||||||
|
);
|
||||||
|
ui.divClass = options.divClass;
|
||||||
|
ui.align = options.align;
|
||||||
|
ui.isDebugMode = options.debug;
|
||||||
|
ui.onClick = options.onClick;
|
||||||
|
ui.onMouseOver = options.onMouseOver;
|
||||||
|
|
||||||
|
ui.isBoolean = (arg) => {
|
||||||
|
if (typeof arg === 'boolean') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.isNotUndefined = (arg) => {
|
||||||
|
if (typeof arg !== 'undefined') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.hasContent = (arg) => {
|
||||||
|
if (arg.length > 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.isString = (arg) => {
|
||||||
|
if (typeof arg === 'string') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.isFunction = (arg) => {
|
||||||
|
if (typeof arg === 'function') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
onAdd() {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
// Create div element.
|
||||||
|
ui.div = document.createElement('div');
|
||||||
|
ui.div.style.position = 'absolute';
|
||||||
|
|
||||||
|
// Validate and set custom div class
|
||||||
|
if (ui.isNotUndefined(ui.divClass) && ui.hasContent(ui.divClass))
|
||||||
|
ui.div.className = ui.divClass;
|
||||||
|
|
||||||
|
// Validate and set custom HTML
|
||||||
|
if (
|
||||||
|
ui.isNotUndefined(ui.html) &&
|
||||||
|
ui.hasContent(ui.html) &&
|
||||||
|
ui.isString(ui.html)
|
||||||
|
)
|
||||||
|
ui.div.innerHTML = ui.html;
|
||||||
|
|
||||||
|
// If debug mode is enabled custom content will be replaced with debug content
|
||||||
|
if (ui.isBoolean(ui.isDebugMode) && ui.isDebugMode) {
|
||||||
|
ui.div.className = 'debug-mode';
|
||||||
|
ui.div.innerHTML =
|
||||||
|
'<div style="height: 10px; width: 10px; background: red; border-radius: 100%;"></div>' +
|
||||||
|
'<div style="position: absolute; top: 5px; padding: 5px; width: 130px; text-align: center; font-size: 18px; text-transform: uppercase; font-weight: bolder; background: red; color: white; font-family: Arial;">Debug mode</div>';
|
||||||
|
ui.div.setAttribute(
|
||||||
|
'style',
|
||||||
|
'position: absolute;' +
|
||||||
|
'border: 5px dashed red;' +
|
||||||
|
'height: 150px;' +
|
||||||
|
'width: 150px;' +
|
||||||
|
'display: flex;' +
|
||||||
|
'justify-content: center;' +
|
||||||
|
'align-items: center;'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add element to clickable layer
|
||||||
|
ui.getPanes().overlayMouseTarget.appendChild(ui.div);
|
||||||
|
|
||||||
|
// Add listeners to the element.
|
||||||
|
google.maps.event.addDomListener(ui.div, 'click', (event) => {
|
||||||
|
google.maps.event.trigger(ui, 'click');
|
||||||
|
if (ui.isFunction(ui.onClick)) ui.onClick();
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
google.maps.event.addDomListener(ui.div, 'mouseover', (event) => {
|
||||||
|
google.maps.event.trigger(ui, 'mouseover');
|
||||||
|
if (ui.isFunction(ui.onMouseOver)) ui.onMouseOver();
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
// Calculate position of div
|
||||||
|
var positionInPixels = ui.getProjection().fromLatLngToDivPixel(
|
||||||
|
new google.maps.LatLng(ui.position)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Align HTML overlay relative to original position
|
||||||
|
var divOffset = {
|
||||||
|
y: undefined,
|
||||||
|
x: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (Array.isArray(ui.align) ? ui.align.join(' ') : '') {
|
||||||
|
case 'left top':
|
||||||
|
divOffset.y = ui.div.offsetHeight;
|
||||||
|
divOffset.x = ui.div.offsetWidth;
|
||||||
|
break;
|
||||||
|
case 'left center':
|
||||||
|
divOffset.y = ui.div.offsetHeight / 2;
|
||||||
|
divOffset.x = ui.div.offsetWidth;
|
||||||
|
break;
|
||||||
|
case 'left bottom':
|
||||||
|
divOffset.y = 0;
|
||||||
|
divOffset.x = ui.div.offsetWidth;
|
||||||
|
break;
|
||||||
|
case 'center top':
|
||||||
|
divOffset.y = ui.div.offsetHeight;
|
||||||
|
divOffset.x = ui.div.offsetWidth / 2;
|
||||||
|
break;
|
||||||
|
case 'center center':
|
||||||
|
divOffset.y = ui.div.offsetHeight / 2;
|
||||||
|
divOffset.x = ui.div.offsetWidth / 2;
|
||||||
|
break;
|
||||||
|
case 'center bottom':
|
||||||
|
divOffset.y = 0;
|
||||||
|
divOffset.x = ui.div.offsetWidth / 2;
|
||||||
|
break;
|
||||||
|
case 'right top':
|
||||||
|
divOffset.y = ui.div.offsetHeight;
|
||||||
|
divOffset.x = 0;
|
||||||
|
break;
|
||||||
|
case 'right center':
|
||||||
|
divOffset.y = ui.div.offsetHeight / 2;
|
||||||
|
divOffset.x = 0;
|
||||||
|
break;
|
||||||
|
case 'right bottom':
|
||||||
|
divOffset.y = 0;
|
||||||
|
divOffset.x = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
divOffset.y = ui.div.offsetHeight / 2;
|
||||||
|
divOffset.x = ui.div.offsetWidth / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set position
|
||||||
|
ui.div.style.top = `${positionInPixels.y - divOffset.y }px`;
|
||||||
|
ui.div.style.left = `${positionInPixels.x - divOffset.x }px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPosition() {
|
||||||
|
const ui = this;
|
||||||
|
return ui.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
getDiv() {
|
||||||
|
const ui = this;
|
||||||
|
return ui.div;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPosition(position, align) {
|
||||||
|
const ui = this;
|
||||||
|
ui.position = position;
|
||||||
|
ui.align = align;
|
||||||
|
ui.draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GoogleMapsHtmlOverlay;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Obj;
|
283
src/js/drivers/_map.google.js
Normal file
283
src/js/drivers/_map.google.js
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import MarkerClusterer from '@googlemaps/markerclustererplus';
|
||||||
|
|
||||||
|
import Events from '../_events';
|
||||||
|
import MarkerUI from './_map.google.marker';
|
||||||
|
|
||||||
|
const GoogleMapsDriver = ((window) => {
|
||||||
|
class GoogleMapsDriver {
|
||||||
|
getName() {
|
||||||
|
return 'GoogleMapsDriver';
|
||||||
|
}
|
||||||
|
|
||||||
|
init(el, config = []) {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
ui.el = el;
|
||||||
|
ui.config = config;
|
||||||
|
ui.markers = [];
|
||||||
|
|
||||||
|
window[`init${ui.getName()}`] = () => {
|
||||||
|
ui.googleApiLoaded();
|
||||||
|
};
|
||||||
|
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = `https://maps.googleapis.com/maps/api/js?key=${config['key']}&callback=init${ui.getName()}`;
|
||||||
|
script.async = true;
|
||||||
|
script.defer = true;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
googleApiLoaded() {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
const el = ui.el;
|
||||||
|
const config = ui.config;
|
||||||
|
const mapDiv = el.querySelector('.mapAPI-map');
|
||||||
|
const zoom = config['mapZoom'] && config['mapZoom'] !== '0' ? config['mapZoom'] : 10;
|
||||||
|
const center = config['center'] && config['center'] !== ',' ?
|
||||||
|
{
|
||||||
|
lat: config['center'][1],
|
||||||
|
lng: config['center'][0],
|
||||||
|
} :
|
||||||
|
{
|
||||||
|
lat: 0,
|
||||||
|
lng: 0,
|
||||||
|
};
|
||||||
|
const style = config['style'] ? config['style'] : null;
|
||||||
|
|
||||||
|
console.log(`${ui.getName()}: API is loaded`);
|
||||||
|
// init fontawesome icons
|
||||||
|
ui.MarkerUI = MarkerUI.init();
|
||||||
|
|
||||||
|
ui.map = new google.maps.Map(mapDiv, {
|
||||||
|
zoom,
|
||||||
|
center,
|
||||||
|
fullscreenControl: true,
|
||||||
|
styles: style,
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.default_zoom = zoom;
|
||||||
|
|
||||||
|
mapDiv.classList.add('mapboxgl-map');
|
||||||
|
|
||||||
|
ui.popup = new ui.MarkerUI({
|
||||||
|
map: ui.map,
|
||||||
|
align: ['center', 'top'],
|
||||||
|
divClass: 'mapboxgl-popup popup mapboxgl-popup-anchor-bottom d-none',
|
||||||
|
html: '<div class="mapboxgl-popup-tip"></div><div class="mapboxgl-popup-content">' +
|
||||||
|
'<div class="mapboxgl-popup-close-button" type="button" aria-label="Close popup">×</div>' +
|
||||||
|
'<div class="html"></div>' +
|
||||||
|
'</div>',
|
||||||
|
});
|
||||||
|
ui.popup.setMap(ui.map);
|
||||||
|
|
||||||
|
ui.geocoder = new google.maps.Geocoder();
|
||||||
|
|
||||||
|
ui.cluster = new MarkerClusterer(ui.map, null, {
|
||||||
|
styles: [{
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
className: 'mapboxgl-cluster',
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
el.dispatchEvent(new Event(Events.MAPAPILOADED));
|
||||||
|
}
|
||||||
|
|
||||||
|
addMarker(crds, config) {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
const pos = {
|
||||||
|
lat: crds[1],
|
||||||
|
lng: crds[0],
|
||||||
|
};
|
||||||
|
|
||||||
|
const marker = new ui.MarkerUI({
|
||||||
|
position: pos,
|
||||||
|
map: ui.map,
|
||||||
|
align: ['center', 'top'],
|
||||||
|
html: `<div class="mapboxgl-marker"><div id="Marker${config['id']}" data-id="${config['id']}" class="marker">${config['icon']}</div></div>`,
|
||||||
|
onClick: () => {
|
||||||
|
const el = document.querySelector(`#Marker${config['id']}`);
|
||||||
|
ui.showPopup(pos, config['content']);
|
||||||
|
|
||||||
|
el.dispatchEvent(new Event(Events.MAPMARKERCLICK));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.markers.push(marker);
|
||||||
|
|
||||||
|
ui.cluster.addMarker(marker);
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
|
||||||
|
showPopup(pos, content) {
|
||||||
|
const ui = this;
|
||||||
|
const popup = ui.popup.getDiv();
|
||||||
|
|
||||||
|
if (ui.config['flyToMarker']) {
|
||||||
|
ui.map.setCenter(pos); // panTo
|
||||||
|
if (!ui.config['noZoom']) {
|
||||||
|
ui.map.setZoom(18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep it hidden to render content
|
||||||
|
popup.style.opacity = '0';
|
||||||
|
popup.classList.remove('d-none');
|
||||||
|
|
||||||
|
popup.querySelector('.mapboxgl-popup-content .html').innerHTML = content;
|
||||||
|
|
||||||
|
popup.querySelector('.mapboxgl-popup-close-button').addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
ui.hidePopup();
|
||||||
|
});
|
||||||
|
|
||||||
|
// set position when content was rendered
|
||||||
|
ui.popup.setPosition(pos, ['center', 'top']);
|
||||||
|
|
||||||
|
// display popup
|
||||||
|
popup.style.opacity = '1';
|
||||||
|
popup.style['margin-top'] = '-1rem';
|
||||||
|
}
|
||||||
|
|
||||||
|
hidePopup() {
|
||||||
|
const ui = this;
|
||||||
|
const popup = ui.popup.getDiv();
|
||||||
|
|
||||||
|
popup.classList.add('d-none');
|
||||||
|
if (!ui.config['noRestoreBounds'] || ui.config['flyToBounds']) {
|
||||||
|
ui.restoreBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.el.dispatchEvent(new Event(Events.MAPPOPUPCLOSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
geocode(addr, callback) {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
ui.geocoder.geocode(
|
||||||
|
{
|
||||||
|
address: addr,
|
||||||
|
},
|
||||||
|
(results, status) => {
|
||||||
|
if (status === 'OK') {
|
||||||
|
//results[0].geometry.location;
|
||||||
|
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`${ui.getName()}: Geocode was not successful for the following reason: ${status}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
reverseGeocode(latLng, callback) {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
ui.geocoder.geocode(
|
||||||
|
{
|
||||||
|
location: latlng,
|
||||||
|
},
|
||||||
|
(results, status) => {
|
||||||
|
if (status === 'OK') {
|
||||||
|
//results[0].formatted_address;
|
||||||
|
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback(results);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`${ui.getName()}: Reverse Geocoding was not successful for the following reason: ${status}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
addGeoJson(config) {
|
||||||
|
const ui = this;
|
||||||
|
const geojson = JSON.parse(config['geojson']);
|
||||||
|
const firstMarker = geojson.features[0].geometry.coordinates;
|
||||||
|
//Map.setCenter(firstMarker);
|
||||||
|
const bounds = new google.maps.LatLngBounds();
|
||||||
|
|
||||||
|
// add markers to map
|
||||||
|
geojson.features.forEach((marker) => {
|
||||||
|
const id = marker.id;
|
||||||
|
const crds = marker.geometry.coordinates;
|
||||||
|
const content = marker.properties.content;
|
||||||
|
|
||||||
|
ui.addMarker(crds, {
|
||||||
|
id,
|
||||||
|
content,
|
||||||
|
icon: marker.icon,
|
||||||
|
flyToMarker: config['flyToMarker'],
|
||||||
|
});
|
||||||
|
|
||||||
|
bounds.extend({
|
||||||
|
lat: crds[1],
|
||||||
|
lng: crds[0],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ui.markers.length > 1) {
|
||||||
|
ui.map.fitBounds(bounds, {
|
||||||
|
padding: 30,
|
||||||
|
}); //panToBounds
|
||||||
|
} else if (ui.markers[0]) {
|
||||||
|
ui.map.setCenter(ui.markers[0].getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.default_bounds = bounds;
|
||||||
|
ui.default_zoom = ui.map.getZoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
getMap() {
|
||||||
|
const ui = this;
|
||||||
|
return ui.map;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPopup() {
|
||||||
|
const ui = this;
|
||||||
|
return ui.popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreBounds() {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
if (ui.default_bounds && ui.markers.length > 1) {
|
||||||
|
ui.map.fitBounds(ui.default_bounds, {
|
||||||
|
padding: 30,
|
||||||
|
}); //panToBounds
|
||||||
|
} else {
|
||||||
|
if (ui.markers[0]) {
|
||||||
|
ui.map.setCenter(ui.markers[0].getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.restoreZoom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreZoom() {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
ui.map.setZoom(ui.default_zoom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GoogleMapsDriver;
|
||||||
|
})(window);
|
||||||
|
|
||||||
|
export default GoogleMapsDriver;
|
222
src/js/drivers/_map.google.marker.js
Normal file
222
src/js/drivers/_map.google.marker.js
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Obj = {
|
||||||
|
init: () => {
|
||||||
|
class GoogleMapsHtmlOverlay extends google.maps.OverlayView {
|
||||||
|
constructor(options) {
|
||||||
|
super();
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
ui.ownerMap = options.map;
|
||||||
|
//ui.setMap(options.map);
|
||||||
|
ui.position = options.position;
|
||||||
|
ui.html = options.html ?
|
||||||
|
options.html :
|
||||||
|
'<div class="mapboxgl-marker"><i class="marker-icon fas fa-map-marker-alt"></i></div>';
|
||||||
|
ui.divClass = options.divClass;
|
||||||
|
ui.align = options.align;
|
||||||
|
ui.isDebugMode = options.debug;
|
||||||
|
ui.onClick = options.onClick;
|
||||||
|
ui.onMouseOver = options.onMouseOver;
|
||||||
|
|
||||||
|
ui.isBoolean = (arg) => {
|
||||||
|
if (typeof arg === 'boolean') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.isNotUndefined = (arg) => {
|
||||||
|
if (typeof arg !== 'undefined') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.hasContent = (arg) => {
|
||||||
|
if (arg.length > 0) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.isString = (arg) => {
|
||||||
|
if (typeof arg === 'string') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ui.isFunction = (arg) => {
|
||||||
|
if (typeof arg === 'function') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
onAdd() {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
// Create div element.
|
||||||
|
ui.div = document.createElement('div');
|
||||||
|
ui.div.style.position = 'absolute';
|
||||||
|
|
||||||
|
// Validate and set custom div class
|
||||||
|
if (ui.isNotUndefined(ui.divClass) && ui.hasContent(ui.divClass))
|
||||||
|
ui.div.className = ui.divClass;
|
||||||
|
|
||||||
|
// Validate and set custom HTML
|
||||||
|
if (
|
||||||
|
ui.isNotUndefined(ui.html) &&
|
||||||
|
ui.hasContent(ui.html) &&
|
||||||
|
ui.isString(ui.html)
|
||||||
|
)
|
||||||
|
ui.div.innerHTML = ui.html;
|
||||||
|
|
||||||
|
// If debug mode is enabled custom content will be replaced with debug content
|
||||||
|
if (ui.isBoolean(ui.isDebugMode) && ui.isDebugMode) {
|
||||||
|
ui.div.className = 'debug-mode';
|
||||||
|
ui.div.innerHTML =
|
||||||
|
'<div style="height: 10px; width: 10px; background: red; border-radius: 100%;"></div>' +
|
||||||
|
'<div style="position: absolute; top: 5px; padding: 5px; width: 130px; text-align: center; font-size: 18px; text-transform: uppercase; font-weight: bolder; background: red; color: white; font-family: Arial;">Debug mode</div>';
|
||||||
|
ui.div.setAttribute(
|
||||||
|
'style',
|
||||||
|
'position: absolute;' +
|
||||||
|
'border: 5px dashed red;' +
|
||||||
|
'height: 150px;' +
|
||||||
|
'width: 150px;' +
|
||||||
|
'display: flex;' +
|
||||||
|
'justify-content: center;' +
|
||||||
|
'align-items: center;',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add element to clickable layer
|
||||||
|
ui.getPanes().overlayMouseTarget.appendChild(ui.div);
|
||||||
|
|
||||||
|
// Add listeners to the element.
|
||||||
|
google.maps.event.addDomListener(ui.div, 'click', (event) => {
|
||||||
|
google.maps.event.trigger(ui, 'click');
|
||||||
|
if (ui.isFunction(ui.onClick)) ui.onClick();
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
|
google.maps.event.addDomListener(ui.div, 'mouseover', (event) => {
|
||||||
|
google.maps.event.trigger(ui, 'mouseover');
|
||||||
|
if (ui.isFunction(ui.onMouseOver)) ui.onMouseOver();
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
let div = document.querySelector('.popup');
|
||||||
|
if (!div.length) {
|
||||||
|
div = ui.div;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate position of div
|
||||||
|
const projection = ui.getProjection();
|
||||||
|
|
||||||
|
if (!projection) {
|
||||||
|
console.log('GoogleMapsHtmlOverlay: current map is missing');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const positionInPixels = projection.fromLatLngToDivPixel(ui.getPosition());
|
||||||
|
|
||||||
|
// Align HTML overlay relative to original position
|
||||||
|
const offset = {
|
||||||
|
y: undefined,
|
||||||
|
x: undefined,
|
||||||
|
};
|
||||||
|
const divWidth = div.offsetWidth;
|
||||||
|
const divHeight = div.offsetHeight;
|
||||||
|
|
||||||
|
switch (Array.isArray(ui.align) ? ui.align.join(' ') : '') {
|
||||||
|
case 'left top':
|
||||||
|
offset.y = divHeight;
|
||||||
|
offset.x = divWidth;
|
||||||
|
break;
|
||||||
|
case 'left center':
|
||||||
|
offset.y = divHeight / 2;
|
||||||
|
offset.x = divWidth;
|
||||||
|
break;
|
||||||
|
case 'left bottom':
|
||||||
|
offset.y = 0;
|
||||||
|
offset.x = divWidth;
|
||||||
|
break;
|
||||||
|
case 'center top':
|
||||||
|
offset.y = divHeight;
|
||||||
|
offset.x = divWidth / 2;
|
||||||
|
break;
|
||||||
|
case 'center center':
|
||||||
|
offset.y = divHeight / 2;
|
||||||
|
offset.x = divWidth / 2;
|
||||||
|
break;
|
||||||
|
case 'center bottom':
|
||||||
|
offset.y = 0;
|
||||||
|
offset.x = divWidth / 2;
|
||||||
|
break;
|
||||||
|
case 'right top':
|
||||||
|
offset.y = divHeight;
|
||||||
|
offset.x = 0;
|
||||||
|
break;
|
||||||
|
case 'right center':
|
||||||
|
offset.y = divHeight / 2;
|
||||||
|
offset.x = 0;
|
||||||
|
break;
|
||||||
|
case 'right bottom':
|
||||||
|
offset.y = 0;
|
||||||
|
offset.x = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
offset.y = divHeight / 2;
|
||||||
|
offset.x = divWidth / 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set position
|
||||||
|
ui.div.style.top = `${positionInPixels.y - offset.y}px`;
|
||||||
|
ui.div.style.left = `${positionInPixels.x - offset.x}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPosition() {
|
||||||
|
const ui = this;
|
||||||
|
return new google.maps.LatLng(ui.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDiv() {
|
||||||
|
const ui = this;
|
||||||
|
return ui.div;
|
||||||
|
}
|
||||||
|
|
||||||
|
setPosition(position, align) {
|
||||||
|
const ui = this;
|
||||||
|
ui.position = position;
|
||||||
|
ui.align = align;
|
||||||
|
ui.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
const ui = this;
|
||||||
|
ui.setMap(null);
|
||||||
|
ui.div.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// emulate google.maps.Marker functionality for compatibility (for example with @googlemaps/markerclustererplus)
|
||||||
|
getDraggable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GoogleMapsHtmlOverlay;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Obj;
|
187
src/js/drivers/_map.mapbox.js
Normal file
187
src/js/drivers/_map.mapbox.js
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import $ from 'jquery';
|
||||||
|
import mapBoxGL from 'mapbox-gl';
|
||||||
|
|
||||||
|
import Events from '../../_events';
|
||||||
|
|
||||||
|
const MapBoxDriver = (($) => {
|
||||||
|
class MapBoxDriver {
|
||||||
|
getName() {
|
||||||
|
return 'MapBoxDriver';
|
||||||
|
}
|
||||||
|
|
||||||
|
init($el, config = []) {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
mapBoxGL.accessToken = config['key'];
|
||||||
|
|
||||||
|
ui.map = new mapBoxGL.Map({
|
||||||
|
container: $el.find('.mapAPI-map')[0],
|
||||||
|
center: config['center'] ? config['center'] : [0, 0],
|
||||||
|
//hash: true,
|
||||||
|
style: config['style']
|
||||||
|
? config['style']
|
||||||
|
: 'mapbox://styles/mapbox/streets-v9',
|
||||||
|
localIdeographFontFamily: config['font-family'],
|
||||||
|
zoom: config['mapZoom'] ? config['mapZoom'] : 10,
|
||||||
|
attributionControl: false,
|
||||||
|
antialias: true,
|
||||||
|
accessToken: config['key'],
|
||||||
|
})
|
||||||
|
.addControl(
|
||||||
|
new mapBoxGL.AttributionControl({
|
||||||
|
compact: true,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.addControl(new mapBoxGL.NavigationControl(), 'top-right')
|
||||||
|
.addControl(
|
||||||
|
new mapBoxGL.GeolocateControl({
|
||||||
|
positionOptions: {
|
||||||
|
enableHighAccuracy: true,
|
||||||
|
},
|
||||||
|
trackUserLocation: true,
|
||||||
|
}),
|
||||||
|
'bottom-right',
|
||||||
|
)
|
||||||
|
.addControl(
|
||||||
|
new mapBoxGL.ScaleControl({
|
||||||
|
maxWidth: 80,
|
||||||
|
unit: 'metric',
|
||||||
|
}),
|
||||||
|
'top-left',
|
||||||
|
)
|
||||||
|
.addControl(new mapBoxGL.FullscreenControl());
|
||||||
|
|
||||||
|
ui.map.on('load', (e) => {
|
||||||
|
$el.trigger(Events.MAPAPILOADED);
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.popup = new mapBoxGL.Popup({
|
||||||
|
closeOnClick: false,
|
||||||
|
className: 'popup',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addMarker(crds, config) {
|
||||||
|
const ui = this;
|
||||||
|
|
||||||
|
// create a DOM el for the marker
|
||||||
|
const $el = $(
|
||||||
|
`<div id="Marker${config['id']}" data-id="${config['id']}" class="marker">${config['icon']}</div>`,
|
||||||
|
);
|
||||||
|
|
||||||
|
$el.on('click', (e) => {
|
||||||
|
ui.popup
|
||||||
|
.setLngLat(crds)
|
||||||
|
.setHTML(config['content'])
|
||||||
|
.addTo(ui.map);
|
||||||
|
|
||||||
|
if (config['flyToMarker']) {
|
||||||
|
ui.map.flyTo({
|
||||||
|
center: crds,
|
||||||
|
zoom: 17,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(e.currentTarget).trigger(Events.MAPMARKERCLICK);
|
||||||
|
});
|
||||||
|
|
||||||
|
// add marker to map
|
||||||
|
const marker = new mapBoxGL.Marker($el[0]).setLngLat(crds).addTo(ui.map);
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
|
||||||
|
addGeoJson(config) {
|
||||||
|
const ui = this;
|
||||||
|
// Insert the layer beneath any symbol layer.
|
||||||
|
/*if (config['3d']) {
|
||||||
|
const layers = Map.getStyle().layers;
|
||||||
|
let labelLayerId;
|
||||||
|
for (let i = 0; i < layers.length; i++) {
|
||||||
|
if (layers[i].type === 'symbol' && layers[i].layout['text-field']) {
|
||||||
|
labelLayerId = layers[i].id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Map.addLayer({
|
||||||
|
'id': '3d-buildings',
|
||||||
|
'source': 'composite',
|
||||||
|
'source-layer': 'building',
|
||||||
|
'filter': ['==', 'extrude', 'true'],
|
||||||
|
'type': 'fill-extrusion',flyToBounds
|
||||||
|
'minzoom': 15,
|
||||||
|
'paint': {
|
||||||
|
'fill-extrusion-color': '#aaa',
|
||||||
|
|
||||||
|
// use an 'interpolate' expression to add a smooth transition effect to the
|
||||||
|
// buildings as the user zooms in
|
||||||
|
'fill-extrusion-height': [
|
||||||
|
"interpolate", ["linear"],
|
||||||
|
["zoom"],
|
||||||
|
15, 0,
|
||||||
|
15.05, ["get", "height"],
|
||||||
|
],
|
||||||
|
'fill-extrusion-base': [
|
||||||
|
"interpolate", ["linear"],
|
||||||
|
["zoom"],
|
||||||
|
15, 0,
|
||||||
|
15.05, ["get", "min_height"],
|
||||||
|
],
|
||||||
|
'fill-extrusion-opacity': .6,
|
||||||
|
},
|
||||||
|
}, labelLayerId);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
const firstMarker = config['geojson'].features[0].geometry.coordinates;
|
||||||
|
//Map.setCenter(firstMarker);
|
||||||
|
const bounds = new mapBoxGL.LngLatBounds(firstMarker, firstMarker);
|
||||||
|
|
||||||
|
// add markers to map
|
||||||
|
config['geojson'].features.forEach((marker) => {
|
||||||
|
const id = marker.id;
|
||||||
|
const crds = marker.geometry.coordinates;
|
||||||
|
const content = marker.properties.content;
|
||||||
|
|
||||||
|
ui.addMarker(crds, {
|
||||||
|
id,
|
||||||
|
content,
|
||||||
|
icon: marker.icon,
|
||||||
|
flyToMarker: config['flyToMarker'],
|
||||||
|
});
|
||||||
|
|
||||||
|
bounds.extend(crds);
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.map.fitBounds(bounds, {
|
||||||
|
padding: 30,
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.popup.on('close', (e) => {
|
||||||
|
if (config['flyToBounds']) {
|
||||||
|
ui.map.fitBounds(bounds, {
|
||||||
|
padding: 30,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(e.currentTarget).trigger(Events.MAPPOPUPCLOSE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getMap() {
|
||||||
|
const ui = this;
|
||||||
|
return ui.map;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPopup() {
|
||||||
|
const ui = this;
|
||||||
|
return ui.popup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MapBoxDriver;
|
||||||
|
})($);
|
||||||
|
|
||||||
|
export default MapBoxDriver;
|
134
src/scss/_ui/map.api.scss
Normal file
134
src/scss/_ui/map.api.scss
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
@import '../_variables';
|
||||||
|
@import '../_animations';
|
||||||
|
|
||||||
|
//@import "~mapbox-gl/src/css/mapbox-gl.css";
|
||||||
|
$map-height: 30rem !default;
|
||||||
|
|
||||||
|
$map-marker-color: $primary !default;
|
||||||
|
$map-marker-size: 30px !default;
|
||||||
|
|
||||||
|
$map-popup-font-size: 0.8rem !default;
|
||||||
|
$map-popup-width: 16rem !default;
|
||||||
|
$map-popup-height: 7rem !default;
|
||||||
|
$map-popup-bg: $white !default;
|
||||||
|
$map-popup-color: $body-color !default;
|
||||||
|
|
||||||
|
.mapAPI-map {
|
||||||
|
height: $map-height;
|
||||||
|
//margin-bottom: $grid-gutter-element-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapboxgl {
|
||||||
|
&-popup {
|
||||||
|
width: $map-popup-width;
|
||||||
|
height: $map-popup-height;
|
||||||
|
font-size: $map-popup-font-size;
|
||||||
|
line-height: 1.2em;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-popup-anchor-bottom,
|
||||||
|
&-popup-anchor-bottom-left,
|
||||||
|
&-popup-anchor-bottom-right {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-popup-content {
|
||||||
|
min-width: $map-popup-width;
|
||||||
|
background: $map-popup-bg;
|
||||||
|
color: $map-popup-color;
|
||||||
|
position: relative;
|
||||||
|
pointer-events: auto;
|
||||||
|
padding: 0.8rem;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
min-height: 5rem;
|
||||||
|
box-shadow: 0 0.1rem 0.8rem 0 rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&-popup-close-button {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
font-size: 2rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-top-right-radius: 0.25rem;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background: $primary;
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-popup-tip {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border: 0.8rem solid transparent;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-popup-anchor-bottom &-popup-tip {
|
||||||
|
border-top-color: $map-popup-bg;
|
||||||
|
align-self: center;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-marker {
|
||||||
|
width: $map-marker-size;
|
||||||
|
height: $map-marker-size;
|
||||||
|
font-size: $map-marker-size;
|
||||||
|
line-height: 1em;
|
||||||
|
color: $map-marker-color;
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.marker-icon,
|
||||||
|
.fas,
|
||||||
|
.fab,
|
||||||
|
.far {
|
||||||
|
animation: pulse 0.8s linear infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-cluster {
|
||||||
|
background: $info;
|
||||||
|
color: color-yiq($info);
|
||||||
|
border-radius: 100%;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
animation: pulse 0.8s linear infinite;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: 140%;
|
||||||
|
height: 140%;
|
||||||
|
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
background: $info;
|
||||||
|
opacity: 0.2;
|
||||||
|
border-radius: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
width: 180%;
|
||||||
|
height: 180%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user