Forgot to add MapContextMenu file
This commit is contained in:
parent
4d2a0d7180
commit
e4f0864805
160
src/components/map/MapContextMenu.vue
Normal file
160
src/components/map/MapContextMenu.vue
Normal 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>
|
Loading…
Reference in New Issue
Block a user