cutting tool, line delete tool
This commit is contained in:
parent
cef1b80679
commit
452bcd5c01
@ -59,6 +59,8 @@ import {
|
||||
HomeIcon,
|
||||
ArrowsPointingOutIcon,
|
||||
ArrowDownOnSquareIcon,
|
||||
ScissorsIcon,
|
||||
XMarkIcon,
|
||||
} from '@heroicons/vue/24/outline';
|
||||
import { useSessionStorage } from '@vueuse/core';
|
||||
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) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<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
|
||||
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) {
|
||||
if (segment.start) {
|
||||
path.moveTo(...segment.start);
|
||||
}
|
||||
if ((segment as BezierSegment).startControl) {
|
||||
this.makeBezier(segment as BezierSegment, path);
|
||||
continue;
|
||||
|
@ -10,6 +10,7 @@ import {
|
||||
ToolEvent,
|
||||
Vec2,
|
||||
} from './interfaces';
|
||||
import { CutTool } from './tools/cut';
|
||||
import { LineTool } from './tools/line';
|
||||
import { MoveTool } from './tools/move';
|
||||
|
||||
@ -22,6 +23,7 @@ export class HousePlannerCanvasTools implements ICanvasToolMouseEvents {
|
||||
public tools: Record<string, ICanvasToolBase<unknown>> = {
|
||||
['move']: new MoveTool(this),
|
||||
['line']: new LineTool(this),
|
||||
['cut']: new CutTool(this),
|
||||
};
|
||||
public history = new HousePlannerCanvasHistory();
|
||||
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 class LineTool extends CanvasToolBase<LineToolType> {
|
||||
public name = 'line';
|
||||
public autoClose = false;
|
||||
private drawingLine: Line | null = null;
|
||||
public subTool: LineToolType = 'line';
|
||||
|
||||
@ -17,8 +18,6 @@ export class LineTool extends CanvasToolBase<LineToolType> {
|
||||
this.ctx.fill();
|
||||
}
|
||||
|
||||
mouseDown(targetObject?: LayerObject | undefined): void {}
|
||||
|
||||
mouseMoved(mouse: Vec2, offset: Vec2, mouseAbsolute: Vec2): void {
|
||||
super.mouseMoved(mouse, offset, mouseAbsolute);
|
||||
if (this.drawingLine) {
|
||||
@ -116,7 +115,7 @@ export class LineTool extends CanvasToolBase<LineToolType> {
|
||||
) ||
|
||||
this.drawingLine.type === 'curve'
|
||||
) {
|
||||
if (this.drawingLine.type !== 'curve') {
|
||||
if (this.drawingLine.type !== 'curve' && this.autoClose) {
|
||||
this.drawingLine.segments.splice(
|
||||
this.drawingLine.segments.length - 1,
|
||||
1
|
||||
@ -136,7 +135,7 @@ export class LineTool extends CanvasToolBase<LineToolType> {
|
||||
value: [],
|
||||
},
|
||||
]);
|
||||
this.drawingLine.closed = true;
|
||||
this.drawingLine.closed = this.autoClose;
|
||||
this.canvas.dispatchEvent(
|
||||
new CustomEvent('hpc:newobject', {
|
||||
detail: this.drawingLine,
|
||||
|
Loading…
Reference in New Issue
Block a user