2023-01-17 18:25:56 +00:00
|
|
|
<template>
|
2023-01-23 22:33:39 +00:00
|
|
|
<ThouCanvas
|
2023-01-17 22:42:21 +00:00
|
|
|
@mousedown.left="draw_start"
|
|
|
|
@mouseup.left="draw_finish"
|
2023-01-17 23:34:42 +00:00
|
|
|
@mousedown.right="drag_start"
|
|
|
|
@mouseup.right="drag_finish"
|
|
|
|
@mousemove="on_mousemove"
|
2023-01-17 23:56:07 +00:00
|
|
|
@click.middle="remove_rect"
|
2023-01-17 23:34:42 +00:00
|
|
|
@dblclick.left="remove_rect"
|
2023-01-17 18:25:56 +00:00
|
|
|
>
|
2023-01-25 11:39:58 +00:00
|
|
|
<SVGRect
|
2023-01-23 14:38:49 +00:00
|
|
|
v-for="(rect, index) in rectangles"
|
2023-01-24 23:17:10 +00:00
|
|
|
:key="`rect-${index}`"
|
2023-01-17 18:25:56 +00:00
|
|
|
:rectangle="rect"
|
|
|
|
/>
|
2023-01-31 14:21:06 +00:00
|
|
|
<SVGRect v-if="preview_visible" :focused="true" :rectangle="preview_rect" />
|
2023-01-23 22:33:39 +00:00
|
|
|
</ThouCanvas>
|
2023-01-17 18:25:56 +00:00
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
|
|
|
import { Vue, Options } from "vue-class-component";
|
2023-01-25 11:39:58 +00:00
|
|
|
import { Vector2D, Rectangle } from "../rects/rectangles";
|
|
|
|
import ThouCanvas from "../rects/ThouCanvas.vue";
|
|
|
|
import SVGRect from "../rects/SVGRect.vue";
|
2023-01-17 18:25:56 +00:00
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
enum CanvasState {
|
|
|
|
Idle,
|
|
|
|
Drawing,
|
|
|
|
Dragging,
|
|
|
|
}
|
|
|
|
|
2023-01-17 18:25:56 +00:00
|
|
|
@Options({
|
|
|
|
components: {
|
2023-01-23 22:33:39 +00:00
|
|
|
ThouCanvas,
|
2023-01-25 11:39:58 +00:00
|
|
|
SVGRect,
|
2023-01-17 18:25:56 +00:00
|
|
|
},
|
2023-02-01 16:53:24 +00:00
|
|
|
props: {
|
|
|
|
rectangles: Array,
|
|
|
|
},
|
|
|
|
emits: ["add_rect", "edit_rect", "remove_rect"],
|
2023-01-17 18:25:56 +00:00
|
|
|
})
|
2023-01-24 23:19:25 +00:00
|
|
|
export default class extends Vue {
|
2023-01-18 00:04:43 +00:00
|
|
|
private readonly min_rect_area = 300;
|
2023-01-31 14:21:06 +00:00
|
|
|
private state = CanvasState.Idle;
|
|
|
|
private preview_rect = new Rectangle();
|
2023-01-17 23:42:07 +00:00
|
|
|
private drag_rect?: Rectangle;
|
2023-01-17 23:34:42 +00:00
|
|
|
private drag_origin = new Vector2D();
|
2023-02-01 16:53:24 +00:00
|
|
|
private rectangles: Rectangle[] = [];
|
2023-01-17 18:25:56 +00:00
|
|
|
|
2023-01-17 23:34:42 +00:00
|
|
|
private get preview_visible(): boolean {
|
2023-01-31 14:21:06 +00:00
|
|
|
return this.state !== CanvasState.Idle;
|
2023-01-19 00:27:38 +00:00
|
|
|
}
|
|
|
|
|
2023-01-17 23:42:07 +00:00
|
|
|
private pop_rectangle(point: Vector2D): Rectangle | undefined {
|
2023-01-23 14:38:49 +00:00
|
|
|
const idx = this.rectangles.findIndex((rect) => rect.contains(point));
|
2023-01-17 23:42:07 +00:00
|
|
|
|
|
|
|
if (idx === -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-23 14:38:49 +00:00
|
|
|
return this.rectangles.splice(idx, 1)[0];
|
2023-01-17 23:34:42 +00:00
|
|
|
}
|
|
|
|
|
2023-01-23 22:33:39 +00:00
|
|
|
private draw_start(event: MouseEvent, point: Vector2D) {
|
2023-01-17 23:34:42 +00:00
|
|
|
if (this.preview_visible) {
|
2023-01-17 22:15:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
this.state = CanvasState.Drawing;
|
|
|
|
this.preview_rect = new Rectangle(point, point);
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
|
|
|
|
2023-01-17 23:34:42 +00:00
|
|
|
private draw_finish() {
|
2023-01-31 14:21:06 +00:00
|
|
|
if (this.state !== CanvasState.Drawing || this.preview_rect === undefined) {
|
2023-01-17 22:42:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
this.state = CanvasState.Idle;
|
2023-01-17 18:25:56 +00:00
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
if (this.preview_rect.area < this.min_rect_area) {
|
2023-01-17 23:50:25 +00:00
|
|
|
return;
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
2023-01-17 23:50:25 +00:00
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
this.rectangles.push(this.preview_rect);
|
2023-02-01 16:53:24 +00:00
|
|
|
this.$emit("add_rect", this.preview_rect);
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
|
|
|
|
2023-01-23 22:33:39 +00:00
|
|
|
private drag_start(event: MouseEvent, point: Vector2D) {
|
2023-01-17 23:34:42 +00:00
|
|
|
if (this.preview_visible) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-17 23:42:07 +00:00
|
|
|
this.drag_rect = this.pop_rectangle(point);
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2023-01-17 23:42:07 +00:00
|
|
|
if (this.drag_rect === undefined) {
|
2023-01-17 23:34:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
this.state = CanvasState.Dragging;
|
2023-01-17 23:34:42 +00:00
|
|
|
this.drag_origin = point;
|
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
this.preview_rect = this.drag_rect;
|
2023-01-17 23:34:42 +00:00
|
|
|
}
|
|
|
|
|
2023-01-17 23:42:07 +00:00
|
|
|
private drag_finish() {
|
2023-01-31 14:21:06 +00:00
|
|
|
if (
|
|
|
|
this.state !== CanvasState.Dragging ||
|
|
|
|
this.preview_rect === undefined
|
|
|
|
) {
|
2023-01-17 23:34:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
this.state = CanvasState.Idle;
|
|
|
|
this.rectangles.push(this.preview_rect);
|
2023-02-01 16:53:24 +00:00
|
|
|
this.$emit("edit_rect", this.drag_rect, this.preview_rect);
|
2023-01-17 23:34:42 +00:00
|
|
|
}
|
|
|
|
|
2023-01-23 22:33:39 +00:00
|
|
|
private on_mousemove(event: MouseEvent, point: Vector2D) {
|
2023-01-31 14:21:06 +00:00
|
|
|
if (this.preview_rect === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2023-01-31 14:21:06 +00:00
|
|
|
if (this.state === CanvasState.Drawing) {
|
|
|
|
this.preview_rect = this.preview_rect.update(undefined, point);
|
|
|
|
} else if (this.state === CanvasState.Dragging && this.drag_rect) {
|
|
|
|
const movement = point.minus(this.drag_origin);
|
|
|
|
this.preview_rect = this.drag_rect.move(movement);
|
2023-01-17 23:34:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-23 22:33:39 +00:00
|
|
|
private remove_rect(event: MouseEvent, point: Vector2D) {
|
2023-01-19 00:27:21 +00:00
|
|
|
if (this.preview_visible) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-23 22:33:39 +00:00
|
|
|
this.pop_rectangle(point);
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
2023-01-23 22:33:39 +00:00
|
|
|
* {
|
2023-01-17 18:25:56 +00:00
|
|
|
cursor: crosshair;
|
|
|
|
}
|
|
|
|
</style>
|