svgRect.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <template>
  2. <g @mousedown="handleMousedown" :id="id">
  3. <rect v-bind="outlineRectAttr" />
  4. <rect v-bind="attr" />
  5. <circle
  6. v-for="i in pointsAttr"
  7. v-bind="i"
  8. :key="i.id"
  9. @mousedown="($event) => startLine($event, i)"
  10. ></circle>
  11. </g>
  12. </template>
  13. <script setup>
  14. import {
  15. defineProps,
  16. ref,
  17. watch,
  18. defineExpose,
  19. defineEmits,
  20. computed,
  21. } from "vue";
  22. import { sticky } from "../utils/index";
  23. const props = defineProps(["pos", "size", "mousePos", "id", "draggingId"]);
  24. const boxPos = ref(props.pos);
  25. const boxSize = ref(props.size);
  26. const innerPos = ref({ x: 0, y: 0 });
  27. const isDraging = computed(() => props.id === props.draggingId);
  28. const emits = defineEmits(["startDrag", "startLine", "updatePos"]);
  29. const attr = computed(() => {
  30. return {
  31. x: boxPos.value.x,
  32. y: boxPos.value.y,
  33. width: boxSize.value.width,
  34. height: boxSize.value.height,
  35. fill: "rgba(255,255,255,1)",
  36. stroke: "#666",
  37. rx: "15",
  38. };
  39. });
  40. const outlineRectAttr = computed(() => {
  41. const space = 8;
  42. return {
  43. x: boxPos.value.x - space,
  44. y: boxPos.value.y - space,
  45. width: boxSize.value.width + space * 2,
  46. height: boxSize.value.height + space * 2,
  47. fill: "rgba(255,255,255,0)",
  48. "stroke-dasharray": "3 4",
  49. stroke: "#000",
  50. rx: "18",
  51. };
  52. });
  53. const pointsAttr = computed(() => [
  54. {
  55. id: `${props.id}-top`,
  56. cx: boxPos.value.x + boxSize.value.width / 2,
  57. cy: boxPos.value.y,
  58. r: 4,
  59. stroke: "#000",
  60. fill: "rgba(255,255,255,1)",
  61. },
  62. {
  63. id: `${props.id}-right`,
  64. cx: boxPos.value.x + boxSize.value.width,
  65. cy: boxPos.value.y + boxSize.value.height / 2,
  66. r: 4,
  67. stroke: "#000",
  68. fill: "rgba(255,255,255,1)",
  69. },
  70. {
  71. id: `${props.id}-bottom`,
  72. cx: boxPos.value.x + boxSize.value.width / 2,
  73. cy: boxPos.value.y + boxSize.value.height,
  74. r: 4,
  75. stroke: "#000",
  76. fill: "rgba(255,255,255,1)",
  77. },
  78. {
  79. id: `${props.id}-left`,
  80. cx: boxPos.value.x,
  81. cy: boxPos.value.y + boxSize.value.height / 2,
  82. r: 4,
  83. stroke: "#000",
  84. fill: "rgba(255,255,255,1)",
  85. },
  86. ]);
  87. function handleMousedown(e) {
  88. emits("startDrag", {
  89. id: props.id,
  90. event: e,
  91. });
  92. innerPos.value = {
  93. x: e.offsetX - boxPos.value.x,
  94. y: e.offsetY - boxPos.value.y,
  95. };
  96. }
  97. function startLine(e, point) {
  98. e.stopPropagation();
  99. emits("startLine", {
  100. id: props.id,
  101. point: point,
  102. });
  103. }
  104. function setPos(pos) {
  105. boxPos.value = {
  106. x: sticky(pos.x - innerPos.value.x),
  107. y: sticky(pos.y - innerPos.value.y),
  108. };
  109. emits("updatePos", {
  110. id: props.id,
  111. pos: boxPos.value,
  112. });
  113. }
  114. watch(
  115. () => props.mousePos,
  116. (pos) => {
  117. if (isDraging.value) {
  118. setPos(pos);
  119. }
  120. }
  121. );
  122. </script>
  123. <style lang="less" scoped>
  124. circle {
  125. cursor: pointer;
  126. }
  127. </style>