123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465 |
- import { TopicType } from "@/enum";
- import { addTopic, getMindMapProjectByLocal } from "@/pages/mindmap/mindMap";
- import { MindMapProjectInfo, TopicItem } from "@/types";
- import { Cell, Graph, Node, Edge } from "@antv/x6";
- import { message } from "antd";
- import { cloneDeep } from "lodash-es";
- import { uuid } from "@/utils";
- import { ContextMenuTool } from "./contentMenu";
- import { MutableRefObject } from "react";
- import { exportImage } from "@/components/ExportImage";
- export const selectTopic = (graph: Graph, topic?: TopicItem) => {
- if (topic?.id) {
- setTimeout(() => {
- graph.resetSelection(topic.id);
- const node = graph.getCellById(topic?.id);
- node?.isNode() && graph.createTransformWidget(node);
- }, 100);
- }
- };
- export const selectTopics = (graph: Graph, topics?: TopicItem[]) => {
- setTimeout(() => {
- graph.resetSelection(topics?.map((item) => item.id));
- topics?.forEach((item) => {
- const node = graph.getCellById(item.id);
- node?.isNode() && graph.createTransformWidget(node);
- });
- }, 100);
- };
- /**
- * 添加同级主题
- * @param node
- * @param graph
- */
- export const addPeerTopic = (
- node: Cell,
- graph: Graph,
- setMindProjectInfo?: (info: MindMapProjectInfo) => void
- ) => {
- if (!setMindProjectInfo) return;
- const parentNode =
- node.data.type === TopicType.main || !node.data?.parentId
- ? node
- : graph.getCellById(node.data.parentId);
- const type =
- node.data.type === TopicType.main ? TopicType.branch : node.data.type;
- if (parentNode?.isNode()) {
- const topic = addTopic(type, setMindProjectInfo, parentNode);
- selectTopic(graph, topic);
- }
- };
- /**
- * 添加子主题
- * @param node
- * @param setMindProjectInfo
- * @param graph
- */
- export const addChildrenTopic = (
- node: Node,
- setMindProjectInfo?: (info: MindMapProjectInfo) => void,
- graph?: Graph
- ) => {
- if (!setMindProjectInfo) return;
- const type =
- node.data?.type === TopicType.main ? TopicType.branch : TopicType.sub;
- const topic = addTopic(type, setMindProjectInfo, node);
- graph && selectTopic(graph, topic);
- };
- /**
- * 添加父主题
- * @param node
- * @param setMindProjectInfo
- * @param graph
- */
- export const addParentTopic = (
- node: Node,
- setMindProjectInfo?: (info: MindMapProjectInfo) => void,
- graph?: Graph
- ) => {
- if (!setMindProjectInfo || !node.data?.parentId) return;
- const type =
- node.data?.type === TopicType.branch ? TopicType.branch : TopicType.sub;
- const parentNode = graph?.getCellById(node.data.parentId);
- // 删除原来的数据
- deleteTopics([node.data.id], setMindProjectInfo);
- // 加入新的父主题
- const topic = addTopic(type, setMindProjectInfo, parentNode as Node, {
- children: [
- {
- ...node.data,
- },
- ],
- });
- graph && selectTopic(graph, topic);
- };
- /**
- * 删除子主题
- * @param ids
- * @param setMindProjectInfo
- */
- export const deleteTopics = (
- ids: string[],
- setMindProjectInfo?: (info: MindMapProjectInfo) => void
- ) => {
- const mindProjectInfo = getMindMapProjectByLocal();
- if (!mindProjectInfo || !setMindProjectInfo) return;
- const topics = cloneDeep(mindProjectInfo.topics);
- const filterTopics = (list: TopicItem[]): TopicItem[] => {
- const result: TopicItem[] = [];
- for (const item of list) {
- if (!ids.includes(item.id) || item.type === TopicType.main) {
- if (item.children?.length) {
- item.children = filterTopics(item.children);
- }
- result.push(item);
- }
- }
- return result;
- };
- mindProjectInfo.topics = filterTopics(topics);
- setMindProjectInfo(mindProjectInfo); // TODO 这个方法删除更新有问题
- localStorage.setItem("minMapProjectInfo", JSON.stringify(mindProjectInfo));
- };
- /**
- * 删除当前主题
- * @param graph
- * @param nodes
- */
- export const handleDeleteCurrentTopic = (
- graph: Graph,
- nodes: Node[],
- ) => {
- const mindProjectInfo = getMindMapProjectByLocal();
- if (!mindProjectInfo) return;
- nodes.forEach((node) => {
- if (node.data.parentId) {
- traverseNode(mindProjectInfo.topics, (topic) => {
- if (topic.id === node.data.parentId) {
- const index = topic.children?.findIndex(
- (item) => item.id === node.id
- );
- if (typeof index === "number" && index >= 0) {
- const newChildren = (node.data.children || []).map(
- (childNode: TopicItem) => {
- return {
- ...childNode,
- type: topic.type === TopicType.main ? TopicType.branch : TopicType.sub,
- parentId: topic.id,
- };
- }
- );
- (topic.children || []).splice(
- index,
- 1,
- ...newChildren
- );
- }
- }
- });
- }
- console.log(mindProjectInfo)
- // @ts-ignore
- graph?.extendAttr?.setMindProjectInfo?.(mindProjectInfo);
- localStorage.setItem("minMapProjectInfo", JSON.stringify(mindProjectInfo));
- });
- };
- /**
- * 执行粘贴
- * @param graph
- * @param setMindProjectInfo
- */
- export const handleMindmapPaste = (
- graph: Graph,
- setMindProjectInfo: (info: MindMapProjectInfo) => void
- ) => {
- // 读取剪切板数据
- navigator.clipboard.read().then((items) => {
- console.log("剪切板内容:", items);
- const currentNode = graph.getSelectedCells().find((cell) => cell.isNode());
- if (!currentNode) {
- message.warning("请先选择一个主题");
- return;
- }
- const item = items?.[0];
- if (item) {
- /**读取图片数据 */
- if (item.types[0] === "image/png") {
- item.getType("image/png").then((blob) => {
- const reader = new FileReader();
- reader.readAsDataURL(blob);
- reader.onload = function (event) {
- const dataUrl = event.target?.result as string;
- // 获取图片大小
- const img = new Image();
- img.src = dataUrl;
- img.onload = function () {
- const width = img.width;
- const height = img.height;
- // 插入图片
- currentNode.setData({
- extraModules: {
- type: "image",
- data: {
- imageUrl: dataUrl,
- width,
- height,
- },
- },
- });
- };
- };
- });
- }
- /**读取文本数据 */
- if (item.types[0] === "text/plain") {
- item.getType("text/plain").then((blob) => {
- const reader = new FileReader();
- reader.readAsText(blob);
- reader.onload = function (event) {
- const text = event.target?.result as string;
- // 内部复制方法
- if (text === " ") {
- const nodes = localStorage.getItem("mindmap-copy-data");
- if (nodes) {
- JSON.parse(nodes)?.forEach((node: Node) => {
- const data = node.data;
- // 修改新的数据嵌套
- data.id = uuid();
- data.parentId = currentNode.id;
- if (data.children?.length) {
- data.children = traverseCopyData(data.children, data.id);
- }
- addTopic(
- currentNode.data?.type === TopicType.main
- ? TopicType.branch
- : TopicType.sub,
- setMindProjectInfo,
- currentNode,
- { ...data }
- );
- });
- }
- } else {
- const topic = addTopic(
- currentNode.data?.type === TopicType.main
- ? TopicType.branch
- : TopicType.sub,
- setMindProjectInfo,
- currentNode,
- { label: text }
- );
- selectTopic(graph, topic);
- }
- };
- });
- }
- }
- });
- };
- const traverseCopyData = (list: TopicItem[], parentId: string): TopicItem[] => {
- return list.map((item) => {
- item.id = uuid();
- item.parentId = parentId;
- if (item.children?.length) {
- item.children = traverseCopyData(item.children, item.id);
- }
- return item;
- });
- };
- /**
- * 遍历主题树
- * @param topics
- * @param callback
- * @returns
- */
- export const traverseNode = (
- topics: TopicItem[],
- callback: (topic: TopicItem, index: number) => void
- ): TopicItem[] => {
- return topics.map((topic, index) => {
- callback && callback(topic, index);
- if (topic.children?.length) {
- topic.children = traverseNode(topic.children, callback);
- }
- return topic;
- });
- };
- // 关联线
- const handleCorrelation = (
- e: MouseEvent,
- correlationEdgeRef: MutableRefObject<Edge | undefined>,
- graph: Graph
- ) => {
- if (correlationEdgeRef.current) {
- const point = graph?.clientToLocal(e.x, e.y);
- point && correlationEdgeRef.current?.setTarget(point);
- }
- };
- /**
- * 添加关联线
- * @param graph
- * @param correlationEdgeRef
- * @param sourceNode
- */
- export const handleCreateCorrelationEdge = (
- graph: Graph,
- correlationEdgeRef: MutableRefObject<Edge | undefined>,
- sourceNode?: Node
- ) => {
- if (sourceNode) {
- correlationEdgeRef.current = graph?.addEdge({
- source: { cell: sourceNode },
- target: {
- x: sourceNode.position().x,
- y: sourceNode.position().y,
- },
- connector: "normal",
- attrs: {
- line: {
- stroke: "#71cb2d",
- strokeWidth: 2,
- sourceMarker: {
- name: "",
- },
- targetMarker: {
- name: "",
- },
- style: {
- opacity: 0.6,
- },
- },
- },
- data: {
- ignoreDrag: true,
- },
- zIndex: 0,
- });
- document.body.addEventListener("mousemove", (e) =>
- handleCorrelation(e, correlationEdgeRef, graph)
- );
- } else {
- document.body.removeEventListener("mousemove", (e) =>
- handleCorrelation(e, correlationEdgeRef, graph)
- );
- if (correlationEdgeRef.current) {
- graph?.removeCell(correlationEdgeRef.current);
- correlationEdgeRef.current = undefined;
- }
- }
- };
- /**
- * 右键菜单处理方法
- */
- export const mindmapMenuHander = {
- addTopic(tool: ContextMenuTool) {
- const node = tool.cell;
- if (node.isNode())
- addChildrenTopic(node, node.data.setMindProjectInfo, tool.graph);
- },
- addPeerTopic(tool: ContextMenuTool) {
- const node = tool.cell;
- if (node.isNode())
- addPeerTopic(node, tool.graph, node.data.setMindProjectInfo);
- },
- addParentTopic(tool: ContextMenuTool) {
- const node = tool.cell;
- if (node.isNode())
- addParentTopic(node, node.data.setMindProjectInfo, tool.graph);
- },
- addCorrelationEdge(tool: ContextMenuTool) {
- if (tool.cell.isNode()) {
- // @ts-ignore
- const correlationEdgeRef = tool.graph?.extendAttr?.correlationEdgeRef;
- handleCreateCorrelationEdge(tool.graph, correlationEdgeRef, tool.cell);
- }
- },
- addRemark(tool: ContextMenuTool) {
- // @ts-ignore
- tool.graph?.extendAttr?.setRightToolbarActive("remark");
- selectTopic(tool.graph, tool.cell.data);
- },
- addHref(tool: ContextMenuTool) {
- console.log(tool.cell)
- // @ts-ignore
- tool.cell?.extendAttr?.showHrefConfig?.();
- },
- addTopicLink(tool: ContextMenuTool) {
- // todo
- },
- addImage(tool: ContextMenuTool) {
- // todo
- },
- addTag(tool: ContextMenuTool) {
- // @ts-ignore
- tool.graph?.extendAttr?.setRightToolbarActive("tag");
- selectTopic(tool.graph, tool.cell.data);
- },
- addIcon(tool: ContextMenuTool) {
- // @ts-ignore
- tool.graph?.extendAttr?.setRightToolbarActive("icon");
- selectTopic(tool.graph, tool.cell.data);
- },
- addCode(tool: ContextMenuTool) {
- tool.cell.setData({
- extraModules: {
- type: "code",
- data: {
- code: "",
- language: "javascript",
- },
- },
- });
- },
- chooseSameLevel(tool: ContextMenuTool) {
- const parentId = tool.cell.data?.parentId;
- if (!parentId) return;
- const parent = tool.graph.getCellById(parentId);
- selectTopics(tool.graph, parent.data?.children);
- },
- chooseAllSameLevel(tool: ContextMenuTool) {
- // todo
- },
- copy(tool: ContextMenuTool) {
- localStorage.setItem("mindmap-copy-data", JSON.stringify([tool.cell]));
- navigator.clipboard.writeText(" ");
- },
- cut(tool: ContextMenuTool) {
- tool.graph.cut([tool.cell]);
- },
- paste(tool: ContextMenuTool) {
- handleMindmapPaste(tool.graph, tool.cell.data.setMindProjectInfo);
- },
- delete(tool: ContextMenuTool) {
- deleteTopics([tool.cell.id], tool.cell.data.setMindProjectInfo);
- },
- deleteCurrent(tool: ContextMenuTool) {
- tool.cell.isNode() && handleDeleteCurrentTopic(tool.graph, [tool.cell]);
- },
- exportImage(tool: ContextMenuTool) {
- exportImage(tool.graph);
- },
- copyImage(tool: ContextMenuTool) {
- // TODO复制为图片
- },
- };
|