Add node resizing

This commit is contained in:
Peaceultime 2025-01-13 00:00:17 +01:00
parent 823f3d7730
commit 9439dd2d95
4 changed files with 70 additions and 19 deletions

View File

@ -1,5 +1,5 @@
<script lang="ts">
import type { Position } from '#shared/canvas.util';
import type { Box, Position } from '#shared/canvas.util';
type Direction = 'bottom' | 'top' | 'left' | 'right';
const rotation: Record<Direction, string> = {
top: "180",
@ -11,7 +11,7 @@ const rotation: Record<Direction, string> = {
interface ActionMap {
move: Position;
edit: string;
resize: string;
resize: Box;
remove: CanvasNode | undefined;
create: CanvasNode | undefined;
property: CanvasNode;
@ -211,6 +211,18 @@ function moveNode(index: number[], deltax: number, deltay: number)
addAction('move', actions);
}
function resizeNode(index: number[], deltax: number, deltay: number, deltaw: number, deltah: number)
{
const actions: HistoryAction<'resize'>[] = [];
for(const i of index)
{
const node = canvas.value.nodes[i];
actions.push({ element: i, from: { x: node.x - deltax, y: node.y - deltay, w: node.width - deltaw, h: node.height - deltah }, to: { x: node.x, y: node.y, w: node.width, h: node.height } });
}
addAction('resize', actions);
}
function selectNode(index: number)
{
if(focusing.value !== index)
@ -297,6 +309,15 @@ const undo = () => {
canvas.value.nodes[action.element].y = a.from.y;
break;
}
case 'resize':
{
const a = action as HistoryAction<'resize'>;
canvas.value.nodes[action.element].x = a.from.x;
canvas.value.nodes[action.element].y = a.from.y;
canvas.value.nodes[action.element].width = a.from.w;
canvas.value.nodes[action.element].height = a.from.h;
break;
}
case 'edit':
{
const a = action as HistoryAction<'edit'>;
@ -345,6 +366,15 @@ const redo = () => {
canvas.value.nodes[action.element].y = a.to.y;
break;
}
case 'resize':
{
const a = action as HistoryAction<'resize'>;
canvas.value.nodes[action.element].x = a.to.x;
canvas.value.nodes[action.element].y = a.to.y;
canvas.value.nodes[action.element].width = a.to.w;
canvas.value.nodes[action.element].height = a.to.h;
break;
}
case 'edit':
{
const a = action as HistoryAction<'edit'>;
@ -504,7 +534,7 @@ useShortcuts({
</div>
</div>
<div>
<CanvasNodeEditor v-for="(node, index) of canvas.nodes" :key="node.id" ref="nodes" :node="node" :index="index" :zoom="zoom" @select="selectNode" @edit="editNode" @move="(i, x, y) => moveNode([i], x, y)"/>
<CanvasNodeEditor v-for="(node, index) of canvas.nodes" :key="node.id" ref="nodes" :node="node" :index="index" :zoom="zoom" @select="selectNode" @edit="editNode" @move="(i, x, y) => moveNode([i], x, y)" @resize="(i, x, y, w, h) => resizeNode([i], x, y, w, h)" />
</div>
<template v-for="edge of edges">
<div :key="edge.id" v-if="edge.label" class="absolute z-10"

View File

@ -7,22 +7,22 @@
</div>
</div>
<div v-if="focusing">
<span @mousedown="(e) => resizeNode(e, 0, -1)" id="n " class="cursor-n-resize absolute -top-3 -right-3 -left-3 h-6 group">
<span @mousedown="(e) => dragEdge(e, 'top')" :class="[style.bg]" class="hidden group-hover:block absolute rounded-full border-2 border-light-70 dark:border-dark-70 w-6 h-6 -top-1.5 left-1/2 -translate-x-3"></span>
<span @mousedown.left="(e) => resizeNode(e, 0, 1, 0, -1)" id="n " class="cursor-n-resize absolute -top-3 -right-3 -left-3 h-6 group">
<span @mousedown.left="(e) => dragEdge(e, 'top')" :class="[style.bg]" class="hidden group-hover:block absolute rounded-full border-2 border-light-70 dark:border-dark-70 w-6 h-6 -top-1.5 left-1/2 -translate-x-3"></span>
</span> <!-- North -->
<span @mousedown="(e) => resizeNode(e, 0, 1)" id="s " class="cursor-s-resize absolute -bottom-3 -right-3 -left-3 h-6 group">
<span @mousedown="(e) => dragEdge(e, 'bottom')" :class="[style.bg]" class="hidden group-hover:block absolute rounded-full border-2 border-light-70 dark:border-dark-70 w-6 h-6 -bottom-1.5 left-1/2 -translate-x-3"></span>
<span @mousedown.left="(e) => resizeNode(e, 0, 0, 0, 1)" id="s " class="cursor-s-resize absolute -bottom-3 -right-3 -left-3 h-6 group">
<span @mousedown.left="(e) => dragEdge(e, 'bottom')" :class="[style.bg]" class="hidden group-hover:block absolute rounded-full border-2 border-light-70 dark:border-dark-70 w-6 h-6 -bottom-1.5 left-1/2 -translate-x-3"></span>
</span> <!-- South -->
<span @mousedown="(e) => resizeNode(e, 1, 0)" id="e " class="cursor-e-resize absolute -top-3 -bottom-3 -right-3 w-6 group">
<span @mousedown="(e) => dragEdge(e, 'right')" :class="[style.bg]" class="hidden group-hover:block absolute rounded-full border-2 border-light-70 dark:border-dark-70 w-6 h-6 -right-1.5 top-1/2 -translate-y-3"></span>
<span @mousedown.left="(e) => resizeNode(e, 0, 0, 1, 0)" id="e " class="cursor-e-resize absolute -top-3 -bottom-3 -right-3 w-6 group">
<span @mousedown.left="(e) => dragEdge(e, 'right')" :class="[style.bg]" class="hidden group-hover:block absolute rounded-full border-2 border-light-70 dark:border-dark-70 w-6 h-6 -right-1.5 top-1/2 -translate-y-3"></span>
</span> <!-- East -->
<span @mousedown="(e) => resizeNode(e, -1, 0)" id="w " class="cursor-w-resize absolute -top-3 -bottom-3 -left-3 w-6 group">
<span @mousedown="(e) => dragEdge(e, 'left')" :class="[style.bg]" class="hidden group-hover:block absolute rounded-full border-2 border-light-70 dark:border-dark-70 w-6 h-6 -left-1.5 top-1/2 -translate-y-3"></span>
<span @mousedown.left="(e) => resizeNode(e, 1, 0, -1, 0)" id="w " class="cursor-w-resize absolute -top-3 -bottom-3 -left-3 w-6 group">
<span @mousedown.left="(e) => dragEdge(e, 'left')" :class="[style.bg]" class="hidden group-hover:block absolute rounded-full border-2 border-light-70 dark:border-dark-70 w-6 h-6 -left-1.5 top-1/2 -translate-y-3"></span>
</span> <!-- West -->
<span @mousedown="(e) => resizeNode(e, 1, -1)" id="nw" class="cursor-nw-resize absolute -top-4 -left-4 w-8 h-8"></span> <!-- North West -->
<span @mousedown="(e) => resizeNode(e, -1, -1)" id="ne" class="cursor-ne-resize absolute -top-4 -right-4 w-8 h-8"></span> <!-- North East -->
<span @mousedown="(e) => resizeNode(e, -1, 1)" id="se" class="cursor-se-resize absolute -bottom-4 -right-4 w-8 h-8"></span> <!-- South East -->
<span @mousedown="(e) => resizeNode(e, 1, 1)" id="sw" class="cursor-sw-resize absolute -bottom-4 -left-4 w-8 h-8"></span> <!-- South West -->
<span @mousedown.left="(e) => resizeNode(e, 1, 1, -1, -1)" id="nw" class="cursor-nw-resize absolute -top-4 -left-4 w-8 h-8"></span> <!-- North West -->
<span @mousedown.left="(e) => resizeNode(e, 0, 1, 1, -1)" id="ne" class="cursor-ne-resize absolute -top-4 -right-4 w-8 h-8"></span> <!-- North East -->
<span @mousedown.left="(e) => resizeNode(e, 0, 0, 1, 1)" id="se" class="cursor-se-resize absolute -bottom-4 -right-4 w-8 h-8"></span> <!-- South East -->
<span @mousedown.left="(e) => resizeNode(e, 1, 0, -1, 1)" id="sw" class="cursor-sw-resize absolute -bottom-4 -left-4 w-8 h-8"></span> <!-- South West -->
</div>
</div>
<div v-else style="outline-style: solid;" :class="[style.border, style.outline, { '!outline-4': focusing }]" class="outline-0 transition-[outline-width] border-2 bg-light-20 dark:bg-dark-20 overflow-hidden contain-strict w-full h-full flex" >
@ -47,9 +47,8 @@ const { node, index, zoom } = defineProps<{
const emit = defineEmits<{
(e: 'select', index: number): void,
(e: 'edit', index: number): void,
(e: 'resize', index: number): void,
(e: 'move', index: number, x: number, y: number): void,
(e: 'resize', index: number, x: number, y: number): void,
(e: 'resize', index: number, x: number, y: number, w: number, h: number): void,
}>();
const dom = useTemplateRef('dom');
@ -73,9 +72,30 @@ function editNode(e: Event) {
dom.value?.removeEventListener('mousedown', dragstart);
emit('edit', index);
}
function resizeNode(e: Event, x: number, y: number) {
function resizeNode(e: MouseEvent, x: number, y: number, w: number, h: number) {
e.stopImmediatePropagation();
emit('resize', index);
const startx = node.x, starty = node.y, startw = node.width, starth = node.height;
const resizemove = (e: MouseEvent) => {
if(e.button !== 0)
return;
node.x += (e.movementX / zoom) * x;
node.y += (e.movementY / zoom) * y;
node.width += (e.movementX / zoom) * w;
node.height += (e.movementY / zoom) * h;
};
const resizeend = (e: MouseEvent) => {
if(e.button !== 0)
return;
emit('resize', index, node.x - startx, node.y - starty, node.width - startw, node.height - starth);
window.removeEventListener('mousemove', resizemove);
window.removeEventListener('mouseup', resizeend);
}
window.addEventListener('mousemove', resizemove);
window.addEventListener('mouseup', resizeend);
}
function dragEdge(e: Event, direction: Direction) {
e.stopImmediatePropagation();

Binary file not shown.

View File

@ -3,6 +3,7 @@ import { clamp } from "#shared/general.utils";
export type Direction = 'bottom' | 'top' | 'left' | 'right';
export type Position = { x: number, y: number };
export type Box = Position & { w: number, h: number };
export type Path = {
path: string;
from: Position;