Skip to content

Commit

Permalink
feat(network): types are now valid
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed Dec 31, 2021
1 parent 375252a commit c3d5dd1
Show file tree
Hide file tree
Showing 11 changed files with 243 additions and 163 deletions.
66 changes: 32 additions & 34 deletions packages/network/src/Network.tsx
Expand Up @@ -13,37 +13,35 @@ type InnerNetworkProps<N extends NetworkInputNode> = Omit<
'animate' | 'motionConfig' | 'renderWrapper' | 'theme'
>

const InnerNetwork = <N extends NetworkInputNode>(props: InnerNetworkProps<N>) => {
const {
width,
height,
margin: partialMargin,
const InnerNetwork = <N extends NetworkInputNode>({
width,
height,
margin: partialMargin,

data: { nodes: rawNodes, links: rawLinks },
data: { nodes: rawNodes, links: rawLinks },

linkDistance = svgDefaultProps.linkDistance,
repulsivity = svgDefaultProps.repulsivity,
distanceMin = svgDefaultProps.distanceMin,
distanceMax = svgDefaultProps.distanceMax,
iterations = svgDefaultProps.iterations,
linkDistance = svgDefaultProps.linkDistance,
repulsivity = svgDefaultProps.repulsivity,
distanceMin = svgDefaultProps.distanceMin,
distanceMax = svgDefaultProps.distanceMax,
iterations = svgDefaultProps.iterations,

layers = svgDefaultProps.layers,
layers = svgDefaultProps.layers,

nodeComponent = svgDefaultProps.nodeComponent,
nodeColor = svgDefaultProps.nodeColor,
nodeBorderWidth = svgDefaultProps.nodeBorderWidth,
nodeBorderColor = svgDefaultProps.nodeBorderColor,
nodeComponent = svgDefaultProps.nodeComponent,
nodeColor = svgDefaultProps.nodeColor,
nodeBorderWidth = svgDefaultProps.nodeBorderWidth,
nodeBorderColor = svgDefaultProps.nodeBorderColor,

linkThickness = svgDefaultProps.linkThickness,
linkColor = svgDefaultProps.linkColor,
linkThickness = svgDefaultProps.linkThickness,
linkColor = svgDefaultProps.linkColor,

isInteractive = svgDefaultProps.isInteractive,
nodeTooltip = svgDefaultProps.nodeTooltip,
onClick,

role = svgDefaultProps.role,
} = props
isInteractive = svgDefaultProps.isInteractive,
nodeTooltip = svgDefaultProps.nodeTooltip,
onClick,

role = svgDefaultProps.role,
}: InnerNetworkProps<N>) => {
const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(
width,
height,
Expand Down Expand Up @@ -85,9 +83,9 @@ const InnerNetwork = <N extends NetworkInputNode>(props: InnerNetworkProps<N>) =
nodes: null,
}

if (layers.includes('links') && false) {
if (layers.includes('links') && links !== null) {
layerById.links = (
<NetworkLinks
<NetworkLinks<N>
key="links"
links={links}
linkThickness={getLinkThickness}
Expand All @@ -96,7 +94,7 @@ const InnerNetwork = <N extends NetworkInputNode>(props: InnerNetworkProps<N>) =
)
}

if (layers.includes('nodes')) {
if (layers.includes('nodes') && nodes !== null) {
layerById.nodes = (
<NetworkNodes<N>
key="nodes"
Expand All @@ -119,18 +117,18 @@ const InnerNetwork = <N extends NetworkInputNode>(props: InnerNetworkProps<N>) =
if (typeof layer === 'function') {
return (
<Fragment key={i}>
{layer({
...props,
innerWidth,
innerHeight,
nodes,
links,
{createElement(layer, {
// ...props,
// innerWidth,
// innerHeight,
nodes: nodes || [],
links: links || [],
})}
</Fragment>
)
}

return layerById[layer]
return layerById?.[layer] ?? null
})}
</SvgWrapper>
)
Expand Down
79 changes: 40 additions & 39 deletions packages/network/src/NetworkCanvas.tsx
@@ -1,55 +1,51 @@
import { useCallback, useRef, useEffect } from 'react'
import * as React from 'react'
import { useCallback, useRef, useEffect, createElement, MouseEvent } from 'react'
import { getDistance, getRelativeCursor, Container, useDimensions, useTheme } from '@nivo/core'
import { useInheritedColor } from '@nivo/colors'
import { useTooltip } from '@nivo/tooltip'
import { canvasDefaultProps } from './defaults'
import { useNetwork, useNodeColor, useLinkThickness } from './hooks'
import { NetworkNodeTooltip } from './NetworkNodeTooltip'
import { NetworkCanvasProps, NetworkInputNode } from './types'

type InnerNetworkCanvasProps<N extends NetworkInputNode> = Omit<
NetworkCanvasProps<N>,
'renderWrapper' | 'theme'
>

const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanvasProps<N>) => {
const {
width,
height,
margin: partialMargin,
pixelRatio = canvasDefaultProps.pixelRatio,

data: { nodes: rawNodes, links: rawLinks },
const InnerNetworkCanvas = <N extends NetworkInputNode>({
width,
height,
margin: partialMargin,
pixelRatio = canvasDefaultProps.pixelRatio,

linkDistance = canvasDefaultProps.linkDistance,
repulsivity = canvasDefaultProps.repulsivity,
distanceMin = canvasDefaultProps.distanceMin,
distanceMax = canvasDefaultProps.distanceMax,
iterations = canvasDefaultProps.iterations,
data: { nodes: rawNodes, links: rawLinks },

layers = canvasDefaultProps.layers,
linkDistance = canvasDefaultProps.linkDistance,
repulsivity = canvasDefaultProps.repulsivity,
distanceMin = canvasDefaultProps.distanceMin,
distanceMax = canvasDefaultProps.distanceMax,
iterations = canvasDefaultProps.iterations,

nodeColor = canvasDefaultProps.nodeColor,
nodeBorderWidth = canvasDefaultProps.nodeBorderWidth,
nodeBorderColor = canvasDefaultProps.nodeBorderColor,
layers = canvasDefaultProps.layers,

linkThickness = canvasDefaultProps.linkThickness,
linkColor = canvasDefaultProps.linkColor,
nodeColor = canvasDefaultProps.nodeColor,
nodeBorderWidth = canvasDefaultProps.nodeBorderWidth,
nodeBorderColor = canvasDefaultProps.nodeBorderColor,

isInteractive = canvasDefaultProps.isInteractive,
tooltip = canvasDefaultProps.tooltip,
onClick,
} = props
linkThickness = canvasDefaultProps.linkThickness,
linkColor = canvasDefaultProps.linkColor,

const canvasEl = useRef(null)
isInteractive = canvasDefaultProps.isInteractive,
nodeTooltip = canvasDefaultProps.nodeTooltip,
onClick,
}: InnerNetworkCanvasProps<N>) => {
const canvasEl = useRef<HTMLCanvasElement | null>(null)
const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(
width,
height,
partialMargin
)

const [nodes, links] = useNetwork({
const [nodes, links] = useNetwork<N>({
nodes: rawNodes,
links: rawLinks,
linkDistance,
Expand All @@ -67,10 +63,12 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
const getLinkColor = useInheritedColor(linkColor, theme)

useEffect(() => {
if (canvasEl.current === null) return

canvasEl.current.width = outerWidth * pixelRatio
canvasEl.current.height = outerHeight * pixelRatio

const ctx = canvasEl.current.getContext('2d')
const ctx = canvasEl.current.getContext('2d')!

ctx.scale(pixelRatio, pixelRatio)

Expand All @@ -79,7 +77,7 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
ctx.translate(margin.left, margin.top)

layers.forEach(layer => {
if (layer === 'links') {
if (layer === 'links' && links !== null) {
links.forEach(link => {
ctx.strokeStyle = getLinkColor(link)
ctx.lineWidth = getLinkThickness(link)
Expand All @@ -88,7 +86,7 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
ctx.lineTo(link.target.x, link.target.y)
ctx.stroke()
})
} else if (layer === 'nodes') {
} else if (layer === 'nodes' && nodes !== null) {
nodes.forEach(node => {
ctx.fillStyle = getNodeColor(node)
ctx.beginPath()
Expand All @@ -101,9 +99,9 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
ctx.stroke()
}
})
} else if (typeof layer === 'function') {
} else if (typeof layer === 'function' && nodes !== null && links !== null) {
layer(ctx, {
...props,
// ...props,
nodes,
links,
})
Expand All @@ -113,6 +111,9 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
canvasEl,
outerWidth,
outerHeight,
margin.left,
margin.top,
pixelRatio,
layers,
theme,
nodes,
Expand All @@ -125,8 +126,8 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
])

const getNodeFromMouseEvent = useCallback(
event => {
if (!canvasEl.current) return null
(event: MouseEvent) => {
if (!canvasEl.current || nodes === null) return undefined

const [x, y] = getRelativeCursor(canvasEl.current, event)

Expand All @@ -146,23 +147,23 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
const { showTooltipFromEvent, hideTooltip } = useTooltip()

const handleMouseHover = useCallback(
event => {
(event: MouseEvent) => {
const node = getNodeFromMouseEvent(event)
if (node) {
showTooltipFromEvent(<NetworkNodeTooltip node={node} tooltip={tooltip} />, event)
showTooltipFromEvent(createElement(nodeTooltip, { node }), event)
} else {
hideTooltip()
}
},
[getNodeFromMouseEvent, showTooltipFromEvent, tooltip, hideTooltip]
[getNodeFromMouseEvent, showTooltipFromEvent, nodeTooltip, hideTooltip]
)

const handleMouseLeave = useCallback(() => {
hideTooltip()
}, [hideTooltip])

const handleClick = useCallback(
event => {
(event: MouseEvent) => {
if (!onClick) return

const node = getNodeFromMouseEvent(event)
Expand Down
11 changes: 7 additions & 4 deletions packages/network/src/NetworkLink.tsx
@@ -1,8 +1,8 @@
import { AnimatedProps, animated } from '@react-spring/web'
import { ComputedLink } from './types'
import { ComputedLink, NetworkInputNode } from './types'

interface NetworkLinkProps {
link: ComputedLink
interface NetworkLinkProps<N extends NetworkInputNode> {
link: ComputedLink<N>
thickness: number
animated: AnimatedProps<{
x1: number
Expand All @@ -13,7 +13,10 @@ interface NetworkLinkProps {
}>
}

export const NetworkLink = ({ thickness, animated: animatedProps }: NetworkLinkProps) => {
export const NetworkLink = <N extends NetworkInputNode>({
thickness,
animated: animatedProps,
}: NetworkLinkProps<N>) => {
return (
<animated.line
stroke={animatedProps.color}
Expand Down

0 comments on commit c3d5dd1

Please sign in to comment.