index.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import React from "react";
  2. import {
  3. ReactZoomPanPinchRef,
  4. TransformComponent,
  5. TransformWrapper,
  6. } from "react-zoom-pan-pinch";
  7. import {
  8. Canvas,
  9. CanvasContainerProps,
  10. EdgeData,
  11. ElkRoot,
  12. NodeData,
  13. } from "reaflow";
  14. import { CustomNode } from "src/components/CustomNode";
  15. import { getEdgeNodes } from "src/containers/Editor/LiveEditor/helpers";
  16. import useConfig from "src/hooks/store/useConfig";
  17. import styled from "styled-components";
  18. import shallow from "zustand/shallow";
  19. interface GraphProps {
  20. json: string;
  21. isWidget?: boolean;
  22. }
  23. const wheelOptions = {
  24. step: 0.05,
  25. };
  26. const StyledEditorWrapper = styled.div<{ isWidget: boolean }>`
  27. position: absolute;
  28. width: 100%;
  29. height: ${({ isWidget }) => (isWidget ? "100vh" : "calc(100vh - 36px)")};
  30. :active {
  31. cursor: move;
  32. }
  33. rect {
  34. fill: ${({ theme }) => theme.BACKGROUND_NODE};
  35. }
  36. `;
  37. export const Graph: React.FC<GraphProps & CanvasContainerProps> = ({
  38. json,
  39. isWidget = false,
  40. ...props
  41. }) => {
  42. const updateSetting = useConfig((state) => state.updateSetting);
  43. const [expand, layout] = useConfig(
  44. (state) => [state.settings.expand, state.settings.layout],
  45. shallow
  46. );
  47. const onInit = (ref: ReactZoomPanPinchRef) => {
  48. updateSetting("zoomPanPinch", ref);
  49. };
  50. const [nodes, setNodes] = React.useState<NodeData[]>([]);
  51. const [edges, setEdges] = React.useState<EdgeData[]>([]);
  52. const [size, setSize] = React.useState({
  53. width: 2000,
  54. height: 2000,
  55. });
  56. React.useEffect(() => {
  57. const { nodes, edges } = getEdgeNodes(json, expand);
  58. setNodes(nodes);
  59. setEdges(edges);
  60. }, [json, expand]);
  61. const onCanvasClick = () => {
  62. const input = document.querySelector("input:focus") as HTMLInputElement;
  63. if (input) input.blur();
  64. };
  65. const onLayoutChange = (layout: ElkRoot) => {
  66. if (layout.width && layout.height)
  67. setSize({ width: layout.width, height: layout.height });
  68. };
  69. return (
  70. <StyledEditorWrapper isWidget={isWidget}>
  71. <TransformWrapper
  72. maxScale={1.8}
  73. minScale={0.4}
  74. initialScale={0.7}
  75. wheel={wheelOptions}
  76. onInit={onInit}
  77. centerOnInit
  78. >
  79. <TransformComponent
  80. wrapperStyle={{
  81. width: "100%",
  82. height: "100%",
  83. overflow: "hidden",
  84. }}
  85. >
  86. <Canvas
  87. nodes={nodes}
  88. edges={edges}
  89. maxWidth={size.width}
  90. maxHeight={size.height}
  91. direction={layout}
  92. key={layout}
  93. onCanvasClick={onCanvasClick}
  94. onLayoutChange={onLayoutChange}
  95. node={CustomNode}
  96. zoomable={false}
  97. readonly
  98. {...props}
  99. />
  100. </TransformComponent>
  101. </TransformWrapper>
  102. </StyledEditorWrapper>
  103. );
  104. };