166 lines
5.6 KiB
Vue
166 lines
5.6 KiB
Vue
<script setup lang="ts">
|
|
import { useDrag, useHover, usePinch, useWheel } from '@vueuse/gesture';
|
|
import { Icon } from '@iconify/vue/dist/iconify.js';
|
|
import { clamp } from '#shared/general.utils';
|
|
|
|
const { path } = defineProps<{ path: string }>();
|
|
const { user } = useUserSession();
|
|
const { content } = useContent();
|
|
const overview = computed(() => content.value.find(e => e.path === path));
|
|
|
|
const isOwner = computed(() => user.value?.id === overview.value?.owner);
|
|
|
|
const dispX = ref(0), dispY = ref(0), minZoom = ref(0.1), zoom = ref(0.5);
|
|
const canvasRef = useTemplateRef('canvasRef');
|
|
|
|
const reset = (_: MouseEvent) => {
|
|
zoom.value = minZoom.value;
|
|
|
|
dispX.value = 0;
|
|
dispY.value = 0;
|
|
}
|
|
|
|
/*
|
|
|
|
stroke-light-red
|
|
stroke-light-orange
|
|
stroke-light-yellow
|
|
stroke-light-green
|
|
stroke-light-cyan
|
|
stroke-light-purple
|
|
dark:stroke-dark-red
|
|
dark:stroke-dark-orange
|
|
dark:stroke-dark-yellow
|
|
dark:stroke-dark-green
|
|
dark:stroke-dark-cyan
|
|
dark:stroke-dark-purple
|
|
fill-light-red
|
|
fill-light-orange
|
|
fill-light-yellow
|
|
fill-light-green
|
|
fill-light-cyan
|
|
fill-light-purple
|
|
dark:fill-dark-red
|
|
dark:fill-dark-orange
|
|
dark:fill-dark-yellow
|
|
dark:fill-dark-green
|
|
dark:fill-dark-cyan
|
|
dark:fill-dark-purple
|
|
bg-light-red
|
|
bg-light-orange
|
|
bg-light-yellow
|
|
bg-light-green
|
|
bg-light-cyan
|
|
bg-light-purple
|
|
dark:bg-dark-red
|
|
dark:bg-dark-orange
|
|
dark:bg-dark-yellow
|
|
dark:bg-dark-green
|
|
dark:bg-dark-cyan
|
|
dark:bg-dark-purple
|
|
border-light-red
|
|
border-light-orange
|
|
border-light-yellow
|
|
border-light-green
|
|
border-light-cyan
|
|
border-light-purple
|
|
dark:border-dark-red
|
|
dark:border-dark-orange
|
|
dark:border-dark-yellow
|
|
dark:border-dark-green
|
|
dark:border-dark-cyan
|
|
dark:border-dark-purple
|
|
outline-light-red
|
|
outline-light-orange
|
|
outline-light-yellow
|
|
outline-light-green
|
|
outline-light-cyan
|
|
outline-light-purple
|
|
dark:outline-dark-red
|
|
dark:outline-dark-orange
|
|
dark:outline-dark-yellow
|
|
dark:outline-dark-green
|
|
dark:outline-dark-cyan
|
|
dark:outline-dark-purple
|
|
|
|
*/
|
|
|
|
const cancelEvent = (e: Event) => e.preventDefault()
|
|
useHover(({ hovering }) => {
|
|
if (!hovering) {
|
|
//@ts-ignore
|
|
window.removeEventListener('wheel', cancelEvent, { passive: false });
|
|
document.removeEventListener('gesturestart', cancelEvent)
|
|
document.removeEventListener('gesturechange', cancelEvent)
|
|
return
|
|
}
|
|
|
|
window.addEventListener('wheel', cancelEvent, { passive: false });
|
|
document.addEventListener('gesturestart', cancelEvent)
|
|
document.addEventListener('gesturechange', cancelEvent)
|
|
}, {
|
|
domTarget: canvasRef,
|
|
});
|
|
|
|
const dragHandler = useDrag(({ delta: [x, y] }: { delta: number[] }) => {
|
|
dispX.value += x / zoom.value;
|
|
dispY.value += y / zoom.value;
|
|
}, {
|
|
domTarget: canvasRef,
|
|
});
|
|
const wheelHandler = useWheel(({ delta: [x, y] }: { delta: number[] }) => {
|
|
zoom.value = clamp(zoom.value + y * -0.001, minZoom.value, 3);
|
|
}, {
|
|
domTarget: canvasRef,
|
|
});
|
|
const pinchHandler = usePinch(({ offset: [z] }: { offset: number[] }) => {
|
|
zoom.value = clamp(z / 2048, minZoom.value, 3);
|
|
}, {
|
|
domTarget: canvasRef,
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div ref="canvasRef" class="absolute top-0 left-0 overflow-hidden w-full h-full touch-none" :style="{ '--zoom-multiplier': (1 / Math.pow(zoom, 0.7)) }">
|
|
<div class="flex flex-col absolute sm:top-2 top-10 left-2 z-[35] overflow-hidden gap-4">
|
|
<div class="border border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10">
|
|
<Tooltip message="Zoom avant" side="right">
|
|
<div @click="zoom = clamp(zoom * 1.1, minZoom, 3)" class="w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer">
|
|
<Icon icon="radix-icons:plus" />
|
|
</div>
|
|
</Tooltip>
|
|
<Tooltip message="Reset" side="right">
|
|
<div @click="zoom = 1" class="w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer">
|
|
<Icon icon="radix-icons:reload" />
|
|
</div>
|
|
</Tooltip>
|
|
<Tooltip message="Tout contenir" side="right">
|
|
<div @click="reset" class="w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer">
|
|
<Icon icon="radix-icons:corners" />
|
|
</div>
|
|
</Tooltip>
|
|
<Tooltip message="Zoom arrière" side="right">
|
|
<div @click="zoom = clamp(zoom * 0.9, minZoom, 3)" class="w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer">
|
|
<Icon icon="radix-icons:minus" />
|
|
</div>
|
|
</Tooltip>
|
|
</div>
|
|
<div class="border border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10" v-if="isOwner">
|
|
<Tooltip message="Modifier" side="right">
|
|
<NuxtLink :to="{ name: 'explore-edit', hash: '#' + path }" class="w-8 h-8 flex justify-center items-center p-2 hover:bg-light-30 dark:hover:bg-dark-30 cursor-pointer">
|
|
<Icon icon="radix-icons:pencil-1" />
|
|
</NuxtLink>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
<div :style="{
|
|
'--tw-translate-x': `${dispX}px`,
|
|
'--tw-translate-y': `${dispY}px`,
|
|
'--tw-scale-x': `${zoom}`,
|
|
'--tw-scale-y': `${zoom}`,
|
|
transform: 'scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)) translate3d(var(--tw-translate-x), var(--tw-translate-y), 0)'
|
|
}">
|
|
<CanvasRenderer :path="path" />
|
|
</div>
|
|
</div>
|
|
</template> |