|
@@ -7,11 +7,35 @@
|
|
|
|
|
|
<div class="buttons">
|
|
<div class="buttons">
|
|
<template v-if="!immutable">
|
|
<template v-if="!immutable">
|
|
- <img v-if="confirmationButton" alt="confirm" src="@/assets/icons/check.svg" @click="confirmSelf">
|
|
|
|
- <img alt="delete" src="@/assets/icons/trash.svg" @click="deleteSelf">
|
|
|
|
|
|
+ <div v-if="position.label" class="label-text">{{ currentLabel }}</div>
|
|
|
|
+
|
|
|
|
+ <img v-if="confirmationButton"
|
|
|
|
+ alt="confirm" src="@/assets/icons/check.svg"
|
|
|
|
+ @click.stop.prevent="confirmSelf"
|
|
|
|
+ @touchstart.stop.prevent="confirmSelf">
|
|
|
|
+ <img v-if="labelButton"
|
|
|
|
+ alt="label" src="@/assets/icons/tag.svg"
|
|
|
|
+ @click.stop.prevent="showLabelSelection = true"
|
|
|
|
+ @touchstart.stop.prevent="showLabelSelection = true">
|
|
|
|
+ <img alt="delete" src="@/assets/icons/trash.svg"
|
|
|
|
+ @click.stop.prevent="deleteSelf"
|
|
|
|
+ @touchstart.stop.prevent="deleteSelf">
|
|
</template>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
+ <select v-if="!immutable && showLabelSelection"
|
|
|
|
+ @touchstart.stop @mousedown.stop
|
|
|
|
+ @change="labelSelf"
|
|
|
|
+ @focusout="showLabelSelection = false">
|
|
|
|
+ <option value="">None</option>
|
|
|
|
+
|
|
|
|
+ <option v-for="label in labelList"
|
|
|
|
+ :key="label.id"
|
|
|
|
+ :value="label.id">
|
|
|
|
+ {{ label.name }}
|
|
|
|
+ </option>
|
|
|
|
+ </select>
|
|
|
|
+
|
|
<div class="ee" @mousedown.stop.prevent="resizeSelf('ee')" @touchstart.stop.prevent="resizeSelf('ee')"></div>
|
|
<div class="ee" @mousedown.stop.prevent="resizeSelf('ee')" @touchstart.stop.prevent="resizeSelf('ee')"></div>
|
|
<div class="sw" @mousedown.stop.prevent="resizeSelf('sw')" @touchstart.stop.prevent="resizeSelf('sw')"></div>
|
|
<div class="sw" @mousedown.stop.prevent="resizeSelf('sw')" @touchstart.stop.prevent="resizeSelf('sw')"></div>
|
|
<div class="ss" @mousedown.stop.prevent="resizeSelf('ss')" @touchstart.stop.prevent="resizeSelf('ss')"></div>
|
|
<div class="ss" @mousedown.stop.prevent="resizeSelf('ss')" @touchstart.stop.prevent="resizeSelf('ss')"></div>
|
|
@@ -22,7 +46,12 @@
|
|
<script>
|
|
<script>
|
|
export default {
|
|
export default {
|
|
name: "annotation-box",
|
|
name: "annotation-box",
|
|
- props: ['type', 'image', 'position', 'socket', 'boxUrl'],
|
|
|
|
|
|
+ props: ['type', 'image', 'position', 'socket', 'boxUrl', 'labels'],
|
|
|
|
+ data: function () {
|
|
|
|
+ return {
|
|
|
|
+ showLabelSelection: false
|
|
|
|
+ }
|
|
|
|
+ },
|
|
computed: {
|
|
computed: {
|
|
immutable: function () {
|
|
immutable: function () {
|
|
return !this.type;
|
|
return !this.type;
|
|
@@ -40,6 +69,15 @@ export default {
|
|
confirmationButton: function () {
|
|
confirmationButton: function () {
|
|
return this.type === 'pipeline';
|
|
return this.type === 'pipeline';
|
|
},
|
|
},
|
|
|
|
+ labelButton: function () {
|
|
|
|
+ return this.type !== 'pipeline';
|
|
|
|
+ },
|
|
|
|
+ labelList: function () {
|
|
|
|
+ return Object.keys(this.labels).map(key => this.labels[key]);
|
|
|
|
+ },
|
|
|
|
+ currentLabel: function () {
|
|
|
|
+ return this.labels[this.position.label].name;
|
|
|
|
+ },
|
|
style: function () {
|
|
style: function () {
|
|
const left = this.image.left;
|
|
const left = this.image.left;
|
|
const top = this.image.top;
|
|
const top = this.image.top;
|
|
@@ -59,8 +97,21 @@ export default {
|
|
confirmSelf: function () {
|
|
confirmSelf: function () {
|
|
this.updateSelf(this.position);
|
|
this.updateSelf(this.position);
|
|
},
|
|
},
|
|
|
|
+ labelSelf: function (event) {
|
|
|
|
+ const options = event.target.options;
|
|
|
|
+ const option = options[options.selectedIndex];
|
|
|
|
+ const value = option.value;
|
|
|
|
+
|
|
|
|
+ if (value)
|
|
|
|
+ this.position.label = value;
|
|
|
|
+ else
|
|
|
|
+ delete this.position.label;
|
|
|
|
+
|
|
|
|
+ this.updateSelf(this.position);
|
|
|
|
+ this.showLabelSelection = false;
|
|
|
|
+ },
|
|
deleteSelf: function () {
|
|
deleteSelf: function () {
|
|
- this.socket.post(this.boxUrl, {delete: true, id: this.id});
|
|
|
|
|
|
+ this.socket.post(this.boxUrl, {delete: true});
|
|
},
|
|
},
|
|
moveSelf: function (event) {
|
|
moveSelf: function (event) {
|
|
this.$emit('move', event, this.position, this.updateSelf);
|
|
this.$emit('move', event, this.position, this.updateSelf);
|
|
@@ -69,6 +120,9 @@ export default {
|
|
this.$emit('resize', this.position, mode, this.updateSelf);
|
|
this.$emit('resize', this.position, mode, this.updateSelf);
|
|
},
|
|
},
|
|
updateSelf: function (value) {
|
|
updateSelf: function (value) {
|
|
|
|
+ if ('label' in this.position && !('label' in value))
|
|
|
|
+ value.label = this.position.label;
|
|
|
|
+
|
|
this.socket.post(this.boxUrl, value);
|
|
this.socket.post(this.boxUrl, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -88,6 +142,7 @@ export default {
|
|
display: flex;
|
|
display: flex;
|
|
justify-content: center;
|
|
justify-content: center;
|
|
align-items: center;
|
|
align-items: center;
|
|
|
|
+ position: relative;
|
|
}
|
|
}
|
|
|
|
|
|
img {
|
|
img {
|
|
@@ -111,4 +166,19 @@ img {
|
|
.nw, .se {
|
|
.nw, .se {
|
|
cursor: nwse-resize;
|
|
cursor: nwse-resize;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+select {
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 0;
|
|
|
|
+ top: 0;
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.label-text {
|
|
|
|
+ position: absolute;
|
|
|
|
+ bottom: 0;
|
|
|
|
+ color: whitesmoke;
|
|
|
|
+ font-size: 80%;
|
|
|
|
+}
|
|
</style>
|
|
</style>
|