123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- <template>
- <div class="annotation-box" :style="style" @mousedown.stop.prevent="moveSelf" @touchstart.stop.prevent="moveSelf">
- <div class="nw" @mousedown.stop.prevent="resizeSelf('nw')" @touchstart.stop.prevent="resizeSelf('nw')"></div>
- <div class="nn" @mousedown.stop.prevent="resizeSelf('nn')" @touchstart.stop.prevent="resizeSelf('nn')"></div>
- <div class="ne" @mousedown.stop.prevent="resizeSelf('ne')" @touchstart.stop.prevent="resizeSelf('ne')"></div>
- <div class="ww" @mousedown.stop.prevent="resizeSelf('ww')" @touchstart.stop.prevent="resizeSelf('ww')"></div>
- <div class="buttons">
- <template v-if="!immutable">
- <div v-if="position.label" class="label-text">{{ currentLabel.name }}</div>
- <img v-if="confirmationButton"
- alt="confirm" src="@/assets/icons/check.svg"
- @click.stop.prevent="confirmSelf"
- @touchstart.stop.prevent="confirmSelf"
- @mousedown.stop.prevent>
- <img v-if="labelButton"
- alt="label" src="@/assets/icons/tag.svg"
- @click.stop.prevent="showLabelSelection = true"
- @touchstart.stop.prevent="showLabelSelection = true"
- @mousedown.stop.prevent>
- <img alt="delete" src="@/assets/icons/trash.svg"
- @click.stop.prevent="deleteSelf"
- @touchstart.stop.prevent="deleteSelf"
- @mousedown.stop.prevent>
- </template>
- </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"
- :selected="label === currentLabel">
- {{ label.name }}
- </option>
- </select>
- <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="ss" @mousedown.stop.prevent="resizeSelf('ss')" @touchstart.stop.prevent="resizeSelf('ss')"></div>
- <div class="se" @mousedown.stop.prevent="resizeSelf('se')" @touchstart.stop.prevent="resizeSelf('se')"></div>
- </div>
- </template>
- <script>
- export default {
- name: "annotation-box",
- props: ['type', 'image', 'position', 'socket', 'boxUrl', 'labels', 'supports'],
- data: function () {
- return {
- showLabelSelection: false
- }
- },
- computed: {
- immutable: function () {
- return !this.type;
- },
- backgroundColor: function () {
- switch (this.type) {
- case 'user':
- return 'rgba(255, 0, 0, 0.3)';
- case 'pipeline':
- return 'rgba(0, 0, 255, 0.3)';
- default:
- return 'rgba(255, 255, 255, 0.3)';
- }
- },
- confirmationButton: function () {
- return this.type === 'pipeline';
- },
- labelButton: function () {
- return this.supports.includes('labeled-bounding-boxes') && this.type !== 'pipeline';
- },
- labelList: function () {
- return Object.keys(this.labels).map(key => this.labels[key]);
- },
- currentLabel: function () {
- return this.labels[this.position.label];
- },
- style: function () {
- const left = this.image.left;
- const top = this.image.top;
- const width = this.image.width;
- const height = this.image.height;
- return {
- left: (left + this.position.x * width) + 'px',
- top: (top + this.position.y * height) + 'px',
- width: (this.position.w * width) + 'px',
- height: (this.position.h * height) + 'px',
- backgroundColor: this.backgroundColor
- }
- }
- },
- methods: {
- confirmSelf: function () {
- 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 () {
- this.socket.post(this.boxUrl, {delete: true});
- },
- moveSelf: function (event) {
- this.$emit('move', event, this.position, this.updateSelf);
- },
- resizeSelf: function (mode) {
- this.$emit('resize', this.position, mode, this.updateSelf);
- },
- updateSelf: function (value) {
- if ('label' in this.position && !('label' in value))
- value.label = this.position.label;
- this.socket.post(this.boxUrl, value);
- }
- }
- }
- </script>
- <style scoped>
- .annotation-box {
- position: absolute;
- display: grid;
- grid-template-rows: 10px auto 10px;
- grid-template-columns: 10px auto 10px;
- }
- .buttons {
- display: flex;
- justify-content: center;
- align-items: center;
- position: relative;
- }
- img {
- width: 2rem;
- filter: invert(1);
- opacity: 0.9;
- }
- .nn, .ss {
- cursor: ns-resize;
- }
- .ww, .ee {
- cursor: ew-resize;
- }
- .ne, .sw {
- cursor: nesw-resize;
- }
- .nw, .se {
- 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>
|