coordinate transformation into ThouCanvas

This commit is contained in:
Jörn-Michael Miehe 2023-01-23 22:33:39 +00:00
parent 1ca9ca6577
commit dde8f172dc
2 changed files with 84 additions and 32 deletions

View file

@ -1,11 +1,7 @@
<template> <template>
<svg <ThouCanvas
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1000 1000"
preserveAspectRatio="none"
@mousedown.left="draw_start" @mousedown.left="draw_start"
@mouseup.left="draw_finish" @mouseup.left="draw_finish"
@contextmenu.prevent
@mousedown.right="drag_start" @mousedown.right="drag_start"
@mouseup.right="drag_finish" @mouseup.right="drag_finish"
@mousemove="on_mousemove" @mousemove="on_mousemove"
@ -22,29 +18,18 @@
:focused="true" :focused="true"
:rectangle="preview_rectangle" :rectangle="preview_rectangle"
/> />
</svg> </ThouCanvas>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Vue, Options } from "vue-class-component"; import { Vue, Options } from "vue-class-component";
import { Vector2D, Rectangle } from "./rectangles"; import { Vector2D, Rectangle } from "./rectangles";
import ThouCanvas from "./ThouCanvas.vue";
import Rect from "./Rect.vue"; import Rect from "./Rect.vue";
function get_event_thous(event: MouseEvent): Vector2D {
if (event.currentTarget === null) {
return new Vector2D();
}
const target = event.currentTarget as Element;
return new Vector2D(
Math.round((event.offsetX / target.clientWidth) * 1000),
Math.round((event.offsetY / target.clientHeight) * 1000)
);
}
@Options({ @Options({
components: { components: {
ThouCanvas,
Rect, Rect,
}, },
}) })
@ -76,14 +61,14 @@ export default class RectPad extends Vue {
return this.rectangles.splice(idx, 1)[0]; return this.rectangles.splice(idx, 1)[0];
} }
private draw_start(event: MouseEvent) { private draw_start(event: MouseEvent, point: Vector2D) {
if (this.preview_visible) { if (this.preview_visible) {
return; return;
} }
this.drawing = true; this.drawing = true;
this.preview_corner1 = get_event_thous(event); this.preview_corner1 = point;
this.preview_corner2 = get_event_thous(event); this.preview_corner2 = point;
} }
private draw_finish() { private draw_finish() {
@ -100,12 +85,11 @@ export default class RectPad extends Vue {
this.rectangles.push(this.preview_rectangle); this.rectangles.push(this.preview_rectangle);
} }
private drag_start(event: MouseEvent) { private drag_start(event: MouseEvent, point: Vector2D) {
if (this.preview_visible) { if (this.preview_visible) {
return; return;
} }
const point = get_event_thous(event);
this.drag_rect = this.pop_rectangle(point); this.drag_rect = this.pop_rectangle(point);
if (this.drag_rect === undefined) { if (this.drag_rect === undefined) {
@ -128,31 +112,29 @@ export default class RectPad extends Vue {
this.rectangles.push(this.preview_rectangle); this.rectangles.push(this.preview_rectangle);
} }
private on_mousemove(event: MouseEvent) { private on_mousemove(event: MouseEvent, point: Vector2D) {
if (this.drawing) { if (this.drawing) {
this.preview_corner2 = get_event_thous(event); this.preview_corner2 = point;
} else if (this.dragging && this.drag_rect) { } else if (this.dragging && this.drag_rect) {
const movement = get_event_thous(event).minus(this.drag_origin); const movement = point.minus(this.drag_origin);
this.preview_corner1 = this.drag_rect.origin.plus(movement); this.preview_corner1 = this.drag_rect.origin.plus(movement);
this.preview_corner2 = this.drag_rect.corner.plus(movement); this.preview_corner2 = this.drag_rect.corner.plus(movement);
} }
} }
private remove_rect(event: MouseEvent) { private remove_rect(event: MouseEvent, point: Vector2D) {
if (this.preview_visible) { if (this.preview_visible) {
return; return;
} }
this.pop_rectangle(get_event_thous(event)); this.pop_rectangle(point);
} }
} }
</script> </script>
<style scoped> <style scoped>
svg { * {
cursor: crosshair; cursor: crosshair;
height: 100%;
width: 100%;
} }
</style> </style>

View file

@ -0,0 +1,70 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1000 1000"
preserveAspectRatio="none"
@contextmenu.prevent
@mousedown="transform_mouse_event"
@mousemove="transform_mouse_event"
@mouseup="transform_mouse_event"
@click="transform_mouse_event"
@dblclick="transform_mouse_event"
>
<slot name="default" />
</svg>
</template>
<script lang="ts">
import { Vue, Options } from "vue-class-component";
import { Vector2D } from "./rectangles";
function get_event_thous(event: MouseEvent): Vector2D {
if (event.currentTarget === null) {
return new Vector2D();
}
const target = event.currentTarget as Element;
return new Vector2D(
Math.round((event.offsetX / target.clientWidth) * 1000),
Math.round((event.offsetY / target.clientHeight) * 1000)
);
}
function mouse_event_validator(event: object, point: object): boolean {
if (!(event instanceof MouseEvent)) {
console.warn(event, "is not a MouseEvent!");
return false;
}
if (!(point instanceof Vector2D)) {
console.warn(point, "is not a Vector2D!");
return false;
}
return true;
}
@Options({
emits: {
mousedown: mouse_event_validator,
mouseup: mouse_event_validator,
mousemove: mouse_event_validator,
click: mouse_event_validator,
dblclick: mouse_event_validator,
},
})
export default class ThouCanvas extends Vue {
private transform_mouse_event(event: MouseEvent) {
const point = get_event_thous(event);
this.$emit(event.type, event, point);
}
}
</script>
<style scoped>
svg {
height: 100%;
width: 100%;
}
</style>