index.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import { lineVector, Pos, vectorAngle, verticalVector } from "@/utils/math.ts";
  2. import { BaseItem, generateSnapInfos, getBaseItem } from "../util.ts";
  3. import { getMouseColors } from "@/utils/colors.ts";
  4. import { InteractiveFix, InteractiveTo, MatResponseProps } from "../index.ts";
  5. import { inRevise, onlyId, rangMod } from "@/utils/shared.ts";
  6. import { MathUtils } from "three";
  7. import { DrawStore, useStore } from "@/core/store/index.ts";
  8. import {
  9. SelectionManageBus,
  10. UseGetSelectionManage,
  11. } from "@/core/hook/use-selection.ts";
  12. import { EntityShape } from "@/deconstruction.js";
  13. import mitt from "mitt";
  14. import { watch } from "vue";
  15. import { getInitCtx, NLineDataCtx, normalLineData } from "./attach-server.ts";
  16. export { default as Component } from "./line.vue";
  17. export { default as TempComponent } from "./temp-line.vue";
  18. export { useDraw } from "./use-draw.ts";
  19. export const shapeName = "线段";
  20. export const defaultStyle = {
  21. stroke: "#000000",
  22. strokeWidth: 20,
  23. dash: [30, 0],
  24. };
  25. export const addMode = "single-dots";
  26. export const getMouseStyle = (data: LineData) => {
  27. const strokeStatus = getMouseColors(data.stroke || defaultStyle.stroke);
  28. const strokeWidth = data.strokeWidth || defaultStyle.strokeWidth;
  29. return {
  30. default: { stroke: data.stroke || defaultStyle.stroke, strokeWidth },
  31. hover: { stroke: strokeStatus.hover },
  32. select: { stroke: strokeStatus.select },
  33. focus: { stroke: strokeStatus.hover },
  34. press: { stroke: strokeStatus.press },
  35. };
  36. };
  37. export const getSnapInfos = (data: LineData) => {
  38. const vh = generateSnapInfos(getSnapPoints(data), true, false, true);
  39. data.lines.forEach((item) => {
  40. const a = data.points.find((p) => p.id === item.a)!;
  41. const b = data.points.find((p) => p.id === item.b)!;
  42. const prevVector = lineVector([a, b]);
  43. const vLine = verticalVector(prevVector);
  44. vh.push({
  45. point: a,
  46. links: [b],
  47. linkDirections: [prevVector],
  48. linkAngle: [rangMod(MathUtils.radToDeg(vectorAngle(vLine)), 180)],
  49. });
  50. });
  51. return vh;
  52. };
  53. export const getSnapPoints = (data: LineData) => {
  54. return data.points;
  55. };
  56. export type LineDataLine = {
  57. id: string;
  58. a: string;
  59. b: string;
  60. strokeWidth: number;
  61. stroke: string;
  62. dash: number[];
  63. };
  64. export type LineDataPoint = Pos & { id: string }
  65. export type LineData = Partial<typeof defaultStyle> &
  66. BaseItem & {
  67. points: LineDataPoint[];
  68. lines: LineDataLine[];
  69. polygon: { points: string[]; id: string }[];
  70. updateTime?: number;
  71. calcTime?: number;
  72. };
  73. export const interactiveToData: InteractiveTo<"line"> = ({
  74. info,
  75. preset = {},
  76. ...args
  77. }) => {
  78. if (info.cur) {
  79. const baseItem = getBaseItem();
  80. return interactiveFixData({
  81. ...args,
  82. info,
  83. data: {
  84. ...defaultStyle,
  85. ...baseItem,
  86. ...preset,
  87. lines: [],
  88. points: [],
  89. polygon: [],
  90. },
  91. });
  92. }
  93. };
  94. export const interactiveFixData: InteractiveFix<"line"> = ({ data, info }) => {
  95. const nv = [...info.consumed, info.cur!];
  96. data.points.length = nv.length;
  97. for (let i = 0; i < nv.length; i++) {
  98. if (inRevise(data.points[i], nv[i])) {
  99. if (!data.points[i]) {
  100. data.points[i] = {
  101. id: onlyId(),
  102. ...nv[i],
  103. };
  104. } else {
  105. data.points[i] = {
  106. ...data.points[i],
  107. ...nv[i],
  108. };
  109. }
  110. }
  111. }
  112. data.lines.length = nv.length - 1;
  113. for (let i = 0; i < nv.length - 1; i++) {
  114. if (!data.lines[i]) {
  115. data.lines[i] = {
  116. id: onlyId(),
  117. ...defaultStyle,
  118. a: data.points[i].id,
  119. b: data.points[i + 1].id,
  120. };
  121. }
  122. }
  123. // data.polygon = [{points: [data.lines.map((item) => item.id)], id: onlyId()}];
  124. return data;
  125. };
  126. const matResPoints = new Set<string>();
  127. let matCtx: NLineDataCtx | null;
  128. export const startMatResponse = () => {
  129. matCtx = getInitCtx();
  130. };
  131. export const matResponse = ({
  132. data,
  133. mat,
  134. operId,
  135. }: MatResponseProps<"line">) => {
  136. const line = data.lines.find((item) => item.id === operId);
  137. if (!line) return;
  138. const ids = [line.a, line.b];
  139. for (const id of ids) {
  140. if (matResPoints.has(id)) {
  141. continue;
  142. }
  143. const ndx = data.points.findIndex((item) => item.id === id);
  144. if (~ndx) {
  145. const point = data.points[ndx];
  146. data.points[ndx] = {
  147. ...point,
  148. ...mat.point(point),
  149. };
  150. matCtx!.update.points[point.id] = data.points[ndx];
  151. matResPoints.add(id);
  152. }
  153. }
  154. return data;
  155. };
  156. export const endMatResponse = () => {
  157. matResPoints.clear();
  158. // matCtx && normalLineData(matData, matCtx)
  159. // console.log(matData, matCtx)
  160. matCtx = null;
  161. };
  162. export const getPredefine = (key: keyof LineData) => {
  163. if (key === "strokeWidth") {
  164. return { proportion: true };
  165. }
  166. };
  167. export const childrenDataGetter = (data: LineData, id: string) => {
  168. const line = data.lines.find((item) => item.id === id);
  169. if (!line) return;
  170. const ids = [line.a, line.b];
  171. return data.points.filter((p) => ids.includes(p.id));
  172. };
  173. export const delItem = (store: DrawStore, data: LineData, childId: string) => {
  174. if (!childId) {
  175. store.delItem("line", data.id);
  176. return;
  177. }
  178. let ndx;
  179. if (~(ndx = data.lines.findIndex((item) => item.id === childId))) {
  180. const delLine = data.lines[ndx];
  181. const ctx = getInitCtx();
  182. ctx.del.lines[delLine.id] = delLine;
  183. data.lines.splice(ndx, 1);
  184. normalLineData(data, ctx);
  185. store.setItem("line", { value: data, id: data.id });
  186. } else if (~(ndx = data.points.findIndex((item) => item.id === childId))) {
  187. const { ctx } = delPoint(data, childId);
  188. normalLineData(data, ctx);
  189. store.setItem("line", { value: data, id: data.id });
  190. }
  191. };
  192. export const delPoint = (data: LineData, id: string, ctx = getInitCtx()) => {
  193. const p = data.points.find((item) => item.id === id);
  194. if (!p) return { data, ctx };
  195. const checkLines = data.lines.filter(
  196. (item) => item.a === p.id || item.b === p.id
  197. );
  198. if (checkLines.length > 1) {
  199. const joinPoints = new Set<string>();
  200. checkLines.forEach((item) => {
  201. joinPoints.add(item.a);
  202. joinPoints.add(item.b);
  203. });
  204. if (joinPoints.size === 3) {
  205. const prev = checkLines.find((item) => item.b === p.id);
  206. const next = checkLines.find((item) => item.a === p.id);
  207. if (prev && next) {
  208. const l = { ...prev, id: onlyId(), b: next.b };
  209. ctx.add.lines[l.id] = l;
  210. data.lines.push(l);
  211. } else {
  212. const l = prev || next || checkLines[0];
  213. const ps = [...joinPoints].filter((item) => item !== p.id);
  214. const nl = { ...l, id: onlyId(), a: ps[0], b: ps[1] };
  215. ctx.add.lines[l.id] = nl;
  216. data.lines.push(nl);
  217. }
  218. }
  219. }
  220. checkLines.forEach((l) => {
  221. ctx.del.lines[l.id] = l;
  222. const ndx = data.lines.findIndex((ln) => ln.id === l.id);
  223. ~ndx && data.lines.splice(ndx, 1);
  224. });
  225. ctx.del.points[p.id] = p;
  226. const ndx = data.points.findIndex((pn) => pn.id === p.id);
  227. ~ndx && data.points.splice(ndx, 1);
  228. return { data, ctx };
  229. };
  230. export const useGetSelectionManage: UseGetSelectionManage = () => {
  231. const store = useStore();
  232. const canSelect = (shape: EntityShape) => {
  233. const id = shape.id();
  234. const line = store.getTypeItems("line")[0];
  235. return !!(id && line.lines.some((item) => item.id === id));
  236. };
  237. const listener = (shape: EntityShape) => {
  238. const bus: SelectionManageBus = mitt();
  239. const stop = watch(
  240. () => canSelect(shape),
  241. (exixts, _) => {
  242. if (!exixts) {
  243. bus.emit("del", shape);
  244. }
  245. },
  246. { immediate: true }
  247. );
  248. return { stop, bus };
  249. };
  250. return { canSelect, listener };
  251. };