194 lines
5.1 KiB
TypeScript
194 lines
5.1 KiB
TypeScript
import { History, LayerObject, Line, Vec2 } from '../interfaces';
|
|
import { LayerObjectType } from '../types';
|
|
import { vec2Equals } from '../utils';
|
|
import { CanvasToolBase } from './tool-base';
|
|
|
|
export type LineToolType = 'line' | 'curve' | 'room';
|
|
export class LineTool extends CanvasToolBase<LineToolType> {
|
|
public name = 'line';
|
|
private drawingLine: Line | null = null;
|
|
public subTool: LineToolType = 'line';
|
|
|
|
drawControls(): void {
|
|
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();
|
|
}
|
|
|
|
mouseMoved(mouse: Vec2, offset: Vec2, mouseAbsolute: Vec2): void {
|
|
super.mouseMoved(mouse, offset, mouseAbsolute);
|
|
if (this.drawingLine) {
|
|
const lastSegment = this.drawingLine.segments.at(-1);
|
|
if (lastSegment) {
|
|
lastSegment.end = [...mouse];
|
|
}
|
|
}
|
|
this.renderer.draw();
|
|
}
|
|
|
|
mouseUp(moved?: boolean): void {
|
|
if (!moved) this.startLine();
|
|
}
|
|
|
|
enterPress(e: KeyboardEvent): void {
|
|
if (this.drawingLine && this.layer) {
|
|
if (this.subTool === 'room') {
|
|
this.drawingLine.closed = true;
|
|
}
|
|
this.drawingLine.segments.splice(this.drawingLine.segments.length - 1, 1);
|
|
this.history.appendToHistory([
|
|
{
|
|
object: this.layer,
|
|
property: 'contents',
|
|
value: [...this.layer.contents].filter(
|
|
(item) => item !== this.drawingLine
|
|
),
|
|
} as History<typeof this.layer>,
|
|
{
|
|
object: this,
|
|
property: 'selectedObjects',
|
|
value: [],
|
|
},
|
|
]);
|
|
this.emitEvent(
|
|
new CustomEvent('hpc:newobject', {
|
|
detail: this.drawingLine,
|
|
})
|
|
);
|
|
this.emitEvent(
|
|
new CustomEvent('hpc:update', {
|
|
detail: { event: 'newobject', object: this.drawingLine },
|
|
})
|
|
);
|
|
this.drawingLine = null;
|
|
this.renderer.draw();
|
|
}
|
|
}
|
|
|
|
escapePress(e: KeyboardEvent): void {
|
|
this.cancel();
|
|
}
|
|
|
|
selectionDeleted(): void {
|
|
this.drawingLine = null;
|
|
}
|
|
|
|
private cancel() {
|
|
if (!this.layer || !this.drawingLine) return;
|
|
const indexOf = this.layer.contents.indexOf(this.drawingLine);
|
|
if (indexOf > -1) {
|
|
this.layer.contents.splice(indexOf, 1);
|
|
}
|
|
this.drawingLine = null;
|
|
this.renderer.draw();
|
|
|
|
this.emitEvent(
|
|
new CustomEvent('hpc:update', {
|
|
detail: { event: 'draw-cancel' },
|
|
})
|
|
);
|
|
}
|
|
|
|
private getSequentialId() {
|
|
return (
|
|
this.renderer.layers.reduce(
|
|
(total, current) =>
|
|
current.contents.reduce(
|
|
(total2, current2) => current2.id + total2,
|
|
0
|
|
) + total,
|
|
0
|
|
) + 1
|
|
);
|
|
}
|
|
|
|
private startLine() {
|
|
if (!this.layer?.visible) return;
|
|
if (this.drawingLine) {
|
|
if (
|
|
vec2Equals(
|
|
this.mousePosition,
|
|
this.drawingLine.segments[0].start as Vec2
|
|
) ||
|
|
this.drawingLine.type === 'curve'
|
|
) {
|
|
if (this.drawingLine.type !== 'curve' && this.manager.autoClose) {
|
|
this.drawingLine.segments.splice(
|
|
this.drawingLine.segments.length - 1,
|
|
1
|
|
);
|
|
}
|
|
this.history.appendToHistory([
|
|
{
|
|
object: this.layer,
|
|
property: 'contents',
|
|
value: [...this.layer.contents].filter(
|
|
(item) => item !== this.drawingLine
|
|
),
|
|
} as History<typeof this.layer>,
|
|
{
|
|
object: this,
|
|
property: 'selectedObjects',
|
|
value: [],
|
|
},
|
|
]);
|
|
this.drawingLine.closed = this.manager.autoClose;
|
|
if (!this.manager.autoClose) {
|
|
this.drawingLine.lineCap = 'square';
|
|
}
|
|
this.canvas.dispatchEvent(
|
|
new CustomEvent('hpc:newobject', {
|
|
detail: this.drawingLine,
|
|
})
|
|
);
|
|
this.canvas.dispatchEvent(
|
|
new CustomEvent('hpc:update', {
|
|
detail: { event: 'newobject', object: this.drawingLine },
|
|
})
|
|
);
|
|
this.drawingLine = null;
|
|
return;
|
|
}
|
|
|
|
this.drawingLine.segments.push({
|
|
end: [...this.mousePosition],
|
|
});
|
|
return;
|
|
}
|
|
|
|
const newLineObject: Line = {
|
|
id: this.getSequentialId(),
|
|
name: this.defaultName,
|
|
type: this.subTool! as LayerObjectType,
|
|
visible: true,
|
|
selected: false,
|
|
closed: false,
|
|
color: this.manager.lastColor,
|
|
width: this.subTool === 'curve' ? 2 : this.manager.lastStrokeWidth,
|
|
segments: [
|
|
{
|
|
start: [...this.mousePosition],
|
|
end: [...this.mousePosition],
|
|
},
|
|
],
|
|
};
|
|
this.drawingLine = newLineObject;
|
|
this.layer.contents.unshift(newLineObject);
|
|
this.manager.selectObject(this.drawingLine);
|
|
this.canvas.dispatchEvent(
|
|
new CustomEvent('hpc:startdrawing', {
|
|
detail: newLineObject,
|
|
})
|
|
);
|
|
}
|
|
|
|
private get defaultName() {
|
|
let name = 'New ';
|
|
if (this.subTool === 'curve') return name + 'Curve';
|
|
if (this.subTool === 'room') return name + 'Room';
|
|
return name + 'Line';
|
|
}
|
|
}
|