You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
114 lines
3.2 KiB
114 lines
3.2 KiB
import React, { useRef, useState, useEffect } from 'react';
|
|
|
|
import styles from './index.module.less';
|
|
|
|
import { Graph } from '@antv/x6';
|
|
import { queryGraph } from '../../api';
|
|
import { parseQuery } from '../../utils';
|
|
import createFlowChart from './createFlowChart';
|
|
import CodeRunModal from './codeRunModal';
|
|
import CodeEditorModal from './codeEditorModal';
|
|
import FlowChartContextMenu from './contextMenu';
|
|
|
|
interface IProps {
|
|
onReady: (graph: Graph) => void;
|
|
}
|
|
|
|
interface IMenuInfo {
|
|
x: number;
|
|
y: number;
|
|
scene: string;
|
|
visible: boolean;
|
|
}
|
|
|
|
const defaultMenuInfo = {
|
|
x: 0,
|
|
y: 0,
|
|
scene: 'blank',
|
|
visible: false,
|
|
};
|
|
|
|
const FlowChart: React.FC<IProps> = (props) => {
|
|
const { onReady } = props;
|
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
const graphRef = useRef<HTMLDivElement>(null);
|
|
const miniMapRef = useRef<HTMLDivElement>(null);
|
|
const [flowChart, setFlowChart] = useState<Graph>();
|
|
const [contextMenuInfo, setContextMenuInfo] = useState<IMenuInfo>(
|
|
defaultMenuInfo,
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (graphRef.current && miniMapRef.current) {
|
|
const flowChart = createFlowChart(graphRef.current, miniMapRef.current);
|
|
onReady(flowChart);
|
|
fetchData(flowChart);
|
|
setFlowChart(flowChart);
|
|
}
|
|
}, []);
|
|
|
|
// resize flowChart's size when window size changes
|
|
useEffect(() => {
|
|
const handler = () => {
|
|
requestAnimationFrame(() => {
|
|
if (flowChart && wrapperRef && wrapperRef.current) {
|
|
const width = wrapperRef.current.clientWidth;
|
|
const height = wrapperRef.current.clientHeight;
|
|
flowChart.resize(width, height);
|
|
}
|
|
});
|
|
};
|
|
window.addEventListener('resize', handler);
|
|
return () => {
|
|
window.removeEventListener('resize', handler);
|
|
};
|
|
}, [flowChart, wrapperRef]);
|
|
|
|
// NOTE: listen toggling context menu event
|
|
useEffect(() => {
|
|
const showHandler = (info: IMenuInfo) => {
|
|
flowChart?.lockScroller();
|
|
setContextMenuInfo({ ...info, visible: true });
|
|
};
|
|
const hideHandler = () => {
|
|
flowChart?.unlockScroller();
|
|
setContextMenuInfo({ ...contextMenuInfo, visible: false });
|
|
};
|
|
if (flowChart) {
|
|
flowChart.on('graph:showContextMenu', showHandler);
|
|
flowChart.on('graph:hideContextMenu', hideHandler);
|
|
}
|
|
return () => {
|
|
if (flowChart) {
|
|
flowChart.off('graph:showContextMenu', showHandler);
|
|
flowChart.off('graph:hideContextMenu', hideHandler);
|
|
}
|
|
};
|
|
}, [flowChart]);
|
|
|
|
const fetchData = (flowChart: Graph) => {
|
|
const { projectId } = parseQuery();
|
|
queryGraph(projectId as string)
|
|
.then((res) => {
|
|
const { data: dsl } = res;
|
|
flowChart.fromJSON(dsl);
|
|
})
|
|
.catch((error) => {
|
|
console.log('query graph data failed, the error is:', error);
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className={styles.container} ref={wrapperRef}>
|
|
<div className={styles.flowChart} ref={graphRef} />
|
|
<div className={styles.miniMap} ref={miniMapRef} />
|
|
{flowChart && <CodeRunModal flowChart={flowChart} />}
|
|
{flowChart && <CodeEditorModal flowChart={flowChart} />}
|
|
{flowChart && (
|
|
<FlowChartContextMenu {...contextMenuInfo} flowChart={flowChart} />
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default FlowChart;
|
|
|