Hussam Saoud
3 years ago
2 changed files with 522 additions and 1 deletions
@ -0,0 +1,519 @@
@@ -0,0 +1,519 @@
|
||||
var markerWithLabel = (function (exports) { |
||||
'use strict'; |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
/** |
||||
* Extends an object's prototype by another's. |
||||
* |
||||
* @param type1 The Type to be extended. |
||||
* @param type2 The Type to extend with. |
||||
* @ignore |
||||
*/ |
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function extend(type1, type2) { |
||||
// eslint-disable-next-line prefer-const
|
||||
for (let property in type2.prototype) { |
||||
type1.prototype[property] = type2.prototype[property]; |
||||
} |
||||
} |
||||
function abortEvent(e) { |
||||
e = e || window.event; |
||||
if (e.stopPropagation) { |
||||
e.stopPropagation(); |
||||
} |
||||
else { |
||||
e.cancelBubble = true; |
||||
} |
||||
if (e.preventDefault) { |
||||
e.preventDefault(); |
||||
} |
||||
else { |
||||
e.returnValue = false; |
||||
} |
||||
} |
||||
function stopPropagation(e) { |
||||
e = e || window.event; |
||||
if (e.stopPropagation) { |
||||
e.stopPropagation(); |
||||
} |
||||
else { |
||||
e.cancelBubble = true; |
||||
} |
||||
} |
||||
function omit(o, keys) { |
||||
const x = Object.assign({}, o); |
||||
keys.forEach((k) => delete x[k]); |
||||
return x; |
||||
} |
||||
|
||||
/** |
||||
* Copyright 2019 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. |
||||
*/ |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
class OverlayViewSafe { |
||||
constructor() { |
||||
extend(OverlayViewSafe, google.maps.OverlayView); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
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"; |
||||
class Label extends OverlayViewSafe { |
||||
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, }) { |
||||
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); |
||||
} |
||||
} |
||||
get element() { |
||||
return this.labelDiv; |
||||
} |
||||
get content() { |
||||
return this.labelDiv.innerHTML; |
||||
} |
||||
set content(content) { |
||||
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)); |
||||
} |
||||
} |
||||
/** |
||||
* Get the class of the label div elements. |
||||
* |
||||
* **Note**: This will always return the default `marker-label`. |
||||
*/ |
||||
get className() { |
||||
return this.labelDiv.className; |
||||
} |
||||
/** |
||||
* Set the class of the label div elements. |
||||
* |
||||
* **Note**: The default `marker-label` will additionaly be added. |
||||
*/ |
||||
set className(className) { |
||||
this.labelDiv.className = className; |
||||
this.labelDiv.classList.add(LABEL_CLASS); |
||||
this.eventDiv.className = className; |
||||
this.eventDiv.classList.add(EVENT_CLASS); |
||||
} |
||||
set cursor(cursor) { |
||||
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) { |
||||
this.labelDiv.style.opacity = String(opacity); |
||||
} |
||||
set title(title) { |
||||
this.eventDiv.title = title; |
||||
} |
||||
set visible(visible) { |
||||
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, handler) { |
||||
return google.maps.event.addDomListener(this.eventDiv, event, handler); |
||||
} |
||||
onRemove() { |
||||
this.labelDiv.parentNode.removeChild(this.labelDiv); |
||||
this.eventDiv.parentNode.removeChild(this.eventDiv); |
||||
} |
||||
createElements() { |
||||
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; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
/** |
||||
* @ignore |
||||
*/ |
||||
class MarkerSafe { |
||||
constructor(options) { |
||||
extend(MarkerSafe, google.maps.Marker); |
||||
google.maps.Marker.call(this, options); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 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. |
||||
*/ |
||||
const CLICK = "click"; |
||||
const DBLCLICK = "dblclick"; |
||||
const DRAG = "drag"; |
||||
const DRAGEND = "dragend"; |
||||
const DRAGSTART = "dragstart"; |
||||
const MOUSEDOWN = "mousedown"; |
||||
const MOUSEMOVE = "mousemove"; |
||||
const MOUSEOVER = "mouseover"; |
||||
const MOUSEOUT = "mouseout"; |
||||
const MOUSEUP = "mouseup"; |
||||
class MarkerWithLabel extends MarkerSafe { |
||||
constructor(options) { |
||||
// need to omit extended options to Marker class that collide with setters/getters
|
||||
super(omit(options, [ |
||||
"labelAnchor", |
||||
"labelZIndexOffset", |
||||
"labelClass", |
||||
"labelContent", |
||||
])); |
||||
this.isTouchScreen = false; |
||||
this.isDraggingLabel = false; |
||||
this.isMouseDownOnLabel = false; |
||||
this.shouldIgnoreClick = false; |
||||
this.label = new Label(Object.assign({}, options)); |
||||
this.propertyListeners = [ |
||||
google.maps.event.addListener(this, "clickable_changed", this.handleClickableOrDraggableChange), |
||||
google.maps.event.addListener(this, "cursor_changed", () => { |
||||
this.label.cursor = this.getCursor(); |
||||
}), |
||||
google.maps.event.addListener(this, "draggable_changed", this.handleClickableOrDraggableChange), |
||||
google.maps.event.addListener(this, "position_changed", () => { |
||||
this.label.position = this.getPosition(); |
||||
}), |
||||
google.maps.event.addListener(this, "opacity_changed", () => { |
||||
this.label.opacity = this.getOpacity(); |
||||
}), |
||||
google.maps.event.addListener(this, "title_changed", () => { |
||||
this.label.title = this.getTitle(); |
||||
}), |
||||
google.maps.event.addListener(this, "visible_changed", () => { |
||||
this.label.visible = this.getVisible(); |
||||
}), |
||||
google.maps.event.addListener(this, "zindex_changed", () => { |
||||
this.label.zIndex = this.getZIndex(); |
||||
this.label.draw(); |
||||
}), |
||||
]; |
||||
} |
||||
get isInteractive() { |
||||
return this.getClickable() || this.getDraggable(); |
||||
} |
||||
/** |
||||
* Gets label element. |
||||
*/ |
||||
get labelElement() { |
||||
return this.label.element; |
||||
} |
||||
/** |
||||
* Gets label `innerHTML`. See {@link Marker.labelElement} for |
||||
* accessing the HTMLElement instead. |
||||
*/ |
||||
get labelContent() { |
||||
return this.label.content; |
||||
} |
||||
set labelContent(content) { |
||||
this.label.content = content; |
||||
} |
||||
get labelClass() { |
||||
return this.label.className; |
||||
} |
||||
set labelClass(className) { |
||||
this.label.className = className; |
||||
} |
||||
setMap(map) { |
||||
super.setMap(map); |
||||
setTimeout(() => { |
||||
this.label.setMap(map); |
||||
this.removeInteractiveListeners(); |
||||
if (map) { |
||||
this.addInteractiveListeners(); |
||||
} |
||||
}); |
||||
} |
||||
handleClickableOrDraggableChange() { |
||||
this.label.clickable = this.getClickable(); |
||||
this.label.draggable = this.getDraggable(); |
||||
if (this.isInteractive) { |
||||
this.addInteractiveListeners(); |
||||
} |
||||
else { |
||||
this.removeInteractiveListeners(); |
||||
} |
||||
} |
||||
removeInteractiveListeners() { |
||||
if (this.interactiveListeners) { |
||||
this.interactiveListeners.forEach((l) => google.maps.event.removeListener(l)); |
||||
this.interactiveListeners = null; |
||||
} |
||||
} |
||||
addInteractiveListeners() { |
||||
if (!this.interactiveListeners) { |
||||
// If the map is not set, do not set listeners
|
||||
if (!this.getMap()) { |
||||
return; |
||||
} |
||||
this.interactiveListeners = [ |
||||
this.label.addDomListener(MOUSEOVER, (e) => { |
||||
if (!this.isTouchScreen) { |
||||
google.maps.event.trigger(this, MOUSEOVER, { |
||||
latLng: this.getPosition(), |
||||
}); |
||||
abortEvent(e); |
||||
} |
||||
}), |
||||
this.label.addDomListener(MOUSEOUT, (e) => { |
||||
if (!this.isTouchScreen) { |
||||
// wrap the mouseout event in a timeout to avoid the case where mouseup occurs out
|
||||
if (this.mouseOutTimeout) { |
||||
clearTimeout(this.mouseOutTimeout); |
||||
} |
||||
if (this.isMouseDownOnLabel) { |
||||
this.mouseOutTimeout = setTimeout(() => { |
||||
if (this.isMouseDownOnLabel) { |
||||
this.isMouseDownOnLabel = false; |
||||
google.maps.event.trigger(this, MOUSEUP, { |
||||
latLng: this.getPosition(), |
||||
}); |
||||
if (this.isDraggingLabel) { |
||||
this.isDraggingLabel = false; |
||||
this.shouldIgnoreClick = true; |
||||
google.maps.event.trigger(this, DRAGEND, { |
||||
latLng: this.getPosition(), |
||||
}); |
||||
} |
||||
} |
||||
google.maps.event.trigger(this, MOUSEOUT, { |
||||
latLng: this.getPosition(), |
||||
}); |
||||
}, 200); |
||||
} |
||||
else { |
||||
google.maps.event.trigger(this, MOUSEOUT, { |
||||
latLng: this.getPosition(), |
||||
}); |
||||
} |
||||
abortEvent(e); |
||||
} |
||||
}), |
||||
this.label.addDomListener(MOUSEDOWN, (e) => { |
||||
this.isDraggingLabel = false; |
||||
this.isMouseDownOnLabel = true; |
||||
google.maps.event.trigger(this, MOUSEDOWN, { |
||||
latLng: this.getPosition(), |
||||
}); |
||||
if (!this.isTouchScreen) { |
||||
abortEvent(e); |
||||
} |
||||
}), |
||||
this.label.addDomListener(MOUSEUP, (e) => { |
||||
const markerEvent = { latLng: this.getPosition() }; |
||||
if (this.isMouseDownOnLabel) { |
||||
this.isMouseDownOnLabel = false; |
||||
google.maps.event.trigger(this, MOUSEUP, markerEvent); |
||||
if (this.isDraggingLabel) { |
||||
this.isDraggingLabel = false; |
||||
this.shouldIgnoreClick = true; |
||||
google.maps.event.trigger(this, DRAGEND, markerEvent); |
||||
} |
||||
if (!this.getDraggable()) { |
||||
abortEvent(e); |
||||
} |
||||
} |
||||
}), |
||||
this.label.addDomListener(CLICK, (e) => { |
||||
if (this.shouldIgnoreClick) { |
||||
this.shouldIgnoreClick = false; |
||||
} |
||||
else { |
||||
google.maps.event.trigger(this, CLICK, { |
||||
latLng: this.getPosition(), |
||||
}); |
||||
} |
||||
abortEvent(e); |
||||
}), |
||||
this.label.addDomListener(DBLCLICK, (e) => { |
||||
google.maps.event.trigger(this, DBLCLICK, { |
||||
latLng: this.getPosition(), |
||||
}); |
||||
abortEvent(e); |
||||
}), |
||||
google.maps.event.addListener(this.getMap(), MOUSEMOVE, (e) => { |
||||
if (this.isMouseDownOnLabel && this.getDraggable()) { |
||||
if (this.isDraggingLabel) { |
||||
// Adjust for offset
|
||||
const position = new google.maps.LatLng(e.latLng.lat() - this.eventOffset.y, e.latLng.lng() - this.eventOffset.x); |
||||
// this.setPosition(position);
|
||||
google.maps.event.trigger(this, DRAG, Object.assign(Object.assign({}, e), { latLng: position })); |
||||
} |
||||
else { |
||||
this.isDraggingLabel = true; |
||||
// Calculate and store event offset from marker position
|
||||
this.eventOffset = new google.maps.Point(e.latLng.lng() - this.getPosition().lng(), e.latLng.lat() - this.getPosition().lat()); |
||||
google.maps.event.trigger(this, DRAGSTART, Object.assign(Object.assign({}, e), { latLng: this.getPosition() })); |
||||
} |
||||
} |
||||
}), |
||||
google.maps.event.addListener(this, DRAGSTART, () => { |
||||
this.label.zIndex = 1000000; |
||||
}), |
||||
google.maps.event.addListener(this, DRAG, ({ latLng }) => { |
||||
this.setPosition(latLng); |
||||
}), |
||||
google.maps.event.addListener(this, DRAGEND, () => { |
||||
this.label.zIndex = this.getZIndex(); |
||||
this.label.draw(); |
||||
}), |
||||
// Prevent touch events from passing through the label DIV to the underlying map.
|
||||
this.label.addDomListener("touchstart", (e) => { |
||||
this.isTouchScreen = true; |
||||
stopPropagation(e); |
||||
}), |
||||
this.label.addDomListener("touchmove", (e) => { |
||||
stopPropagation(e); |
||||
}), |
||||
this.label.addDomListener("touchend", (e) => { |
||||
stopPropagation(e); |
||||
}), |
||||
]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
exports.MarkerWithLabel = MarkerWithLabel; |
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true }); |
||||
|
||||
return exports; |
||||
|
||||
})({}); |
Loading…
Reference in new issue