| @@ -0,0 +1,338 @@ | |||||
| import { defineMock } from 'umi'; | |||||
| export default defineMock({ | |||||
| 'POST /api/mmp/modelDependency/queryModelAtlas': { | |||||
| code: 200, | |||||
| msg: '操作成功', | |||||
| data: { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: 229, | |||||
| version: 'v0.2.0', | |||||
| ref_item: null, | |||||
| train_task: { | |||||
| name: '模型训练测试导出0529', | |||||
| ins_id: 229, | |||||
| task_id: 'model-train-5d76f002', | |||||
| }, | |||||
| train_dataset: [ | |||||
| { | |||||
| dataset_id: 20, | |||||
| dataset_version: 'v0.1.0', | |||||
| dataset_name: '手写体识别模型依赖测试训练数据集', | |||||
| }, | |||||
| ], | |||||
| train_params: ['256', '2'], | |||||
| train_image: '172.20.32.187/machine-learning/pytorch:pytorch_1.9.1_cuda11.1_detection_aim', | |||||
| test_dataset: [ | |||||
| { | |||||
| dataset_id: 20, | |||||
| dataset_version: 'v0.1.0', | |||||
| dataset_name: '手写体识别模型依赖测试训练数据集', | |||||
| }, | |||||
| ], | |||||
| project_dependency: { | |||||
| url: 'https://openi.pcl.ac.cn/somunslotus/somun202304241505581.git', | |||||
| name: 'somun202304241505581', | |||||
| branch: 'train_ci_test', | |||||
| }, | |||||
| parent_models_map: [ | |||||
| { | |||||
| model_id: 29, | |||||
| model_version: 'v0.1.0', | |||||
| model_name: 'mnist模型演化', | |||||
| }, | |||||
| ], | |||||
| parent_models: [ | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.1.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: null, | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| ], | |||||
| children_models: [ | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.3.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: [], | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.31.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: [], | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.4.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: [ | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.6.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: [], | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.7.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: [], | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| ], | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.5.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: [ | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.10.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: [], | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| { | |||||
| current_model_id: 29, | |||||
| exp_ins_id: null, | |||||
| version: 'v0.11.0', | |||||
| ref_item: null, | |||||
| train_task: {}, | |||||
| train_dataset: [], | |||||
| train_params: [], | |||||
| train_image: null, | |||||
| test_dataset: [], | |||||
| project_dependency: {}, | |||||
| parent_models_map: [], | |||||
| parent_models: [], | |||||
| children_models: [], | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| ], | |||||
| workflow_id: null, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172558449/mnist_epoch1_0.00.pkl', | |||||
| file_name: 'mnist_epoch1_0.00.pkl', | |||||
| file_size: '176.63 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:09:56.000+00:00', | |||||
| }, | |||||
| }, | |||||
| ], | |||||
| workflow_id: 144, | |||||
| model_version_dependcy_vo: { | |||||
| name: 'mnist模型演化', | |||||
| description: '手写体识别模型演化', | |||||
| available_range: 0, | |||||
| model_type: '37', | |||||
| model_tag: '46', | |||||
| model_type_name: 'PyTorch', | |||||
| model_tag_name: '图像转文本', | |||||
| url: 'models/admin/1718172760650/mnist_cnn.pt', | |||||
| file_name: 'mnist_cnn.pt', | |||||
| file_size: '176.76 KB', | |||||
| create_by: 'admin', | |||||
| create_time: '2024-06-12T06:12:42.000+00:00', | |||||
| }, | |||||
| }, | |||||
| }, | |||||
| }); | |||||
| @@ -33,7 +33,7 @@ | |||||
| "serve": "umi-serve", | "serve": "umi-serve", | ||||
| "start": "cross-env UMI_ENV=dev max dev", | "start": "cross-env UMI_ENV=dev max dev", | ||||
| "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev", | "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev", | ||||
| "start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev", | |||||
| "start:mock": "cross-env REACT_APP_ENV=dev UMI_ENV=dev max dev", | |||||
| "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev", | "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev", | ||||
| "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev", | "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev", | ||||
| "test": "jest", | "test": "jest", | ||||
| @@ -9,8 +9,8 @@ export const vGap = nodeHeight + 20; | |||||
| export const hGap = nodeHeight + 20; | export const hGap = nodeHeight + 20; | ||||
| export const ellipseWidth = nodeWidth; | export const ellipseWidth = nodeWidth; | ||||
| // 数据集节点矩形数组 | |||||
| const datasetRects: Rect[] = []; | |||||
| // 数据集节点 | |||||
| const datasetNodes: NodeConfig[] = []; | |||||
| export enum NodeType { | export enum NodeType { | ||||
| current = 'current', | current = 'current', | ||||
| @@ -22,8 +22,8 @@ export enum NodeType { | |||||
| } | } | ||||
| export type Rect = { | export type Rect = { | ||||
| x: number; | |||||
| y: number; | |||||
| x: number; // 矩形中心的 x 坐标 | |||||
| y: number; // 矩形中心的 y 坐标 | |||||
| width: number; | width: number; | ||||
| height: number; | height: number; | ||||
| }; | }; | ||||
| @@ -142,14 +142,6 @@ export function normalizeTreeData(apiData: ModelDepsAPIData): ModelDepsData { | |||||
| normalizedData.id = `$M_${normalizedData.current_model_id}_${normalizedData.version}`; | normalizedData.id = `$M_${normalizedData.current_model_id}_${normalizedData.version}`; | ||||
| normalizedData.label = getLabel(normalizedData); | normalizedData.label = getLabel(normalizedData); | ||||
| normalizedData.style = getStyle(NodeType.current); | normalizedData.style = getStyle(NodeType.current); | ||||
| // let first1 = { ...normalizedData.children[0] }; | |||||
| // let first2 = { ...normalizedData.children[0] }; | |||||
| // let first3 = { ...normalizedData.children[0] }; | |||||
| // first1.current_model_id = 202020; | |||||
| // first2.current_model_id = 202021; | |||||
| // first3.current_model_id = 202022; | |||||
| // normalizedData.children.push(first1, first2, first3); | |||||
| normalizeChildren(normalizedData.children as ModelDepsData[]); | normalizeChildren(normalizedData.children as ModelDepsData[]); | ||||
| // 将 parent_models 转换成树形结构 | // 将 parent_models 转换成树形结构 | ||||
| @@ -191,14 +183,12 @@ export function getGraphData(data: ModelDepsData): GraphData { | |||||
| const edges: EdgeConfig[] = []; | const edges: EdgeConfig[] = []; | ||||
| Util.traverseTree(treeLayoutData, (node: NodeConfig, parent: NodeConfig) => { | Util.traverseTree(treeLayoutData, (node: NodeConfig, parent: NodeConfig) => { | ||||
| const data = node.data as ModelDepsData; | const data = node.data as ModelDepsData; | ||||
| console.log('data', data); | |||||
| // 当前模型显示数据集和项目 | // 当前模型显示数据集和项目 | ||||
| if (data.model_type === NodeType.current) { | if (data.model_type === NodeType.current) { | ||||
| addDatasetDependency(data, node, nodes, edges); | addDatasetDependency(data, node, nodes, edges); | ||||
| addProjectDependency(data, node, nodes, edges); | addProjectDependency(data, node, nodes, edges); | ||||
| } else if (data.model_type === NodeType.children) { | } else if (data.model_type === NodeType.children) { | ||||
| adjustChildrenPosition(node); | |||||
| adjustDatasetPosition(node); | |||||
| } | } | ||||
| nodes.push({ | nodes.push({ | ||||
| ...data, | ...data, | ||||
| @@ -224,17 +214,17 @@ const addDatasetDependency = ( | |||||
| ) => { | ) => { | ||||
| const { train_dataset, test_dataset } = data; | const { train_dataset, test_dataset } = data; | ||||
| train_dataset.forEach((item) => { | train_dataset.forEach((item) => { | ||||
| item.id = `$DTrain_${item.dataset_id}`; | |||||
| item.id = `$DTrain_${item.dataset_id}_${item.dataset_version}`; | |||||
| item.model_type = NodeType.trainDataset; | item.model_type = NodeType.trainDataset; | ||||
| item.style = getStyle(NodeType.trainDataset); | item.style = getStyle(NodeType.trainDataset); | ||||
| }); | }); | ||||
| test_dataset.forEach((item) => { | test_dataset.forEach((item) => { | ||||
| item.id = `$DTest_${item.dataset_id}`; | |||||
| item.id = `$DTest_${item.dataset_id}_${item.dataset_version}`; | |||||
| item.model_type = NodeType.testDataset; | item.model_type = NodeType.testDataset; | ||||
| item.style = getStyle(NodeType.testDataset); | item.style = getStyle(NodeType.testDataset); | ||||
| }); | }); | ||||
| datasetRects.length = 0; | |||||
| datasetNodes.length = 0; | |||||
| const len = train_dataset.length + test_dataset.length; | const len = train_dataset.length + test_dataset.length; | ||||
| [...train_dataset, ...test_dataset].forEach((item, index) => { | [...train_dataset, ...test_dataset].forEach((item, index) => { | ||||
| const node = { ...item }; | const node = { ...item }; | ||||
| @@ -246,9 +236,10 @@ const addDatasetDependency = ( | |||||
| fittingString(node.dataset_version, ellipseWidth - 12, 8); | fittingString(node.dataset_version, ellipseWidth - 12, 8); | ||||
| const half = len / 2 - 0.5; | const half = len / 2 - 0.5; | ||||
| node.x = currentNode.x! - (half - index) * (ellipseWidth + hGap); | |||||
| node.x = currentNode.x! - (half - index) * (ellipseWidth + hGap / 2); | |||||
| node.y = currentNode.y! - nodeHeight - vGap; | node.y = currentNode.y! - nodeHeight - vGap; | ||||
| nodes.push(node); | nodes.push(node); | ||||
| datasetNodes.push(node); | |||||
| edges.push({ | edges.push({ | ||||
| source: currentNode.id, | source: currentNode.id, | ||||
| target: node.id, | target: node.id, | ||||
| @@ -256,12 +247,6 @@ const addDatasetDependency = ( | |||||
| targetAnchor: 3, | targetAnchor: 3, | ||||
| type: 'cubic-vertical', | type: 'cubic-vertical', | ||||
| }); | }); | ||||
| datasetRects.push({ | |||||
| x: node.x - ellipseWidth / 2, | |||||
| y: node.y - nodeHeight / 2, | |||||
| width: ellipseWidth, | |||||
| height: nodeHeight, | |||||
| }); | |||||
| }); | }); | ||||
| }; | }; | ||||
| @@ -275,7 +260,7 @@ const addProjectDependency = ( | |||||
| const { project_dependency } = data; | const { project_dependency } = data; | ||||
| if (project_dependency?.url) { | if (project_dependency?.url) { | ||||
| const node = { ...project_dependency }; | const node = { ...project_dependency }; | ||||
| node.id = `$P_${node.url}`; | |||||
| node.id = `$P_${node.url}_${node.branch}`; | |||||
| node.model_type = NodeType.project; | node.model_type = NodeType.project; | ||||
| node.type = 'rect'; | node.type = 'rect'; | ||||
| node.label = fittingString(node.name, nodeWidth - 12, 8); | node.label = fittingString(node.name, nodeWidth - 12, 8); | ||||
| @@ -296,42 +281,48 @@ const addProjectDependency = ( | |||||
| }; | }; | ||||
| // 判断两个矩形是否相交 | // 判断两个矩形是否相交 | ||||
| function isRectanglesIntersect(rect1: Rect, rect2: Rect) { | |||||
| return !( | |||||
| rect1.x + rect1.width < rect2.x || | |||||
| rect1.x > rect2.x + rect2.width || | |||||
| rect1.y + rect1.height < rect2.y || | |||||
| rect1.y > rect2.y + rect2.height | |||||
| ); | |||||
| function isRectanglesOverlap(rect1: Rect, rect2: Rect) { | |||||
| const a2x = rect1.x + rect1.width / 2; | |||||
| const a2y = rect1.y + rect1.height / 2; | |||||
| const b1x = rect2.x - rect2.width / 2; | |||||
| const b1y = rect2.y - rect2.height / 2; | |||||
| return b1y <= a2y && b1x <= a2x; | |||||
| } | } | ||||
| // 判断子节点是否与数据集节点重叠 | // 判断子节点是否与数据集节点重叠 | ||||
| function isChildrenIntersectDataset(rects: Rect[], childrenRect: Rect) { | |||||
| for (const r of rects) { | |||||
| if (isRectanglesIntersect(r, childrenRect)) { | |||||
| return r; | |||||
| function isChildrenOverlapDataset(nodes: NodeConfig[], childrenRect: Rect) { | |||||
| for (const node of nodes) { | |||||
| const rect = { x: node.x!, y: node.y!, width: nodeWidth, height: nodeHeight }; | |||||
| if (isRectanglesOverlap(rect, childrenRect)) { | |||||
| return childrenRect; | |||||
| } | } | ||||
| } | } | ||||
| return null; | return null; | ||||
| } | } | ||||
| // 计算子节点位置 | |||||
| function adjustChildrenPosition(node: NodeConfig) { | |||||
| // 调整数据集位置 | |||||
| function adjustDatasetPosition(node: NodeConfig) { | |||||
| const nodeRect = { | const nodeRect = { | ||||
| x: node.x! - nodeWidth / 2, | |||||
| y: node.y! - nodeHeight / 2, | |||||
| x: node.x!, | |||||
| y: node.y!, | |||||
| width: nodeWidth, | width: nodeWidth, | ||||
| height: nodeHeight, | height: nodeHeight, | ||||
| }; | }; | ||||
| const overlapRect = isChildrenIntersectDataset(datasetRects, nodeRect); | |||||
| const overlapRect = isChildrenOverlapDataset(datasetNodes, nodeRect); | |||||
| if (overlapRect) { | if (overlapRect) { | ||||
| const offsetY = nodeRect.y - overlapRect.y; | |||||
| const space = 10; //(vGap + Math.abs(offsetY) - nodeHeight) / 2; | |||||
| if (offsetY >= 0) { | |||||
| node.y = node.y! + (nodeHeight - offsetY + space); | |||||
| } else { | |||||
| node.y = node.y! - (nodeHeight - Math.abs(offsetY) + space); | |||||
| } | |||||
| console.log(node); | |||||
| const adjustRect = { | |||||
| x: overlapRect.x - nodeWidth - hGap / 2, | |||||
| y: overlapRect.y, | |||||
| width: overlapRect.width, | |||||
| height: overlapRect.height, | |||||
| }; | |||||
| const lastNode = datasetNodes[datasetNodes.length - 1] as NodeConfig; | |||||
| const distance = lastNode.x! - adjustRect.x; | |||||
| datasetNodes.forEach((item) => { | |||||
| item.x = item.x! - distance; | |||||
| }); | |||||
| } | } | ||||
| } | } | ||||