123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- 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<string, any> = {},
- ) => {
- 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<string, any> = {},
- 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<TopicItem>,
- 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);
- }
|