annotation-box.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <template>
  2. <div class="annotation-box"
  3. :class="{draggable: type}"
  4. :style="style"
  5. @mousedown.stop.prevent="moveSelf" @touchstart.stop.prevent="moveSelf">
  6. <div class="nw" @mousedown.stop.prevent="resizeSelf('nw')" @touchstart.stop.prevent="resizeSelf('nw')"></div>
  7. <div class="nn" @mousedown.stop.prevent="resizeSelf('nn')" @touchstart.stop.prevent="resizeSelf('nn')"></div>
  8. <div class="ne" @mousedown.stop.prevent="resizeSelf('ne')" @touchstart.stop.prevent="resizeSelf('ne')"></div>
  9. <div class="ww" @mousedown.stop.prevent="resizeSelf('ww')" @touchstart.stop.prevent="resizeSelf('ww')"></div>
  10. <div class="buttons">
  11. <template v-if="!immutable">
  12. <div v-if="position.label" class="label-text">{{ currentLabel ? currentLabel.name : 'unknown label' }}</div>
  13. <img v-if="confirmationButton"
  14. alt="confirm" src="@/assets/icons/check.svg"
  15. @click.stop.prevent="confirmSelf"
  16. @touchstart.stop.prevent="confirmSelf"
  17. @mousedown.stop.prevent>
  18. <img v-if="labelButton"
  19. alt="label" src="@/assets/icons/tag.svg"
  20. @click.stop.prevent="showLabelSelection = true"
  21. @touchstart.stop.prevent="showLabelSelection = true"
  22. @mousedown.stop.prevent>
  23. <img alt="delete" src="@/assets/icons/trash.svg"
  24. @click.stop.prevent="deleteSelf"
  25. @touchstart.stop.prevent="deleteSelf"
  26. @mousedown.stop.prevent>
  27. </template>
  28. </div>
  29. <select v-if="!immutable && showLabelSelection"
  30. @touchstart.stop @mousedown.stop
  31. @change="labelSelf"
  32. @focusout="showLabelSelection = false">
  33. <option value="">None</option>
  34. <option v-for="label in labelList"
  35. :key="label.id"
  36. :value="label.id"
  37. :selected="label === currentLabel">
  38. {{ label.name }}
  39. </option>
  40. </select>
  41. <div class="ee" @mousedown.stop.prevent="resizeSelf('ee')" @touchstart.stop.prevent="resizeSelf('ee')"></div>
  42. <div class="sw" @mousedown.stop.prevent="resizeSelf('sw')" @touchstart.stop.prevent="resizeSelf('sw')"></div>
  43. <div class="ss" @mousedown.stop.prevent="resizeSelf('ss')" @touchstart.stop.prevent="resizeSelf('ss')"></div>
  44. <div class="se" @mousedown.stop.prevent="resizeSelf('se')" @touchstart.stop.prevent="resizeSelf('se')"></div>
  45. </div>
  46. </template>
  47. <script>
  48. export default {
  49. name: "annotation-box",
  50. props: ['type', 'image', 'position', 'socket', 'boxUrl', 'labels', 'supports'],
  51. data: function () {
  52. return {
  53. showLabelSelection: false
  54. }
  55. },
  56. computed: {
  57. immutable: function () {
  58. return !this.type;
  59. },
  60. backgroundColor: function () {
  61. switch (this.type) {
  62. case 'user':
  63. return 'rgba(255, 0, 0, 0.3)';
  64. case 'pipeline':
  65. return 'rgba(0, 0, 255, 0.3)';
  66. default:
  67. return 'rgba(255, 255, 255, 0.3)';
  68. }
  69. },
  70. confirmationButton: function () {
  71. return this.type === 'pipeline';
  72. },
  73. labelButton: function () {
  74. return this.supports.includes('labeled-bounding-boxes') && this.type !== 'pipeline';
  75. },
  76. labelList: function () {
  77. return Object.keys(this.labels).map(key => this.labels[key]);
  78. },
  79. currentLabel: function () {
  80. if (this.position.label in this.labels)
  81. return this.labels[this.position.label];
  82. else
  83. return false;
  84. },
  85. style: function () {
  86. const left = this.image.left;
  87. const top = this.image.top;
  88. const width = this.image.width;
  89. const height = this.image.height;
  90. return {
  91. left: (left + this.position.x * width) + 'px',
  92. top: (top + this.position.y * height) + 'px',
  93. width: (this.position.w * width) + 'px',
  94. height: (this.position.h * height) + 'px',
  95. backgroundColor: this.backgroundColor
  96. }
  97. }
  98. },
  99. methods: {
  100. confirmSelf: function () {
  101. this.updateSelf(this.position);
  102. },
  103. labelSelf: function (event) {
  104. const options = event.target.options;
  105. const option = options[options.selectedIndex];
  106. const value = option.value;
  107. if (value)
  108. this.position.label = value;
  109. else
  110. delete this.position.label;
  111. this.updateSelf(this.position);
  112. this.showLabelSelection = false;
  113. },
  114. deleteSelf: function () {
  115. this.socket.post(this.boxUrl, {delete: true});
  116. this.$emit('update', true);
  117. },
  118. moveSelf: function (event) {
  119. this.$emit('move', event, this.position, this.updateSelf);
  120. },
  121. resizeSelf: function (mode) {
  122. this.$emit('resize', this.position, mode, this.updateSelf);
  123. },
  124. updateSelf: function (value) {
  125. if ('label' in this.position && !('label' in value))
  126. value.label = this.position.label;
  127. this.socket.post(this.boxUrl, value);
  128. this.$emit('update', true);
  129. }
  130. }
  131. }
  132. </script>
  133. <style scoped>
  134. .annotation-box {
  135. position: absolute;
  136. }
  137. .annotation-box.draggable {
  138. display: grid;
  139. grid-template-rows: 10px auto 10px;
  140. grid-template-columns: 10px auto 10px;
  141. }
  142. .buttons {
  143. display: flex;
  144. justify-content: center;
  145. align-items: center;
  146. position: relative;
  147. }
  148. img {
  149. width: 2rem;
  150. filter: invert(1);
  151. opacity: 0.9;
  152. }
  153. .nn, .ss {
  154. cursor: ns-resize;
  155. }
  156. .ww, .ee {
  157. cursor: ew-resize;
  158. }
  159. .ne, .sw {
  160. cursor: nesw-resize;
  161. }
  162. .nw, .se {
  163. cursor: nwse-resize;
  164. }
  165. select {
  166. position: absolute;
  167. left: 0;
  168. top: 0;
  169. width: 100%;
  170. height: 100%;
  171. }
  172. .label-text {
  173. position: absolute;
  174. bottom: 0;
  175. color: whitesmoke;
  176. font-size: 80%;
  177. }
  178. </style>