2023-03-14 15:55:12 +00:00
|
|
|
import {Cell, Graph} from '@antv/x6';
|
2023-03-14 15:42:33 +00:00
|
|
|
import {CodeBlockContent, CodeBlockShape} from './CodeBlockShape';
|
2023-03-10 14:48:14 +00:00
|
|
|
import {ClassShape} from './ClassShape';
|
|
|
|
|
import {CLASS_SHAPE_ID_TAG, CODE_BLOCK_ID_TAG, CodeData, Utils} from './Utils';
|
2023-03-14 15:55:12 +00:00
|
|
|
import {Edge} from './Edge';
|
2023-03-10 09:44:58 +00:00
|
|
|
|
2023-03-14 15:55:12 +00:00
|
|
|
const myUtils = new Utils();
|
|
|
|
|
const codeBlockShape = new CodeBlockShape();
|
|
|
|
|
const classShape = new ClassShape();
|
|
|
|
|
const edge = new Edge();
|
2023-03-10 09:44:58 +00:00
|
|
|
|
2023-03-14 15:55:12 +00:00
|
|
|
export const initGraph = function (codeBlocks: CodeBlockContent[]) {
|
2023-03-10 09:44:58 +00:00
|
|
|
|
2023-03-10 16:11:18 +00:00
|
|
|
// 創建畫布
|
|
|
|
|
const graph = new Graph({
|
|
|
|
|
container: <HTMLElement>document.getElementById('container'),
|
|
|
|
|
width: 3000,
|
|
|
|
|
height: 5000,
|
|
|
|
|
background: {
|
|
|
|
|
color: '#ffffff', // 设置画布背景颜色
|
|
|
|
|
},
|
|
|
|
|
grid: {
|
|
|
|
|
size: 10, // 網格大小 10px
|
|
|
|
|
visible: true, // 渲染網格背景
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2024-06-03 15:40:40 +00:00
|
|
|
// 將 代碼塊字串 集合 解析成 CodeData 對象集合
|
2023-03-14 15:55:12 +00:00
|
|
|
let codeDatas: CodeData[] = [];
|
2023-03-14 15:42:33 +00:00
|
|
|
codeBlocks.forEach((codeBlock: CodeBlockContent) => {
|
2023-03-14 15:55:12 +00:00
|
|
|
const codeData: CodeData = myUtils.parseCodeData(codeBlock);
|
|
|
|
|
codeDatas.push(codeData);
|
|
|
|
|
});
|
2024-06-03 15:40:40 +00:00
|
|
|
|
|
|
|
|
// 將相同 className 的對象進行合併
|
2023-03-14 15:55:12 +00:00
|
|
|
codeDatas = myUtils.mergeCodeDatas(codeDatas);
|
2023-03-10 16:11:18 +00:00
|
|
|
|
2024-06-03 15:40:40 +00:00
|
|
|
// 設置 CodeDataFunc 中的 calleds 屬性
|
|
|
|
|
myUtils.setCalleds(codeDatas);
|
2023-03-10 16:11:18 +00:00
|
|
|
|
|
|
|
|
// 將 CodeData 對象列表 繪製成 類圖形、代碼塊圖形
|
|
|
|
|
for (const codeData of codeDatas) {
|
|
|
|
|
|
|
|
|
|
// 將 類圖形、代碼塊圖形 加入到 畫布 中
|
2023-03-14 15:55:12 +00:00
|
|
|
const funcNames = codeData.funcs.map(item => item.name);
|
|
|
|
|
graph.addNode(classShape.createClassShape(codeData.className, funcNames));
|
|
|
|
|
graph.addNodes(codeBlockShape.createCodeBlockShape(codeData));
|
2023-03-10 16:11:18 +00:00
|
|
|
|
|
|
|
|
// 創建 函數名稱 與 代碼塊圖形 的 連線
|
2023-03-14 15:55:12 +00:00
|
|
|
graph.addEdges(edge.createFuncToCodeEdges(codeData));
|
2023-03-10 16:11:18 +00:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 繪製 CodeData 中的 函數調用 連線
|
|
|
|
|
for (const codeData of codeDatas) {
|
2023-03-14 15:55:12 +00:00
|
|
|
graph.addEdges(edge.createFuncCallEdges(codeData));
|
2023-03-10 16:11:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 綁定 開啟/關閉 代碼塊圖形 事件
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
graph.on('toggle:codeBlock', ({e}) => {
|
|
|
|
|
|
|
|
|
|
// 獲取 代碼塊圖形、開關文字 對象
|
2023-03-14 15:55:12 +00:00
|
|
|
const codeBlock = graph.getCellById(e.currentTarget.getAttribute('target-code-block'));
|
|
|
|
|
const toggleText = e.currentTarget.parentNode.childNodes[5].children[0];
|
2023-03-10 16:11:18 +00:00
|
|
|
|
|
|
|
|
// 如果當前 代碼塊圖形 正在顯示,則關閉。反之則開啟
|
|
|
|
|
if (codeBlock.getProp().visible) {
|
2023-03-14 15:55:12 +00:00
|
|
|
codeBlock.hide();
|
|
|
|
|
toggleText.textContent = '+';
|
|
|
|
|
toggleText.setAttribute('dy', '0.3em');
|
2023-03-10 16:11:18 +00:00
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
// 計算 代碼塊 顯示位置
|
2023-03-14 15:55:12 +00:00
|
|
|
const intervalX = 100;
|
|
|
|
|
const posX = e.offsetX + intervalX;
|
|
|
|
|
const posY = e.offsetY - (codeBlock.getProp().size.height / 2);
|
|
|
|
|
codeBlock.prop("position", {x: posX, y: posY});
|
2023-03-10 16:11:18 +00:00
|
|
|
|
2023-03-11 04:46:22 +00:00
|
|
|
// 顯示 代碼塊,並更新按鈕內容
|
2023-03-14 15:55:12 +00:00
|
|
|
codeBlock.show();
|
|
|
|
|
toggleText.textContent = '-';
|
|
|
|
|
toggleText.setAttribute('dy', '0.3em');
|
2023-03-10 16:11:18 +00:00
|
|
|
}
|
2023-03-14 15:55:12 +00:00
|
|
|
});
|
2023-03-10 16:11:18 +00:00
|
|
|
|
|
|
|
|
// 最大的 類圖形 的寬度
|
|
|
|
|
let maxClassShapeWidth = 0;
|
|
|
|
|
// 所有的 類圖形 集合
|
2023-03-14 15:55:12 +00:00
|
|
|
const classShapes: Cell[] = [];
|
2023-03-10 16:11:18 +00:00
|
|
|
|
|
|
|
|
// 遍歷 所有的圖形
|
|
|
|
|
for (const node of graph.getCells()) {
|
|
|
|
|
|
|
|
|
|
// 默認隱藏所有的 代碼塊
|
|
|
|
|
if (node.id.startsWith(CODE_BLOCK_ID_TAG)) {
|
2023-03-14 15:55:12 +00:00
|
|
|
node.hide();
|
2023-03-10 16:11:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 計算 類圖形 最大寬度、加入到集合中
|
|
|
|
|
if (node.id.startsWith(CLASS_SHAPE_ID_TAG)) {
|
2023-03-14 15:55:12 +00:00
|
|
|
maxClassShapeWidth = Math.max(maxClassShapeWidth, node.getProp().size.width);
|
|
|
|
|
classShapes.push(node);
|
2023-03-10 16:11:18 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 計算 類圖形 的 座標
|
|
|
|
|
*/
|
|
|
|
|
// 左側保留寬度
|
2023-03-14 15:55:12 +00:00
|
|
|
const marginLeftWidth = 100;
|
2023-03-10 16:11:18 +00:00
|
|
|
// 類圖形的 Y 座標
|
2023-03-14 15:55:12 +00:00
|
|
|
let curY = 200;
|
2023-03-10 16:11:18 +00:00
|
|
|
// 多個 類圖形 的 上下間格
|
2023-03-14 15:55:12 +00:00
|
|
|
const intervalY = 150;
|
2023-03-10 16:11:18 +00:00
|
|
|
// 所有 類圖形 的 中線 X 座標
|
2023-03-14 15:55:12 +00:00
|
|
|
const midX = marginLeftWidth + (maxClassShapeWidth / 2);
|
2023-03-10 16:11:18 +00:00
|
|
|
for (const classShape of classShapes) {
|
|
|
|
|
|
|
|
|
|
// 計算 類圖形 的 左上X 座標,並設置
|
2023-03-14 15:55:12 +00:00
|
|
|
const posX = midX - (classShape.getProp().size.width / 2);
|
|
|
|
|
classShape.prop("position", {x: posX, y: curY});
|
2023-03-10 16:11:18 +00:00
|
|
|
|
|
|
|
|
// 下個 類圖形 的 Y 座標 = 當前 類圖形 高度 + 間隔
|
2023-03-14 15:55:12 +00:00
|
|
|
curY = curY + classShape.getProp().size.height + intervalY;
|
2023-03-10 16:11:18 +00:00
|
|
|
}
|
2023-03-10 09:44:58 +00:00
|
|
|
|
2023-03-14 15:55:12 +00:00
|
|
|
};
|
2023-03-10 09:44:58 +00:00
|
|
|
|
|
|
|
|
|