Rendering vis.js network into container via React.js
Asked Answered
A

5

10

how do I render a vis.js network into a concrete html container?
I've tried the following, however it does not work:

<div id="network">
   {new vis.Network("network", data, options)}
</div>

Or should I render it the following way?

ReactDOM.render(<App />, document.getElementById('app'));
ReactDOM.render(<Network />, document.getElementById('network'));

While the elements "app" and "network" are in a wrapper html container.

I would appreciate a solution that the vis.js network is rendered into the root document:

 ReactDOM.render(<App />, document.getElementById('root'));

Cheers!

Acidulent answered 24/11, 2016 at 18:20 Comment(0)
P
16

this works for me:

 var nodes = new vis.DataSet([
        {id: 1, label: 'Node 1'},
        {id: 2, label: 'Node 2'},
        {id: 3, label: 'Node 3'},
        {id: 4, label: 'Node 4'},
        {id: 5, label: 'Node 5'}
    ]);

    // create an array with edges
    var edges = new vis.DataSet([
        {from: 1, to: 3},
        {from: 1, to: 2},
        {from: 2, to: 4},
        {from: 2, to: 5}
    ]);

var data = {
        nodes: nodes,
        edges: edges
    };
    var options = {};

    // initialize your network!


var VisNetwork = React.createClass({

    componentDidMount(){
            var network = new vis.Network(this.refs.myRef, data, options);
  },

  render: function() {
    return <div ref="myRef"></div>;
  }
});

ReactDOM.render(
  <VisNetwork />,
  document.getElementById('container')
);

https://jsfiddle.net/ginollerena/69z2wepo/63263/

Print answered 24/11, 2016 at 18:54 Comment(1)
That is exactly what I wanted to do, thank you very much, much appreciated!Acidulent
L
10

From React 16.3, it is recommended to use React.createRef Docs

Updating @Gino's answer with 16.3 style.

import { DataSet, Network } from 'vis';
import React, { Component, createRef } from "react";

const nodes = new DataSet([
  { id: 1, label: 'Node 1' },
  { id: 2, label: 'Node 2' },
  { id: 3, label: 'Node 3' },
  { id: 4, label: 'Node 4' },
  { id: 5, label: 'Node 5' }
]);

// create an array with edges
const edges = new DataSet([
  { from: 1, to: 3 },
  { from: 1, to: 2 },
  { from: 2, to: 4 },
  { from: 2, to: 5 }
]);

const data = {
  nodes: nodes,
  edges: edges
};
const options = {};

// initialize your network!


class VisNetwork extends Component {

  constructor() {
    super();
    this.network = {};
    this.appRef = createRef();
  }

  componentDidMount() {
    this.network = new Network(this.appRef.current, data, options);
  }

  render() {
    return (
      <div ref={this.appRef} />
    );
  }
}
Laryngotomy answered 22/7, 2018 at 19:27 Comment(1)
Really appreciated, I was struggling to get it working because I am a React noobCowage
T
10

Here is a modern example using functional components and React hooks.

package.json

{
  "dependencies": {
    "react": "16.13.0",
    "react-dom": "16.13.0",
    "vis-network": "7.4.0"
  }
}

VisNetwork.js

import React, { useEffect, useRef } from 'react';
import { DataSet, Network} from 'vis-network/standalone/esm/vis-network';

const VisNetwork = () => {
  // A reference to the div rendered by this component
  const domNode = useRef(null);

  // A reference to the vis network instance
  const network = useRef(null);

  // An array of nodes
  const nodes = new DataSet([
    { id: 1, label: 'Node 1' },
    { id: 2, label: 'Node 2' },
    { id: 3, label: 'Node 3' },
    { id: 4, label: 'Node 4' },
    { id: 5, label: 'Node 5' }
  ]);

  // An array of edges
  const edges = new DataSet([
    { from: 1, to: 3 },
    { from: 1, to: 2 },
    { from: 2, to: 4 },
    { from: 2, to: 5 }
  ]);

  const data = {
    nodes,
    edges
  };

  const options = {};

  useEffect(
    () => {
      network.current = new Network(domNode.current, data, options);
    },
    [domNode, network, data, options]
  );

  return (
    <div ref = { domNode } />
  );
};

export default VisNetwork;
Telephotography answered 26/3, 2020 at 18:4 Comment(2)
The only caveat with this solution is that, on multiple re-renders, graph gets slower and slower, it seems like previous graphs are still being computed instead of completely cleared. Refreshing the browser makes it go fast again. Do you have a workaround for this?Samuele
Thanks for the comment! I will have to look into this. I haven't noticed this, but it sure sounds like a resource leak. Most probably the useEffect needs destroy the old network instance in network.current before creating a new one.Telephotography
B
3

Here is the modern Typescript way:

import React, { useEffect, useRef } from "react";
import {
  DataSet,
  Network,
  Options,
  Data,
} from "vis-network/standalone/esm/vis-network";

export const LogicTreePanel = () => {
  // A reference to the div rendered by this component
  const domNode = useRef<HTMLDivElement>(null);

  // A reference to the vis network instance
  const network = useRef<Network | null>(null);

  // An array of nodes
  const nodes = new DataSet([
    { id: 1, label: "Node 1" },
    { id: 2, label: "Node 2" },
    { id: 3, label: "Node 3" },
    { id: 4, label: "Node 4" },
    { id: 5, label: "Node 5" },
  ]);

  // An array of edges
  const edges = new DataSet([
    { from: 1, to: 3 },
    { from: 1, to: 2 },
    { from: 2, to: 4 },
    { from: 2, to: 5 },
  ]);

  const data: Data = {
    nodes,
    edges,
  };

  const options: Options = {};

  useEffect(() => {
    if (domNode.current) {
      network.current = new Network(domNode.current, data, options);
    }
  }, [domNode, network, data, options]);

  return (
    <div
      ref={domNode}
    />
  );
};
Bowling answered 16/10, 2020 at 7:28 Comment(0)
F
0

I am trying to do something similar, but I'm using a third party library (Apollo) that uses React Hooks and was giving errors when used within a class component, so I switched to a function component. (I think this has something to do with class components not having hooks, but the Apollo hooks are used in a function called from the component itself, so I'm not quite sure how it all fits together.)

Using refs with function components is a bit different. I think there is a way to do it using the useEffect hook, but in my particular use case I was having an issue with the hook firing before render (because the hook was set up to fire when the data changed, which was dynamic) and the reference still not being available.

To get around this, a solution appears to be to use the useCallback hook, which gets fired when the reference is attached to/detached from a node. I basically took it from here, which describes a situation with a similar precondition: https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node

I just implemented it so I haven't had any time to figure out exactly what's going on and what will happen at later points, but the way it's set up below should cause it to trigger whenever data changes (because it's in the dependency list [data] passed to useCallback). Obviously in this example that's not going to happen but I figured I'd leave it in.

Note that this has been modified from my specific example and I haven't actually run the code below, so there may be some errors but I think it should point others in the right direction.

I'm really new to React so I'm not remotely confident that this is the most appropriate/best/most idiomatic way to solve this problem, so if anyone has any additional input, I'd love to hear it.

import { DataSet, Network } from 'vis';
import React, { Component, createRef } from "react";

const nodes = new DataSet([
  { id: 1, label: 'Node 1' },
  { id: 2, label: 'Node 2' },
  { id: 3, label: 'Node 3' },
  { id: 4, label: 'Node 4' },
  { id: 5, label: 'Node 5' }
]);

// create an array with edges
const edges = new DataSet([
  { from: 1, to: 3 },
  { from: 1, to: 2 },
  { from: 2, to: 4 },
  { from: 2, to: 5 }
]);

const data = {
  nodes: nodes,
  edges: edges
};
const options = {};

// initialize your network!


const VisNetwork = () => {

  const triggeredRef = React.useCallback( node => {
    if ( node === null )
      return;

    const network = new Network(node, data, options);
  }, [data]);

  render() {
    return (
      <div ref={triggeredRef} />
    );
  }
}
Fanchan answered 3/3, 2020 at 19:42 Comment(1)
Have a look at useRef, for the hook way of handling refs: reactjs.org/docs/hooks-reference.html#userefTelephotography

© 2022 - 2024 — McMap. All rights reserved.