cutting tool, line delete tool
This commit is contained in:
parent
cef1b80679
commit
452bcd5c01
@ -59,6 +59,8 @@ import {
|
|||||||
HomeIcon,
|
HomeIcon,
|
||||||
ArrowsPointingOutIcon,
|
ArrowsPointingOutIcon,
|
||||||
ArrowDownOnSquareIcon,
|
ArrowDownOnSquareIcon,
|
||||||
|
ScissorsIcon,
|
||||||
|
XMarkIcon,
|
||||||
} from '@heroicons/vue/24/outline';
|
} from '@heroicons/vue/24/outline';
|
||||||
import { useSessionStorage } from '@vueuse/core';
|
import { useSessionStorage } from '@vueuse/core';
|
||||||
import { onMounted, ref, shallowRef } from 'vue';
|
import { onMounted, ref, shallowRef } from 'vue';
|
||||||
@ -139,6 +141,20 @@ const toolbar: ToolbarTool[] = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Cut',
|
||||||
|
icon: ScissorsIcon,
|
||||||
|
tool: 'cut',
|
||||||
|
subTool: 'cut',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
title: 'Cut Segment',
|
||||||
|
icon: XMarkIcon,
|
||||||
|
tool: 'cut',
|
||||||
|
subTool: 'remove-segment',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const selectTool = (newTool?: string, newSubTool?: string) => {
|
const selectTool = (newTool?: string, newSubTool?: string) => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="absolute bottom-0 z-10 w-screen max-w-xs rounded-lg bg-white lg:left-1/2 lg:ml-0 lg:-translate-x-1/2"
|
class="absolute bottom-0 z-10 w-screen max-w-md rounded-lg bg-white lg:left-1/2 lg:ml-0 lg:-translate-x-1/2"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex flex-1 flex-row items-center justify-center space-x-2 py-4 px-4 shadow-lg ring-1 ring-black ring-opacity-5"
|
class="flex flex-1 flex-row items-center justify-center space-x-2 py-4 px-4 shadow-lg ring-1 ring-black ring-opacity-5"
|
||||||
|
@ -129,6 +129,9 @@ export class HousePlannerCanvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const segment of segments) {
|
for (const segment of segments) {
|
||||||
|
if (segment.start) {
|
||||||
|
path.moveTo(...segment.start);
|
||||||
|
}
|
||||||
if ((segment as BezierSegment).startControl) {
|
if ((segment as BezierSegment).startControl) {
|
||||||
this.makeBezier(segment as BezierSegment, path);
|
this.makeBezier(segment as BezierSegment, path);
|
||||||
continue;
|
continue;
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
ToolEvent,
|
ToolEvent,
|
||||||
Vec2,
|
Vec2,
|
||||||
} from './interfaces';
|
} from './interfaces';
|
||||||
|
import { CutTool } from './tools/cut';
|
||||||
import { LineTool } from './tools/line';
|
import { LineTool } from './tools/line';
|
||||||
import { MoveTool } from './tools/move';
|
import { MoveTool } from './tools/move';
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ export class HousePlannerCanvasTools implements ICanvasToolMouseEvents {
|
|||||||
public tools: Record<string, ICanvasToolBase<unknown>> = {
|
public tools: Record<string, ICanvasToolBase<unknown>> = {
|
||||||
['move']: new MoveTool(this),
|
['move']: new MoveTool(this),
|
||||||
['line']: new LineTool(this),
|
['line']: new LineTool(this),
|
||||||
|
['cut']: new CutTool(this),
|
||||||
};
|
};
|
||||||
public history = new HousePlannerCanvasHistory();
|
public history = new HousePlannerCanvasHistory();
|
||||||
public lastStrokeWidth = 16;
|
public lastStrokeWidth = 16;
|
||||||
|
121
src/modules/house-planner/tools/cut.ts
Normal file
121
src/modules/house-planner/tools/cut.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import {
|
||||||
|
BezierSegment,
|
||||||
|
LayerObject,
|
||||||
|
Line,
|
||||||
|
LineSegment,
|
||||||
|
Vec2,
|
||||||
|
} from '../interfaces';
|
||||||
|
import { CanvasToolBase } from './tool-base';
|
||||||
|
|
||||||
|
export type CutToolType = 'cut' | 'remove-segment';
|
||||||
|
export class CutTool extends CanvasToolBase<CutToolType> {
|
||||||
|
public name = 'cut';
|
||||||
|
public subTool: CutToolType | undefined = 'cut';
|
||||||
|
|
||||||
|
mouseMoved(mouse: Vec2, offset: Vec2, mouseAbsolute: Vec2) {
|
||||||
|
super.mouseMoved(mouse, offset, mouseAbsolute);
|
||||||
|
this.renderer.draw();
|
||||||
|
}
|
||||||
|
mouseDown(targetObject?: LayerObject | undefined): void {
|
||||||
|
if (
|
||||||
|
!targetObject ||
|
||||||
|
targetObject.type === 'curve' ||
|
||||||
|
targetObject.type === 'object'
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
const line = targetObject as Line;
|
||||||
|
const segment = this.manager.getMousedLineSegment(line);
|
||||||
|
if (!segment) return;
|
||||||
|
const segmentIndex = line.segments.indexOf(segment);
|
||||||
|
|
||||||
|
if (this.subTool === 'remove-segment') {
|
||||||
|
const nextSegment = line.segments[segmentIndex + 1];
|
||||||
|
if (!nextSegment) return;
|
||||||
|
if (segment.start) {
|
||||||
|
nextSegment.start = segment.start;
|
||||||
|
line.segments.splice(segmentIndex, 1);
|
||||||
|
} else {
|
||||||
|
nextSegment.start = segment.end;
|
||||||
|
line.segments.splice(segmentIndex, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const currentEnd: Vec2 = [...segment.end];
|
||||||
|
segment.end = [...this.mousePosition];
|
||||||
|
line.segments.splice(segmentIndex + 1, 0, { end: currentEnd });
|
||||||
|
}
|
||||||
|
this.renderer.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawBezierControls(bezier: BezierSegment, previousEnd: Vec2) {
|
||||||
|
const [cp1x, cp1y] = bezier.startControl;
|
||||||
|
const [cp2x, cp2y] = bezier.endControl;
|
||||||
|
const [endx, endy] = bezier.end;
|
||||||
|
const [prevx, prevy] = previousEnd;
|
||||||
|
this.ctx.fillStyle = '#00ddffaa';
|
||||||
|
this.ctx.strokeStyle = '#00ddffaa';
|
||||||
|
this.ctx.lineWidth = 2;
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.arc(cp1x, cp1y, this.manager.selectError / 2, 0, 2 * Math.PI);
|
||||||
|
this.ctx.fill();
|
||||||
|
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.arc(cp2x, cp2y, this.manager.selectError / 2, 0, 2 * Math.PI);
|
||||||
|
this.ctx.fill();
|
||||||
|
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.moveTo(cp1x, cp1y);
|
||||||
|
this.ctx.lineTo(prevx, prevy);
|
||||||
|
this.ctx.stroke();
|
||||||
|
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.moveTo(cp2x, cp2y);
|
||||||
|
this.ctx.lineTo(endx, endy);
|
||||||
|
this.ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawLineControls(line: LineSegment, previousEnd: Vec2) {
|
||||||
|
const [endx, endy] = line.end;
|
||||||
|
this.ctx.fillStyle = '#00ddffaa';
|
||||||
|
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.arc(endx, endy, this.manager.selectError / 2, 0, 2 * Math.PI);
|
||||||
|
this.ctx.fill();
|
||||||
|
|
||||||
|
if (line.start) {
|
||||||
|
const [startx, starty] = line.start;
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.arc(
|
||||||
|
startx,
|
||||||
|
starty,
|
||||||
|
this.manager.selectError / 2,
|
||||||
|
0,
|
||||||
|
2 * Math.PI
|
||||||
|
);
|
||||||
|
this.ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawControls(): void {
|
||||||
|
for (const object of this.manager.selectedObjects) {
|
||||||
|
const line = object as Line;
|
||||||
|
if (line.segments && line.render) {
|
||||||
|
let lastSegment = null;
|
||||||
|
for (const segment of line.segments) {
|
||||||
|
const bezier = segment as BezierSegment;
|
||||||
|
const previousPoint = lastSegment ? lastSegment.end : segment.start!;
|
||||||
|
if (bezier.startControl && bezier.endControl) {
|
||||||
|
this.drawBezierControls(bezier, previousPoint);
|
||||||
|
}
|
||||||
|
this.drawLineControls(segment, previousPoint);
|
||||||
|
lastSegment = segment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [mx, my] = this.mousePosition;
|
||||||
|
this.ctx.fillStyle = '#00ddffaa';
|
||||||
|
this.ctx.beginPath();
|
||||||
|
this.ctx.arc(mx, my, this.manager.selectError / 2, 0, 2 * Math.PI);
|
||||||
|
this.ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import { CanvasToolBase } from './tool-base';
|
|||||||
export type LineToolType = 'line' | 'curve' | 'room';
|
export type LineToolType = 'line' | 'curve' | 'room';
|
||||||
export class LineTool extends CanvasToolBase<LineToolType> {
|
export class LineTool extends CanvasToolBase<LineToolType> {
|
||||||
public name = 'line';
|
public name = 'line';
|
||||||
|
public autoClose = false;
|
||||||
private drawingLine: Line | null = null;
|
private drawingLine: Line | null = null;
|
||||||
public subTool: LineToolType = 'line';
|
public subTool: LineToolType = 'line';
|
||||||
|
|
||||||
@ -17,8 +18,6 @@ export class LineTool extends CanvasToolBase<LineToolType> {
|
|||||||
this.ctx.fill();
|
this.ctx.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseDown(targetObject?: LayerObject | undefined): void {}
|
|
||||||
|
|
||||||
mouseMoved(mouse: Vec2, offset: Vec2, mouseAbsolute: Vec2): void {
|
mouseMoved(mouse: Vec2, offset: Vec2, mouseAbsolute: Vec2): void {
|
||||||
super.mouseMoved(mouse, offset, mouseAbsolute);
|
super.mouseMoved(mouse, offset, mouseAbsolute);
|
||||||
if (this.drawingLine) {
|
if (this.drawingLine) {
|
||||||
@ -116,7 +115,7 @@ export class LineTool extends CanvasToolBase<LineToolType> {
|
|||||||
) ||
|
) ||
|
||||||
this.drawingLine.type === 'curve'
|
this.drawingLine.type === 'curve'
|
||||||
) {
|
) {
|
||||||
if (this.drawingLine.type !== 'curve') {
|
if (this.drawingLine.type !== 'curve' && this.autoClose) {
|
||||||
this.drawingLine.segments.splice(
|
this.drawingLine.segments.splice(
|
||||||
this.drawingLine.segments.length - 1,
|
this.drawingLine.segments.length - 1,
|
||||||
1
|
1
|
||||||
@ -136,7 +135,7 @@ export class LineTool extends CanvasToolBase<LineToolType> {
|
|||||||
value: [],
|
value: [],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
this.drawingLine.closed = true;
|
this.drawingLine.closed = this.autoClose;
|
||||||
this.canvas.dispatchEvent(
|
this.canvas.dispatchEvent(
|
||||||
new CustomEvent('hpc:newobject', {
|
new CustomEvent('hpc:newobject', {
|
||||||
detail: this.drawingLine,
|
detail: this.drawingLine,
|
||||||
|
Loading…
Reference in New Issue
Block a user