Add node resizing
This commit is contained in:
parent
823f3d7730
commit
9439dd2d95
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Position } from '#shared/canvas.util';
|
import type { Box, Position } from '#shared/canvas.util';
|
||||||
type Direction = 'bottom' | 'top' | 'left' | 'right';
|
type Direction = 'bottom' | 'top' | 'left' | 'right';
|
||||||
const rotation: Record<Direction, string> = {
|
const rotation: Record<Direction, string> = {
|
||||||
top: "180",
|
top: "180",
|
||||||
|
|
@ -11,7 +11,7 @@ const rotation: Record<Direction, string> = {
|
||||||
interface ActionMap {
|
interface ActionMap {
|
||||||
move: Position;
|
move: Position;
|
||||||
edit: string;
|
edit: string;
|
||||||
resize: string;
|
resize: Box;
|
||||||
remove: CanvasNode | undefined;
|
remove: CanvasNode | undefined;
|
||||||
create: CanvasNode | undefined;
|
create: CanvasNode | undefined;
|
||||||
property: CanvasNode;
|
property: CanvasNode;
|
||||||
|
|
@ -211,6 +211,18 @@ function moveNode(index: number[], deltax: number, deltay: number)
|
||||||
|
|
||||||
addAction('move', actions);
|
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)
|
function selectNode(index: number)
|
||||||
{
|
{
|
||||||
if(focusing.value !== index)
|
if(focusing.value !== index)
|
||||||
|
|
@ -297,6 +309,15 @@ const undo = () => {
|
||||||
canvas.value.nodes[action.element].y = a.from.y;
|
canvas.value.nodes[action.element].y = a.from.y;
|
||||||
break;
|
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':
|
case 'edit':
|
||||||
{
|
{
|
||||||
const a = action as HistoryAction<'edit'>;
|
const a = action as HistoryAction<'edit'>;
|
||||||
|
|
@ -345,6 +366,15 @@ const redo = () => {
|
||||||
canvas.value.nodes[action.element].y = a.to.y;
|
canvas.value.nodes[action.element].y = a.to.y;
|
||||||
break;
|
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':
|
case 'edit':
|
||||||
{
|
{
|
||||||
const a = action as HistoryAction<'edit'>;
|
const a = action as HistoryAction<'edit'>;
|
||||||
|
|
@ -504,7 +534,7 @@ useShortcuts({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
<template v-for="edge of edges">
|
<template v-for="edge of edges">
|
||||||
<div :key="edge.id" v-if="edge.label" class="absolute z-10"
|
<div :key="edge.id" v-if="edge.label" class="absolute z-10"
|
||||||
|
|
|
||||||
|
|
@ -7,22 +7,22 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="focusing">
|
<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.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="(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) => 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> <!-- 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.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="(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) => 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> <!-- 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.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="(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) => 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> <!-- 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.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="(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) => 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> <!-- 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.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="(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.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="(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.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="(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, 0, -1, 1)" id="sw" class="cursor-sw-resize absolute -bottom-4 -left-4 w-8 h-8"></span> <!-- South West -->
|
||||||
</div>
|
</div>
|
||||||
</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" >
|
<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<{
|
const emit = defineEmits<{
|
||||||
(e: 'select', index: number): void,
|
(e: 'select', index: number): void,
|
||||||
(e: 'edit', index: number): void,
|
(e: 'edit', index: number): void,
|
||||||
(e: 'resize', index: number): void,
|
|
||||||
(e: 'move', index: number, x: number, y: 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');
|
const dom = useTemplateRef('dom');
|
||||||
|
|
@ -73,9 +72,30 @@ function editNode(e: Event) {
|
||||||
dom.value?.removeEventListener('mousedown', dragstart);
|
dom.value?.removeEventListener('mousedown', dragstart);
|
||||||
emit('edit', index);
|
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();
|
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) {
|
function dragEdge(e: Event, direction: Direction) {
|
||||||
e.stopImmediatePropagation();
|
e.stopImmediatePropagation();
|
||||||
|
|
|
||||||
BIN
db.sqlite-wal
BIN
db.sqlite-wal
Binary file not shown.
|
|
@ -3,6 +3,7 @@ import { clamp } from "#shared/general.utils";
|
||||||
|
|
||||||
export type Direction = 'bottom' | 'top' | 'left' | 'right';
|
export type Direction = 'bottom' | 'top' | 'left' | 'right';
|
||||||
export type Position = { x: number, y: number };
|
export type Position = { x: number, y: number };
|
||||||
|
export type Box = Position & { w: number, h: number };
|
||||||
export type Path = {
|
export type Path = {
|
||||||
path: string;
|
path: string;
|
||||||
from: Position;
|
from: Position;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue