1
- import { useCallback , useRef , useEffect } from 'react'
2
- import * as React from 'react'
1
+ import { useCallback , useRef , useEffect , createElement , MouseEvent } from 'react'
3
2
import { getDistance , getRelativeCursor , Container , useDimensions , useTheme } from '@nivo/core'
4
3
import { useInheritedColor } from '@nivo/colors'
5
4
import { useTooltip } from '@nivo/tooltip'
6
5
import { canvasDefaultProps } from './defaults'
7
6
import { useNetwork , useNodeColor , useLinkThickness } from './hooks'
8
- import { NetworkNodeTooltip } from './NetworkNodeTooltip'
9
7
import { NetworkCanvasProps , NetworkInputNode } from './types'
10
8
11
9
type InnerNetworkCanvasProps < N extends NetworkInputNode > = Omit <
12
10
NetworkCanvasProps < N > ,
13
11
'renderWrapper' | 'theme'
14
12
>
15
13
16
- const InnerNetworkCanvas = < N extends NetworkInputNode > ( props : InnerNetworkCanvasProps < N > ) => {
17
- const {
18
- width,
19
- height,
20
- margin : partialMargin ,
21
- pixelRatio = canvasDefaultProps . pixelRatio ,
22
-
23
- data : { nodes : rawNodes , links : rawLinks } ,
14
+ const InnerNetworkCanvas = < N extends NetworkInputNode > ( {
15
+ width,
16
+ height,
17
+ margin : partialMargin ,
18
+ pixelRatio = canvasDefaultProps . pixelRatio ,
24
19
25
- linkDistance = canvasDefaultProps . linkDistance ,
26
- repulsivity = canvasDefaultProps . repulsivity ,
27
- distanceMin = canvasDefaultProps . distanceMin ,
28
- distanceMax = canvasDefaultProps . distanceMax ,
29
- iterations = canvasDefaultProps . iterations ,
20
+ data : { nodes : rawNodes , links : rawLinks } ,
30
21
31
- layers = canvasDefaultProps . layers ,
22
+ linkDistance = canvasDefaultProps . linkDistance ,
23
+ repulsivity = canvasDefaultProps . repulsivity ,
24
+ distanceMin = canvasDefaultProps . distanceMin ,
25
+ distanceMax = canvasDefaultProps . distanceMax ,
26
+ iterations = canvasDefaultProps . iterations ,
32
27
33
- nodeColor = canvasDefaultProps . nodeColor ,
34
- nodeBorderWidth = canvasDefaultProps . nodeBorderWidth ,
35
- nodeBorderColor = canvasDefaultProps . nodeBorderColor ,
28
+ layers = canvasDefaultProps . layers ,
36
29
37
- linkThickness = canvasDefaultProps . linkThickness ,
38
- linkColor = canvasDefaultProps . linkColor ,
30
+ nodeColor = canvasDefaultProps . nodeColor ,
31
+ nodeBorderWidth = canvasDefaultProps . nodeBorderWidth ,
32
+ nodeBorderColor = canvasDefaultProps . nodeBorderColor ,
39
33
40
- isInteractive = canvasDefaultProps . isInteractive ,
41
- tooltip = canvasDefaultProps . tooltip ,
42
- onClick,
43
- } = props
34
+ linkThickness = canvasDefaultProps . linkThickness ,
35
+ linkColor = canvasDefaultProps . linkColor ,
44
36
45
- const canvasEl = useRef ( null )
37
+ isInteractive = canvasDefaultProps . isInteractive ,
38
+ nodeTooltip = canvasDefaultProps . nodeTooltip ,
39
+ onClick,
40
+ } : InnerNetworkCanvasProps < N > ) => {
41
+ const canvasEl = useRef < HTMLCanvasElement | null > ( null )
46
42
const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions (
47
43
width ,
48
44
height ,
49
45
partialMargin
50
46
)
51
47
52
- const [ nodes , links ] = useNetwork ( {
48
+ const [ nodes , links ] = useNetwork < N > ( {
53
49
nodes : rawNodes ,
54
50
links : rawLinks ,
55
51
linkDistance,
@@ -67,10 +63,12 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
67
63
const getLinkColor = useInheritedColor ( linkColor , theme )
68
64
69
65
useEffect ( ( ) => {
66
+ if ( canvasEl . current === null ) return
67
+
70
68
canvasEl . current . width = outerWidth * pixelRatio
71
69
canvasEl . current . height = outerHeight * pixelRatio
72
70
73
- const ctx = canvasEl . current . getContext ( '2d' )
71
+ const ctx = canvasEl . current . getContext ( '2d' ) !
74
72
75
73
ctx . scale ( pixelRatio , pixelRatio )
76
74
@@ -79,7 +77,7 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
79
77
ctx . translate ( margin . left , margin . top )
80
78
81
79
layers . forEach ( layer => {
82
- if ( layer === 'links' ) {
80
+ if ( layer === 'links' && links !== null ) {
83
81
links . forEach ( link => {
84
82
ctx . strokeStyle = getLinkColor ( link )
85
83
ctx . lineWidth = getLinkThickness ( link )
@@ -88,7 +86,7 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
88
86
ctx . lineTo ( link . target . x , link . target . y )
89
87
ctx . stroke ( )
90
88
} )
91
- } else if ( layer === 'nodes' ) {
89
+ } else if ( layer === 'nodes' && nodes !== null ) {
92
90
nodes . forEach ( node => {
93
91
ctx . fillStyle = getNodeColor ( node )
94
92
ctx . beginPath ( )
@@ -101,9 +99,9 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
101
99
ctx . stroke ( )
102
100
}
103
101
} )
104
- } else if ( typeof layer === 'function' ) {
102
+ } else if ( typeof layer === 'function' && nodes !== null && links !== null ) {
105
103
layer ( ctx , {
106
- ...props ,
104
+ // ...props,
107
105
nodes,
108
106
links,
109
107
} )
@@ -113,6 +111,9 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
113
111
canvasEl ,
114
112
outerWidth ,
115
113
outerHeight ,
114
+ margin . left ,
115
+ margin . top ,
116
+ pixelRatio ,
116
117
layers ,
117
118
theme ,
118
119
nodes ,
@@ -125,8 +126,8 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
125
126
] )
126
127
127
128
const getNodeFromMouseEvent = useCallback (
128
- event => {
129
- if ( ! canvasEl . current ) return null
129
+ ( event : MouseEvent ) => {
130
+ if ( ! canvasEl . current || nodes === null ) return undefined
130
131
131
132
const [ x , y ] = getRelativeCursor ( canvasEl . current , event )
132
133
@@ -146,23 +147,23 @@ const InnerNetworkCanvas = <N extends NetworkInputNode>(props: InnerNetworkCanva
146
147
const { showTooltipFromEvent, hideTooltip } = useTooltip ( )
147
148
148
149
const handleMouseHover = useCallback (
149
- event => {
150
+ ( event : MouseEvent ) => {
150
151
const node = getNodeFromMouseEvent ( event )
151
152
if ( node ) {
152
- showTooltipFromEvent ( < NetworkNodeTooltip node = { node } tooltip = { tooltip } /> , event )
153
+ showTooltipFromEvent ( createElement ( nodeTooltip , { node } ) , event )
153
154
} else {
154
155
hideTooltip ( )
155
156
}
156
157
} ,
157
- [ getNodeFromMouseEvent , showTooltipFromEvent , tooltip , hideTooltip ]
158
+ [ getNodeFromMouseEvent , showTooltipFromEvent , nodeTooltip , hideTooltip ]
158
159
)
159
160
160
161
const handleMouseLeave = useCallback ( ( ) => {
161
162
hideTooltip ( )
162
163
} , [ hideTooltip ] )
163
164
164
165
const handleClick = useCallback (
165
- event => {
166
+ ( event : MouseEvent ) => {
166
167
if ( ! onClick ) return
167
168
168
169
const node = getNodeFromMouseEvent ( event )
0 commit comments