import { register } from "@antv/x6-react-shape"; import { EventArgs, Graph, Node } from "@antv/x6"; import { topicData } from "@/config/data"; import { useSizeHook, useShapeProps } from "@/hooks"; import { useEffect, useMemo, useRef, useState } from "react"; import { PlusOutlined } from "@ant-design/icons"; import { TopicType } from "@/enum"; import { addTopic } from "@/pages/mindmap/mindMap"; import Link from "./Link"; import ExtraModule from "./ExtraModule"; import CustomTag from "@/components/mindMap/CustomTag"; import { TopicItem } from "@/types"; import { selectTopic } from "@/utils/mindmapHander"; import { Tooltip, Popover } from "antd"; import LinkForm from "./LinkForm"; import Text from "./Text"; import FlowExtra from "../FlowExtra"; const component = ({ node, graph }: { node: Node; graph: Graph }) => { const { fill, stroke, opacity, label, text, borderSize, setMindProjectInfo, icons, tags, extraModules, remark, href, children, type, collapsed, fixedWidth, linkTopicId, } = node.getData(); const { size, ref } = useSizeHook(); const { fillContent, strokeColor, strokeWidth } = useShapeProps( fill, size, stroke ); const [selected, setSelected] = useState(false); const [showPopover, setShowPopover] = useState(false); const [popoverContent, setPopoverContent] = useState(); const handleSelect = (_args: EventArgs["node:selected"]) => { const cells = graph.getSelectedCells(); setSelected(!!cells.find((item) => item.id === node.id)); }; const [showCollapsePoint, setShowCollapsePoint] = useState(collapsed); const extraModuleRef = useRef(null); const titleRef = useRef(null); const tagRef = useRef(null); const remarkRef = useRef(null); const padding = useMemo(() => { switch (type) { case TopicType.main: return { y: 14, x: 28, }; case TopicType.branch: return { y: 8, x: 16, }; default: return { y: 4, x: 6, }; } }, [type]); const showHrefConfig = () => { setShowPopover(true); setPopoverContent( setShowPopover(false)} onConfirm={(data) => { setShowPopover(false); node.setData({ href: data }); }} /> ); }; // @ts-ignore 绑定一个外部调用方法 node.extendAttr = { showHrefConfig, }; useEffect(() => { // graph.createTransformWidget(node); // graph.select(node); graph.on("node:selected", handleSelect); graph.on("node:unselected", handleSelect); return () => { graph.off("node:selected", handleSelect); graph.off("node:unselected", handleSelect); }; }, []); const changeSize = () => { const { clientHeight = 0, clientWidth = 0 } = ref.current || {}; if ( clientHeight && (size.width !== clientWidth || size.height !== clientHeight) ) { node.setData({ width: clientWidth, height: clientHeight, }); } }; useEffect(() => { changeSize(); }, [node.data]); const childrenCount = useMemo(() => { let count = 0; const traverse = (topics: TopicItem[]) => { topics.forEach((item) => { count++; if (item.children) { traverse(item.children); } }); }; traverse(children); return count; }, [children]); const handleShowRemark = () => { selectTopic(graph, node.data); // @ts-ignore graph.extendAttr.setRightToolbarActive("remark"); }; const handleAddBranch = () => { const data = node.getData(); let topic; if (data.type === TopicType.main) { topic = addTopic(TopicType.branch, setMindProjectInfo, node); } else { topic = addTopic(TopicType.sub, setMindProjectInfo, node); } selectTopic(graph, topic); }; const handleToggleCollapse = () => { node.setData({ collapsed: !collapsed, }); }; const handleDeleteHeft = () => { node.setData( { href: undefined, }, { deep: false, } ); }; const handleChangeTag = (tagInfo: { color?: string; title?: string }, index: number) => { node.setData({ tags: tags.map((item: { color?: string; title?: string }, i: number) => { if (index === i) { return { ...item, ...tagInfo } } return item; }, { deep: false }) }) } const handleDeleteTag = (index: number) => { tags.splice(index, 1); node.setData({ tags }, { deep: false }); } return (
{selected && (
)}
!collapsed && setShowCollapsePoint(true)} onMouseLeave={() => !collapsed && setShowCollapsePoint(false)} > {/* 扩展模块 */} {extraModules && (
)} {/* 图标、标题、链接等 */}
{icons?.map((icon: string) => { return ( ); })}
{href && ( )} {remark && ( )} {linkTopicId && ( )}
{/* 标签 */}
{tags?.map((item: { name: string; color: string }, index: number) => { return ( handleChangeTag(tag, index)} onDelete={() => handleDeleteTag(index)} hideEditBtn > {item.name} ); })}
{/* 添加主题按钮 */} {selected && !children?.length && (
)} {type !== TopicType.main && children.length && (
!collapsed && setShowCollapsePoint(true)} onMouseOut={() => !collapsed && setShowCollapsePoint(false)} /> )} {/* 折叠按钮 */} {type !== TopicType.main && children?.length && showCollapsePoint && (
{collapsed && childrenCount}
)}
); }; // 主题节点 register({ shape: "mind-map-topic", width: 206, height: 70, effect: ["data"], component: component, }); const baseNode = { shape: "mind-map-topic", data: { label: "", ...topicData, }, }; export default baseNode;