Skip to content

Commit d70ad13

Browse files
committedDec 31, 2021
feat(network): memoize default node & link components
1 parent 365f261 commit d70ad13

File tree

8 files changed

+64
-59
lines changed

8 files changed

+64
-59
lines changed
 

‎packages/network/src/NetworkLink.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { animated } from '@react-spring/web'
22
import { InputNode, LinkProps } from './types'
3+
import { memo } from 'react'
34

4-
export const NetworkLink = <Node extends InputNode>({
5+
const NonMemoizedNetworkLink = <Node extends InputNode>({
56
link,
67
animated: animatedProps,
78
blendMode,
@@ -12,9 +13,12 @@ export const NetworkLink = <Node extends InputNode>({
1213
style={{ mixBlendMode: blendMode }}
1314
strokeWidth={link.thickness}
1415
strokeLinecap="round"
16+
opacity={animatedProps.opacity}
1517
x1={animatedProps.x1}
1618
y1={animatedProps.y1}
1719
x2={animatedProps.x2}
1820
y2={animatedProps.y2}
1921
/>
2022
)
23+
24+
export const NetworkLink = memo(NonMemoizedNetworkLink) as typeof NonMemoizedNetworkLink

‎packages/network/src/NetworkLinks.tsx

+2-14
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,15 @@ const getRegularTransition =
3131
opacity: 1,
3232
})
3333

34-
const getExitTransition =
35-
<Node extends InputNode>() =>
36-
(link: ComputedLink<Node>) => ({
37-
x1: link.source.x,
38-
y1: link.source.y,
39-
x2: link.source.x,
40-
y2: link.source.y,
41-
color: link.color,
42-
opacity: 0,
43-
})
44-
4534
export const NetworkLinks = <Node extends InputNode>({
4635
links,
4736
linkComponent,
4837
blendMode,
4938
}: NetworkLinksProps<Node>) => {
5039
const { animate, config: springConfig } = useMotionConfig()
5140

52-
const [enterTransition, regularTransition, exitTransition] = useMemo(
53-
() => [getEnterTransition<Node>(), getRegularTransition<Node>(), getExitTransition<Node>()],
41+
const [enterTransition, regularTransition] = useMemo(
42+
() => [getEnterTransition<Node>(), getRegularTransition<Node>()],
5443
[]
5544
)
5645

@@ -70,7 +59,6 @@ export const NetworkLinks = <Node extends InputNode>({
7059
from: enterTransition,
7160
enter: regularTransition,
7261
update: regularTransition,
73-
leave: exitTransition,
7462
expires: true,
7563
config: springConfig,
7664
immediate: !animate,

‎packages/network/src/NetworkNode.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { memo } from 'react'
12
import { animated, to } from '@react-spring/web'
23
import { InputNode, NodeProps } from './types'
34

4-
export const NetworkNode = <Node extends InputNode>({
5+
const NonMemoizedNetworkNode = <Node extends InputNode>({
56
node,
67
animated: animatedProps,
78
blendMode,
@@ -26,3 +27,5 @@ export const NetworkNode = <Node extends InputNode>({
2627
onMouseLeave={onMouseLeave ? event => onMouseLeave(node, event) : undefined}
2728
/>
2829
)
30+
31+
export const NetworkNode = memo(NonMemoizedNetworkNode) as typeof NonMemoizedNetworkNode

‎packages/network/src/hooks.ts

+1-19
Original file line numberDiff line numberDiff line change
@@ -222,25 +222,7 @@ export const useNetwork = <Node extends InputNode = InputNode>({
222222

223223
// d3 mutates data, hence the castings
224224
setCurrentNodes(nodesCopy)
225-
setCurrentLinks(
226-
(linksCopy as unknown as ComputedLink<Node>[]).map(link => {
227-
const previousSource = currentNodes
228-
? currentNodes.find(n => n.id === link.source.id)
229-
: undefined
230-
link.previousSource = previousSource
231-
? (previousSource as ComputedNode<Node>)
232-
: undefined
233-
234-
const previousTarget = currentNodes
235-
? currentNodes.find(n => n.id === link.target.id)
236-
: undefined
237-
link.previousTarget = previousTarget
238-
? (previousTarget as ComputedNode<Node>)
239-
: undefined
240-
241-
return link
242-
})
243-
)
225+
setCurrentLinks(linksCopy as unknown as ComputedLink<Node>[])
244226

245227
return () => {
246228
// prevent the simulation from continuing in case the data is updated.

‎website/src/data/components/network/mapper.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { settingsMapper } from '../../../lib/settings'
22

33
export const dynamicNodeSizeValue = 'dynamic: (node: InputNode) => node.radius * 2'
4+
export const dynamicActiveNodeSizeValue = 'dynamic: (node: InputNode) => node.radius * 3'
45
export const dynamicLinkThicknessValue =
56
'dynamic: (link: ComputedLink) => (2 - link.source.data.depth) * 2'
67

@@ -12,9 +13,16 @@ export default settingsMapper({
1213

1314
return value
1415
},
16+
activeNodeSize: (value: number | typeof dynamicActiveNodeSizeValue) => {
17+
if (value === dynamicActiveNodeSizeValue) {
18+
return (node: any) => node.radius * 3
19+
}
20+
21+
return value
22+
},
1523
linkThickness: (value: number | typeof dynamicLinkThicknessValue) => {
1624
if (value === dynamicLinkThicknessValue) {
17-
return (link: any) => (2 - link.source.data.depth) * 3
25+
return (link: any) => (2 - link.source.data.depth) * 2
1826
}
1927

2028
return value

‎website/src/data/components/network/props.ts

+35-22
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ import {
88
annotations,
99
} from '../../../lib/chart-properties'
1010
import { ChartProperty, Flavor } from '../../../types'
11-
import { dynamicNodeSizeValue, dynamicLinkThicknessValue } from './mapper'
11+
import {
12+
dynamicNodeSizeValue,
13+
dynamicActiveNodeSizeValue,
14+
dynamicLinkThicknessValue,
15+
} from './mapper'
1216

1317
const allFlavors: Flavor[] = ['svg', 'canvas']
1418

@@ -43,7 +47,6 @@ const props: ChartProperty[] = [
4347
key: 'linkDistance',
4448
group: 'Simulation',
4549
type: 'number | string | (link: Link) => number',
46-
required: false,
4750
help: `Control links' distance.`,
4851
flavors: allFlavors,
4952
description: `
@@ -61,7 +64,6 @@ const props: ChartProperty[] = [
6164
key: 'repulsivity',
6265
group: 'Simulation',
6366
type: 'number',
64-
required: false,
6567
help: 'Control how nodes repel each other.',
6668
description: `
6769
This value will also affect the strength
@@ -79,7 +81,6 @@ const props: ChartProperty[] = [
7981
key: 'distanceMin',
8082
group: 'Simulation',
8183
type: 'number',
82-
required: false,
8384
help: 'Sets the minimum distance between nodes for the many-body force.',
8485
flavors: allFlavors,
8586
defaultValue: defaults.distanceMin,
@@ -88,7 +89,6 @@ const props: ChartProperty[] = [
8889
key: 'distanceMax',
8990
group: 'Simulation',
9091
type: 'number',
91-
required: false,
9292
help: 'Sets the maximum disteance between nodes for the many-body force.',
9393
flavors: allFlavors,
9494
defaultValue: defaults.distanceMax,
@@ -102,7 +102,6 @@ const props: ChartProperty[] = [
102102
however it will also involve more computing.
103103
`,
104104
type: 'number',
105-
required: false,
106105
flavors: allFlavors,
107106
defaultValue: defaults.iterations,
108107
control: {
@@ -116,7 +115,6 @@ const props: ChartProperty[] = [
116115
key: 'nodeComponent',
117116
group: 'Nodes',
118117
type: 'NetworkNodeComponent',
119-
required: false,
120118
help: `Custom node component for the SVG implementation.`,
121119
flavors: ['svg'],
122120
defaultValue: 'NetworkNode',
@@ -125,15 +123,13 @@ const props: ChartProperty[] = [
125123
key: 'renderNode',
126124
group: 'Nodes',
127125
type: 'NetworkNodeCanvasRenderer',
128-
required: false,
129126
help: `Custom node rendering for the canvas implementation.`,
130127
flavors: ['canvas'],
131128
},
132129
{
133130
key: 'nodeSize',
134131
group: 'Nodes',
135132
type: 'number | (node: InputNode) => number',
136-
required: false,
137133
help: `Control nodes' size.`,
138134
flavors: allFlavors,
139135
defaultValue: defaults.nodeSize,
@@ -146,11 +142,40 @@ const props: ChartProperty[] = [
146142
max: 64,
147143
},
148144
},
145+
{
146+
key: 'activeNodeSize',
147+
group: 'Nodes',
148+
type: 'number | (node: InputNode) => number',
149+
help: `Control active nodes' size.`,
150+
flavors: allFlavors,
151+
defaultValue: defaults.activeNodeSize,
152+
control: {
153+
type: 'switchableRange',
154+
disabledValue: dynamicActiveNodeSizeValue,
155+
defaultValue: defaults.activeNodeSize as number,
156+
unit: 'px',
157+
min: 4,
158+
max: 64,
159+
},
160+
},
161+
{
162+
key: 'inactiveNodeSize',
163+
group: 'Nodes',
164+
type: 'number | (node: InputNode) => number',
165+
help: `Control inactive nodes' size.`,
166+
flavors: allFlavors,
167+
defaultValue: defaults.inactiveNodeSize,
168+
control: {
169+
type: 'range',
170+
unit: 'px',
171+
min: 4,
172+
max: 64,
173+
},
174+
},
149175
{
150176
key: 'nodeColor',
151177
group: 'Nodes',
152178
type: 'string | (node: InputNode) => string',
153-
required: false,
154179
help: `Control nodes' color.`,
155180
flavors: allFlavors,
156181
defaultValue: defaults.nodeColor,
@@ -166,7 +191,6 @@ const props: ChartProperty[] = [
166191
key: 'nodeBorderWidth',
167192
group: 'Nodes',
168193
type: 'number | (node: NetworkComputedNode) => number',
169-
required: false,
170194
help: `Control nodes' border width.`,
171195
flavors: allFlavors,
172196
defaultValue: defaults.nodeBorderWidth,
@@ -176,7 +200,6 @@ const props: ChartProperty[] = [
176200
key: 'nodeBorderColor',
177201
group: 'Nodes',
178202
type: 'InheritedColorConfig<NetworkComputedNode>',
179-
required: false,
180203
help: `Control nodes' border color.`,
181204
flavors: allFlavors,
182205
defaultValue: defaults.nodeBorderColor,
@@ -186,7 +209,6 @@ const props: ChartProperty[] = [
186209
key: 'linkComponent',
187210
group: 'Links',
188211
type: 'NetworkLinkComponent',
189-
required: false,
190212
help: `Custom link component for the SVG implementation.`,
191213
flavors: ['svg'],
192214
defaultValue: 'NetworkLink',
@@ -195,15 +217,13 @@ const props: ChartProperty[] = [
195217
key: 'renderLink',
196218
group: 'Links',
197219
type: 'NetworkLinkCanvasRenderer',
198-
required: false,
199220
help: `Custom link rendering for the canvas implementation.`,
200221
flavors: ['canvas'],
201222
},
202223
{
203224
key: 'linkThickness',
204225
group: 'Links',
205226
type: 'number | (link: NetworkComputedLink) => number',
206-
required: false,
207227
help: `Control links' thickness.`,
208228
flavors: allFlavors,
209229
defaultValue: defaults.linkThickness,
@@ -220,7 +240,6 @@ const props: ChartProperty[] = [
220240
key: 'linkColor',
221241
group: 'Links',
222242
type: 'InheritedColorConfig<ComputedLink>',
223-
required: false,
224243
help: `Control links' color.`,
225244
flavors: allFlavors,
226245
defaultValue: defaults.linkColor,
@@ -241,7 +260,6 @@ const props: ChartProperty[] = [
241260
key: 'nodeTooltip',
242261
group: 'Interactivity',
243262
type: 'NetworkNodeTooltipComponent',
244-
required: false,
245263
help: 'Custom tooltip component for nodes.',
246264
flavors: allFlavors,
247265
description: `
@@ -255,31 +273,27 @@ const props: ChartProperty[] = [
255273
group: 'Interactivity',
256274
help: 'onClick handler.',
257275
type: '(node: NetworkComputedNode, event: MouseEvent) => void',
258-
required: false,
259276
flavors: allFlavors,
260277
},
261278
{
262279
key: 'onMouseEnter',
263280
group: 'Interactivity',
264281
help: 'onMouseEnter handler.',
265282
type: '(node: ComputedNode, event: MouseEvent) => void',
266-
required: false,
267283
flavors: allFlavors,
268284
},
269285
{
270286
key: 'onMouseMove',
271287
group: 'Interactivity',
272288
help: 'onMouseMove handler.',
273289
type: '(node: ComputedNode, event: MouseEvent) => void',
274-
required: false,
275290
flavors: allFlavors,
276291
},
277292
{
278293
key: 'onMouseLeave',
279294
group: 'Interactivity',
280295
help: 'onMouseLeave handler.',
281296
type: '(node: ComputedNode, event: MouseEvent) => void',
282-
required: false,
283297
flavors: allFlavors,
284298
},
285299
annotations({
@@ -300,7 +314,6 @@ const props: ChartProperty[] = [
300314
type: `('links' | 'nodes')[] | FunctionComponent<LayerProps>`,
301315
group: 'Customization',
302316
help: 'Defines the order of layers and add custom layers.',
303-
required: false,
304317
defaultValue: defaults.layers,
305318
flavors: ['svg', 'canvas'],
306319
},

‎website/src/pages/network/canvas.tsx

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,17 @@ const initialProperties = Object.freeze({
2323
iterations: 60,
2424

2525
nodeSize: defaults.nodeSize,
26-
nodeColor: '#ff0000', // node => node.color,
26+
activeNodeSize: defaults.activeNodeSize,
27+
inactiveNodeSize: defaults.inactiveNodeSize,
28+
nodeColor: (node: any) => node.color,
2729
nodeBorderWidth: 1,
2830
nodeBorderColor: { theme: 'background' },
2931

3032
linkColor: defaults.linkColor,
3133
linkThickness: defaults.linkThickness,
3234

35+
annotations: defaults.annotations,
36+
3337
isInteractive: true,
3438
})
3539

‎website/src/pages/network/index.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ComponentTemplate } from '../../components/components/ComponentTemplate
66
import meta from '../../data/components/network/meta.yml'
77
import mapper, {
88
dynamicNodeSizeValue,
9+
dynamicActiveNodeSizeValue,
910
dynamicLinkThicknessValue,
1011
} from '../../data/components/network/mapper'
1112
import { groups } from '../../data/components/network/props'
@@ -23,6 +24,8 @@ const initialProperties = Object.freeze({
2324
iterations: 60,
2425

2526
nodeSize: dynamicNodeSizeValue,
27+
activeNodeSize: dynamicActiveNodeSizeValue,
28+
inactiveNodeSize: defaults.inactiveNodeSize,
2629
nodeColor: (node: any) => node.color,
2730
nodeBlendMode: 'normal',
2831
nodeBorderWidth: 1,

0 commit comments

Comments
 (0)
Please sign in to comment.