This repository has been archived on 2026-10-11. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
SnapEdit/frontend/src/components/Image.vue
T
2023-04-13 20:55:23 +02:00

166 lines
4.5 KiB
Vue

<script setup lang="ts">
import { defineComponent } from 'vue';
import { api } from '@/http-api';
import { ImageType } from '@/image';
import { Area } from '@/filter';
</script>
<script lang="ts">
export default defineComponent({
props: {
id: {
type: Number,
required: true
},
images: {
type: Map<number, ImageType>,
required: true
},
redirect: {
type: String
},
selectedArea: {
type: Area,
}
},
data() {
return {
data: "" as string,
canvas: null as HTMLCanvasElement | null,
mouseDowned: false,
image: null as HTMLImageElement | null,
}
},
methods: {
getImage(id: number, force: boolean = false) {
if (!force && (this.images.has(id) && this.images.get(id)!.data != null)) {
this.data = this.images.get(id)!.data;
}
else
api.getImage(this.images.get(id)!.id).then((imageData) => {
const reader = new window.FileReader();
reader.readAsDataURL(imageData);
reader.onload = () => {
this.data = reader.result as string;
this.images.get(id)!.data = this.data;
};
});
},
drawImage() {
if (this.data === "") return;
if (this.canvas === null) return;
const ctx = this.canvas.getContext('2d');
if (ctx === null) return;
if (this.image === null) {
this.image = new Image();
}
this.image.src = this.data;
this.image.onload = () => {
if (this.image === null) return;
this.canvas!.width = this.image.naturalWidth;
this.canvas!.height = this.image.naturalHeight;
ctx.drawImage(this.image, 0, 0, this.image.naturalWidth, this.image.naturalHeight);
if (this.selectedArea === undefined) return;
ctx.fillStyle = "rgba(0, 0, 50, 0.5)";
ctx.fillRect(this.selectedArea.xMin, this.selectedArea.yMin, this.selectedArea.xMax - this.selectedArea.xMin, this.selectedArea.yMax - this.selectedArea.yMin);
}
},
handleMouse(event: MouseEvent) {
if (this.redirect === undefined || this.redirect === '') {
if (event.type === "mousedown" || event.type === "mouseup") {
event.preventDefault();
var newTab = window.open("images/" + this.id, '_blank');
if (!newTab) return;
newTab.focus();
return;
}
}
else if (this.redirect !== "disabled") {
if (event.type === "mousedown" || event.type === "mouseup") {
event.preventDefault();
this.$router.push({ name: this.redirect, params: { id: this.id } });
return;
}
}
if (this.selectedArea === undefined) return;
if (this.canvas === null) return;
const ratio = this.image!.naturalWidth / this.canvas!.clientWidth;
const rect = this.canvas.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
if (event.type === "mousedown") {
this.selectedArea.xMin = x * ratio;
this.selectedArea.yMin = y * ratio;
this.selectedArea.xMax = x * ratio;
this.selectedArea.yMax = y * ratio;
this.mouseDowned = true;
this.drawImage();
}
else if (this.mouseDowned && event.type === "mousemove") {
this.selectedArea.xMax = x * ratio;
this.selectedArea.yMax = y * ratio;
this.drawImage();
}
else if (event.type === "mouseup") {
this.mouseDowned = false;
this.selectedArea.xMax = x * ratio;
this.selectedArea.yMax = y * ratio;
if (this.selectedArea.xMin > this.selectedArea.xMax) {
const tmp = this.selectedArea.xMin;
this.selectedArea.xMin = this.selectedArea.xMax;
this.selectedArea.xMax = tmp;
}
if (this.selectedArea.yMin > this.selectedArea.yMax) {
const tmp = this.selectedArea.yMin;
this.selectedArea.yMin = this.selectedArea.yMax;
this.selectedArea.yMax = tmp;
}
this.drawImage();
}
},
},
created() {
this.getImage(this.id);
},
watch: {
id() {
this.getImage(this.id)
},
data() {
this.drawImage();
},
selectedArea() {
this.drawImage();
},
},
mounted() {
this.canvas = document.getElementById('canvas-' + this.id) as HTMLCanvasElement;
this.drawImage();
},
})
</script>
<template>
<div class="imageContainer">
<canvas :id="'canvas-' + id" redirect="disabled" @mousedown="handleMouse($event)" @mouseup="handleMouse($event)"
@mousemove="handleMouse($event)" />
</div>
</template>
<style>
.imageContainer canvas {
max-width: 100%;
max-height: 100%;
object-fit: contain;
cursor: v-bind("redirect === 'disabled' ? 'crosshair' : 'pointer'");
}
.imageContainer {
display: flex;
justify-content: center;
align-items: center;
}
.imageContainer:hover {
transform: scale(1.1);
transition: transform 0.5s;
}
</style>