Forgot to add MapContextMenu file

This commit is contained in:
James Lyne 2021-05-24 16:43:42 +01:00
parent 4d2a0d7180
commit e4f0864805

View File

@ -0,0 +1,160 @@
<template>
<nav id="map__context-menu" v-show="menuVisible" ref="menuElement" :style="style">
<ul class="menu">
<li>
<button ref="locationButton" type="button" v-clipboard="locationCopy">{{locationLabel}}</button>
</li>
<li><button type="button" v-clipboard="url">Copy link to here</button></li>
<li><button type="button" @click.prevent="pan">Center here</button></li>
<WorldListItem v-if="currentWorld" :world="currentWorld"></WorldListItem>
</ul>
</nav>
</template>
<script lang="ts">
import DynmapMap from "@/leaflet/DynmapMap";
import {computed, defineComponent, onMounted, onUnmounted} from "@vue/runtime-core";
import {LeafletMouseEvent} from "leaflet";
import {useStore} from "@/store";
import WorldListItem from "@/components/sidebar/WorldListItem.vue";
import {ref, watch} from "vue";
import {getUrlForLocation} from "@/util";
export default defineComponent({
name: "MapContextMenu",
components: {WorldListItem},
props: {
leaflet: {
type: Object as () => DynmapMap,
required: true,
}
},
setup(props) {
const store = useStore(),
event = ref<LeafletMouseEvent|null>(null),
menuElement = ref<HTMLInputElement | null>(null),
locationButton = ref<HTMLInputElement | null>(null),
menuVisible = computed(() => !!event.value),
currentProjection = computed(() => store.state.currentProjection),
currentWorld = computed(() => store.state.currentWorld),
currentMap = computed(() => store.state.currentMap),
currentZoom = computed(() => store.state.currentZoom),
location = computed(() => {
if(!event.value) {
return {x: 0, y: 0, z: 0}
}
return currentProjection.value.latLngToLocation(event.value.latlng, 64);
}),
//Label for location button
locationLabel = computed(() => {
return `X: ${Math.round(location.value.x)}, Z: ${Math.round(location.value.z)}`;
}),
//Location text to copy
locationCopy = computed(() => {
return `${Math.round(location.value.x)}, ${Math.round(location.value.z)}`;
}),
//Url to copy
url = computed(() => {
if(!currentWorld.value || !currentMap.value) {
return '';
}
const url = new URL(window.location.href);
url.hash = getUrlForLocation(currentWorld.value, currentMap.value, location.value, currentZoom.value);
return url;
}),
style = computed(() => {
if(!menuElement.value || !event.value) {
return {};
}
//Don't position offscreen
const x = Math.min(
window.innerWidth - menuElement.value.offsetWidth - 10,
event.value.originalEvent.clientX
),
y = Math.min(
window.innerHeight - menuElement.value.offsetHeight - 10,
event.value.originalEvent.clientY
);
return {
'transform': `translate(${x}px, ${y}px)`
}
});
const handleEsc = (e: KeyboardEvent) => {
console.log(e);
if (e.key === "Escape") {
closeContextMenu();
}
},
closeContextMenu = () => {
event.value = null;
},
pan = () => {
if(event.value) {
props.leaflet.panTo(event.value.latlng);
}
};
watch(menuVisible, visible => {
if(visible) {
requestAnimationFrame(() => locationButton.value && locationButton.value.focus());
}
});
onMounted(() => {
window.addEventListener('click', closeContextMenu);
window.addEventListener('keyup', handleEsc);
});
onUnmounted(() => {
window.removeEventListener('click', closeContextMenu);
window.removeEventListener('keyup', handleEsc);
});
props.leaflet.on('contextmenu', (e: LeafletMouseEvent) => {
e.originalEvent.preventDefault();
event.value = e;
});
return {
menuVisible,
menuElement,
locationButton,
url,
locationLabel,
locationCopy,
currentWorld,
style,
pan,
}
},
})
</script>
<style lang="scss" scoped>
#map__context-menu {
background-color: var(--background-base);
color: var(--text-base);
border-radius: var(--border-radius);
position: fixed;
z-index: 1001;
padding: 0.5rem;
min-width: 15rem;
max-width: 22.5rem;
}
</style>