|
@@ -0,0 +1,137 @@
|
|
|
+<template>
|
|
|
+ <div class="annotated-image" v-on="events">
|
|
|
+ <img alt="media" :src="mediaUrl" ref="image">
|
|
|
+
|
|
|
+ <div style="position: absolute; top: 0.5rem; left: 0.5rem">{{ data }}</div>
|
|
|
+
|
|
|
+ <annotation-box v-if="current"
|
|
|
+ :image="image"
|
|
|
+ :position="current"/>
|
|
|
+
|
|
|
+ <annotation-box v-for="result in data.result"
|
|
|
+ v-bind:key="result"
|
|
|
+ :image="image"
|
|
|
+ :position="result"/>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import AnnotationBox from "@/components/media/annotation-box";
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "annotated-image",
|
|
|
+ components: {AnnotationBox},
|
|
|
+ props: ['project', 'data', 'socket'],
|
|
|
+ mounted: function() {
|
|
|
+ window.addEventListener("resize", this.resizeEvent);
|
|
|
+
|
|
|
+ if (this.$refs.image.complete)
|
|
|
+ this.resizeEvent();
|
|
|
+ else
|
|
|
+ this.$refs.image.addEventListener('load', this.resizeEvent);
|
|
|
+ },
|
|
|
+ destroyed() {
|
|
|
+ window.removeEventListener("resize", this.resizeEvent);
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ data: function() {
|
|
|
+ this.current = false;
|
|
|
+ this.resizeEvent();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data: function() {
|
|
|
+ return {
|
|
|
+ image: {
|
|
|
+ left: 0,
|
|
|
+ top: 0,
|
|
|
+ width: 0,
|
|
|
+ height: 0
|
|
|
+ },
|
|
|
+ start: false,
|
|
|
+ current: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ mediaUrl: function() {
|
|
|
+ return this.socket.media(this.project.id, this.data.id);
|
|
|
+ },
|
|
|
+ events: function() {
|
|
|
+ return {
|
|
|
+ 'touchstart': this.press,
|
|
|
+ 'touchmove': this.track,
|
|
|
+ 'touchend': this.release,
|
|
|
+ 'mousedown': this.press,
|
|
|
+ 'drag': this.track,
|
|
|
+ 'dragend': this.release,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ resizeEvent: function() {
|
|
|
+ const element = this.$refs.image.getBoundingClientRect();
|
|
|
+ const parent = this.$refs.image.parentElement.getBoundingClientRect();
|
|
|
+
|
|
|
+ this.image.left = element.x - parent.x;
|
|
|
+ this.image.top = element.y - parent.y;
|
|
|
+ this.image.width = element.width;
|
|
|
+ this.image.height = element.height;
|
|
|
+ },
|
|
|
+ get: function(event) {
|
|
|
+ if ('clientX' in event)
|
|
|
+ return event;
|
|
|
+ else if ('touches' in event && event.touches.length > 0)
|
|
|
+ return event.touches[0];
|
|
|
+ else if ('changedTouches' in event && event.changedTouches.length > 0)
|
|
|
+ return event.changedTouches[0];
|
|
|
+ },
|
|
|
+ getX: function(event) {
|
|
|
+ const bcr = event.target.getBoundingClientRect();
|
|
|
+ return (this.get(event).clientX - bcr.left) / bcr.width;
|
|
|
+ },
|
|
|
+ getY: function(event) {
|
|
|
+ const bcr = event.target.getBoundingClientRect();
|
|
|
+ return (this.get(event).clientY - bcr.top) / bcr.height;
|
|
|
+ },
|
|
|
+ buildRectangle: function(x1, y1, x2, y2) {
|
|
|
+ const lx = Math.max(Math.min(x1, x2), 0);
|
|
|
+ const hx = Math.min(Math.max(x1, x2), 1);
|
|
|
+ const ly = Math.max(Math.min(y1, y2), 0);
|
|
|
+ const hy = Math.min(Math.max(y1, y2), 1);
|
|
|
+
|
|
|
+ return {
|
|
|
+ x: lx,
|
|
|
+ y: ly,
|
|
|
+ w: hx - lx,
|
|
|
+ h: hy - ly
|
|
|
+ }
|
|
|
+ },
|
|
|
+ press: function(event) {
|
|
|
+ this.start = {
|
|
|
+ x: this.getX(event),
|
|
|
+ y: this.getY(event)
|
|
|
+ };
|
|
|
+ },
|
|
|
+ track: function(event) {
|
|
|
+ const x = this.getX(event);
|
|
|
+ const y = this.getY(event);
|
|
|
+
|
|
|
+ // Chrome 88 fires a drag event with negative coordinates on mouseup.
|
|
|
+ if (x >= 0 && y >= 0)
|
|
|
+ this.current = this.buildRectangle(this.start.x, this.start.y, x, y);
|
|
|
+ },
|
|
|
+ release: function(event) {
|
|
|
+ console.log('release', event);
|
|
|
+ // TODO send to server
|
|
|
+ this.start = false;
|
|
|
+ // this.current = this.buildRectangle(this.start.x, this.start.y, this.getX(event), this.getY(event));
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+img {
|
|
|
+ max-width: 100%;
|
|
|
+ max-height: 100%;
|
|
|
+}
|
|
|
+</style>
|