icon.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. <template>
  2. <TempIcon :data="tData" :ref="(e: any) => shape = e?.shape" />
  3. <PropertyUpdate
  4. :describes="describes"
  5. :data="data"
  6. :target="shape"
  7. @delete="emit('delShape')"
  8. @change="emit('updateShape', { ...data })"
  9. />
  10. <Operate :target="shape" :menus="operateMenus" />
  11. </template>
  12. <script lang="ts" setup>
  13. import TempIcon from "./temp-icon.vue";
  14. import {
  15. LineIconData,
  16. getMouseStyle,
  17. defaultStyle,
  18. matResponse,
  19. getLineIconMat,
  20. getSnapLine,
  21. getLineIconEndpoints,
  22. } from "./index.ts";
  23. import { useComponentStatus } from "@/core/hook/use-component.ts";
  24. import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
  25. import { Transform } from "konva/lib/Util";
  26. import {
  27. useCustomTransformer,
  28. useGetTransformerOperType,
  29. } from "@/core/hook/use-transformer.ts";
  30. import { Group } from "konva/lib/Group";
  31. import { Rect } from "konva/lib/shapes/Rect";
  32. import { setShapeTransform } from "@/utils/shape.ts";
  33. import { useStore } from "@/core/store/index.ts";
  34. import { usePointerPos } from "@/core/hook/use-global-vars.ts";
  35. import { useViewerInvertTransform } from "@/core/hook/use-viewer.ts";
  36. import { computed, watch } from "vue";
  37. import { useHistory } from "@/core/hook/use-history.ts";
  38. import { eqPoint, line2IncludedAngle, lineInner, lineLen, Pos } from "@/utils/math.ts";
  39. import { copy } from "@/utils/shared.ts";
  40. const props = defineProps<{ data: LineIconData }>();
  41. const emit = defineEmits<{
  42. (e: "updateShape", value: LineIconData): void;
  43. (e: "addShape", value: LineIconData): void;
  44. (e: "delShape"): void;
  45. }>();
  46. const store = useStore();
  47. const getOperType = useGetTransformerOperType();
  48. const viewMat = useViewerInvertTransform();
  49. const pos = usePointerPos();
  50. const { shape, tData, data, operateMenus, describes } = useComponentStatus({
  51. emit,
  52. props,
  53. getMouseStyle,
  54. transformType: "custom",
  55. customTransform(callback, shape, data) {
  56. let prevInvMat: Transform;
  57. return useCustomTransformer(shape, data, {
  58. getRepShape() {
  59. const group = new Group();
  60. const rect = new Rect();
  61. group.add(rect);
  62. const update = () => {
  63. const mat = getLineIconMat(getSnapLine(store, data.value)!, data.value);
  64. const width = Math.abs(data.value.endLen - data.value.startLen);
  65. const height = data.value.height;
  66. prevInvMat = mat;
  67. rect.width(width);
  68. rect.height(height);
  69. rect.offset({ x: width / 2, y: height / 2 });
  70. setShapeTransform(group, mat);
  71. };
  72. update();
  73. return { shape: group, update };
  74. },
  75. handler(data, mat) {
  76. if (pos.value && !getOperType()) {
  77. const rpos = viewMat.value.point(pos.value);
  78. const m = mat.m;
  79. m[4] = rpos.x;
  80. m[5] = rpos.y;
  81. mat = new Transform(m);
  82. }
  83. matResponse({
  84. data,
  85. mat: mat,
  86. operType: getOperType(),
  87. store,
  88. });
  89. return true;
  90. },
  91. callback,
  92. openSnap: false,
  93. transformerConfig: {
  94. flipEnabled: true,
  95. rotateEnabled: false,
  96. enabledAnchors: ["middle-left", "middle-right"],
  97. },
  98. });
  99. },
  100. defaultStyle,
  101. copyHandler(mat, data) {
  102. return matResponse({ data, mat });
  103. },
  104. propertys: ["name", "fill", "stroke", "strokeWidth", "strokeScaleEnabled"],
  105. });
  106. const line = computed(() => getSnapLine(store, props.data));
  107. const history = useHistory();
  108. watch(
  109. () => copy(line.value) as Pos[],
  110. (line, oldLine) => {
  111. history.preventTrack(() => {
  112. if (!line) {
  113. emit("delShape");
  114. }
  115. if (!oldLine) return;
  116. const eq0 = eqPoint(oldLine[0], line[0]);
  117. const eq1 = eqPoint(oldLine[1], line[1]);
  118. if (eq0 === eq1) return;
  119. // 联动
  120. const startNdx = eq0 ? 0 : 1;
  121. const endNdx = eq0 ? 1 : 0;
  122. const rotate = line2IncludedAngle(
  123. [oldLine[startNdx], oldLine[endNdx]],
  124. [line[startNdx], line[endNdx]]
  125. );
  126. const mat = new Transform()
  127. .translate(line[startNdx].x, line[startNdx].y)
  128. .rotate(rotate)
  129. .translate(-line[startNdx].x, -line[startNdx].y);
  130. const endPoints = getLineIconEndpoints(oldLine, data.value).map((p) =>
  131. mat.point(p)
  132. );
  133. if (lineInner(line, endPoints[0]) && lineInner(line, endPoints[1])) {
  134. emit("updateShape", {
  135. ...data.value,
  136. startLen: lineLen(line[0], endPoints[0]),
  137. endLen: lineLen(line[0], endPoints[1]),
  138. });
  139. } else {
  140. emit("delShape");
  141. }
  142. });
  143. },
  144. { immediate: true }
  145. );
  146. operateMenus.splice(
  147. operateMenus.length - 1,
  148. 0,
  149. {
  150. label: "内外翻转",
  151. handler: () => {
  152. emit("updateShape", {
  153. ...data.value,
  154. openSide: data.value.openSide === "LEFT" ? "RIGHT" : "LEFT",
  155. });
  156. },
  157. },
  158. {
  159. label: "左右翻转",
  160. handler: () => {
  161. emit("updateShape", {
  162. ...data.value,
  163. openSide: data.value.openSide === "LEFT" ? "RIGHT" : "LEFT",
  164. startLen: data.value.endLen,
  165. endLen: data.value.startLen,
  166. });
  167. },
  168. }
  169. );
  170. </script>