helper-v2.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import { getStepLine, Step, traversalSteps } from "./tree-helper";
  2. import {
  3. getStepsTreeCtx as getStepsTreeCtxRaw,
  4. StepsCtx as StepsCtxRaw,
  5. } from "./tree-helper";
  6. type DataStep = {
  7. serviceTypeParallel?: boolean | "True" | "Flase";
  8. subStepsParallel?: boolean | "True" | "Flase";
  9. };
  10. export type DataStepTree<T extends DataStep = DataStep> = T & {
  11. steps: DataStepTree<T>[];
  12. };
  13. export type NStep<T extends DataStepTree> = Step<T>;
  14. const _flatSteps = <T extends DataStep>(
  15. steps: DataStepTree<T>[],
  16. nsteps: NStep<DataStepTree<T>>[] = [],
  17. parents: NStep<DataStepTree<T>>[] = [],
  18. parallel = false
  19. ) => {
  20. const lonelySteps: NStep<DataStepTree<T>>[] = [];
  21. let tempParents = parents;
  22. for (const step of steps) {
  23. const stepParallel = parallel;
  24. if (!stepParallel && lonelySteps.length) {
  25. tempParents = [...lonelySteps];
  26. lonelySteps.length = 0;
  27. }
  28. const nstep = {
  29. raw: step,
  30. children: [],
  31. parents: tempParents,
  32. } as NStep<DataStepTree<T>>;
  33. nsteps.push(nstep);
  34. tempParents.forEach((parent) => parent.children.push(nstep));
  35. if (step.steps && step.steps.length) {
  36. step.serviceTypeParallel;
  37. lonelySteps.push(
  38. ..._flatSteps(
  39. step.steps,
  40. nsteps,
  41. [nstep],
  42. step.subStepsParallel === "True" ||
  43. step.serviceTypeParallel === "True" ||
  44. !!step.subStepsParallel ||
  45. !!step.serviceTypeParallel
  46. )
  47. );
  48. } else {
  49. lonelySteps.push(nstep);
  50. }
  51. }
  52. return lonelySteps;
  53. };
  54. export const flatSteps = <T extends DataStep>(steps: DataStepTree<T>[]) => {
  55. const nsteps: NStep<DataStepTree<T>>[] = [];
  56. _flatSteps(steps, nsteps);
  57. return nsteps;
  58. };
  59. // 获取step所有子级
  60. const getStepFlatSteps = <T extends DataStep>(step: DataStepTree<T>) => {
  61. if (!step.steps || step.steps.length === 0) return [];
  62. const children: DataStepTree<T>[] = [];
  63. for (const child of step.steps) {
  64. children.push(child);
  65. children.push(...getStepFlatSteps(child));
  66. }
  67. return children;
  68. };
  69. // 获取steps组成的bound
  70. const getStepsBound = <T>(nsteps: NStep<DataStepTree<T>>[]) => {
  71. const bounds = nsteps.map((nstep) => {
  72. return { ...nstep.box.offset, ...nstep.box.size };
  73. });
  74. let maxX = -Number.MAX_VALUE,
  75. maxY = -Number.MAX_VALUE,
  76. minX = Number.MAX_VALUE,
  77. minY = Number.MAX_VALUE;
  78. for (const bound of bounds) {
  79. minX = Math.min(bound.x, minX);
  80. minY = Math.min(bound.y, minY);
  81. maxX = Math.max(bound.x + bound.w, maxX);
  82. maxY = Math.max(bound.y + bound.h, maxY);
  83. }
  84. return {
  85. x: minX,
  86. y: minY,
  87. w: maxX - minX,
  88. h: maxY - minY,
  89. };
  90. };
  91. export type StepsCtx<T> = StepsCtxRaw<T> & {
  92. groupBoxs: {
  93. step: Step<T>;
  94. bound: { w: number; h: number; x: number; y: number };
  95. line: number[][];
  96. }[];
  97. };
  98. const setGroupBack = <T>(
  99. steps: NStep<DataStepTree<T>>[],
  100. ctx: StepsCtx<DataStepTree<T>>,
  101. groups: NStep<DataStepTree<T>>[]
  102. ) => {
  103. const maxWidth = Math.max(...groups.map(({ box }) => box.size.w));
  104. for (const groupStep of groups) {
  105. const children = getStepFlatSteps(groupStep.raw);
  106. const childSteps = children.map((raw) =>
  107. steps.find((step) => raw === step.raw)
  108. );
  109. ctx.groupBoxs.push({
  110. step: groupStep,
  111. line: [],
  112. bound: getStepsBound(childSteps),
  113. });
  114. groupStep.box.offset.x = -maxWidth + (maxWidth - groupStep.box.size.w) / 2;
  115. }
  116. ctx.offset.x = -maxWidth;
  117. ctx.size.w += maxWidth;
  118. };
  119. const setGroupOffset = <T>(
  120. steps: NStep<DataStepTree<T>>[],
  121. ctx: StepsCtx<DataStepTree<T>>,
  122. groupSteps: NStep<DataStepTree<T>>[],
  123. margin: number
  124. ) => {
  125. // margin = 0;
  126. const offsetYs: number[] = [];
  127. const offsetLYs: number[] = [];
  128. for (let i = 0; i < groupSteps.length; i++) {
  129. const groupStep = groupSteps[i];
  130. if (i > 0) {
  131. offsetYs[i] = -groupStep.box.size.h + offsetYs[i - 1] + margin;
  132. offsetLYs[i] = offsetLYs[i - 1] - groupStep.box.size.h + margin;
  133. } else {
  134. offsetYs[i] = -groupStep.box.size.h + margin;
  135. offsetLYs[i] = -groupStep.box.size.h + margin;
  136. }
  137. groupStep.box.offset.y += margin;
  138. }
  139. let offsetNdx = offsetYs.length - 1;
  140. let offsetLNdx = offsetYs.length - 1;
  141. traversalSteps({
  142. steps,
  143. ctx,
  144. oper: ({ currents }) => {
  145. const isBorder = currents.some((current) => groupSteps.includes(current));
  146. if (isBorder) {
  147. offsetNdx -= 1;
  148. }
  149. for (const current of currents) {
  150. if (offsetNdx === -1) {
  151. current.box.lines = [];
  152. break;
  153. }
  154. current.box.offset.y += offsetYs[offsetNdx];
  155. for (const points of current.box.lines) {
  156. for (const point of points) {
  157. point[1] = point[1] + offsetLYs[offsetLNdx];
  158. }
  159. }
  160. }
  161. if (isBorder) {
  162. offsetLNdx -= 1;
  163. }
  164. },
  165. reverse: true,
  166. });
  167. ctx.size.h += offsetYs[offsetYs.length - 1];
  168. };
  169. export const setGroupLine = <T>(
  170. ctx: StepsCtx<DataStepTree<T>>,
  171. groupSteps: NStep<DataStepTree<T>>[],
  172. margin: number[]
  173. ) => {
  174. for (let i = 0; i < groupSteps.length - 1; i++) {
  175. ctx.groupBoxs[i].line = getStepLine(
  176. ctx,
  177. groupSteps[i],
  178. groupSteps[i + 1],
  179. margin
  180. );
  181. }
  182. };
  183. export const getStepsTreeCtx = <T extends DataStep>(
  184. steps: NStep<DataStepTree<T>>[],
  185. margin: number[],
  186. getStepSize: (step: T) => { w: number; h: number },
  187. groups: DataStepTree<T>[]
  188. ) => {
  189. const ctx = getStepsTreeCtxRaw(steps, margin, getStepSize) as StepsCtx<
  190. DataStepTree<T>
  191. >;
  192. const groupSteps = groups.map((group) =>
  193. steps.find((step) => group === step.raw)
  194. );
  195. setGroupOffset(steps, ctx, groupSteps, margin[0]);
  196. ctx.groupBoxs = [];
  197. setGroupBack(steps, ctx, groupSteps);
  198. setGroupLine(ctx, groupSteps, margin);
  199. return ctx;
  200. };