122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
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();
|
|
}
|
|
}
|