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"
|
|
|
|
|
>
|
2023-10-27 15:04:07 +00:00
|
|
|
<CalendarDoor
|
2025-12-04 18:51:57 +00:00
|
|
|
v-for="(door, index) in model"
|
2023-10-27 15:04:07 +00:00
|
|
|
:key="`door-${index}`"
|
|
|
|
|
:door="door"
|
2023-11-05 23:51:16 +00:00
|
|
|
force_visible
|
2023-09-07 01:17:14 +00:00
|
|
|
/>
|
2023-09-20 22:04:47 +00:00
|
|
|
<SVGRect
|
2025-12-12 16:50:19 +00:00
|
|
|
v-if="preview_visible"
|
2023-09-20 22:04:47 +00:00
|
|
|
variant="success"
|
2025-12-04 18:51:57 +00:00
|
|
|
:rectangle="preview"
|
2023-11-05 23:51:16 +00:00
|
|
|
visible
|
2023-09-20 22:04:47 +00:00
|
|
|
/>
|
2023-01-23 22:33:39 +00:00
|
|
|
</ThouCanvas>
|
2023-01-17 18:25:56 +00:00
|
|
|
</template>
|
|
|
|
|
|
2025-12-04 18:51:57 +00:00
|
|
|
<script setup lang="ts">
|
2024-08-23 16:38:04 +00:00
|
|
|
import { Door } from "@/lib/rects/door";
|
|
|
|
|
import { Rectangle } from "@/lib/rects/rectangle";
|
|
|
|
|
import { Vector2D } from "@/lib/rects/vector2d";
|
2025-12-12 16:50:19 +00:00
|
|
|
import { computed, ref } from "vue";
|
2023-09-07 02:08:56 +00:00
|
|
|
|
2025-12-28 01:24:31 +00:00
|
|
|
import { VueLike } from "@/lib/helpers";
|
2023-10-27 15:04:07 +00:00
|
|
|
import CalendarDoor from "../calendar/CalendarDoor.vue";
|
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
|
|
|
|
2025-12-04 18:51:57 +00:00
|
|
|
type CanvasState =
|
|
|
|
|
| { kind: "idle" }
|
|
|
|
|
| { kind: "drawing" }
|
2025-12-28 01:24:31 +00:00
|
|
|
| { kind: "dragging"; door: VueLike<Door>; origin: Vector2D };
|
2023-01-31 14:21:06 +00:00
|
|
|
|
2025-12-28 01:24:31 +00:00
|
|
|
const model = defineModel<VueLike<Door>[]>({ required: true });
|
2023-01-19 00:27:38 +00:00
|
|
|
|
2025-12-04 18:51:57 +00:00
|
|
|
const MIN_RECT_AREA = 300;
|
2025-12-07 03:28:00 +00:00
|
|
|
const state = ref<CanvasState>({ kind: "idle" });
|
|
|
|
|
const preview = ref(new Rectangle());
|
2023-01-17 23:42:07 +00:00
|
|
|
|
2025-12-12 16:50:19 +00:00
|
|
|
const preview_visible = computed(() => state.value.kind !== "idle");
|
2025-12-05 02:12:33 +00:00
|
|
|
|
2025-12-28 01:24:31 +00:00
|
|
|
function pop_door(point: Vector2D): VueLike<Door> | undefined {
|
2025-12-04 18:51:57 +00:00
|
|
|
const idx = model.value.findIndex((rect) => rect.position.contains(point));
|
2023-01-17 23:42:07 +00:00
|
|
|
|
2025-12-04 18:51:57 +00:00
|
|
|
if (idx === -1) {
|
|
|
|
|
return;
|
2023-01-17 23:34:42 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-04 18:51:57 +00:00
|
|
|
return model.value.splice(idx, 1)[0];
|
|
|
|
|
}
|
2023-01-17 22:15:12 +00:00
|
|
|
|
2025-12-28 16:35:10 +00:00
|
|
|
function draw_start(event: MouseEvent, point: Vector2D): void {
|
2025-12-12 16:50:19 +00:00
|
|
|
if (preview_visible.value) {
|
2025-12-04 18:51:57 +00:00
|
|
|
return;
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-07 03:28:00 +00:00
|
|
|
preview.value = new Rectangle(point, point);
|
|
|
|
|
state.value = { kind: "drawing" };
|
2025-12-04 18:51:57 +00:00
|
|
|
}
|
2023-01-17 22:42:21 +00:00
|
|
|
|
2025-12-28 16:35:10 +00:00
|
|
|
function draw_finish(): void {
|
2025-12-12 16:50:19 +00:00
|
|
|
if (state.value.kind !== "drawing") {
|
2025-12-04 18:51:57 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-12 16:50:19 +00:00
|
|
|
if (preview.value.area >= MIN_RECT_AREA) {
|
2025-12-25 19:56:25 +00:00
|
|
|
model.value.push(new Door(preview.value));
|
2025-12-12 16:50:19 +00:00
|
|
|
}
|
2023-01-17 18:25:56 +00:00
|
|
|
|
2025-12-07 03:28:00 +00:00
|
|
|
state.value = { kind: "idle" };
|
2025-12-04 18:51:57 +00:00
|
|
|
}
|
2023-01-17 23:50:25 +00:00
|
|
|
|
2025-12-28 16:35:10 +00:00
|
|
|
function drag_start(event: MouseEvent, point: Vector2D): void {
|
2025-12-12 16:50:19 +00:00
|
|
|
if (preview_visible.value) {
|
2025-12-04 18:51:57 +00:00
|
|
|
return;
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-04 18:51:57 +00:00
|
|
|
const drag_door = pop_door(point);
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2025-12-04 18:51:57 +00:00
|
|
|
if (drag_door === undefined) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2025-12-07 03:28:00 +00:00
|
|
|
preview.value = drag_door.position;
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2025-12-07 03:28:00 +00:00
|
|
|
state.value = { kind: "dragging", door: drag_door, origin: point };
|
2025-12-04 18:51:57 +00:00
|
|
|
}
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2025-12-28 16:35:10 +00:00
|
|
|
function drag_finish(): void {
|
2025-12-07 03:28:00 +00:00
|
|
|
if (state.value.kind !== "dragging") {
|
2025-12-04 18:51:57 +00:00
|
|
|
return;
|
2023-01-17 23:34:42 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-25 19:56:25 +00:00
|
|
|
model.value.push(new Door(preview.value, state.value.door.day));
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2025-12-07 03:28:00 +00:00
|
|
|
state.value = { kind: "idle" };
|
2025-12-04 18:51:57 +00:00
|
|
|
}
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2025-12-28 16:35:10 +00:00
|
|
|
function on_mousemove(event: MouseEvent, point: Vector2D): void {
|
2025-12-07 03:28:00 +00:00
|
|
|
if (state.value.kind === "drawing") {
|
|
|
|
|
preview.value = preview.value.update(undefined, point);
|
|
|
|
|
} else if (state.value.kind === "dragging") {
|
|
|
|
|
const movement = point.minus(state.value.origin);
|
|
|
|
|
preview.value = state.value.door.position.move(movement);
|
2023-01-17 23:34:42 +00:00
|
|
|
}
|
2025-12-04 18:51:57 +00:00
|
|
|
}
|
2023-01-17 23:34:42 +00:00
|
|
|
|
2025-12-28 16:35:10 +00:00
|
|
|
function remove_rect(event: MouseEvent, point: Vector2D): void {
|
2025-12-12 16:50:19 +00:00
|
|
|
if (preview_visible.value) {
|
2025-12-04 18:51:57 +00:00
|
|
|
return;
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
2025-12-04 18:51:57 +00:00
|
|
|
|
|
|
|
|
pop_door(point);
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
2023-11-09 17:51:56 +00:00
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
svg {
|
2023-01-17 18:25:56 +00:00
|
|
|
cursor: crosshair;
|
2023-11-09 17:51:56 +00:00
|
|
|
|
|
|
|
|
* {
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
2023-01-17 18:25:56 +00:00
|
|
|
}
|
2023-09-07 01:17:14 +00:00
|
|
|
</style>
|