media-control.vue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <template>
  2. <div class="media-control">
  3. <button-input type="transparent"
  4. style="color: var(--on_error)"
  5. :class="{disabled: !hasNext}"
  6. @click="$emit('control', !control)">
  7. {{ control ? '&#9660;' : '&#9650;' }}
  8. </button-input>
  9. <button-input type="transparent"
  10. style="color: var(--on_error)"
  11. :class="{disabled: !hasPrevious}"
  12. @click="previous">
  13. &lt;
  14. </button-input>
  15. <button-row class="media-control">
  16. <button-input type="primary"
  17. style="color: var(--on_error)"
  18. @click="reset">
  19. Reset
  20. </button-input>
  21. <button-input type="primary"
  22. style="color: var(--on_error)"
  23. @click="$emit('predict', 'current')">
  24. Predict
  25. </button-input>
  26. </button-row>
  27. <button-input type="transparent"
  28. style="color: var(--on_error)"
  29. :class="{disabled: !hasNext}"
  30. @click="next">
  31. &gt;
  32. </button-input>
  33. <button-input type="transparent" v-if="project.model.supports.includes('labeled-images')">
  34. <img alt="label" src="@/assets/icons/tag.svg"
  35. :class="{tagged: currentLabel}"
  36. @touchstart.stop @mousedown.stop
  37. @click.stop="showLabelSelection = true">
  38. </button-input>
  39. <select v-if="showLabelSelection"
  40. @touchstart.stop @mousedown.stop
  41. @change="labelSelf"
  42. @focusout="showLabelSelection = false">
  43. <option value="">None</option>
  44. <option v-for="label in labelList"
  45. :key="label.id"
  46. :value="label.id"
  47. :selected="label === currentLabel">
  48. {{ label.name }}
  49. </option>
  50. </select>
  51. <button-input type="transparent" v-if="project.model.supports.includes('bounding-boxes') || project.model.supports.includes('labeled-bounding-boxes')">
  52. <img alt="label" src="@/assets/icons/people.svg"
  53. @touchstart.stop @mousedown.stop
  54. @click.stop="showFilterSelection = true">
  55. </button-input>
  56. <select v-if="showFilterSelection"
  57. @touchstart.stop @mousedown.stop
  58. @change="filterSelf"
  59. @focusout="showFilterSelection = false">
  60. <option :selected="this.filter === ''" value="">None</option>
  61. <option :selected="this.filter === 'user'" value="user">User</option>
  62. <option :selected="this.filter === 'pipeline'" value="pipeline">Pipeline</option>
  63. </select>
  64. <button-input type="transparent"
  65. v-if="!extremeClicking && (project.model.supports.includes('bounding-boxes') || project.model.supports.includes('labeled-bounding-boxes'))">
  66. <img alt="label" src="@/assets/icons/flame.svg"
  67. @touchstart.stop @mousedown.stop
  68. @click.stop="$emit('extremeClicking', true)">
  69. </button-input>
  70. <button-input type="transparent" v-if="extremeClicking">
  71. <img alt="label" src="@/assets/icons/check.svg"
  72. @touchstart.stop @mousedown.stop
  73. @click.stop="$emit('extremeClicking', false)">
  74. </button-input>
  75. </div>
  76. </template>
  77. <script>
  78. import ButtonInput from "@/components/base/button-input";
  79. import ButtonRow from "@/components/base/button-row";
  80. export default {
  81. name: "media-control",
  82. components: {ButtonRow, ButtonInput},
  83. props: ['hasPrevious', 'hasNext', 'control', 'data', 'project', 'socket', 'filter', 'extremeClicking'],
  84. data: function () {
  85. return {
  86. showLabelSelection: false,
  87. showFilterSelection: false
  88. }
  89. },
  90. computed: {
  91. mediaUrl: function () {
  92. return this.socket.media(this.project.id, this.data.id);
  93. },
  94. labelList: function () {
  95. return Object.keys(this.project.labels).map(key => this.project.labels[key]);
  96. },
  97. currentLabel: function () {
  98. const predictions = Object.keys(this.data.predictionResults).map(k => this.data.predictionResults[k]);
  99. for (let result of predictions) {
  100. if (!('x' in result || 'y' in result || 'w' in result || 'h' in result)) {
  101. return this.project.labels[result.label];
  102. }
  103. }
  104. return false;
  105. }
  106. },
  107. methods: {
  108. previous: function () {
  109. if (this.hasPrevious)
  110. this.$emit('previous', null);
  111. },
  112. next: function () {
  113. if (this.hasNext)
  114. this.$emit('next', null);
  115. },
  116. labelSelf: function (event) {
  117. const options = event.target.options;
  118. const option = options[options.selectedIndex];
  119. const value = option.value;
  120. this.socket.post(this.mediaUrl, {
  121. label: value ? value : false
  122. });
  123. this.showLabelSelection = false;
  124. },
  125. filterSelf: function (event) {
  126. this.$emit('filter', event.target.value);
  127. },
  128. reset: function () {
  129. this.socket.post(this.mediaUrl, {
  130. reset: true
  131. });
  132. }
  133. }
  134. }
  135. </script>
  136. <style scoped>
  137. .media-control {
  138. position: relative;
  139. display: flex;
  140. justify-content: center;
  141. align-items: center;
  142. margin: 0 0.5rem;
  143. }
  144. .disabled {
  145. opacity: 0.4;
  146. }
  147. img {
  148. filter: invert(1);
  149. opacity: 0.4;
  150. }
  151. img.tagged {
  152. opacity: 1;
  153. }
  154. select {
  155. position: absolute;
  156. width: 100%;
  157. height: 100%;
  158. }
  159. </style>