Visual improvement + code cleanup

This commit is contained in:
Peaceultime 2024-09-09 23:13:18 +02:00
parent 6c0bfb9e4c
commit f2261c3f35
5 changed files with 23 additions and 101 deletions

View File

@ -7,85 +7,7 @@ interface Props
}
const props = defineProps<Props>();
let dragging = false, posX = 0, posY = 0, dispX = ref(0), dispY = ref(0), minZoom = ref(0.1), zoom = ref(0.5);
let lastDistance = 0;
let lastClickTime = 0;
const onPointerDown = (event: PointerEvent) => {
if (event.isPrimary === false) return;
dragging = true;
const now = performance.now();
if(now - lastClickTime < 500 && Math.abs(event.clientX - posX) < 20 && Math.abs(event.clientY - posY) < 20)
{
if(event.ctrlKey)
{
zoom.value = clamp(zoom.value * 0.9, minZoom.value, 3);
}
else
{
zoom.value = clamp(zoom.value * 1.1, minZoom.value, 3);
}
}
lastClickTime = now;
posX = event.clientX;
posY = event.clientY;
document.addEventListener('pointermove', onPointerMove);
document.addEventListener('pointerup', onPointerUp);
}
const onPointerMove = (event: PointerEvent) => {
if (event.isPrimary === false || dragging === false) return;
dispX.value -= (posX - event.clientX) / zoom.value;
dispY.value -= (posY - event.clientY) / zoom.value;
posX = event.clientX;
posY = event.clientY;
}
const onPointerUp = (event: PointerEvent) => {
if (event.isPrimary === false) return;
dragging = false;
document.removeEventListener('pointermove', onPointerMove);
document.removeEventListener('pointerup', onPointerUp);
}
const onWheel = (event: WheelEvent) => {
zoom.value = clamp(zoom.value + (event.deltaY * -0.001), minZoom.value, 3);
}
const onTouchStart = (event: TouchEvent) => {
if(event.touches?.length === 2)
{
dragging = false;
lastDistance = length(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY);
document.addEventListener('touchmove', onTouchMove);
document.addEventListener('touchend', onTouchEnd);
}
}
const onTouchEnd = (event: TouchEvent) => {
if(event.touches?.length !== 2)
dragging = true;
document.removeEventListener('touchmove', onTouchMove);
document.removeEventListener('touchend', onTouchEnd);
}
const onTouchMove = (event: TouchEvent) => {
if(event.touches?.length === 2)
{
const distance = length(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY);
zoom.value = clamp(zoom.value * (distance / lastDistance), minZoom.value, 3);
lastDistance = distance;
}
}
const dispX = ref(0), dispY = ref(0), minZoom = ref(0.1), zoom = ref(0.5);
const reset = (_: MouseEvent) => {
zoom.value = minZoom.value;
@ -100,30 +22,27 @@ function clamp(x: number, min: number, max: number): number {
return min;
return x;
}
function length(x1: number, y1: number, x2: number, y2: number): number {
return Math.sqrt((x2 - x1)^2 + (y2 - y1)^2);
}
function edgePos(side: 'bottom' | 'top' | 'left' | 'right', pos: { x: number, y: number }, n: number): { x: number, y: number } {
function edgePos(side: 'bottom' | 'top' | 'left' | 'right', pos: { x: number, y: number }, offset: number): { x: number, y: number } {
switch (side) {
case "left":
return {
x: pos.x - n,
x: pos.x - offset,
y: pos.y
};
case "right":
return {
x: pos.x + n,
x: pos.x + offset,
y: pos.y
};
case "top":
return {
x: pos.x,
y: pos.y - n
y: pos.y - offset
};
case "bottom":
return {
x: pos.x,
y: pos.y + n
y: pos.y + offset
}
}
}
@ -131,7 +50,7 @@ function getNode(id: string): CanvasNode | undefined
{
return props.canvas.nodes.find(e => e.id === id);
}
function mK(e: { minX: number, minY: number, maxX: number, maxY: number }, t: 'bottom' | 'top' | 'left' | 'right'): { x: number, y: number } {
function posFromDir(e: { minX: number, minY: number, maxX: number, maxY: number }, t: 'bottom' | 'top' | 'left' | 'right'): { x: number, y: number } {
switch (t) {
case "top":
return { x: (e.minX + e.maxX) / 2, y: e.minY };
@ -156,9 +75,8 @@ function path(from: CanvasNode, fromSide: 'bottom' | 'top' | 'left' | 'right', t
toSide: '',
}
}
const a = mK(getBbox(from), fromSide),
l = mK(getBbox(to), toSide);
return bezier(a, fromSide, l, toSide);
const start = posFromDir(getBbox(from), fromSide), end = posFromDir(getBbox(to), toSide);
return bezier(start, fromSide, end, toSide);
}
function bezier(from: { x: number, y: number }, fromSide: 'bottom' | 'top' | 'left' | 'right', to: { x: number, y: number }, toSide: 'bottom' | 'top' | 'left' | 'right'): any {
const r = Math.hypot(from.x - to.x, from.y - to.y), o = clamp(r / 2, 70, 150), a = edgePos(fromSide, from, o), s = edgePos(toSide, to, o);
@ -170,9 +88,9 @@ function bezier(from: { x: number, y: number }, fromSide: 'bottom' | 'top' | 'le
};
}
function labelCenter(from: CanvasNode, fromSide: 'bottom' | 'top' | 'left' | 'right', to: CanvasNode, toSide: 'bottom' | 'top' | 'left' | 'right'): string {
const a = mK(getBbox(from), fromSide), l = mK(getBbox(to), toSide);
const r = Math.hypot(a.x - l.x, a.y - l.y), o = clamp(r / 2, 70, 150), b = edgePos(fromSide, a, o), s = edgePos(toSide, l, o);
const center = getCenter(a, l, b, s, 0.5);
const start = posFromDir(getBbox(from), fromSide), end = posFromDir(getBbox(to), toSide);
const len = Math.hypot(start.x - end.x, start.y - end.y), offset = clamp(len / 2, 70, 150), b = edgePos(fromSide, start, offset), s = edgePos(toSide, end, offset);
const center = getCenter(start, end, b, s, 0.5);
return `translate(${center.x}px, ${center.y}px)`;
}
function getCenter(n: { x: number, y: number }, i: { x: number, y: number }, r: { x: number, y: number }, o: { x: number, y: number }, e: number): { x: number, y: number } {
@ -249,9 +167,8 @@ const wheelHandler = ({ delta: [x, y] }: { delta: number[] }) => {
<template>
<Suspense>
<template #default> <!-- @pointerdown="onPointerDown" @touchstart="onTouchStart" -->
<div id="canvas" v-drag="dragHandler" v-pinch="pinchHandler" v-wheel="wheelHandler"
@dragstart.prevent="" class="absolute top-0 left-0 overflow-hidden w-full h-full touch-none"
<template #default>
<div id="canvas" v-drag="dragHandler" v-pinch="pinchHandler" v-wheel="wheelHandler" 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="border border-light-35 dark:border-dark-35 bg-light-10 dark:bg-dark-10 absolute sm:top-2 top-10 left-2 z-30 overflow-hidden">
<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"

View File

@ -1,5 +1,5 @@
<template>
<a>
<span class="text-accent-blue inline-flex items-center cursor-pointer">
<slot></slot>
</a>
</span>
</template>

View File

@ -1,5 +1,5 @@
<template>
<h1 :id="parseId(id)" class="text-5xl font-thin mt-3 mb-8 first:pt-0 pt-2 relative sm:right-8 right-4">
<h1 :id="parseId(id)" class="text-5xl font-thin mt-3 mb-8 first:pt-0 pt-2">
<slot />
</h1>
</template>

View File

@ -1,5 +1,5 @@
<template>
<h2 :id="parseId(id)" class="text-4xl font-semibold mt-3 mb-6 ms-1 first:pt-0 pt-2 relative sm:right-8 right-4">
<h2 :id="parseId(id)" class="text-4xl font-semibold mt-3 mb-6 ms-1 first:pt-0 pt-2">
<slot />
</h2>
</template>

View File

@ -0,0 +1,5 @@
<template>
<span class="before:content-['#'] cursor-default bg-accent-blue bg-opacity-10 hover:bg-opacity-20 text-accent-blue text-sm px-1 ms-1 pb-0.5 rounded-full rounded-se-none border border-accent-blue border-opacity-30">
<slot></slot>
</span>
</template>