Skip to content

Instantly share code, notes, and snippets.

@dilverdev
Created March 25, 2021 16:59
Show Gist options
  • Save dilverdev/bf9c66dac49a8b265d5abf384f194184 to your computer and use it in GitHub Desktop.
Save dilverdev/bf9c66dac49a8b265d5abf384f194184 to your computer and use it in GitHub Desktop.
<template>
<div :style="{opacity: opacity}">
<slot />
</div>
</template>
<script>
import VueGoogleMaps from "map-element.js";
export default {
mixins: [VueGoogleMaps],
props: {
marker: {
type: Object,
default: undefined
},
offsetX: {
type: Number,
default: 0
},
offsetY: {
type: Number,
default: 0
},
alignment: {
type: String,
default: "top"
},
zIndex: {
type: Number,
default: 50
},
cssPosition: {
type: Boolean,
default: false
}
},
inject: {
$clusterPromise: {
default: null
}
},
beforeCreate (options) {
if (this.$clusterPromise) {
options.map = null;
}
return this.$clusterPromise;
},
methods: {
afterCreate (inst) {
if (this.$clusterPromise && !this.isMarkerAdded) {
this.$clusterPromise.then(co => {
co.addMarker(inst);
this.$clusterObject = co;
this.isMarkerAdded = true;
});
}
}
},
data () {
return {
opacity: 0.01
};
},
watch: {
marker (val) {
this.$mapPromise.then(map => this.$overlay.setPosition());
},
zIndex (val) {
if (this.$overlay) {
this.$overlay.repaint()
}
}
},
provide () {
const self = this;
return this.$mapPromise.then(map => {
class Overlay extends google.maps.OverlayView {
constructor(map) {
super();
this.setMap(map);
this.draw = () => this.repaint();
this.setPosition = () => this.repaint();
}
repaint () {
const div = self.$el;
const projection = this.getProjection();
if (projection && div) {
const posPixel = projection.fromLatLngToDivPixel(self.latLng);
let x, y;
switch (self.alignment) {
case "top":
x = posPixel.x - div.offsetWidth / 2;
y = posPixel.y - div.offsetHeight;
break;
case "bottom":
x = posPixel.x - div.offsetWidth / 2;
y = posPixel.y;
break;
case "left":
x = posPixel.x - div.offsetWidth;
y = posPixel.y - div.offsetHeight / 2;
break;
case "right":
x = posPixel.x;
y = posPixel.y - div.offsetHeight / 2;
break;
case "center":
x = posPixel.x - div.offsetWidth / 2;
y = posPixel.y - div.offsetHeight / 2;
break;
case "topleft":
case "lefttop":
x = posPixel.x - div.offsetWidth;
y = posPixel.y - div.offsetHeight;
break;
case "topright":
case "righttop":
x = posPixel.x;
y = posPixel.y - div.offsetHeight;
break;
case "bottomleft":
case "leftop":
x = posPixel.x - div.offsetWidth;
y = posPixel.y;
break;
case "bottomright":
case "rightbottom":
x = posPixel.x;
y = posPixel.y;
break;
default:
throw new Error("Invalid alignment type of custom marker!");
break;
}
if (self.cssPosition) {
div.style.transform = `translate(${x + self.offsetX}px, ${y + self.offsetY}px)`;
} else {
div.style.left = x + self.offsetX + "px";
div.style.top = y + self.offsetY + "px";
}
div.style["z-index"] = self.zIndex;
}
}
onAdd () {
const div = self.$el;
const panes = this.getPanes();
div.style.position = "absolute";
div.style.display = "inline-block";
div.style.zIndex = self.zIndex;
panes.overlayLayer.appendChild(div);
panes.overlayMouseTarget.appendChild(div);
this.getDraggable = () => false;
this.getPosition = () => {
return new google.maps.LatLng(self.lat, self.lng);
};
self.afterCreate(this);
}
onRemove () {
if (self.$el) {
const ua = window.navigator.userAgent
const msie = ua.indexOf("MSIE ")
if (msie > 0 || !!ua.match(/Trident.*rv\:11\./)) {
self.$el.parentNode.removeChild(self.$el)
} else {
self.$el.remove();
}
}
}
}
this.$overlay = new Overlay(map);
setTimeout(() => {
if (this.$overlay) {
this.$overlay.repaint();
this.opacity = 1;
}
}, 100);
});
},
computed: {
lat () {
return parseFloat(
isNaN(this.marker.lat) ? this.marker.latitude : this.marker.lat
);
},
lng () {
return parseFloat(
isNaN(this.marker.lng) ? this.marker.longitude : this.marker.lng
);
},
latLng () {
if (this.marker instanceof google.maps.LatLng) {
return this.marker;
}
return new google.maps.LatLng(this.lat, this.lng);
}
},
destroyed () {
if (this.$clusterObject) {
this.$clusterObject.removeMarker(this.$overlay, true);
} else {
if (this.$overlay) {
this.$overlay.setMap(null);
this.$overlay = undefined;
}
}
}
};
</script>
export default {
inject: {
$mapPromise: { default: 'abcdef' }
},
provide () {
// Note: although this mixin is not "providing" anything,
// components' expect the `$map` property to be present on the component.
// In order for that to happen, this mixin must intercept the $mapPromise
// .then(() =>) first before its component does so.
//
// Since a provide() on a mixin is executed before a provide() on the
// component, putting this code in provide() ensures that the $map is
// already set by the time the
// component's provide() is called.
this.$mapPromise.then((map) => {
this.$map = map
})
return {}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment