6
0

annotated-image.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. <template>
  2. <div class="annotated-image" v-on="events">
  3. <img alt="media" ref="image" draggable="false"
  4. :src="mediaUrl" :srcset="mediaUrlSet" :sizes="mediaUrlSizes"/>
  5. <div style="position: absolute; top: 0.5rem; left: 0.5rem">{{ data }}</div>
  6. <annotation-box v-if="current"
  7. :image="image"
  8. :position="current"/>
  9. <annotation-box v-for="(result, index) in predictions"
  10. type="server"
  11. :key="index"
  12. :image="image"
  13. :position="result"/>
  14. </div>
  15. </template>
  16. <script>
  17. import AnnotationBox from "@/components/media/annotation-box";
  18. export default {
  19. name: "annotated-image",
  20. components: {AnnotationBox},
  21. props: ['project', 'data', 'socket'],
  22. mounted: function() {
  23. window.addEventListener("resize", this.resizeEvent);
  24. if (this.$refs.image.complete)
  25. this.resizeEvent();
  26. else
  27. this.$refs.image.addEventListener('load', this.resizeEvent);
  28. },
  29. destroyed() {
  30. window.removeEventListener("resize", this.resizeEvent);
  31. },
  32. watch: {
  33. data: function() {
  34. this.current = false;
  35. this.resizeEvent();
  36. }
  37. },
  38. data: function() {
  39. return {
  40. sizes: [600, 800, 1200, 1600, 2000, 3000],
  41. image: {
  42. left: 0,
  43. top: 0,
  44. width: 0,
  45. height: 0
  46. },
  47. start: false,
  48. current: false
  49. }
  50. },
  51. computed: {
  52. mediaUrl: function () {
  53. return this.socket.media(this.project.id, this.data.id);
  54. },
  55. mediaUrlSet: function () {
  56. return this.sizes.map(e => this.mediaUrl + '/' + e + ' ' + e + 'w').join(',');
  57. },
  58. mediaUrlSizes: function () {
  59. return this.sizes.map(e => '(max-width: ' + e + 'px) ' + e + 'px').join(',');
  60. },
  61. predictions: function () {
  62. return Object.keys(this.data.predictionResults).map(k => this.data.predictionResults[k]);
  63. },
  64. events: function () {
  65. return {
  66. 'touchstart': this.press,
  67. 'touchmove': this.track,
  68. 'touchend': this.release,
  69. 'mousedown': this.press,
  70. 'mousemove': this.track,
  71. 'mouseup': this.release,
  72. 'dragstart': e => e.stopPropagation()
  73. }
  74. }
  75. },
  76. methods: {
  77. resizeEvent: function() {
  78. const element = this.$refs.image.getBoundingClientRect();
  79. const parent = this.$refs.image.parentElement.getBoundingClientRect();
  80. this.image.left = element.x - parent.x;
  81. this.image.top = element.y - parent.y;
  82. this.image.width = element.width;
  83. this.image.height = element.height;
  84. },
  85. get: function(event) {
  86. if ('clientX' in event)
  87. return event;
  88. if ('touches' in event && event.touches.length > 0)
  89. return event.touches[0];
  90. if ('changedTouches' in event && event.changedTouches.length > 0)
  91. return event.changedTouches[0];
  92. },
  93. getX: function(event) {
  94. const bcr = this.$refs.image.getBoundingClientRect();
  95. return (this.get(event).clientX - bcr.left) / bcr.width;
  96. },
  97. getY: function(event) {
  98. const bcr = this.$refs.image.getBoundingClientRect();
  99. return (this.get(event).clientY - bcr.top) / bcr.height;
  100. },
  101. buildRectangle: function(x1, y1, x2, y2) {
  102. const lx = Math.max(Math.min(x1, x2), 0);
  103. const hx = Math.min(Math.max(x1, x2), 1);
  104. const ly = Math.max(Math.min(y1, y2), 0);
  105. const hy = Math.min(Math.max(y1, y2), 1);
  106. return {
  107. x: lx,
  108. y: ly,
  109. w: hx - lx,
  110. h: hy - ly
  111. }
  112. },
  113. press: function(event) {
  114. this.start = {
  115. x: this.getX(event),
  116. y: this.getY(event)
  117. };
  118. },
  119. track: function (event) {
  120. if (this.start) {
  121. const x = this.getX(event);
  122. const y = this.getY(event);
  123. this.current = this.buildRectangle(this.start.x, this.start.y, x, y);
  124. }
  125. },
  126. release: function () {
  127. this.socket.post(this.mediaUrl, this.current);
  128. this.start = false;
  129. this.current = false;
  130. }
  131. }
  132. }
  133. </script>
  134. <style scoped>
  135. img {
  136. max-width: 100%;
  137. max-height: 100%;
  138. }
  139. </style>