"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>
|
<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>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Vue } from "vue-class-component";
|
import { Vue } from "vue-class-component";
|
||||||
|
|
||||||
export default class CalendarImage extends Vue {}
|
class Vector2D {
|
||||||
</script>
|
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