interactive_image.js 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. Vue.component("interactive_image", {
  2. template: `
  3. <div :id="jp_props.id" style="position:relative;display:inline-block" :style="jp_props.style" :class="jp_props.classes">
  4. <img style="max-width:100%">
  5. <svg style="position:absolute;top:0;left:0;pointer-events:none">
  6. <g style="display:none">
  7. <line x1="100" y1="0" x2="100" y2="100%" stroke="black" />
  8. <line x1="0" y1="100" x2="100%" y2="100" stroke="black" />
  9. </g>
  10. <g v-html="jp_props.options.svg_content"></g>
  11. </svg>
  12. </div>
  13. `,
  14. mounted() {
  15. comp_dict[this.$props.jp_props.id] = this;
  16. const image = document.getElementById(this.$props.jp_props.id).firstChild;
  17. const handle_completion = () => {
  18. if (this.waiting_source) {
  19. image.src = this.waiting_source;
  20. this.waiting_source = undefined;
  21. } else {
  22. this.loading = false;
  23. }
  24. };
  25. image.addEventListener("load", handle_completion);
  26. image.addEventListener("error", handle_completion);
  27. const svg = document.getElementById(this.$props.jp_props.id).lastChild;
  28. const cross = svg.firstChild;
  29. image.ondragstart = () => false;
  30. if (this.$props.jp_props.options.cross) {
  31. image.style.cursor = "none";
  32. image.addEventListener("mouseenter", (e) => {
  33. cross.style.display = "block";
  34. });
  35. image.addEventListener("mouseleave", (e) => {
  36. cross.style.display = "none";
  37. });
  38. image.addEventListener("mousemove", (e) => {
  39. const x = (e.offsetX * e.target.naturalWidth) / e.target.clientWidth;
  40. const y = (e.offsetY * e.target.naturalHeight) / e.target.clientHeight;
  41. cross.firstChild.setAttribute("x1", x);
  42. cross.firstChild.setAttribute("x2", x);
  43. cross.lastChild.setAttribute("y1", y);
  44. cross.lastChild.setAttribute("y2", y);
  45. });
  46. }
  47. image.onload = (e) => {
  48. const viewBox = `0 0 ${image.naturalWidth} ${image.naturalHeight}`;
  49. svg.setAttribute("viewBox", viewBox);
  50. };
  51. image.src = this.$props.jp_props.options.source;
  52. for (const type of this.$props.jp_props.options.events) {
  53. image.addEventListener(type, (e) => {
  54. const event = {
  55. event_type: "onMouse",
  56. mouse_event_type: type,
  57. vue_type: this.$props.jp_props.vue_type,
  58. id: this.$props.jp_props.id,
  59. page_id: page_id,
  60. websocket_id: websocket_id,
  61. image_x: (e.offsetX * e.target.naturalWidth) / e.target.clientWidth,
  62. image_y: (e.offsetY * e.target.naturalHeight) / e.target.clientHeight,
  63. };
  64. send_to_server(event, "event");
  65. });
  66. }
  67. },
  68. methods: {
  69. set_source(source) {
  70. if (this.loading) {
  71. this.waiting_source = source;
  72. return;
  73. }
  74. this.loading = true;
  75. image = document.getElementById(this.$props.jp_props.id).firstChild;
  76. image.src = source;
  77. },
  78. },
  79. props: {
  80. jp_props: Object,
  81. },
  82. });