Hello World
diff --git a/src/slidePane/__tests/index.test.tsx b/src/drawer/__tests/index.test.tsx
similarity index 87%
rename from src/slidePane/__tests/index.test.tsx
rename to src/drawer/__tests/index.test.tsx
index 2ff570254..154285153 100644
--- a/src/slidePane/__tests/index.test.tsx
+++ b/src/drawer/__tests/index.test.tsx
@@ -29,7 +29,7 @@ describe('test SlidePane ', () => {
});
test('should render mask correct ', () => {
const { unmount } = render(
Hello World);
- const dom = document.querySelector('.dtc-slide-pane-mask');
+ const dom = document.querySelector('.dtc-drawer-mask');
expect(dom).toBe(null);
unmount();
render(
@@ -37,7 +37,7 @@ describe('test SlidePane ', () => {
Hello World
);
- const domMask = document.querySelector('.dtc-slide-pane-mask');
+ const domMask = document.querySelector('.dtc-drawer-mask');
expect(domMask).not.toBe(null);
});
test('should render width correct', () => {
@@ -46,7 +46,7 @@ describe('test SlidePane ', () => {
Hello World
);
- expect(document.querySelector('.dtc-slide-pane-content-wrapper')).toHaveStyle({
+ expect(document.querySelector('.dtc-drawer-content-wrapper')).toHaveStyle({
width: '640px',
});
});
@@ -56,7 +56,7 @@ describe('test SlidePane ', () => {
Hello World
);
- expect(document.querySelector('.dtc-slide-pane-content-wrapper')).toHaveStyle({
+ expect(document.querySelector('.dtc-drawer-content-wrapper')).toHaveStyle({
width: '1256px',
});
});
@@ -72,10 +72,10 @@ describe('test SlidePane ', () => {
Hello World
);
- expect(document.querySelector('.dtc-slide-pane')).toHaveClass('root-className');
- expect(document.querySelector('.dtc-slide-pane-body')).toHaveClass('body-className');
- expect(document.querySelector('.dtc-slide-pane')).toHaveStyle({ color: 'red' });
- expect(document.querySelector('.dtc-slide-pane-body')).toHaveStyle({
+ expect(document.querySelector('.dtc-drawer')).toHaveClass('root-className');
+ expect(document.querySelector('.dtc-drawer-body')).toHaveClass('body-className');
+ expect(document.querySelector('.dtc-drawer')).toHaveStyle({ color: 'red' });
+ expect(document.querySelector('.dtc-drawer-body')).toHaveStyle({
backgroundColor: 'forestgreen',
});
unmount();
@@ -102,7 +102,7 @@ describe('test SlidePane ', () => {
}}
);
- expect(document.querySelector('.dtc-slide-pane-tabs')).not.toBe(null);
+ expect(document.querySelector('.dtc-drawer-tabs')).not.toBe(null);
expect(getByText('tab1')).toBeTruthy();
expect(getByText('基本信息')).toBeTruthy();
unmount();
diff --git a/src/slidePane/demos/basic.tsx b/src/drawer/demos/basic.tsx
similarity index 100%
rename from src/slidePane/demos/basic.tsx
rename to src/drawer/demos/basic.tsx
diff --git a/src/slidePane/demos/basicBanner.tsx b/src/drawer/demos/basicBanner.tsx
similarity index 100%
rename from src/slidePane/demos/basicBanner.tsx
rename to src/drawer/demos/basicBanner.tsx
diff --git a/src/slidePane/demos/basicBannerProps.tsx b/src/drawer/demos/basicBannerProps.tsx
similarity index 100%
rename from src/slidePane/demos/basicBannerProps.tsx
rename to src/drawer/demos/basicBannerProps.tsx
diff --git a/src/slidePane/demos/basicSize.tsx b/src/drawer/demos/basicSize.tsx
similarity index 95%
rename from src/slidePane/demos/basicSize.tsx
rename to src/drawer/demos/basicSize.tsx
index 5397fe779..e1a04fbce 100644
--- a/src/slidePane/demos/basicSize.tsx
+++ b/src/drawer/demos/basicSize.tsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react';
import { Button, Space } from 'antd';
import { SlidePane } from 'dt-react-component';
-import { SlidePaneProps } from 'dt-react-component/slidePane';
+import { SlidePaneProps } from 'dt-react-component/drawer';
export default () => {
const [visible, setVisible] = useState(false);
diff --git a/src/slidePane/demos/basic_mask.tsx b/src/drawer/demos/basic_mask.tsx
similarity index 100%
rename from src/slidePane/demos/basic_mask.tsx
rename to src/drawer/demos/basic_mask.tsx
diff --git a/src/slidePane/demos/basic_top.tsx b/src/drawer/demos/basic_top.tsx
similarity index 100%
rename from src/slidePane/demos/basic_top.tsx
rename to src/drawer/demos/basic_top.tsx
diff --git a/src/slidePane/demos/customTitle.tsx b/src/drawer/demos/customTitle.tsx
similarity index 100%
rename from src/slidePane/demos/customTitle.tsx
rename to src/drawer/demos/customTitle.tsx
diff --git a/src/slidePane/demos/footer.tsx b/src/drawer/demos/footer.tsx
similarity index 100%
rename from src/slidePane/demos/footer.tsx
rename to src/drawer/demos/footer.tsx
diff --git a/src/slidePane/demos/tabs.tsx b/src/drawer/demos/tabs.tsx
similarity index 100%
rename from src/slidePane/demos/tabs.tsx
rename to src/drawer/demos/tabs.tsx
diff --git a/src/slidePane/demos/tabsControl.tsx b/src/drawer/demos/tabsControl.tsx
similarity index 100%
rename from src/slidePane/demos/tabsControl.tsx
rename to src/drawer/demos/tabsControl.tsx
diff --git a/src/slidePane/index.md b/src/drawer/index.md
similarity index 100%
rename from src/slidePane/index.md
rename to src/drawer/index.md
diff --git a/src/slidePane/index.tsx b/src/drawer/index.tsx
similarity index 84%
rename from src/slidePane/index.tsx
rename to src/drawer/index.tsx
index a0d7f8f74..9a0083809 100644
--- a/src/slidePane/index.tsx
+++ b/src/drawer/index.tsx
@@ -2,7 +2,7 @@ import React, { CSSProperties, useEffect, useState } from 'react';
import { Alert, AlertProps, Spin, Tabs } from 'antd';
import classNames from 'classnames';
import { omit } from 'lodash';
-import RcDrawer, { DrawerProps } from 'rc-drawer';
+import RcDrawer, { DrawerProps as AntdDrawerProps } from 'rc-drawer';
import motionProps from './motion';
import './style.scss';
@@ -16,7 +16,7 @@ type readOnlyTab = readonly Tab[];
type TabKey
= T[number]['key'];
-interface NormalSlidePane extends Omit {
+interface NormalDrawerProps extends Omit {
/** @deprecated */
visible?: boolean;
size?: 'small' | 'default' | 'large';
@@ -28,7 +28,7 @@ interface NormalSlidePane extends Omit {
banner?: AlertProps['message'] | Omit;
}
-interface TabsSlidePane extends Omit {
+interface TabsDrawerProps extends Omit {
tabs?: T;
defaultKey?: TabKey;
activeKey?: TabKey;
@@ -36,33 +36,33 @@ interface TabsSlidePane extends Omit) => void;
}
-function isFunction(props: SlidePaneProps): props is TabsSlidePane {
+function isFunction(props: DrawerProps): props is TabsDrawerProps {
return typeof props.children === 'function';
}
-function isTabMode(props: SlidePaneProps): props is TabsSlidePane {
+function isTabMode(props: DrawerProps): props is TabsDrawerProps {
return 'tabs' in props;
}
-function isControlled(props: SlidePaneProps): props is TabsSlidePane {
+function isControlled(props: DrawerProps): props is TabsDrawerProps {
return 'activeKey' in props;
}
-export type SlidePaneProps = TabsSlidePane | NormalSlidePane;
+export type DrawerProps = TabsDrawerProps | NormalDrawerProps;
-const getWidthFromSize = (size: NormalSlidePane['size']) => {
+const getWidthFromSize = (size: NormalDrawerProps['size']) => {
if (size === 'small') return 720;
if (size === 'large') return 1256;
return 1000;
};
-const isValidBanner = (banner: NormalSlidePane['banner']): banner is AlertProps['message'] => {
+const isValidBanner = (banner: NormalDrawerProps['banner']): banner is AlertProps['message'] => {
if (typeof banner === 'object') return React.isValidElement(banner);
return true;
};
-const SlidePane = (props: SlidePaneProps) => {
- const slidePrefixCls = 'dtc-slide-pane';
+const Drawer = (props: DrawerProps) => {
+ const slidePrefixCls = 'dtc-drawer';
const {
visible,
@@ -156,4 +156,4 @@ const SlidePane = (props: SlidePaneProps) => {
);
};
-export default SlidePane;
+export default Drawer;
diff --git a/src/slidePane/motion.ts b/src/drawer/motion.ts
similarity index 100%
rename from src/slidePane/motion.ts
rename to src/drawer/motion.ts
diff --git a/src/slidePane/style.scss b/src/drawer/style.scss
similarity index 99%
rename from src/slidePane/style.scss
rename to src/drawer/style.scss
index 9110d7ed8..d9c590130 100644
--- a/src/slidePane/style.scss
+++ b/src/drawer/style.scss
@@ -1,4 +1,4 @@
-$prefix: "dtc-slide-pane";
+$prefix: "dtc-drawer";
.#{$prefix} {
top: 0;
diff --git a/src/index.ts b/src/index.ts
index a1b7bf6b8..bb7e98a4f 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -5,6 +5,7 @@ export { default as ContentLayout } from './contentLayout';
export { default as ContextMenu } from './contextMenu';
export { default as useCookieListener } from './cookies';
export { default as Copy } from './copy';
+export { default as Drawer } from './drawer';
export { default as Dropdown } from './dropdown';
export { default as EllipsisText } from './ellipsisText';
export { default as Empty } from './empty';
@@ -19,18 +20,16 @@ export { default as Input } from './input';
export { default as KeyEventListener } from './keyEventListener';
export { default as MarkdownRender } from './markdownRender';
export { default as Modal } from './modal';
-export { default as MxGraphContainer, WIDGETS_PREFIX } from './mxGraph';
export { default as NotFound } from './notFound';
export { default as ProgressBar } from './progressBar';
export { default as ProgressLine } from './progressLine';
export { default as Resize } from './resize';
-export { default as SlidePane } from './slidePane';
export { default as SpreadSheet } from './spreadSheet';
export { default as StatusTag } from './statusTag';
-export { default as useWindowSwitchListener } from './switchWindow';
export { default as Table } from './table';
export { default as TinyTag } from './tinyTag';
export { default as useDebounce } from './useDebounce';
export { default as useIntersectionObserver } from './useIntersectionObserver';
export { default as useList } from './useList';
export { default as useModal } from './useModal';
+export { default as useWindowSwitchListener } from './useWindowSwitchListener';
diff --git a/src/mxGraph/__tests__/__snapshots__/index.test.tsx.snap b/src/mxGraph/__tests__/__snapshots__/index.test.tsx.snap
deleted file mode 100644
index 7149f0f22..000000000
--- a/src/mxGraph/__tests__/__snapshots__/index.test.tsx.snap
+++ /dev/null
@@ -1,469 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`The mxGraph Container test Match Snapshot 1`] = `
-
-
-
-`;
-
-exports[`The mxGraph Container test Match Snapshot with data and toolbar 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`The mxGraph Container test Match Snapshot with data and widgets 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
-
-exports[`The mxGraph Container test Match Snapshot with style and bottom status bar 1`] = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/src/mxGraph/__tests__/factory.test.tsx b/src/mxGraph/__tests__/factory.test.tsx
deleted file mode 100644
index c06dbd6da..000000000
--- a/src/mxGraph/__tests__/factory.test.tsx
+++ /dev/null
@@ -1,237 +0,0 @@
-/* eslint-disable new-cap */
-import { cleanup } from '@testing-library/react';
-import '@testing-library/jest-dom';
-
-import MxFactory from '../factory';
-
-describe('mxGraph Factory Component Tests', () => {
- afterEach(() => {
- cleanup();
- });
- test('Static Properties in Factory', () => {
- expect(MxFactory.VertexSize).toEqual({
- width: 210,
- height: 50,
- });
-
- expect(MxFactory.config).toEqual({
- mxImageBasePath: 'images',
- mxLanguage: 'none',
- mxLoadResources: false,
- mxLoadStylesheets: false,
- });
- });
-
- test('Should create a graph instance', () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- document.body.appendChild(container);
- const graph = factory.create(container);
- expect(graph).toBeInstanceOf(factory.mxInstance.mxGraph);
- // Enable tooltip in default
- expect(graph.tooltipHandler.enabled).toBe(true);
- // Disable connection in default
- expect(graph.connectionHandler.enabled).toBe(false);
- graph.getSelectionCell = jest
- .fn()
- .mockImplementationOnce(() => {
- const cell = new factory.mxInstance.mxCell(
- '',
- new factory.mxInstance.mxGeometry(0, 0)
- );
- cell.edge = true;
- return cell;
- })
- .mockImplementation(() => {
- const cell = new factory.mxInstance.mxCell(
- '',
- new factory.mxInstance.mxGeometry(0, 0)
- );
- return cell;
- });
- // Disable edge movable in default
- expect(graph.isCellsMovable()).toBe(false);
- // Enable vertex movable in default
- expect(graph.isCellsMovable()).toBe(true);
-
- expect(graph.getStylesheet().getDefaultVertexStyle()).toEqual({
- '1': 'normal',
- align: 'center',
- fontFamily: 'PingFangSC-Regular',
- perimeter: factory.mxInstance.mxPerimeter.RectanglePerimeter,
- fontSize: '12',
- fontStyle: 1,
- shape: 'rectangle',
- verticalAlign: 'middle',
- whiteSpace: 'nowrap',
- });
- expect(graph.getStylesheet().getDefaultEdgeStyle()).toEqual({
- align: 'center',
- endArrow: 'block',
- fontSize: '10',
- edgeStyle: factory.mxInstance.mxEdgeStyle.TopToBottom,
- rounded: false,
- shape: 'connector',
- strokeColor: '#3f87ff',
- strokeWidth: 1,
- verticalAlign: 'middle',
- });
- });
-
- test('Should support config', () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- document.body.appendChild(container);
- const graph = factory.create(container, {
- tooltips: false,
- connectable: true,
- vertexMovable: false,
- });
- graph.getSelectionCell = jest.fn().mockImplementation(() => {
- const cell = new factory.mxInstance.mxCell('', new factory.mxInstance.mxGeometry(0, 0));
- return cell;
- });
- expect(graph.tooltipHandler.enabled).toBe(false);
- expect(graph.connectionHandler.enabled).toBe(true);
- expect(graph.isCellsMovable()).toBe(false);
- });
-
- test('Should support change the default style for edge and vertex', () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- document.body.appendChild(container);
- const graph = factory.create(container, {
- defaultEdgeStyle: {
- fontSize: '12',
- strokeWidth: 2,
- },
- defaultVertexStyle: {
- fontSize: '14',
- fontFamily: 'sans-serif',
- },
- });
-
- expect(graph.getStylesheet().getDefaultVertexStyle()).toEqual(
- expect.objectContaining({
- fontSize: '14',
- fontFamily: 'sans-serif',
- })
- );
- expect(graph.getStylesheet().getDefaultEdgeStyle()).toEqual(
- expect.objectContaining({
- fontSize: '12',
- strokeWidth: 2,
- })
- );
- });
-
- test('Should throw error when call createRubberBand before create', () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- document.body.appendChild(container);
-
- expect(factory.createRubberBand).toThrow();
-
- const mockRubberband = jest.fn();
- factory.mxInstance.mxRubberband = mockRubberband;
-
- factory.create(container);
- factory.createRubberBand();
- expect(mockRubberband).toBeCalled();
- });
-
- test('Should support initial functions', () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- document.body.appendChild(container);
- const graph = factory.create(container);
- factory.createRubberBand();
- factory.initContainerScroll();
-
- // The following functions are all for container scroll
- // @ts-ignore
- expect(graph.scrollTileSize).not.toBeUndefined();
- // @ts-ignore
- expect(graph.getPagePadding).not.toBeUndefined();
- // @ts-ignore
- expect(graph.getPageSize).not.toBeUndefined();
- // @ts-ignore
- expect(graph.getPageLayout).not.toBeUndefined();
-
- factory.resetScrollPosition();
- expect(graph.container.scrollTop).toBe(0);
- expect(graph.container.scrollLeft).toBe(0);
- });
-
- test('Should support to reset View', () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- document.body.appendChild(container);
- const mockScale = jest.fn();
- const mockTranslate = jest.fn();
- factory.mxInstance.mxGraphView.prototype.setScale = mockScale;
- factory.mxInstance.mxGraphView.prototype.setTranslate = mockTranslate;
-
- factory.setView({ scale: 1, dx: 1, dy: 1 });
- expect(mockScale).not.toBeCalled();
- expect(mockTranslate).not.toBeCalled();
-
- factory.create(container);
- factory.setView({ scale: 1, dx: 1, dy: 1 });
- expect(mockScale).toBeCalled();
- expect(mockTranslate).toBeCalled();
- });
-
- test('Should support dispose', () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- document.body.appendChild(container);
- const mockDestroy = jest.fn();
- factory.mxInstance.mxGraph.prototype.destroy = mockDestroy;
-
- factory.dispose();
- expect(mockDestroy).not.toBeCalled();
-
- factory.create(container);
- factory.dispose();
- expect(mockDestroy).toBeCalled();
- });
-
- test("Should apply graph's sizeDidChange function", () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- container.style.overflow = 'scroll';
- document.body.appendChild(container);
- const graph = factory.create(container);
-
- const mockSizeDidChange = jest.fn();
- graph.sizeDidChange = mockSizeDidChange;
- factory.initContainerScroll();
-
- // dispatch refresh to call sizeDidChange
- graph.view.setTranslate(100, 10);
-
- expect(mockSizeDidChange).toBeCalled();
- });
-
- test('Should support define render vertex', () => {
- const factory = new MxFactory();
- const container = document.createElement('div');
- document.body.appendChild(container);
- const graph = factory.create(container);
-
- factory.renderVertex(() => 'test
');
-
- graph.insertVertex(
- graph.getDefaultParent(),
- '',
- '',
- 0,
- 0,
- MxFactory.VertexSize.width,
- MxFactory.VertexSize.height
- );
-
- expect(container.querySelector('div[data-testid=mxGraph]')).toBeInTheDocument();
- });
-});
diff --git a/src/mxGraph/__tests__/index.test.tsx b/src/mxGraph/__tests__/index.test.tsx
deleted file mode 100644
index c38d6a981..000000000
--- a/src/mxGraph/__tests__/index.test.tsx
+++ /dev/null
@@ -1,744 +0,0 @@
-import React from 'react';
-import { cleanup, fireEvent, render, waitFor } from '@testing-library/react';
-import '@testing-library/jest-dom';
-
-import MxGraphContainer, { IContainerRef, WIDGETS_PREFIX } from '../index';
-
-describe('The mxGraph Container test', () => {
- afterEach(() => {
- cleanup();
- });
-
- test('Match Snapshot', () => {
- const { asFragment } = render();
- expect(asFragment()).toMatchSnapshot();
- });
-
- test('Match Snapshot with data and toolbar', () => {
- const { asFragment } = render(
- {
- return (
- <>
-
-
- >
- );
- }}
- />
- );
- expect(asFragment()).toMatchSnapshot();
- });
-
- test('Match Snapshot with data and widgets', () => {
- const { asFragment, container } = render(
- (
- <>
- 拖拽组件
-
- >
- )}
- />
- );
-
- const widgetsParentNode = container.querySelector('.dtc-graph-widgets')!;
- // NOTHING happened
- fireEvent.contextMenu(widgetsParentNode);
- expect(asFragment()).toMatchSnapshot();
- });
-
- test('Match Snapshot with style and bottom status bar', () => {
- const { asFragment } = render(
-
- {() => This is legend
}
-
- );
- expect(asFragment()).toMatchSnapshot();
- });
-
- test('Should support all keyboard binding events', () => {
- const bindKeyFn = jest.fn();
- render(
- [
- {
- id: 'bindKey',
- method: 'bindKey',
- keyCode: 8,
- func: bindKeyFn,
- },
- {
- id: 'bindShiftKey',
- method: 'bindShiftKey',
- keyCode: 8,
- func: bindKeyFn,
- },
- {
- id: 'bindControlKey',
- method: 'bindControlKey',
- keyCode: 8,
- func: bindKeyFn,
- },
- {
- id: 'bindControlShiftKey',
- method: 'bindControlShiftKey',
- keyCode: 8,
- func: bindKeyFn,
- },
- ]}
- />
- );
-
- expect(bindKeyFn).not.toBeCalled();
- fireEvent.keyDown(document.documentElement, {
- key: 'Backspace',
- keyCode: 8,
- });
- expect(bindKeyFn).toBeCalledTimes(1);
-
- fireEvent.keyDown(document.documentElement, {
- shiftKey: true,
- key: 'Backspace',
- keyCode: 8,
- });
- expect(bindKeyFn).toBeCalledTimes(2);
-
- fireEvent.keyDown(document.documentElement, {
- ctrlKey: true,
- key: 'Backspace',
- keyCode: 8,
- });
- expect(bindKeyFn).toBeCalledTimes(3);
-
- fireEvent.keyDown(document.documentElement, {
- ctrlKey: true,
- key: 'Backspace',
- keyCode: 8,
- });
- expect(bindKeyFn).toBeCalledTimes(4);
-
- fireEvent.keyDown(document.documentElement, {
- shiftKey: true,
- ctrlKey: true,
- key: 'Backspace',
- keyCode: 8,
- });
- expect(bindKeyFn).toBeCalledTimes(5);
- });
-
- test('Should support to set loading', () => {
- const { getByText } = render(
-
- );
- expect(getByText('Loading...')).toBeInTheDocument();
- });
-
- test('Should support to change the vertex size', () => {
- const { container, rerender } = render(
- ``}
- />
- );
- expect(container.querySelector('rect[width="210"]')).toBeInTheDocument();
-
- rerender(
- ``}
- />
- );
- // All vertexes are with 250px's width
- expect(container.querySelector('rect[width="210"]')).toBeNull();
- expect(container.querySelector('rect[width="250"]')).toBeInTheDocument();
-
- // Dynamic control the sizes of each vertexes
- rerender(
- ({
- width: data.taskId === 1 ? 250 : 210,
- height: 50,
- })}
- onRenderCell={(cell) => ``}
- />
- );
- expect(container.querySelector('rect[width="210"]')).toBeInTheDocument();
- expect(container.querySelector('rect[width="250"]')).toBeInTheDocument();
- });
-
- test('Should render both parent node and children node', () => {
- const { getByTestId } = render(
- ``}
- />
- );
- expect(getByTestId('1')).toBeInTheDocument();
- expect(getByTestId('2')).toBeInTheDocument();
- expect(getByTestId('3')).toBeInTheDocument();
- });
-
- test('Should listen the container changed', () => {
- const mockContainerChanged = jest.fn();
- const { container } = render(
- ``}
- />
- );
-
- const mxGraphContainer = container.querySelector('div[tabindex="-1"]')!;
- fireEvent.scroll(mxGraphContainer, { target: { scrollY: 100 } });
-
- expect(mockContainerChanged).toBeCalled();
- });
-
- test('Should support to set the layout orientation', () => {
- const { getByTestId, rerender } = render(
- ``}
- />
- );
- const getVertex = (text: string) =>
- getByTestId(text)!.parentElement!.parentElement!.parentElement!;
-
- // The default orientation of layout is north
- // So the layout should be like:
- // 3
- // |
- // 1
- // |
- // 2
- expect(parseInt(getVertex('1').style.top, 10)).toBeLessThan(
- parseInt(getVertex('2').style.top, 10)
- );
- expect(parseInt(getVertex('3').style.top, 10)).toBeLessThan(
- parseInt(getVertex('1').style.top, 10)
- );
- expect(parseInt(getVertex('1').style.left, 10)).toEqual(
- parseInt(getVertex('2').style.left, 10)
- );
- expect(parseInt(getVertex('2').style.left, 10)).toEqual(
- parseInt(getVertex('3').style.left, 10)
- );
-
- rerender(
- ``}
- />
- );
-
- // The layout should be like:
- // 3-1-2
- expect(parseInt(getVertex('1').style.top, 10)).toEqual(
- parseInt(getVertex('2').style.top, 10)
- );
- expect(parseInt(getVertex('2').style.top, 10)).toEqual(
- parseInt(getVertex('3').style.top, 10)
- );
- expect(parseInt(getVertex('3').style.left, 10)).toBeLessThan(
- parseInt(getVertex('1').style.left, 10)
- );
- expect(parseInt(getVertex('1').style.left, 10)).toBeLessThan(
- parseInt(getVertex('2').style.left, 10)
- );
- });
-
- test('Should support call onClick', () => {
- const clickFn = jest.fn();
- const { container } = render(
-
- );
-
- const svg = container.querySelector('svg')!;
- fireEvent.mouseDown(svg.querySelector('g[transform="translate(0.5,0.5)"]')!, {
- clientX: 200,
- clientY: 120,
- });
- fireEvent.mouseUp(svg.querySelector('g[transform="translate(0.5,0.5)"]')!, {
- clientX: 200,
- clientY: 120,
- });
- expect(clickFn).toBeCalled();
- });
-
- test('Should support call onContextMenu', async () => {
- const menuFn = jest.fn();
- const { container, getByText } = render(
- [
- {
- id: 'test',
- title: '测试',
- },
- {
- id: 'disabled',
- title: '禁用',
- disabled: true,
- },
- {
- id: 'func',
- title: 'func',
- callback: menuFn,
- },
- {
- id: 'subMenu',
- title: 'subMenu',
- children: [
- {
- id: 'subMenu-1',
- title: 'subMenu-1',
- },
- ],
- },
- ]}
- onRenderCell={(cell) => ``}
- />
- );
-
- const svg = container.querySelector('svg')!;
- fireEvent.mouseDown(
- svg.querySelector('g[transform="translate(0.5,0.5)"]')!,
- // Both contextMenu and click event are called by mousedown and mouseup
- // They distinguish through which property, refer by: mxEvent.isRightMouseButton
- { clientX: 200, clientY: 120, which: 3 }
- );
- fireEvent.mouseUp(svg.querySelector('g[transform="translate(0.5,0.5)"]')!, {
- clientX: 200,
- clientY: 120,
- });
-
- await waitFor(
- () => {
- expect(document.querySelector('table.mxPopupMenu')).toBeInTheDocument();
-
- expect(getByText('禁用').classList.contains('mxDisabled')).toBeTruthy();
-
- // The mousemove is used in mxGraph to mock a hover behavior
- fireEvent.mouseMove(getByText('subMenu'));
- expect(getByText('subMenu-1')).toBeInTheDocument();
-
- // The click is mocked by mousedown and mouseup
- fireEvent.mouseDown(getByText('func'));
- fireEvent.mouseUp(getByText('func'));
- expect(menuFn).toBeCalled();
-
- // After clicking, popup should be disappeared
- expect(document.querySelector('table.mxPopupMenu')).toBeNull();
- },
- { timeout: 500 }
- );
- });
-
- test('Should support to render the keyboard event in contextMenu', async () => {
- const keydownFunc = jest.fn();
- const { container, getByText } = render(
- [
- {
- id: 'test',
- title: '测试',
- },
- ]}
- onKeyDown={() => [
- {
- // Keep the same id with the context menu
- // So the item with same id in context menu will call keydown's event
- id: 'test',
- method: 'bindControlKey',
- keyCode: 8,
- func: keydownFunc,
- },
- ]}
- onRenderCell={(cell) => ``}
- />
- );
-
- const svg = container.querySelector('svg')!;
- fireEvent.mouseDown(
- svg.querySelector('g[transform="translate(0.5,0.5)"]')!,
- // Both contextMenu and click event are called by mousedown and mouseup
- // They distinguish through which property, refer by: mxEvent.isRightMouseButton
- { clientX: 200, clientY: 120, which: 3 }
- );
- fireEvent.mouseUp(svg.querySelector('g[transform="translate(0.5,0.5)"]')!, {
- clientX: 200,
- clientY: 120,
- });
-
- await waitFor(
- () => {
- expect(document.querySelector('table.mxPopupMenu')).toBeInTheDocument();
-
- // mxGraph detects the same id in keydown, so this menu has character codes
- expect(getByText('测试(Meta ⌫)')).toBeInTheDocument();
-
- fireEvent.mouseDown(getByText('测试(Meta ⌫)'));
- fireEvent.mouseUp(getByText('测试(Meta ⌫)'));
- expect(keydownFunc).toBeCalled();
- },
- { timeout: 500 }
- );
- });
-
- test('Should ONLY render one popup menu in graph', async () => {
- const { container } = render(
- [
- {
- id: 'test',
- title: '测试',
- },
- ]}
- onRenderCell={(cell) => ``}
- />
- );
-
- const svg = container.querySelector('svg')!;
- const vertexes = svg.querySelectorAll('g[transform="translate(0.5,0.5)"]');
- fireEvent.mouseDown(
- vertexes[0],
- // Both contextMenu and click event are called by mousedown and mouseup
- // They distinguish through which property, refer by: mxEvent.isRightMouseButton
- { clientX: 200, clientY: 120, which: 3 }
- );
- fireEvent.mouseUp(vertexes[0], { clientX: 200, clientY: 120 });
-
- await waitFor(
- async () => {
- expect(document.querySelectorAll('table.mxPopupMenu').length).toBe(1);
-
- fireEvent.mouseDown(
- vertexes[1],
- // Both contextMenu and click event are called by mousedown and mouseup
- // They distinguish through which property, refer by: mxEvent.isRightMouseButton
- { clientX: 200, clientY: 120, which: 3 }
- );
- fireEvent.mouseUp(vertexes[1], { clientX: 200, clientY: 120 });
-
- // Call context menu in other vertex, there still only is one popup in graph
- await waitFor(
- () => {
- expect(document.querySelectorAll('table.mxPopupMenu').length).toBe(1);
- },
- { timeout: 500 }
- );
- },
- { timeout: 500 }
- );
- });
-
- test('Should support to call onDoubleClick', () => {
- const doubleClickFn = jest.fn();
- const { container } = render(
- ``}
- />
- );
-
- const svg = container.querySelector('svg')!;
- const vertex = svg.querySelectorAll('g[transform="translate(0.5,0.5)"]')[0];
-
- fireEvent.doubleClick(vertex);
-
- expect(doubleClickFn).toBeCalled();
- });
-
- test('Should support to highlight cells', () => {
- const { container } = render(
- ``}
- />
- );
-
- const svg = container.querySelector('svg')!;
- const vertex = svg.querySelectorAll('g[transform="translate(0.5,0.5)"]')[0];
- const edge = svg.querySelectorAll('g[transform="translate(0.5,0.5)"]')[2];
-
- fireEvent.mouseDown(vertex);
- fireEvent.mouseUp(vertex);
-
- const getActiveEdgeLength = () => {
- return Array.prototype.filter.call(
- svg.querySelectorAll('path[fill="none"]'),
- (dom: SVGPathElement) => {
- return (
- dom.getAttribute('stroke') === '#3f87ff' &&
- dom.getAttribute('stroke-width') === '2'
- );
- }
- ).length;
- };
- const getActiveVertexLength = () => {
- return svg.querySelectorAll('rect[stroke="transparent"]').length;
- };
-
- // Active the in and out edges both, and current selected vertex
- expect(getActiveEdgeLength()).toBe(2);
- expect(getActiveVertexLength()).toBe(1);
-
- fireEvent.mouseDown(svg);
- fireEvent.mouseUp(svg);
-
- // Click on graph will unselect all cells
- expect(getActiveEdgeLength()).toBe(0);
- expect(getActiveVertexLength()).toBe(0);
-
- fireEvent.mouseDown(edge);
- fireEvent.mouseUp(edge);
-
- // Click on edge will ONLY active current edge
- expect(getActiveEdgeLength()).toBe(1);
- expect(getActiveVertexLength()).toBe(0);
- });
-
- test('Should support to drag cells', () => {
- const cellChangedFn = jest.fn();
- const { container } = render(
- ``}
- />
- );
-
- const svg = container.querySelector('svg')!;
- const vertex = svg.querySelectorAll('g[transform="translate(0.5,0.5)"]')[0];
-
- fireEvent.mouseDown(vertex);
- fireEvent.mouseMove(vertex, { clientX: 100, clientY: 0 });
- fireEvent.mouseUp(vertex);
-
- expect(cellChangedFn).toBeCalled();
- });
-
- test('Should support to call ref functions', async () => {
- const refMock: { current: IContainerRef } = { current: null } as any;
- render(
- ``}
- />
- );
-
- expect(refMock.current.getCells().length).toBe(5);
- expect(refMock.current.getSelectedCell()!.value.taskId).toBe(1);
-
- refMock.current.insertCell({ taskId: 4 }, 0, 0);
- expect(refMock.current.getCells().length).toBe(6);
-
- refMock.current.updateCell('7', { test: 1 });
- expect(refMock.current.getCells()!.find((i) => i.id === '7')!.value).toEqual({
- taskId: 4,
- test: 1,
- });
-
- refMock.current.removeCell('7');
- expect(refMock.current.getCells().find((i) => i.id === '7')).toBeUndefined();
-
- const cells = refMock.current.getCells();
- cells.forEach((cell) => {
- refMock.current.removeCell(cell.id);
- });
- expect(refMock.current.getCells().length).toBe(0);
- refMock.current.setCells(cells);
- expect(refMock.current.getCells().length).toBe(5);
-
- const mockScrollTo = jest.fn();
- HTMLElement.prototype.scrollTo = mockScrollTo;
- refMock.current.setView({
- scale: 1,
- scrollTop: 100,
- scrollLeft: 100,
- });
-
- await waitFor(
- () => {
- expect(mockScrollTo).toBeCalled();
- },
- { timeout: 100 }
- );
- });
-
- test('Should support to drag widgets into graph', () => {
- const dropWidgetsFn = jest.fn();
- const { container } = render(
- (
- <>
- 拖拽组件
-
- >
- )}
- />
- );
- const svg = container.querySelector('svg')!;
- const mockEleFromPoint = jest
- .fn()
- .mockImplementationOnce(() => null)
- .mockImplementationOnce(() => container)
- .mockImplementation(() => svg);
- document.elementFromPoint = mockEleFromPoint;
-
- const widget = container.querySelector('.' + WIDGETS_PREFIX + '__')!;
- const dragWidget = () => {
- fireEvent.mouseDown(widget);
- fireEvent.mouseMove(svg, {
- clientX: 0,
- clientY: 0,
- });
- fireEvent.mouseUp(svg);
- };
-
- dragWidget();
- expect(mockEleFromPoint).toBeCalled();
- // The elementFromPoint returns null at first, so it won't call onDropWidgets
- expect(dropWidgetsFn).not.toBeCalled();
-
- dragWidget();
- // Although the elementFromPoint returns container, but is't not the ancestor node about graph
- // So it won't call onDropWidgets
- expect(dropWidgetsFn).not.toBeCalled();
-
- dragWidget();
- expect(dropWidgetsFn).toBeCalled();
- });
-});
diff --git a/src/mxGraph/demos/basic.tsx b/src/mxGraph/demos/basic.tsx
deleted file mode 100644
index c1e0ee42d..000000000
--- a/src/mxGraph/demos/basic.tsx
+++ /dev/null
@@ -1,87 +0,0 @@
-import React from 'react';
-import ReactDOMServer from 'react-dom/server';
-import { ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons';
-import { Tooltip } from 'antd';
-import { MxGraphContainer } from 'dt-react-component';
-
-import './index.scss';
-
-export default () => {
- return (
- 'whiteSpace=wrap;fillColor=#f5ffe6;strokeColor=#12bc6a;'}
- onRenderActions={(graph) => (
-
-
- graph.zoomIn()} />
-
-
- graph.zoomOut()} />
-
-
- )}
- onRenderCell={(cell) => {
- if (cell.vertex && cell.value) {
- const task = cell.value;
- if (task) {
- return ReactDOMServer.renderToString(
-
- {task.taskName}
-
- {task.taskId}
-
- );
- }
- }
- return '';
- }}
- onRenderTooltips={(cell) => {
- if (cell.vertex && cell.value) {
- return cell.value.taskName;
- }
- return '';
- }}
- />
- );
-};
diff --git a/src/mxGraph/demos/context.tsx b/src/mxGraph/demos/context.tsx
deleted file mode 100644
index 87655e4c4..000000000
--- a/src/mxGraph/demos/context.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-import React from 'react';
-import ReactDOMServer from 'react-dom/server';
-import { MxGraphContainer } from 'dt-react-component';
-
-import './index.scss';
-
-export default () => {
- return (
- {
- const fillColors = ['#fffbe6', '#e6f6ff', '#f5ffe6', '#fff1f0', '#e6e9f2'];
- const strokeColors = ['#fdb313', '#3f87ff', '#12bc6a', '#fe615c', '#5b6da6'];
- return (
- 'whiteSpace=wrap;fillColor=' +
- fillColors[data.taskType - 1] +
- ';strokeColor=' +
- strokeColors[data.taskType - 1] +
- ';'
- );
- }}
- onContextMenu={(data, cell) => {
- const titles = ['执行中', '部署中', '取消中', '运行成功', '运行失败'];
- return cell.vertex
- ? [
- {
- id: 'operation',
- title: titles[data.taskType - 1],
- callback: () => {
- alert('当前 vertex 处于' + titles[data.taskType - 1]);
- },
- },
- {
- id: 'remove',
- title: '删除当前节点',
- callback: () => {
- console.log('删除');
- },
- },
- ]
- : [
- {
- id: 'remove',
- title: '删除连线',
- callback: () => {
- console.log('删除');
- },
- },
- ];
- }}
- onRenderCell={(cell) => {
- if (cell.vertex && cell.value) {
- const task = cell.value;
- if (task) {
- return ReactDOMServer.renderToString(
-
- {task.taskName}
-
- {task.taskId}
-
- );
- }
- }
- return '';
- }}
- />
- );
-};
diff --git a/src/mxGraph/demos/defaultGraphData.ts b/src/mxGraph/demos/defaultGraphData.ts
deleted file mode 100644
index 876fd9d55..000000000
--- a/src/mxGraph/demos/defaultGraphData.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-export default [
- {
- metaId: 'test-1',
- metaInfo: {
- name: 'tableName',
- type: 1,
- },
- childNode: [
- {
- metaId: 'test-2',
- metaInfo: {
- name: 'tableName2',
- type: 2,
- },
- },
- {
- metaId: 'test-3',
- metaInfo: {
- name: 'tableName3',
- type: 2,
- },
- },
- {
- metaId: 'test-4',
- metaInfo: {
- name: 'tableName4',
- type: 2,
- },
- },
- {
- metaId: 'test-5',
- metaInfo: {
- name: 'tableName5',
- type: 2,
- },
- },
- ],
- parentNode: [
- {
- metaId: 'test-6',
- metaInfo: {
- name: 'tableName6',
- type: 3,
- },
- },
- {
- metaId: 'test-7',
- metaInfo: {
- name: 'tableName7',
- type: 3,
- },
- },
- {
- metaId: 'test-8',
- metaInfo: {
- name: 'tableName8',
- type: 3,
- },
- },
- {
- metaId: 'test-9',
- metaInfo: {
- name: 'tableName9',
- type: 3,
- },
- },
- ],
- },
-];
diff --git a/src/mxGraph/demos/drag.tsx b/src/mxGraph/demos/drag.tsx
deleted file mode 100644
index bd6905781..000000000
--- a/src/mxGraph/demos/drag.tsx
+++ /dev/null
@@ -1,164 +0,0 @@
-import React from 'react';
-import ReactDOMServer from 'react-dom/server';
-import { MxGraphContainer, WIDGETS_PREFIX } from 'dt-react-component';
-
-import './index.scss';
-
-export default () => {
- return (
- {
- console.group('onDropWidgets');
- console.log('node:', node);
- console.log('graph:', graph);
- console.log('target:', target);
- console.log('x and y:', x, y);
- console.groupEnd();
- const taskId = 'randomId__' + new Date().valueOf();
- graph.insertVertex(
- graph.getDefaultParent(),
- taskId,
- {
- taskName: node.innerText,
- taskId,
- },
- x,
- y,
- 210,
- 50,
- 'whiteSpace=wrap;fillColor=#f5ffe6;strokeColor=#12bc6a;'
- );
- }}
- onCellsChanged={(cell) => {
- console.group('onCellsChanged');
- console.log('cell:', cell);
- console.groupEnd();
- }}
- onDrawVertex={() => 'whiteSpace=wrap;fillColor=#f5ffe6;strokeColor=#12bc6a;'}
- onRenderCell={(cell) => {
- if (cell.vertex && cell.value) {
- const task = cell.value;
- if (task) {
- return ReactDOMServer.renderToString(
-
- {task.taskName}
-
- {task.taskId}
-
- );
- }
- }
- return '';
- }}
- onGetPreview={(node) => {
- const previewDragTarget = document.createElement('div');
- previewDragTarget.style.width = '210px';
- previewDragTarget.style.height = '50px';
- previewDragTarget.style.border = '1px solid #ddd';
- previewDragTarget.style.textAlign = 'center';
- previewDragTarget.dataset.name = node.innerText;
- previewDragTarget.innerHTML = ReactDOMServer.renderToString(
- <>
- 新节点
-
- {node.innerText}
- >
- );
- return previewDragTarget;
- }}
- onRenderWidgets={() => {
- return (
- <>
- 拖拽组件
-
- -
- 你好1
-
- -
- 你好2
-
- -
- 你好3
-
- -
- 你好4
-
-
- >
- );
- }}
- />
- );
-};
diff --git a/src/mxGraph/demos/event.tsx b/src/mxGraph/demos/event.tsx
deleted file mode 100644
index 27470c398..000000000
--- a/src/mxGraph/demos/event.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-import React from 'react';
-import ReactDOMServer from 'react-dom/server';
-import { MxGraphContainer } from 'dt-react-component';
-
-import './index.scss';
-
-export default () => {
- return (
- {
- console.group('onClick');
- console.log('当前点击的 cell 是:', cell);
- console.log('当前点击的 graph 是:', graph);
- console.log('当前点击的 dom 是:', event.target);
- console.groupEnd();
- }}
- onDoubleClick={(cell, graph, event) => {
- console.group('onDoubleClick');
- console.log('当前点击的 cell 是:', cell);
- console.log('当前点击的 graph 是:', graph);
- console.log('当前点击的 dom 是:', event.target);
- console.groupEnd();
- }}
- onContainerChanged={(geo) => {
- console.group('onContainerChanged');
- console.log(geo);
- console.groupEnd();
- }}
- onKeyDown={() => {
- return [
- {
- id: 'remove',
- method: 'bindControlKey',
- keyCode: 8,
- func: () => {
- alert('删除');
- },
- },
- ];
- }}
- onContextMenu={() => {
- return [{ id: 'remove', title: '删除' }];
- }}
- onDrawVertex={() => 'whiteSpace=wrap;fillColor=#f5ffe6;strokeColor=#12bc6a;'}
- onRenderCell={(cell) => {
- if (cell.vertex && cell.value) {
- const task = cell.value;
- if (task) {
- return ReactDOMServer.renderToString(
-
- {task.taskName}
-
- {task.taskId}
-
- );
- }
- }
- return '';
- }}
- />
- );
-};
diff --git a/src/mxGraph/demos/expand.tsx b/src/mxGraph/demos/expand.tsx
deleted file mode 100644
index 238331ad6..000000000
--- a/src/mxGraph/demos/expand.tsx
+++ /dev/null
@@ -1,178 +0,0 @@
-import React, { useState } from 'react';
-import ReactDOMServer from 'react-dom/server';
-import { MxGraphContainer } from 'dt-react-component';
-
-import './index.scss';
-
-export default () => {
- const [loading, setLoading] = useState(false);
- const [currentSelect, setCurrent] = useState('b');
- const [graphData, setGraphData] = useState([
- {
- metaId: '1',
- metaInfo: {
- name: 'tableName',
- type: 1,
- list: ['a', 'b', 'c', 'd'],
- },
- childNode: [
- {
- metaId: '2',
- metaInfo: {
- name: 'tableName',
- type: 2,
- list: ['1-c'],
- },
- },
- {
- metaId: '3',
- metaInfo: {
- name: 'tableName',
- type: 2,
- list: ['1-c'],
- },
- },
- ],
- },
- ]);
-
- const handleGetSize = (data: any) => {
- if (data.metaId === '1') {
- return {
- width: 194,
- height: 120,
- };
- }
- return {
- width: 196,
- height: 54,
- };
- };
-
- return (
- ({
- [mxConstants.STYLE_ROUNDED]: 1,
- [mxConstants.STYLE_CURVED]: 0,
- [mxConstants.STYLE_EDGE]: mxEdgeStyle.EntityRelation,
- }),
- getPortOffset: (edgeState, source) => {
- const container =
- edgeState[
- source ? 'visibleSourceState' : 'visibleTargetState'
- ].text.node.querySelectorAll('div')[1];
- const portDom =
- container.querySelector(
- 'li[data-id=' + currentSelect + ']'
- ) || container.querySelector('li');
-
- return portDom!;
- },
- }}
- vertexKey="metaId"
- onClick={(cell, graph, event) => {
- if (cell.value.metaId === '1') {
- setLoading(true);
- setTimeout(() => {
- const nextGraph: any = [
- {
- ...graphData[0],
- childNode: [],
- parentNode: [],
- },
- ];
- const handler = Math.random() > 0.5 ? 'childNode' : 'parentNode';
- const length = Math.floor(Math.random() * 5 + 1);
- nextGraph[0][handler].push(
- ...new Array(length).fill({}).map((_, idx) => {
- return {
- metaId: '1-' + idx,
- metaInfo: {
- name: 'tableName',
- type: 2,
- list: ['1-c'],
- },
- };
- })
- );
- const target: any = event.target;
- setCurrent(target.dataset.id);
- setGraphData(nextGraph);
- setLoading(false);
- }, 300);
- }
- }}
- onGetSize={handleGetSize}
- graphData={graphData}
- onDrawVertex={() => 'whiteSpace=wrap;fillColor=#ffffff;strokeColor=#7460EF;'}
- onDrawEdge={() => 'whiteSpace=wrap;fillColor=#ffffff;strokeColor=#7460EF;'}
- onRenderCell={(cell) => {
- if (cell.vertex && cell.value) {
- const meta = cell.value;
- if (meta) {
- const size = handleGetSize(meta);
- return ReactDOMServer.renderToString(
-
- {meta.metaInfo.name}
-
-
-
- {meta.metaInfo.list.map((l) => (
- -
- {l}
-
- ))}
-
-
-
- );
- }
- }
- return '';
- }}
- />
- );
-};
diff --git a/src/mxGraph/demos/index.scss b/src/mxGraph/demos/index.scss
deleted file mode 100644
index 8d8c0a413..000000000
--- a/src/mxGraph/demos/index.scss
+++ /dev/null
@@ -1,68 +0,0 @@
-.mxTooltip {
- position: absolute;
- display: block;
- box-sizing: border-box;
- margin: 0;
- padding: 10px;
- color: #333;
- font-size: 11px;
- font-family: Arial, sans-serif;
- font-variant: tabular-nums;
- line-height: 1.5;
- word-wrap: break-word;
- list-style: none;
- background: #FFF;
- border: none;
- border-radius: 0;
- box-shadow: 0 2px 20px 0 rgba(0, 0, 0, 0.08);
- cursor: default;
- font-feature-settings: "tnum";
- .vertex-title {
- color: inherit;
- }
- .vertex {
- color: #FFF;
- }
-}
-
-div.mxPopupMenu {
- position: absolute;
- background: #FFF;
- border: 0;
- border-radius: 0;
- box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.08);
- table.mxPopupMenu {
- margin: 4px 0;
- border-collapse: collapse;
- tr.mxPopupMenuItem {
- color: #000;
- cursor: default;
- }
- td.mxPopupMenuItem {
- padding: 6px 60px 6px 30px;
- color: #000;
- font-size: 12px;
- font-family: PingFangSC-Regular, sans-serif;
- letter-spacing: 0;
- border: none;
- &.mxDisabled {
- color: #DDD;
- cursor: not-allowed;
- }
- }
- td.mxPopupMenuIcon {
- padding: 0;
- background-color: #FFF;
- }
- tr.mxPopupMenuItemHover {
- background-color: #E6F7FF;
- cursor: pointer;
- .mxPopupMenuItem {
- color: #2491F7;
- }
- }
- hr {
- border-top: solid 1px #CCC;
- }
- }
-}
diff --git a/src/mxGraph/demos/relationship.tsx b/src/mxGraph/demos/relationship.tsx
deleted file mode 100644
index 60ea2f720..000000000
--- a/src/mxGraph/demos/relationship.tsx
+++ /dev/null
@@ -1,231 +0,0 @@
-import React, { useState } from 'react';
-import ReactDOMServer from 'react-dom/server';
-import { message, Tooltip } from 'antd';
-import { MxGraphContainer } from 'dt-react-component';
-
-import defaultGraphData from './defaultGraphData';
-import './index.scss';
-
-export default () => {
- const [loading, setLoading] = useState(false);
- const [graphData, setGraphData] = useState([...defaultGraphData]);
-
- return (
- ({
- [mxConstants.STYLE_ROUNDED]: 1,
- [mxConstants.STYLE_CURVED]: 0,
- [mxConstants.STYLE_EDGE]: mxEdgeStyle.EntityRelation,
- }),
- }}
- vertexKey="metaId"
- onContextMenu={(_, cell) =>
- cell.vertex
- ? [
- {
- id: 'insert',
- title: '插入',
- },
- {
- id: 'remove',
- title: '删除',
- },
- ]
- : []
- }
- onClick={(cell, graph, event) => {
- const target: any = event.target;
- if (target.closest('.loadData')) {
- setLoading(true);
- setTimeout(() => {
- setGraphData((g) => {
- const stack: any[] = [...g];
- while (stack.length) {
- const item = stack.pop();
- if (item.metaId === cell.value.metaId) {
- const uniqueId = 'randomId__' + new Date().valueOf();
- const insertHandler =
- cell.value.metaInfo.type === 2 ? 'childNode' : 'parentNode';
- item[insertHandler] = item[insertHandler] || [];
- item[insertHandler].push({
- metaId: uniqueId,
- metaInfo: {
- name: uniqueId + 'tableName',
- type: item.metaInfo.type,
- },
- });
- break;
- }
-
- stack.push(...(item.childNode || []));
- stack.push(...(item.parentNode || []));
- }
-
- return [...g];
- });
- setLoading(false);
- }, 300);
- }
- }}
- graphData={graphData}
- onDrawVertex={(data) => {
- return [
- '',
- 'whiteSpace=wrap;fillColor=#ffffff;strokeColor=#3F87FF;',
- 'whiteSpace=wrap;fillColor=#ffffff;strokeColor=#7460EF;',
- 'whiteSpace=wrap;fillColor=#ffffff;strokeColor=#26D6AE;',
- ][data.metaInfo.type];
- }}
- onDrawEdge={(source, target) => {
- if (source.value.metaInfo.type === 3) {
- return 'whiteSpace=wrap;fillColor=#ffffff;strokeColor=#26D6AE;';
- }
-
- if (target.value.metaInfo.type === 2) {
- return 'whiteSpace=wrap;fillColor=#ffffff;strokeColor=#7460EF;';
- }
-
- return 'whiteSpace=wrap;fillColor=#ffffff;strokeColor=#3F87FF;';
- }}
- onRenderActions={(graph, { mxOutline: MxOutline }) => {
- return (
- <>
-
-
-
-
-
-
-
-
- >
- );
- }}
- onRenderCell={(cell) => {
- if (cell.vertex && cell.value) {
- const meta = cell.value;
- if (meta) {
- const isLeft = meta.metaInfo.type === 3;
- const position = isLeft ? 'left' : 'right';
- return ReactDOMServer.renderToString(
-
-
{meta.metaInfo.name}
- {meta.metaInfo.type !== 1 && (
-

- )}
-
- );
- }
- }
- return '';
- }}
- >
- {() => (
-
-
- -
-
- 1
-
- -
-
- 2
-
- -
-
- 3
-
-
-
- )}
-
- );
-};
diff --git a/src/mxGraph/factory.tsx b/src/mxGraph/factory.tsx
deleted file mode 100644
index 37c719988..000000000
--- a/src/mxGraph/factory.tsx
+++ /dev/null
@@ -1,565 +0,0 @@
-/* eslint-disable prefer-rest-params */
-import type {
- mxCell,
- mxCellState,
- mxGraph,
- mxGraphExportObject,
- mxGraphOptions,
- mxGraphView,
- mxPoint,
- mxRectangle,
- StyleMap,
-} from 'mxgraph';
-import factory from 'mxgraph';
-
-import { IContainerProps } from '.';
-
-type IMxGraph = mxGraph & {
- scrollTileSize?: mxRectangle;
- getPagePadding?: () => mxPoint;
- getPageSize?: () => mxRectangle;
- getPageLayout?: () => mxRectangle;
-};
-
-/**
- * refer to: https://jgraph.github.io/mxgraph/docs/js-api/files/index-txt.html
- * typings refer to: https://github.com/typed-mxgraph/typed-mxgraph#readme
- */
-class MxFactory {
- static config: mxGraphOptions = {
- mxImageBasePath: 'images',
- mxLanguage: 'none',
- mxLoadResources: false,
- mxLoadStylesheets: false,
- };
-
- static VertexSize = {
- width: 210,
- height: 50,
- };
-
- // eslint-disable-next-line no-void
- public layoutEventHandler: () => void = () => void 0;
-
- public mxInstance: mxGraphExportObject;
-
- public mxGraph: IMxGraph | null = null;
-
- constructor() {
- this.mxInstance = factory(MxFactory.config);
- }
-
- /**
- * 边框的默认样式
- */
- private getDefaultVertexStyle = () => {
- const { mxConstants, mxPerimeter } = this.mxInstance;
- const style: StyleMap = [];
- style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
- style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
- style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
- style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
- style[mxConstants.STYLE_FONTSIZE] = '12';
- style[mxConstants.STYLE_FONTFAMILY] = 'PingFangSC-Regular';
- style[mxConstants.FONT_BOLD] = 'normal';
- style[mxConstants.STYLE_WHITE_SPACE] = 'nowrap';
- style[mxConstants.STYLE_FONTSTYLE] = 1;
- return style;
- };
-
- /**
- * 边线的默认样式
- */
- private getDefaultEdgeStyle = () => {
- const { mxConstants, mxEdgeStyle } = this.mxInstance;
- const style: StyleMap = [];
- style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_CONNECTOR;
- style[mxConstants.STYLE_STROKECOLOR] = '#3f87ff';
- style[mxConstants.STYLE_STROKEWIDTH] = 1;
- style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
- style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
- style[mxConstants.STYLE_EDGE] = mxEdgeStyle.TopToBottom;
- style[mxConstants.STYLE_ENDARROW] = mxConstants.ARROW_BLOCK;
- style[mxConstants.STYLE_FONTSIZE] = '10';
- style[mxConstants.STYLE_ROUNDED] = false;
- return style;
- };
-
- /**
- * 初始化 mxgraph 实例
- */
- create(containerDom: HTMLElement, config?: IContainerProps['config']) {
- const {
- mxGraphView,
- mxText,
- mxGraph: MxGraph,
- mxEvent,
- mxConstants,
- mxGraphHandler,
- mxSvgCanvas2D,
- mxClient,
- mxPoint: MxPoint,
- } = this.mxInstance;
-
- /**
- * Function: updateStroke
- *
- * Transfers the stroke attributes from to .
- */
- mxSvgCanvas2D.prototype.updateStroke = function () {
- const s = this.state;
-
- const strokeColor = String(s.strokeColor);
- this.node.setAttribute(
- 'stroke',
- // Prevent transform css constiables into lower case
- strokeColor.startsWith('const') ? strokeColor : strokeColor.toLowerCase()
- );
-
- if (s.alpha < 1 || s.strokeAlpha < 1) {
- this.node.setAttribute(
- 'stroke-opacity',
- (s.alpha * s.strokeAlpha) as unknown as string
- );
- }
-
- const sw = this.getCurrentStrokeWidth();
-
- if (sw !== 1) {
- this.node.setAttribute('stroke-width', sw as unknown as string);
- }
-
- if (this.node.nodeName === 'path') {
- this.updateStrokeAttributes();
- }
-
- if (s.dashed) {
- this.node.setAttribute(
- 'stroke-dasharray',
- this.createDashPattern((s.fixDash ? 1 : s.strokeWidth) * s.scale)
- );
- }
- };
-
- /**
- * Function: updateFill
- *
- * Transfers the stroke attributes from to .
- */
- mxSvgCanvas2D.prototype.updateFill = function () {
- const s = this.state;
-
- if (s.alpha < 1 || s.fillAlpha < 1) {
- this.node.setAttribute(
- 'fill-opacity',
- (s.alpha * s.fillAlpha) as unknown as string
- );
- }
-
- if (s.fillColor != null) {
- if (s.gradientColor != null) {
- const id = this.getSvgGradient(
- String(s.fillColor),
- String(s.gradientColor),
- s.gradientFillAlpha as unknown as string,
- s.gradientAlpha as unknown as string,
- s.gradientDirection
- );
-
- if (
- !mxClient.IS_CHROMEAPP &&
- !mxClient.IS_IE &&
- !mxClient.IS_IE11 &&
- !mxClient.IS_EDGE &&
- this.root.ownerDocument === document
- ) {
- // Workaround for potential base tag and brackets must be escaped
- const base = this.getBaseUrl().replace(/([()])/g, '\\$1');
- this.node.setAttribute('fill', `url(${base}#${id})`);
- } else {
- this.node.setAttribute('fill', `url(#${id})`);
- }
- } else {
- const fillColor = String(s.fillColor);
- this.node.setAttribute(
- 'fill',
- // Prevent transform css constiables into lower case
- fillColor.startsWith('const') ? fillColor : fillColor.toLowerCase()
- );
- }
- }
- };
-
- mxGraphView.prototype.optimizeVmlReflows = false;
- // to avoid calling getBBox
- mxText.prototype.ignoreStringSize = true;
- mxGraphHandler.prototype.guidesEnabled = true;
- // Disable context menu
- mxEvent.disableContextMenu(containerDom);
- const graph = new MxGraph(containerDom);
-
- this.mxGraph = graph;
-
- // 启用绘制
- graph.setPanning(true);
- // 允许鼠标移动画布
- graph.panningHandler.useLeftButtonForPanning = true;
- graph.setTooltips(config?.tooltips ?? true);
- graph.view.setScale(1);
- // Enables HTML labels
- graph.setHtmlLabels(true);
-
- graph.setAllowDanglingEdges(false);
- // 禁止连接
- graph.setConnectable(config?.connectable ?? false);
- // Disabled cells movable
- graph.isCellsMovable = function () {
- const movable = config?.vertexMovable;
- if (movable === true || movable === undefined) {
- const cell = graph.getSelectionCell();
- return !(cell && cell.edge);
- }
-
- return false;
- };
- // 禁止cell编辑
- graph.isCellEditable = () => false;
- graph.isCellResizable = () => false;
-
- const userVertexStyle: Record | undefined =
- typeof config?.defaultVertexStyle === 'function'
- ? config.defaultVertexStyle(this.mxInstance)
- : config?.defaultVertexStyle;
-
- graph.getStylesheet().putDefaultVertexStyle({
- ...this.getDefaultVertexStyle(),
- ...(userVertexStyle || {}),
- });
-
- const userEdgeStyle: Record | undefined =
- typeof config?.defaultEdgeStyle === 'function'
- ? config.defaultEdgeStyle(this.mxInstance)
- : config?.defaultEdgeStyle;
- // 默认边界样式
- graph.getStylesheet().putDefaultEdgeStyle({
- ...this.getDefaultEdgeStyle(),
- ...(userEdgeStyle || {}),
- });
-
- mxGraphView.prototype.updateFloatingTerminalPoint = function (edge, start, end, source) {
- if (config?.getPortOffset) {
- const next = this.getNextPoint(edge, end, source);
- if (!start.text) return;
- const div = start.text.node.getElementsByTagName('div')[1];
- let x = start.x;
- let y = start.getCenterY();
-
- // Checks on which side of the terminal to leave
- if (next.x > x + start.width / 2) {
- x += start.width;
- }
-
- if (div != null) {
- y = start.getCenterY() - div.scrollTop;
- const offset = config?.getPortOffset?.(edge, source);
- if (offset) {
- y = getRowY(start, offset);
- }
-
- // Updates the vertical position of the nearest point if we're not
- // dealing with a connection preview, in which case either the
- // edgeState or the absolutePoints are null
- if (edge != null && edge.absolutePoints != null) {
- next.y = y;
- }
- }
-
- edge.setAbsoluteTerminalPoint(new MxPoint(x, y), source);
- } else {
- edge.setAbsoluteTerminalPoint(
- this.getFloatingTerminalPoint(edge, start, end, source),
- source
- );
- }
- };
-
- // Defines global helper function to get y-coordinate for a given cell state and row
- const getRowY = function (state: mxCellState, tr: HTMLElement) {
- const div = tr!.parentNode!.parentNode!.parentElement!; // Here is vertex-content element
- const offset = tr.offsetTop - div.offsetTop + tr.offsetHeight / 2;
- return state.y + offset;
- };
-
- // anchor styles
- mxConstants.HANDLE_FILLCOLOR = '#ffffff';
- mxConstants.HANDLE_STROKECOLOR = '#2491F7';
- mxConstants.VERTEX_SELECTION_COLOR = 'transparent';
- // @ts-ignore
- mxConstants.CURSOR_MOVABLE_VERTEX = 'pointer';
- // @ts-ignore
- mxConstants.STYLE_OVERFLOW = 'hidden';
-
- return graph;
- }
-
- /**
- * Event handler that selects rectangular regions.
- */
- createRubberBand() {
- const { mxRubberband: MxRubberband } = this.mxInstance;
- if (!this.mxGraph) {
- throw new Error('Please call create before createRubberBand');
- }
-
- return new MxRubberband(this.mxGraph);
- }
-
- /**
- * Vertex 渲染的 HTML 样式
- * @description Returns the textual representation for the given cell. This implementation returns the nodename or string-representation of the user object.
- */
- renderVertex(handler: (cell: mxCell) => string) {
- if (this.mxGraph) {
- this.mxGraph.getLabel = (cell) => {
- if (cell && cell.vertex) {
- return handler(cell);
- }
- return '';
- };
- }
- }
-
- /**
- * 渲染 tooltips 的 HTML 样式
- * @description Returns the string or DOM node to be used as the tooltip for the given cell. This implementation uses the cells getTooltip function if it exists, or else it returns convertValueToString for the cell.
- */
- renderTooltips(handler: (cell: mxCell) => string | undefined) {
- if (this.mxGraph) {
- // 默认 tooltips
- this.mxGraph.getTooltipForCell = (cell) => {
- if (cell && cell.vertex) {
- const result = handler(cell);
- if (result === undefined) {
- return this.mxGraph!.getLabel(cell) as string;
- }
- return result;
- }
- return '';
- };
- }
- }
-
- /**
- * 初始化 graph 相关配置
- */
- public initContainerScroll = () => {
- const { mxRectangle: MxRectangle, mxPoint: MxPoint, mxUtils } = this.mxInstance;
- if (this.mxGraph) {
- const graph = this.mxGraph;
- /**
- * Specifies the size of the size for "tiles" to be used for a graph with
- * scrollbars but no visible background page. A good value is large
- * enough to reduce the number of repaints that is caused for auto-
- * translation, which depends on this value, and small enough to give
- * a small empty buffer around the graph. Default is 400x400.
- */
- graph.scrollTileSize = new MxRectangle(0, 0, 200, 200);
-
- /**
- * Returns the padding for pages in page view with scrollbars.
- */
- graph.getPagePadding = function () {
- return new MxPoint(
- Math.max(0, Math.round(graph.container.offsetWidth - 34)),
- Math.max(0, Math.round(graph.container.offsetHeight - 34))
- );
- };
-
- /**
- * Returns the size of the page format scaled with the page size.
- */
- graph.getPageSize = function (this: mxGraph & { scrollTileSize: mxRectangle }) {
- return this.pageVisible
- ? new MxRectangle(
- 0,
- 0,
- this.pageFormat.width * this.pageScale,
- this.pageFormat.height * this.pageScale
- )
- : this.scrollTileSize!;
- };
-
- /**
- * Returns a rectangle describing the position and count of the
- * background pages, where x and y are the position of the top,
- * left page and width and height are the vertical and horizontal
- * page count.
- */
- graph.getPageLayout = function () {
- const size = this.pageVisible ? this.getPageSize!() : this.scrollTileSize!;
- const bounds = this.getGraphBounds();
-
- if (bounds.width === 0 || bounds.height === 0) {
- return new MxRectangle(0, 0, 1, 1);
- }
-
- // Computes untransformed graph bounds
- const x = Math.ceil(bounds.x / this.view.scale - this.view.translate.x);
- const y = Math.ceil(bounds.y / this.view.scale - this.view.translate.y);
- const w = Math.floor(bounds.width / this.view.scale);
- const h = Math.floor(bounds.height / this.view.scale);
-
- const x0 = Math.floor(x / size.width);
- const y0 = Math.floor(y / size.height);
- const w0 = Math.ceil((x + w) / size.width) - x0;
- const h0 = Math.ceil((y + h) / size.height) - y0;
-
- return new MxRectangle(x0, y0, w0, h0);
- };
-
- // Fits the number of background pages to the graph
- graph.view.getBackgroundPageBounds = function () {
- const layout = (this.graph as IMxGraph).getPageLayout!();
- const page = (this.graph as IMxGraph).getPageSize!();
-
- return new MxRectangle(
- this.scale * (this.translate.x + layout.x * page.width),
- this.scale * (this.translate.y + layout.y * page.height),
- this.scale * layout.width * page.width,
- this.scale * layout.height * page.height
- );
- };
-
- graph.getPreferredPageSize = function () {
- const pages = this.getPageLayout!();
- const size = this.getPageSize!();
-
- return new MxRectangle(0, 0, pages.width * size.width, pages.height * size.height);
- };
-
- /**
- * Guesses autoTranslate to avoid another repaint (see below).
- * Works if only the scale of the graph changes or if pages
- * are visible and the visible pages do not change.
- */
- const graphViewValidate = graph.view.validate;
- graph.view.validate = function (this: {
- graph: IMxGraph;
- translate: mxPoint;
- scale: number;
- // set in customized sizeDidChange method
- x0: number;
- y0: number;
- }) {
- if (this.graph.container != null && mxUtils.hasScrollbars(this.graph.container)) {
- const pad = this.graph.getPagePadding!();
- const size = this.graph.getPageSize!();
-
- // Updating scrollbars here causes flickering in quirks and is not needed
- // if zoom method is always used to set the current scale on the graph.
- this.translate.x = pad.x / this.scale - (this.x0 || 0) * size.width;
- this.translate.y = pad.y / this.scale - (this.y0 || 0) * size.height;
- }
-
- graphViewValidate.apply(this, arguments as any);
- };
-
- const graphSizeDidChange = graph.sizeDidChange;
- graph.sizeDidChange = function (
- this: IMxGraph & {
- autoTranslate: boolean;
- // used in view.validate method
- view: mxGraphView & { x0: number; y0: number };
- }
- ) {
- if (this.container != null && mxUtils.hasScrollbars(this.container)) {
- const pages = this.getPageLayout!();
- const pad = this.getPagePadding!();
- const size = this.getPageSize!();
-
- // Updates the minimum graph size
- const minw = Math.ceil(
- (2 * pad.x) / this.view.scale + pages.width * size.width
- );
- const minh = Math.ceil(
- (2 * pad.y) / this.view.scale + pages.height * size.height
- );
-
- const min = graph.minimumGraphSize;
-
- // LATER: Fix flicker of scrollbar size in IE quirks mode
- // after delayed call in window.resize event handler
- if (min === null || min.width !== minw || min.height !== minh) {
- graph.minimumGraphSize = new MxRectangle(0, 0, minw, minh);
- }
-
- // Updates auto-translate to include padding and graph size
- const dx = pad.x / this.view.scale - pages.x * size.width;
- const dy = pad.y / this.view.scale - pages.y * size.height;
-
- if (
- !this.autoTranslate &&
- (this.view.translate.x !== dx || this.view.translate.y !== dy)
- ) {
- this.autoTranslate = true;
- this.view.x0 = pages.x;
- this.view.y0 = pages.y;
-
- // NOTE: THIS INVOKES THIS METHOD AGAIN. UNFORTUNATELY THERE IS NO WAY AROUND THIS SINCE THE
- // BOUNDS ARE KNOWN AFTER THE VALIDATION AND SETTING THE TRANSLATE TRIGGERS A REVALIDATION.
- // SHOULD MOVE TRANSLATE/SCALE TO VIEW.
- const tx = graph.view.translate.x;
- const ty = graph.view.translate.y;
-
- graph.view.setTranslate(dx, dy);
- graph.container.scrollLeft += (dx - tx) * graph.view.scale;
- graph.container.scrollTop += (dy - ty) * graph.view.scale;
-
- this.autoTranslate = false;
- }
-
- graphSizeDidChange.apply(this, arguments as any);
- }
- };
- }
- };
-
- setView({ scale, dx, dy }: { scale: number; dx: number; dy: number }) {
- if (this.mxGraph) {
- this.mxGraph.view.setScale(scale);
- this.mxGraph.view.setTranslate(dx, dy);
- }
- }
-
- resetScrollPosition() {
- if (this.mxGraph && this.mxGraph.container) {
- const graph = this.mxGraph;
- const bounds = graph.getGraphBounds();
- const boundsWidth = Math.max(
- bounds.width,
- graph.scrollTileSize!.width * graph.view.scale
- );
- const boundsHeight = Math.max(
- bounds.height,
- graph.scrollTileSize!.height * graph.view.scale
- );
- graph.container.scrollTop = Math.floor(
- Math.max(
- 0,
- bounds.y - Math.max(20, (graph.container.clientHeight - boundsHeight) / 2)
- )
- );
- graph.container.scrollLeft = Math.floor(
- Math.max(0, bounds.x - Math.max(0, (graph.container.clientWidth - boundsWidth) / 2))
- );
- }
- }
-
- dispose() {
- if (this.mxGraph) {
- this.mxGraph.destroy();
- }
- }
-}
-
-export default MxFactory;
diff --git a/src/mxGraph/index.md b/src/mxGraph/index.md
deleted file mode 100644
index 85564b345..000000000
--- a/src/mxGraph/index.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-title: mxGraph
-group: 组件
-toc: content
----
-
-# mxGraph
-
-:::warning{title=deprecated}
-该组件已废弃
-:::
-
-:::info
-mxTooltip、mxPopupMenu、mxPopupMenuItem 等样式请自行实现,可参考:[mxGraph.scss](https://github.com/DTStack/dt-react-component/blob/master/src/stories/style/mxGraph.scss)
-:::
-
-## 示例
-
-
-
-
-
-
-
-:::warning
-部分事件存在相同交集,需要自行区分判断
-:::
-
-
-
-
-
-
-
-## API
-
-| 参数 | 说明 | 类型 | 默认值 |
-| ------------------ | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ---------------------------- |
-| enableDrag | 是否开启拖拽,开启后每一个图形的四周会有拖拽点 | `boolean` | `false` |
-| loading | 加载中状态 | `boolean` | `false` |
-| graphData | 当前图数据 | `T[] \| null` | - |
-| vertexKey | vertex 的 key 值 | `string` | `'taskId'` |
-| vertexSize | Vertex 尺寸 | `{ width?: number; height?: number }` | `{ width: 210, height: 50 }` |
-| config | 配置项目 | `IConfig` | - |
-| direction | re-layout 的方向,`MxHierarchicalLayout` 的第二个参数 | `string` | `'north'` |
-| style | 样式 | `CSSProperties` | - |
-| children | 底部状态栏 | `(current: T \| null) => JSX.Element` | - |
-| onRenderActions | 渲染自定义 actions | `(graph: mxGraph, instances: mxGraphExportObject) => JSX.Element` | - |
-| onGetSize | 针对不同的数据渲染不同 size 的 vertex | `(data: T) => { width: number; height: number } \| undefined` | - |
-| onRenderWidgets | 渲染 widgets 的组件 | `() => JSX.Element` | - |
-| onDropWidgets | 组件拖拽 drop 的回调函数 | `(node: HTMLElement, graph: mxGraph, target: mxCell, x: number, y: number) => void` | - |
-| onGetPreview | 获取拖拽中的预览节点 | `(node: HTMLElement) => HTMLElement` | - |
-| onRenderCell | 渲染 cell 的内容 | `(cell: mxCell, graph: mxGraph) => string` | - |
-| onRenderTooltips | 渲染 cell 的 tooltips | `(cell: mxCell, graph: mxGraph) => string` | - |
-| onDrawVertex | 获取 vertex 的 style,通常用于设置特殊状态的 vertex | `(data: T) => string` | - |
-| onDrawEdge | 获取 edge 的 style,常用于设置特殊样式的 edge | `(source: mxCell, target: mxCell) => string` | - |
-| onClick | Vertex 的点击回调函数 | ` (cell: mxCell, graph: mxGraph, event: React.MouseEvent) => void` | - |
-| onContextMenu | 右键菜单的回调函数 | `(data: T, cell: mxCell, graph: mxGraph) => IContextMenuConfig[] \| Promise` | - |
-| onDoubleClick | Vertex 的双击回调事件 | ` (cell: mxCell, graph: mxGraph, event: React.MouseEvent) => void` | - |
-| onKeyDown | KeyDown 事件 | `() => IKeyDownConfig[]` | - |
-| onCellsChanged | 当节点改变的回调事件 | `(cell: mxCell) => void` | - |
-| onContainerChanged | 布局改变回调事件,包括滚动,改变 scale 等 | `(geometry: IGeometryPosition) => void` | - |
-
-### IMxGraphData
-
-`T` 范型需要满足以下类型
-
-| 参数 | 说明 | 类型 | 默认值 |
-| ---------- | -------- | ------- | ------ |
-| childNode | 下游节点 | `any[]` | - |
-| parentNode | 上游节点 | `any[]` | - |
-
-### IConfig
-
-| 参数 | 说明 | 类型 | 默认值 |
-| ------------------ | ------------------------------- | ---------------------------------------------------------------------------------- | ------- |
-| tooltips | 是否开启 tooltips | `boolean` | `false` |
-| connectable | 是否可连接 | `boolean` | `false` |
-| highlight | 选中是否高亮相关 vertex 及 edge | `boolean` | `false` |
-| toolbarStyle | 设置 toolbar 的样式 | `CSSProperties` | - |
-| vertexMovable | vertex 是否可移动,默认可移动 | `boolean` | `false` |
-| defaultVertexStyle | 修改默认的 vertex 样式 | `Record \| ((instances: mxGraphExportObject) => Record)` | - |
-| defaultEdgeStyle | 修改默认的 edge 样式 | `Record \| ((instances: mxGraphExportObject) => Record)` | - |
-| getPortOffset | - | `(edgeState: mxCellState, source: boolean) => HTMLElement` | - |
-
-### IKeyDownConfig
-
-| 参数 | 说明 | 类型 | 默认值 |
-| ------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ------ |
-| id | - | `string` | - |
-| method | - | `'bindKey' \| 'bindShiftKey' \| 'bindControlKey' \| 'bindControlShiftKey'` | - |
-| keyCode | [参考](https://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes) | `number` | - |
-| func | - | `() => void` | - |
diff --git a/src/mxGraph/index.tsx b/src/mxGraph/index.tsx
deleted file mode 100644
index 2822141fd..000000000
--- a/src/mxGraph/index.tsx
+++ /dev/null
@@ -1,901 +0,0 @@
-import React, {
- CSSProperties,
- ForwardedRef,
- forwardRef,
- Ref,
- useEffect,
- useImperativeHandle,
- useRef,
- useState,
-} from 'react';
-import { Spin } from 'antd';
-import {
- mxCell,
- mxCellHighlight,
- mxCellState,
- mxEventObject,
- mxEventSource,
- mxGraph,
- mxGraphExportObject,
- mxPopupMenuHandler,
-} from 'mxgraph';
-
-import MxFactory from './factory';
-import './style.scss';
-
-const Mx = new MxFactory();
-
-const {
- mxHierarchicalLayout: MxHierarchicalLayout,
- mxCellHighlight: MxCellHighlight,
- mxEvent,
- mxPopupMenu,
- mxEventObject: MxEventObject,
- mxImage: MxImage,
- mxUtils,
- mxDragSource,
- mxGraph: MxGraph,
- mxShape: MxShape,
- mxConnectionConstraint: MxConnectionConstraint,
- mxPoint: MxPoint,
- mxPolyline: MxPolyline,
- mxConstraintHandler: MxConstraintHandler,
- mxKeyHandler: MxKeyHandler,
- mxClient,
-} = Mx.mxInstance;
-
-/**
- * MxGraphContainer 会为所有带该 class 名称前缀的 dom 元素注册拖拽事件
- */
-export const WIDGETS_PREFIX = 'taier__widgets';
-const draggableEleSymbol = Symbol('draggable');
-
-export interface IContextMenuConfig {
- /**
- * 如果发现 contextMenu 和 keydown 的 id 有一致的,则调用 keydown 的回调函数
- */
- id?: string;
- title: string;
- callback?: () => void;
- children?: IContextMenuConfig[];
- disabled?: boolean;
-}
-
-export interface IKeyDownConfig {
- id: string;
- method: 'bindKey' | 'bindShiftKey' | 'bindControlKey' | 'bindControlShiftKey';
- /**
- * @reference: https://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
- */
- keyCode: number;
- func: () => void;
-}
-
-interface IMxGraphData {
- /**
- * 下游节点
- */
- childNode: any[];
- /**
- * 上游节点
- */
- parentNode?: any[];
-
- [key: string]: any;
-}
-
-export interface IContainerProps {
- /**
- * 是否开启拖拽,开启后每一个图形的四周会有拖拽点
- */
- enableDrag?: boolean;
- /**
- * 加载中状态
- */
- loading?: boolean;
- /**
- * 当前图数据
- */
- graphData?: T[] | null;
- /**
- * vertex 的 key 值,默认是 taskId
- */
- vertexKey?: string;
- /**
- * Vertex 尺寸,默认宽度 210, 默认高度 50,
- */
- vertexSize?: { width?: number; height?: number };
- /**
- * 配置项目
- */
- config?: {
- /**
- * 是否开启 tooltips
- */
- tooltips?: boolean;
- /**
- * 是否可连接
- */
- connectable?: boolean;
- /**
- * 选中是否高亮相关 vertex 及 edge
- */
- highlight?: boolean;
- /**
- * 设置 toolbar 的样式
- */
- toolbarStyle?: CSSProperties;
- /**
- * vertex 是否可移动,默认可移动
- */
- vertexMovable?: boolean;
- /**
- * 修改默认的 vertex 样式
- * @notice 仅在实例初始化的时候生效
- */
- defaultVertexStyle?:
- | Record
- | ((instances: mxGraphExportObject) => Record);
- /**
- * 修改默认的 edge 样式
- * @notice 仅在实例初始化的时候生效
- */
- defaultEdgeStyle?:
- | Record
- | ((instances: mxGraphExportObject) => Record);
- getPortOffset?: (edgeState: mxCellState, source: boolean) => HTMLElement;
- [key: string]: any;
- };
- /**
- * re-layout 的方向,MxHierarchicalLayout 的第二个参数
- */
- direction?: string;
- /**
- * 样式
- */
- style?: CSSProperties;
- /**
- * children 会渲染底部状态栏
- */
- children?: (current: T | null) => JSX.Element;
- /**
- * 渲染自定义 actions
- */
- onRenderActions?: (graph: mxGraph, instances: mxGraphExportObject) => JSX.Element;
- /**
- * 针对不同的数据渲染不同 size 的 vertex
- */
- onGetSize?: (data: T) => { width: number; height: number } | undefined;
- /**
- * 渲染 widgets 的组件
- */
- onRenderWidgets?: () => JSX.Element;
- /**
- * 组件拖拽 drop 的回调函数
- */
- onDropWidgets?: (
- node: HTMLElement,
- graph: mxGraph,
- target: mxCell,
- x: number,
- y: number
- ) => void;
- /**
- * 获取拖拽中的预览节点
- */
- onGetPreview?: (node: HTMLElement) => HTMLElement;
- /**
- * 渲染 cell 的内容,返回 string 类型
- */
- onRenderCell?: (cell: mxCell, graph: mxGraph) => string;
- /**
- * 渲染 cell 的 tooltips,返回 string 类型或 undefined
- */
- onRenderTooltips?: (cell: mxCell, graph: mxGraph) => string;
- /**
- * 获取 vertex 的 style,由于存在默认样式,所以通常用于设置特殊状态的 vertex
- */
- onDrawVertex?: (data: T) => string;
- /**
- * 获取 edge 的 style,由于存在默认样式,通常用于设置特殊样式的 edge
- */
- onDrawEdge?: (source: mxCell, target: mxCell) => string;
- /**
- * Vertex 的点击回调函数
- */
- onClick?: (
- cell: mxCell,
- graph: mxGraph,
- event: React.MouseEvent
- ) => void;
- /**
- * 右键菜单的回调函数
- */
- onContextMenu?: (
- data: T,
- cell: mxCell,
- graph: mxGraph
- ) => IContextMenuConfig[] | Promise;
- /**
- * Vertex 的双击回调事件
- */
- onDoubleClick?: (
- cell: mxCell,
- graph: mxGraph,
- event: React.MouseEvent
- ) => void;
- /**
- * KeyDown 事件
- */
- onKeyDown?: () => IKeyDownConfig[];
- /**
- * 当节点改变的回调事件
- */
- onCellsChanged?: (cell: mxCell) => void;
- /**
- * 布局改变回调事件,包括滚动,改变 scale 等
- */
- onContainerChanged?: (geometry: IGeometryPosition) => void;
-}
-
-export interface IContainerRef {
- insertCell: (data: T, x: number, y: number) => void;
- updateCell: (cellId: string, data: Partial) => void;
- removeCell: (cellId: string) => void;
- getSelectedCell: () => mxCell | null;
- getCells: () => mxCell[];
- setCells: (cells: mxCell[]) => void;
- setView: (geometry: IGeometryPosition) => void;
-}
-
-export interface IGeometryPosition {
- scrollTop: number;
- scrollLeft: number;
- scale: number;
-}
-
-function renderCharacterByCode(keyCode: number) {
- const unicodeCharacter = String.fromCharCode(keyCode);
- if (unicodeCharacter === '\b') return '⌫';
-}
-
-function MxGraphContainer(
- {
- enableDrag,
- loading = false,
- style,
- graphData,
- vertexKey = 'taskId',
- vertexSize,
- config,
- direction,
- children,
- onRenderCell,
- onRenderTooltips,
- onDrawVertex,
- onDrawEdge,
- onClick,
- onContextMenu,
- onDoubleClick,
- onGetSize,
- onRenderWidgets,
- onGetPreview,
- onDropWidgets,
- onRenderActions,
- onKeyDown,
- onCellsChanged,
- onContainerChanged,
- }: IContainerProps,
- ref: Ref>
-) {
- const container = useRef(null);
- const graph = useRef();
- const keybindingsRef = useRef([]);
- const [current, setCurrent] = useState(null);
-
- useImperativeHandle(ref, () => ({
- /**
- * 在某一位置插入节点
- */
- insertCell: (data, x, y) => {
- if (graph.current) {
- const width = vertexSize?.width || MxFactory.VertexSize.width;
- const height = vertexSize?.height || MxFactory.VertexSize.height;
- const style = onDrawVertex?.(data);
-
- graph.current.insertVertex(
- graph.current.getDefaultParent(),
- data[vertexKey],
- data,
- x,
- y,
- width,
- height,
- style
- );
-
- const parent = graph.current.getDefaultParent();
- const vertices = graph.current.getChildVertices(parent);
- if (vertices.length === 1) {
- graph.current.center(true, true, 0.55, 0.4);
- }
- }
- },
- /**
- * 更新某一节点
- */
- updateCell: (cellId, data) => {
- if (graph.current) {
- const cell = graph.current.getModel().getCell(cellId);
- if (cell) {
- cell.setValue({ ...cell.value, ...data });
- onCellsChanged?.(cell);
- graph.current.view.refresh();
- }
- }
- },
- /**
- * 删除某一节点及其附带的 edge
- */
- removeCell: (cellId) => {
- if (graph.current) {
- const cell = graph.current.getModel().getCell(cellId);
- if (cell) {
- graph.current.removeCells([cell], true);
- }
- }
- },
- /**
- * 获取当前选中的 cell
- */
- getSelectedCell: () => {
- if (graph.current) {
- return graph.current.getSelectionCell();
- }
-
- return null;
- },
- /**
- * 获取当前 mxGraph 的全部 cells
- */
- getCells: () => {
- const cells =
- graph.current?.getModel().getChildCells(graph.current.getDefaultParent()) || [];
- return cells;
- },
- /**
- * 在 graph 中插入 cells
- */
- setCells: (cells) => {
- graph.current?.addCells(cells);
- },
- /**
- * 设置布局
- */
- setView: (geometry) => {
- if (graph.current) {
- graph.current.view.setScale(geometry.scale);
-
- if (graph.current.container) {
- setTimeout(() => {
- graph.current?.container.scrollTo({
- top: geometry.scrollTop,
- left: geometry.scrollLeft,
- });
- }, 0);
- }
- }
- },
- }));
-
- const initGraph = () => {
- graph.current = Mx.create(container.current!, config);
- Mx.createRubberBand();
- // 转换value显示的内容
- Mx.renderVertex((cell) => {
- return onRenderCell?.(cell, graph.current!) || '';
- });
-
- // 自定义 tooltips
- Mx.renderTooltips((cell) => {
- return onRenderTooltips?.(cell, graph.current!);
- });
-
- Mx.layoutEventHandler = () => {
- const parent = graph.current!.getDefaultParent();
- graph.current!.getModel().beginUpdate();
- try {
- const layout2 = new MxHierarchicalLayout(graph.current!, direction || 'north');
- layout2.disableEdgeStyle = false;
- layout2.interRankCellSpacing = 60;
- layout2.intraCellSpacing = 80;
- layout2.execute(parent);
- } finally {
- graph.current!.getModel().endUpdate();
- }
- };
-
- // Init container scroll
- Mx.initContainerScroll();
- };
-
- const initWidgetDraggable = () => {
- const nodes = document.querySelectorAll(`*[class*="${WIDGETS_PREFIX}"]`);
- nodes.forEach((node) => {
- if (Object.hasOwnProperty(draggableEleSymbol)) return;
- const dragElt =
- onGetPreview?.(node) ||
- (() => {
- const dom = document.createElement('div');
- dom.innerHTML = `新节点`;
- return dom;
- })();
-
- const width = vertexSize?.width || MxFactory.VertexSize.width;
- const height = vertexSize?.height || MxFactory.VertexSize.height;
-
- dragElt.style.width = `${width}px`;
- dragElt.style.height = `${height}px`;
-
- const draggableEle = mxUtils.makeDraggable(
- node,
- // @ts-ignore
- (evt: MouseEvent) => {
- const x = mxEvent.getClientX(evt);
- const y = mxEvent.getClientY(evt);
-
- const elt = document.elementFromPoint(x, y);
- if (!elt) return null;
- if (mxUtils.isAncestorNode(graph.current!.container, elt)) {
- return graph.current;
- }
- return null;
- },
- (g: mxGraph, _: mxEventSource, target: mxCell, x: number, y: number) => {
- if (g.canImportCell(target)) {
- onDropWidgets?.(node, g, target, x, y);
- }
- },
- dragElt,
- undefined,
- undefined,
- graph.current!.autoScroll,
- true
- );
-
- draggableEle.createPreviewElement = function () {
- // ctx._currentSourceType = type;
- return dragElt;
- };
- draggableEle.isGuidesEnabled = () => {
- return graph.current!.graphHandler.guidesEnabled;
- };
- draggableEle.createDragElement = mxDragSource.prototype.createDragElement;
-
- // insert a flag into element
- Object.defineProperty(node, draggableEleSymbol, {
- value: true,
- writable: false,
- enumerable: false,
- });
- });
- };
-
- const initKeyDownEvent = () => {
- if (onKeyDown) {
- const keyHandler = new MxKeyHandler(graph.current!);
- // @ts-ignore
- keyHandler.getFunction = function (evt: any) {
- if (evt !== null && !mxEvent.isAltDown(evt)) {
- if (this.isControlDown(evt) || (mxClient.IS_MAC && evt.metaKey)) {
- if (mxEvent.isShiftDown(evt)) {
- return this.controlShiftKeys[evt.keyCode];
- }
-
- return this.controlKeys[evt.keyCode];
- }
-
- if (mxEvent.isShiftDown(evt)) {
- return this.shiftKeys[evt.keyCode];
- }
-
- return this.normalKeys[evt.keyCode];
- }
-
- return null;
- };
-
- const keyBindings = onKeyDown();
- keybindingsRef.current = keyBindings;
-
- keyBindings.forEach(({ method, keyCode, func }) => {
- keyHandler[method](keyCode, () => {
- if (graph.current?.isEnabled()) {
- func();
- }
- });
- });
- }
- };
-
- const initConnectionConstraints = () => {
- if (enableDrag) {
- // Replaces the port image
- MxConstraintHandler.prototype.pointImage = new MxImage('images/points.gif', 5, 5);
- // Constraint highlight color
- MxConstraintHandler.prototype.highlightColor = '#3f87ff';
- // Overridden to define per-shape connection points
- MxGraph.prototype.getAllConnectionConstraints = function (terminal: mxCellState) {
- if (terminal?.shape) {
- if (terminal.shape.stencil) {
- return terminal.shape.stencil.constraints;
- }
-
- if (terminal.shape.constraints) {
- return terminal.shape.constraints;
- }
- }
- return [];
- };
-
- // Defines the default constraints for all shapes
- MxShape.prototype.constraints = [
- new MxConnectionConstraint(new MxPoint(0.5, 0), true),
- new MxConnectionConstraint(new MxPoint(0, 0.5), true),
- new MxConnectionConstraint(new MxPoint(1, 0.5), true),
- new MxConnectionConstraint(new MxPoint(0.5, 1), true),
- ];
- // Edges have no connection points
- MxPolyline.prototype.constraints = [];
- // Disables floating connections (only connections via ports allowed)
- graph.current!.connectionHandler.isConnectableCell = () => false;
-
- graph.current!.isValidConnection = function (source: mxCell, target: mxCell) {
- // Only connectable between vertexes
- if (!source.vertex || !target.vertex) return false;
-
- // Can't have infinite edges
- const edges = this.getEdgesBetween(source, target);
- if (edges.length > 0) return false;
-
- // Can't connect self with self
- let isLoop = false;
- this.traverse(target, true, (vertex: mxCell) => {
- if (source.id === vertex.id) {
- isLoop = true;
- return false;
- }
- });
- if (isLoop) return false;
-
- return true;
- };
- }
- };
-
- const initEvent = () => {
- const highlightEdges: mxCellHighlight[] = [];
-
- // 添加 cells 事件,包括 vertexes 和 edges
- graph.current?.addListener(mxEvent.ADD_CELLS, (_, evt: mxEventObject) => {
- const cell: mxCell = evt.getProperty('cell');
- onCellsChanged?.(cell);
- });
- // 删除 cell 事件
- // TODO: Interesting, MOVE cell will call REMOVE_CELLS event
- // Don't know why yet
- graph.current?.addListener(mxEvent.REMOVE_CELLS, (_, evt: mxEventObject) => {
- const cell: mxCell = evt.getProperty('cell');
- onCellsChanged?.(cell);
- });
-
- // 移动 cell 事件
- graph.current?.addListener(mxEvent.MOVE_END, (_, evt: mxEventObject) => {
- const cell: mxCell = evt.getProperty('cell');
- onCellsChanged?.(cell);
- });
-
- // Click 事件
- graph.current?.addListener(mxEvent.CLICK, (_, evt) => {
- const cell: mxCell = evt.getProperty('cell');
- setCurrent(cell?.value || null);
- highlightEdges.forEach((e) => e.destroy());
-
- if (config?.highlight === true) {
- if (cell) {
- if (cell.vertex) {
- // highlight cells and edges
- const outEdges = graph.current?.getOutgoingEdges(cell) || [];
- const inEdges =
- graph.current?.getIncomingEdges(
- cell,
- graph.current.getDefaultParent()
- ) || [];
- const edges = outEdges.concat(inEdges);
- for (let i = 0; i < edges.length; i += 1) {
- const highlight = new MxCellHighlight(graph.current!, '#3f87ff', 2);
- const state = graph.current!.view.getState(edges[i]);
- highlight.highlight(state);
- highlightEdges.push(highlight);
- }
- } else {
- // only highlight current edge
- const highlight = new MxCellHighlight(graph.current!, '#3f87ff', 2);
- const state = graph.current!.view.getState(cell);
- highlight.highlight(state);
- highlightEdges.push(highlight);
- }
- } else {
- const cells = graph.current!.getSelectionCells();
- graph.current?.removeSelectionCells(cells);
- }
- }
-
- if (cell?.vertex) {
- // vertex will call onClick function
- onClick?.(cell, graph.current!, evt.getProperty('event'));
- }
- });
-
- graph.current?.addListener(mxEvent.DOUBLE_CLICK, (_, evt) => {
- const cell: mxCell = evt.getProperty('cell');
- if (cell && cell.vertex) {
- onDoubleClick?.(cell, graph.current!, evt.getProperty('event'));
- }
- });
-
- // ContextMenu 事件
- const mxPopupMenuShowMenu = mxPopupMenu.prototype.showMenu;
- mxPopupMenu.prototype.showMenu = function (this: { graph: mxGraph }) {
- const cells = this.graph.getSelectionCells() || [];
- if (cells.length > 0) {
- // eslint-disable-next-line prefer-rest-params
- mxPopupMenuShowMenu.apply(this, arguments as any);
- } else return false;
- };
- graph.current!.popupMenuHandler.autoExpand = true;
-
- // change it to for supporting async factoryMethod
- mxPopupMenu.prototype.popup = async function (
- this: mxPopupMenuHandler & {
- div: HTMLDivElement;
- tbody: HTMLElement;
- itemCount: number;
- },
- x: number,
- y: number,
- cell: mxCell,
- evt: any
- ) {
- if (this.div != null && this.tbody != null && this.factoryMethod != null) {
- this.div.style.left = `${x}px`;
- this.div.style.top = `${y}px`;
-
- // Removes all child nodes from the existing menu
- while (this.tbody.firstChild != null) {
- mxEvent.release(this.tbody.firstChild);
- this.tbody.removeChild(this.tbody.firstChild);
- }
-
- this.itemCount = 0;
- await this.factoryMethod(this, cell, evt);
-
- if (this.itemCount > 0) {
- this.showMenu();
- this.fireEvent(new MxEventObject(mxEvent.SHOW), []);
- }
- }
- };
-
- // Reset collapsed image
- graph.current!.collapsedImage = new MxImage('', 0, 0);
-
- graph.current!.popupMenuHandler.factoryMethod = async (
- menu: mxPopupMenuHandler,
- cell: mxCell
- ) => {
- if (!cell) return;
-
- const contextMenus = await onContextMenu?.(cell.value!, cell, graph.current!);
-
- contextMenus?.forEach(({ id, title, disabled, children: subMenu, callback }) => {
- // 如果发现当前菜单项在快捷键里存在相同 id 的注册事件
- const target =
- !!keybindingsRef.current.length &&
- !!id &&
- keybindingsRef.current.find((k) => k.id === id);
-
- const parent = menu.addItem(
- target
- ? `${title}(${(() => {
- switch (target.method) {
- case 'bindControlKey':
- return mxClient.IS_MAC ? '⌘' : 'Meta';
- case 'bindKey':
- default:
- return '';
- }
- })()} ${renderCharacterByCode(target.keyCode)})`
- : title,
- undefined,
- () => {
- if (target) {
- target.func();
- return;
- }
-
- callback?.();
- },
- undefined,
- undefined,
- !disabled
- );
-
- // 暂时先支持两层菜单
- if (subMenu?.length) {
- subMenu.forEach((child) => {
- menu.addItem(
- child.title,
- undefined,
- child.callback,
- parent,
- undefined,
- !child.disabled
- );
- });
- }
- });
- };
- };
-
- const initData = () => {
- if (graphData) {
- if (graphData.length === 1) {
- // default to select the only one graphData
- setCurrent(graphData[0]);
- }
-
- const stack: { sourceOrTarget: mxCell | null; data: T }[] = graphData.map((d) => ({
- sourceOrTarget: null,
- data: d,
- }));
-
- while (stack.length) {
- const { sourceOrTarget, data } = stack.pop()!;
- const style = onDrawVertex?.(data);
-
- const size = onGetSize?.(data);
- const width = size?.width || vertexSize?.width || MxFactory.VertexSize.width;
- const height = size?.height || vertexSize?.height || MxFactory.VertexSize.height;
- const vertex = graph.current!.insertVertex(
- graph.current!.getDefaultParent(),
- data[vertexKey],
- data,
- 0,
- 0,
- width,
- height,
- style
- );
-
- if (sourceOrTarget) {
- // 判断 sourceOrTarget 存放的 vertex 是 source 还是 target
- const isSource = !!sourceOrTarget.value?.childNode?.find(
- (i: T) => i[vertexKey] === data[vertexKey]
- );
-
- const source = isSource ? sourceOrTarget : vertex;
- const target = isSource ? vertex : sourceOrTarget;
- const style = onDrawEdge?.(
- isSource ? sourceOrTarget : vertex,
- isSource ? vertex : sourceOrTarget
- );
-
- graph.current!.insertEdge(
- graph.current!.getDefaultParent(),
- null,
- null,
- source,
- target,
- style
- );
- } else {
- graph.current?.setSelectionCell(vertex);
- }
-
- if (data.childNode?.length) {
- data.childNode.forEach((i: T) => {
- stack.push({
- sourceOrTarget: vertex,
- data: i,
- });
- });
- }
-
- if (data.parentNode?.length) {
- data.parentNode.forEach((i: T) => {
- stack.push({
- sourceOrTarget: vertex,
- data: i,
- });
- });
- }
- }
-
- Mx.layoutEventHandler?.();
- restoreView();
- }
- };
-
- const restoreView = () => {
- // Sets initial scrollbar positions
- window.setTimeout(() => {
- Mx.resetScrollPosition();
- }, 0);
- };
-
- useEffect(() => {
- initGraph();
- initData();
- initEvent();
-
- initConnectionConstraints();
- initWidgetDraggable();
- initKeyDownEvent();
-
- return () => {
- graph.current?.destroy();
- };
- }, [graphData]);
-
- useEffect(() => {
- function scrollEvent() {
- onContainerChanged?.({
- scrollTop: container.current!.scrollTop,
- scrollLeft: container.current!.scrollLeft,
- scale: graph.current?.getView().getScale() || -1,
- });
- }
-
- // container 滚动事件
- container.current?.addEventListener('scroll', scrollEvent);
- return () => {
- container.current?.removeEventListener('scroll', scrollEvent);
- };
- }, []);
-
- return (
-
-
-
-
- {onRenderWidgets && (
-
e.preventDefault()}>
- {onRenderWidgets?.()}
-
- )}
-
{children?.(current)}
-
- {onRenderActions?.(graph.current!, Mx.mxInstance)}
-
-
- );
-}
-
-export default forwardRef(MxGraphContainer) as (
- props: IContainerProps & { ref?: ForwardedRef> }
-) => JSX.Element;
diff --git a/src/mxGraph/style.scss b/src/mxGraph/style.scss
deleted file mode 100644
index 2e435a681..000000000
--- a/src/mxGraph/style.scss
+++ /dev/null
@@ -1,39 +0,0 @@
-.dtc-graph-editor {
- position: relative;
- height: 100%;
- background-color: #FFF;
- .dtc-task-graph {
- height: 100%;
- }
- .ant-spin-container {
- height: 100%;
- }
- .dtc-graph-widgets {
- background: #FFF;
- border: 1px solid #DDD;
- max-height: 517px;
- left: 20px;
- overflow: auto;
- position: absolute;
- text-align: center;
- top: 20px;
- width: 150px;
- z-index: 3;
- }
- .dtc-graph-bottom {
- position: absolute;
- bottom: 0;
- z-index: 999;
- border-radius: 0;
- width: 100%;
- }
- .dtc-graph-toolbar {
- position: absolute;
- top: 20px;
- right: 14px;
- z-index: 901;
- height: 18px;
- text-align: center;
- border-radius: 0;
- }
-}
diff --git a/src/switchWindow/__tests__/switchWindow.test.tsx b/src/useWindowSwitchListener/__tests__/switchWindow.test.tsx
similarity index 100%
rename from src/switchWindow/__tests__/switchWindow.test.tsx
rename to src/useWindowSwitchListener/__tests__/switchWindow.test.tsx
diff --git a/src/switchWindow/demos/basic.tsx b/src/useWindowSwitchListener/demos/basic.tsx
similarity index 100%
rename from src/switchWindow/demos/basic.tsx
rename to src/useWindowSwitchListener/demos/basic.tsx
diff --git a/src/switchWindow/index.md b/src/useWindowSwitchListener/index.md
similarity index 100%
rename from src/switchWindow/index.md
rename to src/useWindowSwitchListener/index.md
diff --git a/src/switchWindow/index.tsx b/src/useWindowSwitchListener/index.tsx
similarity index 100%
rename from src/switchWindow/index.tsx
rename to src/useWindowSwitchListener/index.tsx