|
@@ -1,5 +1,5 @@
|
|
|
import { register } from "@antv/x6-react-shape";
|
|
|
-import { EventArgs, Graph, Node, Path } from "@antv/x6";
|
|
|
+import { EventArgs, Graph, Node } from "@antv/x6";
|
|
|
import { topicData } from "@/config/data";
|
|
|
import { useSizeHook, useShapeProps } from "@/hooks";
|
|
|
import CustomInput from "../CustomInput";
|
|
@@ -13,6 +13,8 @@ import ExtraModule from "./ExtraModule";
|
|
|
import CustomTag from "@/components/CustomTag";
|
|
|
import { TopicItem } from "@/types";
|
|
|
import { selectTopic } from "@/utils/mindmapHander";
|
|
|
+import { Tooltip, Popover } from "antd";
|
|
|
+import LinkForm from "./LinkForm";
|
|
|
const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
const {
|
|
|
fill,
|
|
@@ -30,11 +32,15 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
children,
|
|
|
type,
|
|
|
collapsed,
|
|
|
+ fixedWidth,
|
|
|
+ linkTopicId,
|
|
|
} = node.getData();
|
|
|
const { size, ref } = useSizeHook();
|
|
|
const { fillContent, strokeColor, strokeWidth, strokeDasharray } =
|
|
|
useShapeProps(fill, size, stroke);
|
|
|
const [selected, setSelected] = useState(false);
|
|
|
+ const [showPopover, setShowPopover] = useState(false);
|
|
|
+ const [popoverContent, setPopoverContent] = useState<React.ReactNode>();
|
|
|
const handleSelect = (_args: EventArgs["node:selected"]) => {
|
|
|
const cells = graph.getSelectedCells();
|
|
|
setSelected(!!cells.find((item) => item.id === node.id));
|
|
@@ -45,21 +51,79 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
const tagRef = useRef<HTMLDivElement>(null);
|
|
|
const remarkRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
|
+ const padding = useMemo(() => {
|
|
|
+ switch (type) {
|
|
|
+ case TopicType.main:
|
|
|
+ return "14px 28px";
|
|
|
+ case TopicType.branch:
|
|
|
+ return "8px 16px";
|
|
|
+ default:
|
|
|
+ return "4px 6px";
|
|
|
+ }
|
|
|
+ }, [type]);
|
|
|
+
|
|
|
+ const showHerfConfig = () => {
|
|
|
+ setShowPopover(true);
|
|
|
+ setPopoverContent(
|
|
|
+ <LinkForm
|
|
|
+ title={herf?.title}
|
|
|
+ value={herf?.value}
|
|
|
+ onCancel={() => setShowPopover(false)}
|
|
|
+ onConfirm={(data) => {
|
|
|
+ setShowPopover(false);
|
|
|
+ node.setData({ herf: data });
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ // @ts-ignore 绑定一个外部调用方法
|
|
|
+ node.extendAttr = {
|
|
|
+ showHerfConfig,
|
|
|
+ };
|
|
|
+
|
|
|
useEffect(() => {
|
|
|
// graph.createTransformWidget(node);
|
|
|
// graph.select(node);
|
|
|
graph.on("node:selected", handleSelect);
|
|
|
graph.on("node:unselected", handleSelect);
|
|
|
+ graph.on("node:resized", handleResize);
|
|
|
return () => {
|
|
|
graph.off("node:selected", handleSelect);
|
|
|
graph.off("node:unselected", handleSelect);
|
|
|
+ graph.off("node:resized", handleResize);
|
|
|
};
|
|
|
}, []);
|
|
|
|
|
|
useEffect(() => {
|
|
|
- // 动态计算出所需的宽高
|
|
|
- let width = extraModules?.width || 0;
|
|
|
- }, [extraModules, label, icons, tags, remarkRef]);
|
|
|
+ if (size.height && size.width) {
|
|
|
+ const w = Math.max(
|
|
|
+ size.width,
|
|
|
+ titleRef.current?.clientWidth || 0,
|
|
|
+ tagRef.current?.clientWidth || 0,
|
|
|
+ extraModuleRef.current?.clientWidth || 0
|
|
|
+ );
|
|
|
+ const h = Math.max(
|
|
|
+ size.height,
|
|
|
+ titleRef.current?.clientHeight || 0,
|
|
|
+ tagRef.current?.clientHeight || 0,
|
|
|
+ extraModuleRef.current?.clientHeight || 0
|
|
|
+ );
|
|
|
+ if (h !== node.size().height || w !== node.size().width) {
|
|
|
+ node.setData({
|
|
|
+ width: w,
|
|
|
+ });
|
|
|
+ node.size(w, h);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, [size, titleRef, tagRef, extraModuleRef]);
|
|
|
+
|
|
|
+ const handleResize = () => {
|
|
|
+ node.setData({
|
|
|
+ fixedWidth: true,
|
|
|
+ width: node.size().width,
|
|
|
+ });
|
|
|
+ };
|
|
|
|
|
|
const childrenCount = useMemo(() => {
|
|
|
let count = 0;
|
|
@@ -76,6 +140,12 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
return count;
|
|
|
}, [children]);
|
|
|
|
|
|
+ const handleShowRemark = () => {
|
|
|
+ selectTopic(graph, node.data);
|
|
|
+ // @ts-ignore
|
|
|
+ graph.extendAttr.setRightToolbarActive("remark");
|
|
|
+ };
|
|
|
+
|
|
|
const handleAddBranch = () => {
|
|
|
const data = node.getData();
|
|
|
let topic;
|
|
@@ -84,7 +154,7 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
} else {
|
|
|
topic = addTopic(TopicType.sub, setMindProjectInfo, node);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
selectTopic(graph, topic);
|
|
|
};
|
|
|
|
|
@@ -94,6 +164,14 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
+ const handleDeleteHeft = () => {
|
|
|
+ node.setData({
|
|
|
+ herf: undefined,
|
|
|
+ }, {
|
|
|
+ deep: false
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
return (
|
|
|
<>
|
|
|
{selected && (
|
|
@@ -108,82 +186,108 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
}}
|
|
|
/>
|
|
|
)}
|
|
|
- <div
|
|
|
- className="relative text-0 w-full h-full px-4px"
|
|
|
- ref={ref}
|
|
|
- style={{
|
|
|
- opacity: opacity / 100,
|
|
|
- border: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
- background: fillContent,
|
|
|
- borderRadius: borderSize,
|
|
|
- }}
|
|
|
- onMouseOver={() => !collapsed && setShowCollapsePoint(true)}
|
|
|
- onMouseLeave={() => !collapsed && setShowCollapsePoint(false)}
|
|
|
- >
|
|
|
- <div className="w-full h-full flex flex-col">
|
|
|
+ <Popover open={showPopover} content={popoverContent}>
|
|
|
+ <div
|
|
|
+ className="content relative text-0"
|
|
|
+ ref={ref}
|
|
|
+ style={{
|
|
|
+ minWidth: "100%",
|
|
|
+ // minHeight: "100%",
|
|
|
+ opacity: opacity / 100,
|
|
|
+ border: `solid ${strokeWidth}px ${strokeColor}`,
|
|
|
+ background: fillContent,
|
|
|
+ borderRadius: borderSize,
|
|
|
+ padding,
|
|
|
+ }}
|
|
|
+ onMouseOver={() => !collapsed && setShowCollapsePoint(true)}
|
|
|
+ onMouseLeave={() => !collapsed && setShowCollapsePoint(false)}
|
|
|
+ >
|
|
|
+ {/* 扩展模块 */}
|
|
|
{extraModules && (
|
|
|
- <div ref={extraModuleRef}>
|
|
|
+ <div className="extra" ref={extraModuleRef}>
|
|
|
<ExtraModule node={node} extraModules={extraModules} />
|
|
|
</div>
|
|
|
)}
|
|
|
|
|
|
- <div className="flex-1 flex">
|
|
|
+ {/* 图标、标题、链接等 */}
|
|
|
+ <div
|
|
|
+ className="flex-1 flex items-center justify-center"
|
|
|
+ ref={titleRef}
|
|
|
+ >
|
|
|
+ <div className="flex items-center text-20px">
|
|
|
+ {icons?.map((icon: string) => {
|
|
|
+ return (
|
|
|
+ <svg key={icon} className="icon mr-6px" aria-hidden="true">
|
|
|
+ <use xlinkHref={`#${icon}`}></use>
|
|
|
+ </svg>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </div>
|
|
|
+ <CustomInput
|
|
|
+ value={label}
|
|
|
+ node={node}
|
|
|
+ styles={{
|
|
|
+ ...text,
|
|
|
+ position: "relative",
|
|
|
+ padding: "0",
|
|
|
+ }}
|
|
|
+ txtStyle={{
|
|
|
+ position: "relative",
|
|
|
+ flexShrink: 0,
|
|
|
+ transform: "translateY(50%)",
|
|
|
+ width: "auto",
|
|
|
+ ...(fixedWidth ? { maxWidth: "100%" } : {}),
|
|
|
+ }}
|
|
|
+ />
|
|
|
<div
|
|
|
- className="flex-1 flex flex-col justify-center"
|
|
|
- // style={{ height: getSize.contentHeight }}
|
|
|
+ className="flex items-center color-#fff m-l-8px"
|
|
|
+ ref={remarkRef}
|
|
|
>
|
|
|
- <div
|
|
|
- className="flex justify-start items-center text-20px"
|
|
|
- ref={titleRef}
|
|
|
- >
|
|
|
- {icons?.map((icon: string) => {
|
|
|
- return (
|
|
|
- <svg key={icon} className="icon mr-6px" aria-hidden="true">
|
|
|
- <use xlinkHref={`#${icon}`}></use>
|
|
|
- </svg>
|
|
|
- );
|
|
|
- })}
|
|
|
- <CustomInput
|
|
|
- value={label}
|
|
|
- node={node}
|
|
|
- styles={{
|
|
|
- ...text,
|
|
|
- position: "relative",
|
|
|
- }}
|
|
|
- txtStyle={{
|
|
|
- position: "relative",
|
|
|
- flex: 1,
|
|
|
- }}
|
|
|
+ {herf && (
|
|
|
+ <Link
|
|
|
+ link={herf}
|
|
|
+ onEdit={showHerfConfig}
|
|
|
+ onDelete={handleDeleteHeft}
|
|
|
/>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div className="flex" ref={tagRef}>
|
|
|
- {tags?.map((item: { name: string; color: string }) => {
|
|
|
- return (
|
|
|
- <CustomTag
|
|
|
- className="text-14px"
|
|
|
- key={item.name}
|
|
|
- title={item.name}
|
|
|
- color={item.color}
|
|
|
- >
|
|
|
- {item.name}
|
|
|
- </CustomTag>
|
|
|
- );
|
|
|
- })}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div ref={remarkRef}>
|
|
|
- {herf && <Link link={herf} />}
|
|
|
- {remark && <i className="iconfont icon-pinglun1" />}
|
|
|
+ )}
|
|
|
+ {remark && (
|
|
|
+ <Tooltip color="yellow" title={remark}>
|
|
|
+ <i
|
|
|
+ className="iconfont icon-pinglun1 cursor-pointer ml-4px"
|
|
|
+ onClick={handleShowRemark}
|
|
|
+ />
|
|
|
+ </Tooltip>
|
|
|
+ )}
|
|
|
+ {linkTopicId && (
|
|
|
+ <Tooltip color="yellow" title={remark}>
|
|
|
+ <i
|
|
|
+ className="iconfont icon-liangdianlianjie-01 cursor-pointer ml-4px"
|
|
|
+ onClick={handleShowRemark}
|
|
|
+ />
|
|
|
+ </Tooltip>
|
|
|
+ )}
|
|
|
</div>
|
|
|
</div>
|
|
|
- </div>
|
|
|
+ {/* 标签 */}
|
|
|
+ <div className="flex items-center justify-center" ref={titleRef}>
|
|
|
+ {tags?.map((item: { name: string; color: string }) => {
|
|
|
+ return (
|
|
|
+ <CustomTag
|
|
|
+ className="text-14px"
|
|
|
+ key={item.name}
|
|
|
+ title={item.name}
|
|
|
+ color={item.color}
|
|
|
+ >
|
|
|
+ {item.name}
|
|
|
+ </CustomTag>
|
|
|
+ );
|
|
|
+ })}
|
|
|
+ </div>
|
|
|
|
|
|
- {/* 添加主题按钮 */}
|
|
|
- {selected && !children?.length && (
|
|
|
- <div
|
|
|
- className={`
|
|
|
+ {/* 添加主题按钮 */}
|
|
|
+ {selected && !children?.length && (
|
|
|
+ <div
|
|
|
+ className={`
|
|
|
absolute
|
|
|
w-20px
|
|
|
h-20px
|
|
@@ -200,22 +304,22 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
color-#9aa5b8
|
|
|
hover:bg-#067bef
|
|
|
hover:color-white`}
|
|
|
- onClick={handleAddBranch}
|
|
|
- >
|
|
|
- <PlusOutlined />
|
|
|
- </div>
|
|
|
- )}
|
|
|
- {type !== TopicType.main && children.length && (
|
|
|
- <div
|
|
|
- className="absolute right--30px top-0 w-30px h-full"
|
|
|
- onMouseOver={() => !collapsed && setShowCollapsePoint(true)}
|
|
|
- onMouseOut={() => !collapsed && setShowCollapsePoint(false)}
|
|
|
- />
|
|
|
- )}
|
|
|
- {/* 折叠按钮 */}
|
|
|
- {type !== TopicType.main && children?.length && showCollapsePoint && (
|
|
|
- <div
|
|
|
- className={`
|
|
|
+ onClick={handleAddBranch}
|
|
|
+ >
|
|
|
+ <PlusOutlined />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {type !== TopicType.main && children.length && (
|
|
|
+ <div
|
|
|
+ className="absolute right--30px top-0 w-30px h-full"
|
|
|
+ onMouseOver={() => !collapsed && setShowCollapsePoint(true)}
|
|
|
+ onMouseOut={() => !collapsed && setShowCollapsePoint(false)}
|
|
|
+ />
|
|
|
+ )}
|
|
|
+ {/* 折叠按钮 */}
|
|
|
+ {type !== TopicType.main && children?.length && showCollapsePoint && (
|
|
|
+ <div
|
|
|
+ className={`
|
|
|
absolute
|
|
|
rounded-full
|
|
|
bg-white
|
|
@@ -229,16 +333,17 @@ const component = ({ node, graph }: { node: Node; graph: Graph }) => {
|
|
|
justify-center
|
|
|
${collapsed ? "w-16px h-16px right--20px" : "w-10px h-10px right--15px"}
|
|
|
`}
|
|
|
- onClick={handleToggleCollapse}
|
|
|
- style={{
|
|
|
- border: `1px solid ${fill.color1}`,
|
|
|
- color: fill.color1,
|
|
|
- }}
|
|
|
- >
|
|
|
- {collapsed && childrenCount}
|
|
|
- </div>
|
|
|
- )}
|
|
|
- </div>
|
|
|
+ onClick={handleToggleCollapse}
|
|
|
+ style={{
|
|
|
+ border: `1px solid ${fill.color1}`,
|
|
|
+ color: fill.color1,
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {collapsed && childrenCount}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ </Popover>
|
|
|
</>
|
|
|
);
|
|
|
};
|