single-line.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <template>
  2. <EditLine
  3. :ref="(d: any) => shape = d?.shape"
  4. :data="{ ...line, ...style, lineJoin: 'miter' }"
  5. :opacity="0"
  6. :points="points"
  7. :closed="false"
  8. :id="line.id"
  9. :disablePoint="!canEdit || mode.include(Mode.readonly)"
  10. :ndx="0"
  11. @dragstart="emit('dragLineStart', props.line)"
  12. @update:line="(ps) => emit('dragLine', props.line, ps)"
  13. @dragend="emit('dragLineEnd', props.line)"
  14. @add-point="addPoint"
  15. />
  16. <SizeLine
  17. v-if="
  18. status.active ||
  19. config.showComponentSize ||
  20. isDrawIng ||
  21. dragPointIds?.includes(line.a) ||
  22. dragPointIds?.includes(line.b)
  23. "
  24. :points="points"
  25. :strokeWidth="style.strokeWidth"
  26. :stroke="style.stroke"
  27. />
  28. <v-line
  29. v-for="polygon in diffPolygons"
  30. :config="{
  31. points: flatPositions(polygon),
  32. fill: line.stroke,
  33. closed: true,
  34. listening: false,
  35. }"
  36. v-if="diffPolygons"
  37. />
  38. <template v-if="showEditPoint">
  39. <EditPoint
  40. v-for="(point, ndx) in points"
  41. :key="point.id"
  42. :size="line.strokeWidth"
  43. :points="points"
  44. :opacity="1"
  45. :drawIng="ndx === 0 && isDrawIng"
  46. :ndx="ndx"
  47. :closed="false"
  48. :id="line.id"
  49. :disable="addMode"
  50. :color="isDrawIng ? themeColor : style.stroke"
  51. @dragstart="dragstartHandler([point.id])"
  52. @update:position="(p) => emit('updatePoint', { ...point, ...p })"
  53. @dragend="dragendHandler"
  54. @delete="delPoint(point)"
  55. />
  56. </template>
  57. <PropertyUpdate
  58. :describes="describes"
  59. :data="line"
  60. :target="shape"
  61. :name="shapeName"
  62. @change="
  63. () => {
  64. isStartChange || emit('updateBefore', []);
  65. emit('updateLine', { ...line });
  66. emit('update');
  67. isStartChange = false;
  68. }
  69. "
  70. @delete="delHandler"
  71. />
  72. <Operate :target="shape" :menus="menus" />
  73. </template>
  74. <script lang="ts" setup>
  75. import { computed, ref, watchEffect } from "vue";
  76. import { getMouseStyle, getSnapInfos, LineData, shapeName } from "./index.ts";
  77. import { flatPositions, onlyId } from "@/utils/shared.ts";
  78. import EditLine from "../share/edit-line.vue";
  79. import { getVectorLine, lineCenter, lineLen, lineVector, Pos } from "@/utils/math.ts";
  80. import { Line } from "konva/lib/shapes/Line";
  81. import { DC } from "@/deconstruction.js";
  82. import { useMode } from "@/core/hook/use-status.ts";
  83. import { Mode } from "@/constant/mode.ts";
  84. import SizeLine from "../share/size-line.vue";
  85. import { useConfig } from "@/core/hook/use-config.ts";
  86. import { ComponentSnapInfo } from "../index.ts";
  87. import { useCustomSnapInfos } from "@/core/hook/use-snap.ts";
  88. import { mergeDescribes } from "@/core/html-mount/propertys/index.ts";
  89. import { PropertyUpdate, Operate } from "../../html-mount/propertys/index.ts";
  90. import {
  91. useAnimationMouseStyle,
  92. useMouseShapeStatus,
  93. } from "@/core/hook/use-mouse-status.ts";
  94. import { themeColor } from "@/constant";
  95. import { Vector2 } from "three";
  96. import { useGetDiffPolygons, useGetExtendPolygon } from "./attach-view.ts";
  97. import EditPoint from "../share/edit-point.vue";
  98. const mode = useMode();
  99. const props = defineProps<{
  100. line: LineData["lines"][number];
  101. addMode?: boolean;
  102. canEdit?: boolean;
  103. data: LineData;
  104. dragPointIds?: string[];
  105. }>();
  106. const getExtendPolygon = useGetExtendPolygon();
  107. const polygon = computed(() =>
  108. getExtendPolygon(props.data, props.line, !showEditPoint.value)
  109. );
  110. const getDiffPolygons = useGetDiffPolygons();
  111. const diffPolygons = computed(() => getDiffPolygons(polygon.value));
  112. const showEditPoint = computed(
  113. () => (!mode.include(Mode.readonly) && props.canEdit) || isDrawIng.value
  114. );
  115. const emit = defineEmits<{
  116. (e: "updatePoint", value: LineData["points"][number]): void;
  117. (e: "addPoint", value: LineData["points"][number]): void;
  118. (e: "delPoint", value: LineData["points"][number]): void;
  119. (e: "delLine"): void;
  120. (e: "updateLine", value: LineData["lines"][number]): void;
  121. (e: "updateBefore", value: string[]): void;
  122. (e: "update"): void;
  123. (e: "dragLineStart", value: LineData["lines"][number]): void;
  124. (e: "dragLine", line: LineData["lines"][number], move: Pos[]): void;
  125. (e: "dragLineEnd", value: LineData["lines"][number]): void;
  126. }>();
  127. const shape = ref<DC<Line>>();
  128. const points = computed(() => [
  129. props.data.points.find((p) => p.id === props.line.a)!,
  130. props.data.points.find((p) => p.id === props.line.b)!,
  131. ]);
  132. const lineData = computed(() => props.line);
  133. const describes = mergeDescribes(lineData, {}, ["stroke", "strokeWidth"]);
  134. const d = describes as any;
  135. d.strokeWidth.props = {
  136. ...d.strokeWidth.props,
  137. proportion: true,
  138. };
  139. d.strokeWidth.label = "粗细";
  140. d.stroke.label = "颜色";
  141. let isStartChange = false;
  142. let setLineVector: Vector2;
  143. describes.length = {
  144. type: "inputNum",
  145. label: "线段长度",
  146. "layout-type": "row",
  147. get value() {
  148. return lineLen(points.value[0], points.value[1]);
  149. },
  150. set value(val) {
  151. if (!isStartChange) {
  152. emit("updateBefore", [props.line.a, props.line.b]);
  153. setLineVector = lineVector(points.value);
  154. }
  155. isStartChange = true;
  156. const aCount = props.data.lines.filter(
  157. (line) => line.a === points.value[0].id || line.b === points.value[0].id
  158. ).length;
  159. const bCount = props.data.lines.filter(
  160. (line) => line.a === points.value[1].id || line.b === points.value[1].id
  161. ).length;
  162. if (aCount === bCount || (aCount > 1 && bCount > 1)) {
  163. // 两端伸展
  164. const center = lineCenter(points.value);
  165. const l1 = getVectorLine(setLineVector.clone().multiplyScalar(-1), center, val / 2);
  166. const l2 = getVectorLine(setLineVector, center, val / 2);
  167. emit("updatePoint", { ...points.value[0], ...l1[1] });
  168. emit("updatePoint", { ...points.value[1], ...l2[1] });
  169. } else {
  170. // 单端伸展
  171. const changeNdx = aCount > 1 ? 1 : 0;
  172. const start = points.value[aCount > 1 ? 0 : 1];
  173. const lineVec =
  174. aCount > 1 ? setLineVector : setLineVector.clone().multiplyScalar(-1);
  175. const line = getVectorLine(lineVec, start, val);
  176. emit("updatePoint", { ...points.value[changeNdx], ...line[1] });
  177. }
  178. },
  179. props: { proportion: true },
  180. };
  181. const delHandler = () => {
  182. emit("updateBefore", [props.line.a, props.line.b]);
  183. emit("delLine");
  184. emit("update");
  185. };
  186. const menus = [
  187. {
  188. label: "删除",
  189. handler: delHandler,
  190. },
  191. ];
  192. const status = useMouseShapeStatus(shape);
  193. const [mstyle] = useAnimationMouseStyle({
  194. shape,
  195. getMouseStyle,
  196. data: lineData as any,
  197. });
  198. const isDrawIng = computed(
  199. () =>
  200. props.addMode && props.data.lines.indexOf(props.line) === props.data.lines.length - 1
  201. );
  202. const style = computed(() =>
  203. isDrawIng.value ? { ...mstyle.value, stroke: themeColor } : mstyle.value
  204. );
  205. const addPoint = (pos: Pos) => {
  206. emit("updateBefore", []);
  207. emit("addPoint", { ...points.value[0], ...pos, id: onlyId() });
  208. emit("update");
  209. };
  210. const config = useConfig();
  211. const delPoint = (point: LineData["points"][number]) => {
  212. emit("updateBefore", []);
  213. emit("delPoint", point);
  214. emit("update");
  215. };
  216. const infos = useCustomSnapInfos();
  217. let snapInfos: ComponentSnapInfo[];
  218. const dragstartHandler = (eIds: string[]) => {
  219. emit("updateBefore", eIds);
  220. snapInfos = getSnapInfos({
  221. ...props.data,
  222. lines: props.data.lines.filter(
  223. (item) => !(eIds.includes(item.a) || eIds.includes(item.b))
  224. ),
  225. points: props.data.points.filter((item) => !eIds.includes(item.id)),
  226. });
  227. snapInfos.forEach((item) => {
  228. infos.add(item);
  229. });
  230. };
  231. const dragendHandler = () => {
  232. emit("update");
  233. snapInfos.forEach((item) => infos.remove(item));
  234. };
  235. // const padstart = computed(() => {
  236. // props.line.
  237. // })
  238. </script>