import { TopicType } from "@/enum"; import { MindMapProjectInfo, TopicItem } from "@/types"; import { Graph, Cell, Node } from "@antv/x6"; import TopicComponent from "@/components/mindMap/Topic"; import { topicData } from "@/config/data"; import { uuid } from "@/utils"; import { hierarchyMethodMap } from "@/pages/mindmap/hierarchy"; import { createEdge } from "./edge"; import { getTheme } from "./theme"; interface HierarchyResult { id: string; x: number; y: number; data: TopicItem; children?: HierarchyResult[]; } /** * 渲染思维导图项目 * @param graph */ export const renderMindMap = ( graph: Graph, setMindProjectInfo: () => void ) => { const projectInfo = getMindMapProjectByLocal(); if(!projectInfo) return; const { topics, pageSetting } = projectInfo; const cells: Cell[] = []; topics.forEach((topic) => { // 遍历出层次结构 const result: HierarchyResult = hierarchyMethodMap[projectInfo.structure]?.(topic, pageSetting); let originPosition = { x: topic?.x ?? -10, y: topic?.y ?? -10 }; if(graph.hasCell(topic.id)) { const node = graph.getCellById(topic.id); if(node.isNode()) { originPosition = node.position(); } } const offsetX = originPosition.x - result.x; const offsetY = originPosition.y - result.y; const traverse = ( hierarchyItem: HierarchyResult, parent?: Node ) => { if (hierarchyItem) { const { data, children, x, y } = hierarchyItem; const id = data?.id || uuid(); // 创建主题 const node = graph.createNode({ ...TopicComponent, width: data.width, height: data.height, data: { ...data, // 节点内部执行数据更新方法 setMindProjectInfo, }, id, x: offsetX + x, y: offsetY + y, }); cells.push(node); parent && parent.addChild(node); if (children) { children.forEach((item: HierarchyResult) => { cells.push( // 创建连线 createEdge(graph, id, item, projectInfo.structure, projectInfo.theme) ); // 递归遍历 traverse(item, node); }); } } }; traverse(result); }); // 处理节点 cells.filter(cell => cell.isNode()).forEach((cell) => { // 存在更新位置,否则添加 if (graph.hasCell(cell.id)) { const oldCell = graph.getCellById(cell.id); if(oldCell.isNode()) { oldCell.position(cell.position().x, cell.position().y); oldCell.setData({ ...cell.data }) } } else { graph.addCell(cell); } }); cells.filter(cell => cell.isEdge()).forEach((cell) => { graph.removeCell(cell.id); graph.addCell(cell); }) const oldCells = graph.getCells(); // 移除不存在的节点 oldCells.forEach((cell) => { if (!cells.find(item => cell.id === item.id)) { graph.removeCell(cell.id + '-edge'); graph.removeCell(cell); } }); // graph.centerContent(); }; /** * 添加分支主题 */ export const addTopic = ( type: TopicType, setMindProjectInfo: (info: MindMapProjectInfo) => void, node?: Node, otherData: Record = {}, ) => { const projectInfo = getMindMapProjectByLocal(); if (!projectInfo || !setMindProjectInfo) return; const topic = buildTopic(type, { ...(otherData || {}), parentId: node?.id }, node); if( node) { const parentId = node.id; const traverse = (topics: TopicItem[]) => { topics.forEach((item) => { if (item.id === parentId) { if (item.children) { item.children?.push(topic); } else { item.children = [topic]; } } if (item.children) { traverse(item.children); } }); }; traverse(projectInfo?.topics || []); } else { projectInfo.topics.push(topic); } setMindProjectInfo(projectInfo); return topic; }; const topicMap = { [TopicType.main]: { label: "中心主题", width: 206, height: 70 }, [TopicType.branch]: { label: "分支主题", width: 104, height: 40 }, [TopicType.sub]: { label: "子主题", width: 76, height: 27 } }; /** * 构建一个主题数据 * @param type 主题类型 * @param options 配置项 * @returns */ export const buildTopic = ( type: TopicType, options: Record = {}, parentNode?: Node ) => { const projectInfo = getMindMapProjectByLocal(); const theme = getTheme(projectInfo?.theme, type === TopicType.sub ? parentNode : undefined); return { ...topicData, id: uuid(), type, label: topicMap[type].label || "自由主题", width: topicMap[type].width || 206, height: topicMap[type].height || 70, fill: { ...topicData.fill, ...theme[type]?.fill, }, text: { ...topicData.text, ...theme[type]?.text, }, stroke: { ...topicData.stroke, ...theme[type]?.stroke, }, edge: { ...topicData.edge, color: theme[type]?.edge.color, }, ...options, }; }; /** * 从本地获取项目信息 * @returns */ export const getMindMapProjectByLocal = (): MindMapProjectInfo | null => { return JSON.parse(localStorage.getItem("minMapProjectInfo") || "null"); }; /** * 更新主题数据 * @param id 主题id * @param value 更新的数据 * @param setMindProjectInfo 更新项目信息方法 */ export const updateTopic = ( id: string, value: Partial, setMindProjectInfo: (info: MindMapProjectInfo) => void ) => { const projectInfo = getMindMapProjectByLocal(); if (!projectInfo || !setMindProjectInfo) return; const traverse = (topics: TopicItem[]) => { topics.forEach((item) => { if (item.id === id) { Object.assign(item, value); } if (item.children) { traverse(item.children); } }); }; traverse(projectInfo?.topics || []); setMindProjectInfo(projectInfo); }