123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- export type NStep = {
- id: number;
- parentIds: number[];
- name: string;
- bound: { width: number; height: number; left: number; top: number };
- prevId: number;
- raw: any;
- level: number;
- };
- const idFactory = () => {
- let id = 0;
- return () => id++;
- };
- const getId = idFactory();
- const _flatSteps = (
- steps: any,
- parentIds: number[] = [],
- level = 0,
- parallel = false,
- nsteps: NStep[] = []
- ): number[] => {
- const lonelyStepIds: number[] = [];
- let tempLevel = level;
- let tempParentIds = parentIds;
- for (const step of steps) {
- const id = getId();
- const stepParallel = parallel;
- if (!stepParallel && lonelyStepIds.length) {
- tempParentIds = [...lonelyStepIds];
- tempLevel =
- Math.max(
- ...nsteps
- .filter((nstep) => lonelyStepIds.includes(nstep.id))
- .map((nstep) => nstep.level)
- ) + 1;
- lonelyStepIds.length = 0;
- }
- let tempPrevId = -1;
- for (let i = nsteps.length - 1; i >= 0; i--) {
- if (nsteps[i].level === tempLevel) {
- tempPrevId = nsteps[i].id;
- break;
- }
- }
- const nstep = {
- id,
- name: step.name,
- parentIds: tempParentIds,
- prevId: tempPrevId,
- raw: step,
- level: tempLevel,
- } as NStep;
- nsteps.push(nstep);
- if (step.steps && step.steps.length) {
- lonelyStepIds.push(
- ..._flatSteps(
- step.steps as any,
- [id],
- tempLevel + 1,
- step.subStepsParallel === "True" ||
- step.serviceTypeParallel === "True",
- nsteps
- )
- );
- } else {
- lonelyStepIds.push(nstep.id);
- }
- }
- return lonelyStepIds;
- };
- type Size = { width: number; height: number };
- export const attachBoundAttrib = (
- steps: NStep[],
- getStepSize: (step: any) => { width: number; height: number }
- ) => {
- steps.sort((a, b) => a.level - b.level);
- const stepSizeMap = new Map<NStep, Size>();
- for (const step of steps) {
- const size = getStepSize(step.raw);
- stepSizeMap.set(step, size);
- }
- const treeSizeMap = new Map<NStep, Size>();
- const levelHeights: number[] = new Array(
- steps[steps.length - 1].level + 1
- ).fill(0);
- for (let i = steps.length - 1; i >= 0; i--) {
- const root = steps[i];
- const child = steps.filter(
- (oStep) =>
- oStep.parentIds.length === 1 &&
- oStep.parentIds.some((id) => root.id === id)
- );
- const rootBound = stepSizeMap.get(steps[i])!;
- const topLevel = root.level;
- let treeWidth = rootBound.width;
- let treeHeight = rootBound.height;
- levelHeights[topLevel] = Math.max(levelHeights[topLevel], treeHeight);
- if (child.length) {
- const bottomLevel = child[child.length - 1]?.level;
- for (let i = topLevel; i <= bottomLevel; i++) {
- let width = 0;
- let height = 0;
- for (let j = 0; j < child.length; j++) {
- if (child[j].level === i) {
- const childTreeSize = treeSizeMap.get(child[j])!;
- width += childTreeSize.width;
- height = Math.max(childTreeSize.height + rootBound.height, height);
- }
- }
- treeWidth = Math.max(treeWidth, width);
- treeHeight = Math.max(treeHeight, height);
- }
- }
- treeSizeMap.set(root, { width: treeWidth, height: treeHeight });
- }
- const levelsSteps: NStep[][] = [];
- let level = 0;
- while (true) {
- const levelSteps = steps.filter((step) => step.level === level);
- if (levelSteps.length === 0) {
- break;
- } else {
- levelsSteps[level] = levelSteps;
- }
- level++;
- }
- const getStepOffset = (step: NStep) => {
- const stepBound = stepSizeMap.get(step)!;
- const treeBound = treeSizeMap.get(step)!;
- let offset = 0;
- let prevId = step.prevId;
- while (prevId !== -1) {
- const prevStep = steps.find((tstep) => tstep.id === prevId)!;
- const treeBound = treeSizeMap.get(prevStep)!;
- offset += treeBound.width;
- prevId = prevStep.prevId;
- }
- const prevStep = steps.find((tstep) => tstep.id === step.prevId)!;
- if (prevStep) {
- offset = Math.max(prevStep.bound.left + prevStep.bound.width, offset);
- }
- let left = offset + (treeBound.width - stepBound.width) / 2;
- // 如果超出预设范围则修正
- if (step.parentIds.length === 1 && step.parentIds[0] !== -1) {
- if (step.parentIds[0] !== -1) {
- const parent = steps.find((pstep) => pstep.id === step.parentIds[0])!;
- const paretnBound = treeSizeMap.get(parent)!;
- if (parent.bound.left - left > paretnBound.width / 2) {
- // const width = stepBound.width;
- const width = steps
- .filter((step) => step.parentIds.includes(parent.id))
- .reduce((t, c) => t + stepSizeMap.get(c)!.width, 0);
- left = Math.max(
- left,
- parent.bound.left + (parent.bound.width - width) / 2
- );
- }
- }
- }
- return left;
- };
- let top = 0;
- let width = 0;
- for (let i = 0; i < levelsSteps.length; i++) {
- let levelHeight = levelHeights[i];
- for (const step of levelsSteps[i]) {
- const stepSize = stepSizeMap.get(step)!;
- step.bound = {
- left: getStepOffset(step),
- top: top + (levelHeight - stepSize.height) / 2,
- ...stepSize,
- };
- width = Math.max(step.bound.left + step.bound.width, width);
- }
- top += levelHeight;
- }
- const getParentBound = (step: NStep) => {
- const parentSteps = step.parentIds.map(
- (id) => steps.find((parentStep) => parentStep.id === id)!
- );
- let left = 0;
- let top = 0;
- let width = 0,
- height = 0;
- for (const step of parentSteps) {
- left = Math.min(step.bound.left, left);
- top = Math.min(step.bound.top, top);
- width += step.bound.width;
- height += step.bound.height;
- }
- return {
- width,
- height,
- left,
- top,
- };
- };
- const getCompleteTree = (root: NStep) => {
- const completeTree = [root];
- const completeTreeIds = [root.id];
- const levelsChilds = levelsSteps.slice(root.level);
- for (const childs of levelsChilds) {
- for (const step of childs) {
- if (step.parentIds.some((id) => completeTreeIds.includes(id))) {
- completeTree.push(step);
- completeTreeIds.push(step.id);
- }
- }
- }
- return completeTree;
- };
- // 偏移所有多父级树
- for (let i = 0; i < levelsSteps.length; i++) {
- for (const step of levelsSteps[i]) {
- if (step.parentIds.length <= 1) continue;
- const parentBound = getParentBound(step);
- const offset = (parentBound.width - treeSizeMap.get(step)!.width) / 2;
- getCompleteTree(step).forEach((ctStep) => {
- ctStep.bound.left += offset;
- });
- }
- }
- let left = 0,
- right = 0;
- for (let i = 0; i < steps.length; i++) {
- left = Math.min(steps[i].bound.left, left);
- right = Math.max(steps[i].bound.left + steps[i].bound.width, right);
- }
- return { left, right, top: 0, bottom: top, levelHeights };
- };
- export const flatSteps = (data: any) => {
- const nsteps: NStep[] = [];
- _flatSteps(data, [], 0, false, nsteps);
- return nsteps;
- };
- const ctx = document.createElement("canvas").getContext("2d")!;
- export const getTextBound = (
- text: string,
- padding: number[],
- margin: number[],
- font: string
- ) => {
- ctx.font = font;
- const textMetrics = ctx.measureText(text);
- const width = textMetrics.width + (padding[1] + margin[1]) * 2;
- const height = textMetrics.hangingBaseline + (padding[0] + margin[0]) * 2;
- return { width, height };
- };
|