"preview" rectangle
This commit is contained in:
parent
f0db5e57ec
commit
e1bd10980c
1 changed files with 179 additions and 3 deletions
|
@ -1,9 +1,185 @@
|
|||
<template>
|
||||
<img src="@/assets/adventskalender.png" />
|
||||
<div id="container" ref="container">
|
||||
<img id="background" ref="background" src="@/assets/adventskalender.png" />
|
||||
<svg
|
||||
id="drawpad"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 1000 1000"
|
||||
preserveAspectRatio="none"
|
||||
@mousedown="on_mousedown"
|
||||
@mousemove="on_mousemove"
|
||||
@mouseup="on_mouseup"
|
||||
>
|
||||
<rect
|
||||
v-if="preview_state.visible"
|
||||
id="preview"
|
||||
:x="preview_rectangle.origin.x"
|
||||
:y="preview_rectangle.origin.y"
|
||||
:width="preview_rectangle.size.x"
|
||||
:height="preview_rectangle.size.y"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Vue } from "vue-class-component";
|
||||
|
||||
export default class CalendarImage extends Vue {}
|
||||
</script>
|
||||
class Vector2D {
|
||||
public x: number;
|
||||
public y: number;
|
||||
|
||||
constructor(x = 0, y = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public copy(): Vector2D {
|
||||
return new Vector2D(this.x, this.y);
|
||||
}
|
||||
|
||||
public minus(other: Vector2D): Vector2D {
|
||||
return new Vector2D(this.x - other.x, this.y - other.y);
|
||||
}
|
||||
}
|
||||
|
||||
class Rectangle {
|
||||
private origin: Vector2D;
|
||||
private size: Vector2D;
|
||||
|
||||
constructor(corner1: Vector2D, corner2: Vector2D) {
|
||||
this.origin = corner1.copy();
|
||||
this.size = corner2.minus(corner1);
|
||||
}
|
||||
|
||||
public normalize() {
|
||||
if (this.size.x < 0) {
|
||||
this.size.x *= -1;
|
||||
this.origin.x -= this.size.x;
|
||||
}
|
||||
|
||||
if (this.size.y < 0) {
|
||||
this.size.y *= -1;
|
||||
this.origin.y -= this.size.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PreviewState {
|
||||
public visible = false;
|
||||
private down_location = new Vector2D();
|
||||
private move_location = new Vector2D();
|
||||
|
||||
public mouse_down(location: Vector2D) {
|
||||
this.down_location = location;
|
||||
this.move_location = location;
|
||||
}
|
||||
|
||||
public mouse_move(location: Vector2D) {
|
||||
this.move_location = location;
|
||||
}
|
||||
|
||||
public get_rect(): Rectangle {
|
||||
return new Rectangle(this.down_location, this.move_location);
|
||||
}
|
||||
}
|
||||
|
||||
function get_event_thous(event: MouseEvent): Vector2D {
|
||||
if (event.currentTarget === null) {
|
||||
return new Vector2D();
|
||||
}
|
||||
|
||||
let target = event.currentTarget as Element;
|
||||
|
||||
return new Vector2D(
|
||||
Math.round((event.offsetX / target.clientWidth) * 1000),
|
||||
Math.round((event.offsetY / target.clientHeight) * 1000)
|
||||
);
|
||||
}
|
||||
|
||||
export default class CalendarImage extends Vue {
|
||||
// "preview" rectangle on click-drag
|
||||
|
||||
private preview_state = new PreviewState();
|
||||
|
||||
private on_mousedown(event: MouseEvent) {
|
||||
this.preview_state.visible = true;
|
||||
this.preview_state.mouse_down(get_event_thous(event));
|
||||
}
|
||||
|
||||
private on_mousemove(event: MouseEvent) {
|
||||
this.preview_state.mouse_move(get_event_thous(event));
|
||||
}
|
||||
|
||||
private on_mouseup() {
|
||||
this.preview_state.visible = false;
|
||||
}
|
||||
|
||||
private get preview_rectangle(): Rectangle {
|
||||
let rect = this.preview_state.get_rect();
|
||||
rect.normalize();
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// Hook "resize" events
|
||||
|
||||
private resize_observer?: ResizeObserver;
|
||||
|
||||
declare $refs: {
|
||||
container: HTMLDivElement;
|
||||
background: HTMLImageElement;
|
||||
};
|
||||
|
||||
private on_resize() {
|
||||
this.$refs.container.style.setProperty(
|
||||
"height",
|
||||
this.$refs.background.offsetHeight + "px"
|
||||
);
|
||||
}
|
||||
|
||||
public mounted() {
|
||||
this.resize_observer = new ResizeObserver(this.on_resize);
|
||||
this.resize_observer.observe(this.$refs.background);
|
||||
}
|
||||
|
||||
public unmounted() {
|
||||
if (this.resize_observer instanceof ResizeObserver) {
|
||||
this.resize_observer.disconnect();
|
||||
delete this.resize_observer;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
div#container {
|
||||
position: relative;
|
||||
max-height: 100%;
|
||||
user-select: none;
|
||||
|
||||
img#background {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
svg#drawpad {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
rect {
|
||||
stroke-width: 1;
|
||||
stroke-opacity: 0.9;
|
||||
fill-opacity: 0.2;
|
||||
|
||||
&#preview {
|
||||
fill: white;
|
||||
stroke: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in a new issue