edit-point.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <template>
  2. <v-circle
  3. :config="{ ...style, ...position, hitStrokeWidth: style.strokeWidth }"
  4. ref="circle"
  5. />
  6. <Operate
  7. :target="circle"
  8. :menus="[{ label: '删除', handler: () => emit('delete') }]"
  9. v-if="!notDelete"
  10. />
  11. </template>
  12. <script lang="ts" setup>
  13. import { Pos } from "@/utils/math.ts";
  14. import { themeColor } from "@/constant";
  15. import { computed, onUnmounted, ref, watch } from "vue";
  16. import { DC } from "@/deconstruction";
  17. import { Circle } from "konva/lib/shapes/Circle";
  18. import { useShapeDrag } from "@/core/hook/use-transformer.ts";
  19. import { getMouseColors } from "@/utils/colors";
  20. import {
  21. useCustomSnapInfos,
  22. useGlobalSnapInfos,
  23. useSnap,
  24. useSnapResultInfo,
  25. } from "@/core/hook/use-snap";
  26. import { generateSnapInfos } from "../util";
  27. import { ComponentSnapInfo } from "..";
  28. import { useShapeIsHover } from "@/core/hook/use-mouse-status";
  29. import { useCursor } from "@/core/hook/use-global-vars";
  30. import { mergeFuns, rangMod } from "@/utils/shared";
  31. import { Operate } from "../../html-mount/propertys/index.ts";
  32. import {
  33. useFixedScale,
  34. useViewer,
  35. useViewerInvertTransformConfig,
  36. } from "@/core/hook/use-viewer.ts";
  37. import { useMode } from "@/core/hook/use-status";
  38. import { Mode } from "@/constant/mode";
  39. const props = defineProps<{
  40. points: Pos[];
  41. ndx: number;
  42. id: string;
  43. color?: string;
  44. size?: number;
  45. fixed?: boolean;
  46. disable?: boolean;
  47. drawIng?: boolean;
  48. opacity?: number;
  49. closed?: boolean;
  50. notDelete?: boolean;
  51. getSelfSnapInfos?: (point: Pos) => ComponentSnapInfo[];
  52. }>();
  53. const emit = defineEmits<{
  54. (e: "update:position", position: Pos): void;
  55. (e: "dragend"): void;
  56. (e: "dragstart"): void;
  57. (e: "delete"): void;
  58. }>();
  59. const position = computed(() => props.points[props.ndx]);
  60. const scale = useFixedScale();
  61. const viewer = useViewer();
  62. const style = computed(() => {
  63. const color = getMouseColors(props.color || themeColor);
  64. let size = Math.max(props.size || 10, 10);
  65. size = props.fixed ? scale.value * size : size;
  66. return {
  67. radius: size / 2,
  68. fill: props.drawIng || isHover.value || dragIng.value ? "#fff" : color.pub,
  69. stroke: color.pub,
  70. strokeWidth: size / 4,
  71. opacity: props.opacity !== undefined ? props.opacity : props.disable ? 0.5 : 1,
  72. };
  73. });
  74. const infos = useCustomSnapInfos();
  75. const addedInfos = [] as ComponentSnapInfo[];
  76. const clearInfos = () => {
  77. addedInfos.forEach(infos.remove);
  78. };
  79. const startHandler = () => {
  80. viewer.disabled.value = true;
  81. clearInfos();
  82. const ndx = props.ndx;
  83. const geos = [
  84. props.points.slice(0, ndx),
  85. props.points.slice(ndx + 1, props.points.length),
  86. ];
  87. if (props.closed || (ndx > 0 && ndx < props.points.length - 1)) {
  88. const prev = rangMod(ndx - 1, props.points.length);
  89. const next = rangMod(ndx + 1, props.points.length);
  90. geos.push([props.points[prev], props.points[next]]);
  91. }
  92. geos.forEach((geo) => {
  93. const snapInfos = generateSnapInfos(geo, true, true, true);
  94. snapInfos.forEach((item) => {
  95. infos.add(item);
  96. addedInfos.push(item);
  97. });
  98. });
  99. };
  100. const snapInfos = useGlobalSnapInfos();
  101. const refSnapInfos = computed(() => {
  102. if (!props.id) {
  103. return snapInfos.value;
  104. } else {
  105. return snapInfos.value.filter((p) => !("id" in p) || p.id !== props.id);
  106. }
  107. });
  108. const snap = useSnap(refSnapInfos);
  109. const circle = ref<DC<Circle>>();
  110. const offset = useShapeDrag(circle);
  111. const hResult = useShapeIsHover(circle);
  112. const isHover = hResult[0];
  113. const cursor = useCursor();
  114. const mode = useMode();
  115. const drawing = computed(() => mode.include(Mode.draw));
  116. watch(
  117. [isHover, drawing],
  118. ([hover, drawing], _, onCleanup) => {
  119. if (hover && !drawing) {
  120. onCleanup(cursor.push("./icons/m_move.png"));
  121. }
  122. },
  123. { immediate: true }
  124. );
  125. const dragIng = ref(false);
  126. let init: Pos;
  127. let onUmHooks: (() => void)[] = [];
  128. const resultInfo = useSnapResultInfo();
  129. watch(offset, (offset, oldOffsert) => {
  130. snap.clear();
  131. if (!oldOffsert) {
  132. init = { ...position.value };
  133. emit("dragstart");
  134. startHandler();
  135. dragIng.value = true;
  136. onUmHooks.push(() => {
  137. emit("dragend");
  138. clearInfos();
  139. dragIng.value = false;
  140. viewer.disabled.value = false;
  141. resultInfo.clear();
  142. });
  143. }
  144. if (offset) {
  145. const point = {
  146. x: init.x + offset.x,
  147. y: init.y + offset.y,
  148. };
  149. const refSnapInfos = props.getSelfSnapInfos
  150. ? props.getSelfSnapInfos(point)
  151. : generateSnapInfos([point], true, true);
  152. const transform = snap.move(refSnapInfos);
  153. emit("update:position", transform ? transform.point(point) : point);
  154. } else {
  155. mergeFuns(onUmHooks)();
  156. onUmHooks.length = 0;
  157. }
  158. });
  159. onUnmounted(() => mergeFuns(onUmHooks)());
  160. watch(
  161. () => props.disable,
  162. (disable) => {
  163. if (disable) {
  164. offset.pause();
  165. hResult.pause();
  166. } else {
  167. offset.resume();
  168. hResult.resume();
  169. }
  170. },
  171. { immediate: true }
  172. );
  173. defineExpose({
  174. get shape() {
  175. return circle.value;
  176. },
  177. });
  178. </script>