advent22/ui/src/components/editor/RectangleCanvas.vue

154 lines
3.3 KiB
Vue
Raw Normal View History

2023-01-17 18:25:56 +00:00
<template>
2023-09-07 01:17:14 +00:00
<ThouCanvas
@mousedown.left="draw_start"
@mouseup.left="draw_finish"
@mousedown.right="drag_start"
@mouseup.right="drag_finish"
@mousemove="on_mousemove"
@click.middle="remove_rect"
@dblclick.left="remove_rect"
>
<SVGRect
v-for="(rect, index) in rectangles"
:key="`rect-${index}`"
:rectangle="rect"
/>
2023-01-31 14:21:06 +00:00
<SVGRect v-if="preview_visible" :focused="true" :rectangle="preview_rect" />
</ThouCanvas>
2023-01-17 18:25:56 +00:00
</template>
<script lang="ts">
2023-09-07 02:08:56 +00:00
import { Rectangle } from "@/lib/rectangle";
import { Vector2D } from "@/lib/vector2d";
2023-09-06 16:25:35 +00:00
import { Options, Vue } from "vue-class-component";
2023-09-07 02:08:56 +00:00
2023-09-10 01:59:19 +00:00
import SVGRect from "../calendar/SVGRect.vue";
import ThouCanvas from "../calendar/ThouCanvas.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: {
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,
},
2023-02-02 14:12:44 +00:00
emits: ["draw", "drag", "remove"],
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;
2023-09-06 16:25:35 +00:00
public 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-09-06 16:25:35 +00:00
public rectangles!: Rectangle[];
2023-01-17 18:25:56 +00:00
2023-09-06 16:25:35 +00:00
public 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-09-06 16:25:35 +00:00
public draw_start(event: MouseEvent, point: Vector2D) {
2023-01-17 23:34:42 +00:00
if (this.preview_visible) {
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-09-06 16:25:35 +00:00
public 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-02 14:12:44 +00:00
this.$emit("draw", this.preview_rect);
2023-01-17 18:25:56 +00:00
}
2023-09-06 16:25:35 +00:00
public 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-09-06 16:25:35 +00:00
public 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-02 14:12:44 +00:00
this.$emit("drag", this.drag_rect, this.preview_rect);
2023-01-17 23:34:42 +00:00
}
2023-09-06 16:25:35 +00:00
public 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-09-06 16:25:35 +00:00
public remove_rect(event: MouseEvent, point: Vector2D) {
2023-01-19 00:27:21 +00:00
if (this.preview_visible) {
return;
}
2023-02-02 14:12:44 +00:00
const rect = this.pop_rectangle(point);
if (rect === undefined) {
return;
}
this.$emit("remove", rect);
2023-01-17 18:25:56 +00:00
}
}
</script>
<style scoped>
* {
2023-01-17 18:25:56 +00:00
cursor: crosshair;
}
2023-09-07 01:17:14 +00:00
</style>