@lifeomic/react-vis-network
v1.1.0
Published
Declarative vis.js network for react
Downloads
14
Readme
React Vis Network
Installation
yarn install @lifeomic/react-vis-network
Overview
react-vis-network uses a declarative approach to defining vis.js networks. This allows developers to work in React using normal stateful approaches like Redux and have the underlying network chart manage it's own lifecycle.
Example
import React, { Component } from 'react';
import { Network, Node, Edge } from '@lifeomic/react-vis-network';
class MyNetwork extends Component {
render() {
return (
<Network>
<Node id="vader" label="Darth Vader" />
<Node id="luke" label="Luke Skywalker" />
<Node id="leia" label="Leia Organa" />
<Edge id="1" from="vader" to="luke" />
<Edge id="2" from="vader" to="leia" />
</Network>
);
}
}
API
< Network />
<Network />
is the top level component that defines your network. All Node
s, Edge
s and Cluster*
components need to be inside a Network
to work properly.
Props
options
: Object of vis options to configure the look and feel, physics, and interaction patterns in the graph. All options are passed directly to vis and can be overriden on a case by case bases by setting individual options on each Node
or Edge
scale
: Zoom scale of the network. Defined as a number from 0-1 where 1 is 100% zoomed and 0 is zoomed out infinitely. As returned from network.getScale
.
position
: Object ({ x, y }
) containing coordinates of the central focus point. As returned from network.getViewPosition
.
style
/className
: Normal style and className props to enable styling the network's wrapping element. NB: Overidding position: relative
and overflow: hidden
will result in wonky node decorator
behavior.
< Node />
A Node
represents a vis.js network node. As props, a Node
accepts all options accepted in normal configuration. It also accepts two special props component
and decorator
.
component
: SVG element to be rendered as the Node in the Network. component
is a render prop recieves all of the props passed to Node
and returns a react component. The svg will be rendered as the image
of the node. Helpful tip, you can pass additional props to node
that can be used in your render prop to dynamically change your image.
const CustomIcon = ({ icon, color = '#5596ed' }) => {
const viewBox = 36;
const iconSize = 20;
const pad = (viewBox - iconSize) / 2;
const center = viewBox / 2;
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox={`0 0 ${viewBox} ${viewBox}`}
>
<g>
<circle cx={center} cy={center} r={16} fill={color} />
<g transform={`translate(${pad}, ${pad})`}>
{React.createElement(icon, { color: 'white', size: iconSize })}
</g>
</g>
</svg>
);
};
// Use your render prop and custom props passed to `Node` to
// Generate differnt icons per node
const MyNetwork = () => (
<Network>
<Node
id="vader"
label="Darth Vader"
component={CustomIcon}
color="black"
icon={Sith}
/>
<Node
id="luke"
label="Luke Skywalker"
component={CustomIcon}
color="white"
icon={Jedi}
/>
<Node
id="leia"
label="Leia Organa"
component={CustomIcon}
color="gold"
icon={Princess}
/>
<Edge id="1" from="vader" to="luke" />
<Edge id="2" from="vader" to="leia" />
</Network>
);
NB: This is simply syntactic sugar over using HTML in Nodes and will end up being a data+image. You will not recieve dom events through this component, use Network
's event system or decorator
s instead.
decorator
: A react element positioned at the top center of rendered Node
. A decorator is similar to component
in that it's a render prop that recieves the props of a the node, and returns a react element. This element however doesn't need to be an svg.
const Decorator = props => {
return (
<button
style={decoratorStyles}
onClick={() => console.log(`You clicked ${props.label}`}
>
Click Me
</button>
);
};
// Use your render prop and custom props passed to `Node` to
// cause differnet actions in your Decorator
const MyNetwork = () => (
<Network>
<Node id='vader' label='Darth Vader' decorator={Decorator} />
<Node id='luke' label='Luke Skywalker' decorator={Decorator} />
<Node id='leia' label='Leia Organa' decorator={Decorator} />
<Edge id='1' from='vader' to='luke' />
<Edge id='1' from='vader' to='leia' />
</Network>
);
NB: Because this is a positioned HTML element, it can recieve DOM events like click
and input
. While fairly performant in positioning and rendering, it can be straining if many nodes have decorators and should be used sparingly. For static (non-interactable) content, it would be better to use a component
with a changing prop to re-render it.
< Edge />
An Edge
represents a vis.js edge and connects nodes together.
Edges accept all of the options vis exposes for edges as props. One specific note, vis doesn't require that edges have an id
, react-vis-network does in order to keep the network updated.
< ClusterByConnection />
A ClusterByConnection
is a representation of a vis.js cluster. This particular cluster implementation collapses all nodes around, and including, it's rootNodeId
into a cluster.
ClusterByConnection
takes all props that Node
does including component
and decorator
.
rootNodeId
: id
of a Node
for which to cluster around.
Performance Considerations
All exported components are Pure Components. It's important to not define anonymous functions and objects inside the render function as it will cause unnecessary re-renders.
// bad, re-renders every time
render () {
return <Node component={() => <SomeIcon />} />
}
// good, only re-renders when other props change
renderSomeIcon = () => <SomeIcon />
render () {
return <Node component={this.renderSomeIcon} />
}
Use decorators
on Node
s sparingly, if you can do it in the component
you should.
Extending, custom clusters, and custom modules
⚠️ Advanced topics, here be dragons.
Want to write a custom Cluster component? Want to add a bit to the lifecycle of a node?
The base of Node
s and Cluster
s is a Module
. Take a peak at the source and create your own class that extends the Module (if you want decorator
and compoment
support anyway) and use it.
The design of each component is to manage it's lifecycle inside the vis network with react lifecycle methods. Every child
inside a Network
is passed as props a network
(vis.Network), edges
(vis.Dataset) and nodes
(vis.Dataset).
Helpers
In order to help you roll your own lifecycle methods, the internal converter for component
and decorator
is exposed as reactToSvgImageUrl
.
reactToSvgImageUrl (element) -> String
: Accepts a JSX element and returns it rendered as a data:image string.
Accessing the underlying vis network
⚠️ This is an escape hatch, if you find yourself needing to do this, it's likely that the package authors simply haven't thought of your use-case. We would like to! Please open an issue and we can work to build a supported solution.
The Network
component has, as instance properties, network
(a vis.js network), edges
(a vis.js Dataset representing it's edges), and nodes
a vis.js Dataset representing it's nodes).
You can access these by creating a ref
to the mounted Network
.