From 1b03cecd8070279cfac4dd5d7f802d382376c9d9 Mon Sep 17 00:00:00 2001 From: plouc Date: Sun, 12 Sep 2021 11:45:32 +0900 Subject: [PATCH] feat(network): network can be used in standalone mode via the useNetwork hook --- packages/network/src/Network.tsx | 2 +- packages/network/src/NetworkCanvas.tsx | 2 +- packages/network/src/hooks.ts | 84 +++++++++++--------- website/src/data/components/network/meta.yml | 9 +++ 4 files changed, 57 insertions(+), 40 deletions(-) diff --git a/packages/network/src/Network.tsx b/packages/network/src/Network.tsx index e83780d6ed..89d077fddc 100644 --- a/packages/network/src/Network.tsx +++ b/packages/network/src/Network.tsx @@ -49,6 +49,7 @@ const InnerNetwork = ({ ) const [nodes, links] = useNetwork({ + center: [innerWidth / 2, innerHeight / 2], nodes: rawNodes, links: rawLinks, linkDistance, @@ -56,7 +57,6 @@ const InnerNetwork = ({ distanceMin, distanceMax, iterations, - center: [innerWidth / 2, innerHeight / 2], nodeColor, nodeBorderWidth, nodeBorderColor, diff --git a/packages/network/src/NetworkCanvas.tsx b/packages/network/src/NetworkCanvas.tsx index 1da1b3ff6d..0706edaab3 100644 --- a/packages/network/src/NetworkCanvas.tsx +++ b/packages/network/src/NetworkCanvas.tsx @@ -47,6 +47,7 @@ const InnerNetworkCanvas = ({ ) const [nodes, links] = useNetwork({ + center: [innerWidth / 2, innerHeight / 2], nodes: rawNodes, links: rawLinks, linkDistance, @@ -54,7 +55,6 @@ const InnerNetworkCanvas = ({ distanceMin, distanceMax, iterations, - center: [innerWidth / 2, innerHeight / 2], nodeColor, nodeBorderWidth, nodeBorderColor, diff --git a/packages/network/src/hooks.ts b/packages/network/src/hooks.ts index 6a40d864da..e7dae0ba80 100644 --- a/packages/network/src/hooks.ts +++ b/packages/network/src/hooks.ts @@ -4,6 +4,8 @@ import isString from 'lodash/isString' import isNumber from 'lodash/isNumber' import { forceSimulation, forceManyBody, forceCenter, forceLink } from 'd3-force' import { useTheme } from '@nivo/core' +import { useInheritedColor } from '@nivo/colors' +import { commonDefaultProps } from './defaults' import { InputLink, NetworkInputNode, @@ -13,7 +15,6 @@ import { NetworkComputedNode, ComputedLink, } from './types' -import { useInheritedColor } from '@nivo/colors' const computeForces = ({ linkDistance, @@ -51,45 +52,62 @@ const computeForces = ({ return { link: linkForce, charge: chargeForce, center: centerForce } } +const useNodeColor = (color: NetworkNodeColor) => + useMemo(() => { + if (typeof color === 'function') return color + return () => color + }, [color]) + +const useLinkThickness = (thickness: NetworkLinkThickness) => + useMemo(() => { + if (typeof thickness === 'function') return thickness + return () => thickness + }, [thickness]) + export const useNetwork = ({ + center, nodes, links, - linkDistance, - repulsivity, - distanceMin, - distanceMax, - center, - iterations, - nodeColor, - nodeBorderWidth, - nodeBorderColor, - linkThickness, - linkColor, + linkDistance = commonDefaultProps.linkDistance, + repulsivity = commonDefaultProps.repulsivity, + distanceMin = commonDefaultProps.distanceMin, + distanceMax = commonDefaultProps.distanceMax, + iterations = commonDefaultProps.iterations, + nodeColor = commonDefaultProps.nodeColor, + nodeBorderWidth = commonDefaultProps.nodeBorderWidth, + nodeBorderColor = commonDefaultProps.nodeBorderColor, + linkThickness = commonDefaultProps.linkThickness, + linkColor = commonDefaultProps.linkColor, }: { + center: [number, number] nodes: N[] links: InputLink[] - linkDistance: NetworkCommonProps['linkDistance'] - repulsivity: NetworkCommonProps['repulsivity'] - distanceMin: NetworkCommonProps['distanceMin'] - distanceMax: NetworkCommonProps['distanceMax'] - center: [number, number] - iterations: NetworkCommonProps['iterations'] - nodeColor: NetworkCommonProps['nodeColor'] - nodeBorderWidth: NetworkCommonProps['nodeBorderWidth'] - nodeBorderColor: NetworkCommonProps['nodeBorderColor'] - linkThickness: NetworkCommonProps['linkThickness'] - linkColor: NetworkCommonProps['linkColor'] + linkDistance?: NetworkCommonProps['linkDistance'] + repulsivity?: NetworkCommonProps['repulsivity'] + distanceMin?: NetworkCommonProps['distanceMin'] + distanceMax?: NetworkCommonProps['distanceMax'] + iterations?: NetworkCommonProps['iterations'] + nodeColor?: NetworkCommonProps['nodeColor'] + nodeBorderWidth?: NetworkCommonProps['nodeBorderWidth'] + nodeBorderColor?: NetworkCommonProps['nodeBorderColor'] + linkThickness?: NetworkCommonProps['linkThickness'] + linkColor?: NetworkCommonProps['linkColor'] }): [null | NetworkComputedNode[], null | ComputedLink[]] => { + // we're using `null` instead of empty array so that we can dissociate + // initial rendering from updates when using transitions. const [currentNodes, setCurrentNodes] = useState[]>(null) const [currentLinks, setCurrentLinks] = useState[]>(null) + const centerX = center[0] + const centerY = center[1] + useEffect(() => { const forces = computeForces({ linkDistance, repulsivity, distanceMin, distanceMax, - center, + center: [centerX, centerY], }) const nodesCopy: N[] = nodes.map(node => ({ ...node })) @@ -122,9 +140,13 @@ export const useNetwork = ({ ) return () => { + // prevent the simulation from continuing in case the data is updated, + // would be a waste of resource. simulation.stop() } }, [ + centerX, + centerY, nodes, links, linkDistance, @@ -132,8 +154,6 @@ export const useNetwork = ({ distanceMin, distanceMax, iterations, - center[0], - center[1], ]) const theme = useTheme() @@ -169,15 +189,3 @@ export const useNetwork = ({ return [enhancedNodes, enhancedLinks] } - -export const useNodeColor = (color: NetworkNodeColor) => - useMemo(() => { - if (typeof color === 'function') return color - return () => color - }, [color]) - -export const useLinkThickness = (thickness: NetworkLinkThickness) => - useMemo(() => { - if (typeof thickness === 'function') return thickness - return () => thickness - }, [thickness]) diff --git a/website/src/data/components/network/meta.yml b/website/src/data/components/network/meta.yml index 5dc4b33efe..e6904eb066 100644 --- a/website/src/data/components/network/meta.yml +++ b/website/src/data/components/network/meta.yml @@ -12,8 +12,14 @@ Network: - experimental stories: [] description: | + A network component connecting nodes with links. + The responsive alternative of this component is `ResponsiveNetwork`. + Please note that you can also use the `useNetwork` React hook if you want + to handle the rendering by yourself, it accepts an object with almost + the same props as the component and returns computed nodes & links. + NetworkCanvas: package: '@nivo/network' tags: @@ -28,3 +34,6 @@ NetworkCanvas: The responsive alternative of this component is `ResponsiveNetworkCanvas`. + Please note that you can also use the `useNetwork` React hook if you want + to handle the rendering by yourself, it accepts an object with almost + the same props as the component and returns computed nodes & links.