Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

vivagraphjs

anvaka2.5kBSD-3-Clause0.12.0

Graph Drawing Library

graph

readme

VivaGraph Build Status

VivaGraphJS is designed to be extensible and to support different rendering engines and layout algorithms. Underlying algorithms have been broken out into ngraph.

The larger family of modules can be found by querying npm for "ngraph".

Gitter

Enough talking. Show me the demo!

Some examples of library usage in the real projects:

To start using the library include vivagraph.js script from the dist folder. The following code is the minimum required to render a graph with two nodes and one edge:

var graph = Viva.Graph.graph();
graph.addLink(1, 2);

var renderer = Viva.Graph.View.renderer(graph);
renderer.run();

This will instantiate a graph inside document.body:

Simple graph

If you want to render graph in your own DOM element:

var graph = Viva.Graph.graph();
graph.addLink(1, 2);

// specify where it should be rendered:
var renderer = Viva.Graph.View.renderer(graph, {
  container: document.getElementById('graphDiv')
});
renderer.run();

The code above adds a link to the graph between nodes 1 and 2. Since nodes are not yet in the graph they will be created. It's equivalent to

var graph = Viva.Graph.graph();
graph.addNode(1);
graph.addNode(2);
graph.addLink(1, 2);

var renderer = Viva.Graph.View.renderer(graph);
renderer.run();

Customization

VivaGraphJS is all about customization. You can easily change the appearance of nodes and links. You can also change the layouting algorithm and medium that displays elements of the graph. For example: The following code allows you to use WebGL-based rendering, instead of the default SVG.

var graph = Viva.Graph.graph();
graph.addLink(1, 2);

var graphics = Viva.Graph.View.webglGraphics();

var renderer = Viva.Graph.View.renderer(graph,
    {
        graphics : graphics
    });
renderer.run();

graphics class is responsible for rendering nodes and links on the page. And renderer orchestrates the process. To change nodes appearance tell graphics how to represent them. Here is an example of graph with six people who I follow at github:

var graph = Viva.Graph.graph();

// Construct the graph
graph.addNode('anvaka', {url : 'https://secure.gravatar.com/avatar/91bad8ceeec43ae303790f8fe238164b'});
graph.addNode('manunt', {url : 'https://secure.gravatar.com/avatar/c81bfc2cf23958504617dd4fada3afa8'});
graph.addNode('thlorenz', {url : 'https://secure.gravatar.com/avatar/1c9054d6242bffd5fd25ec652a2b79cc'});
graph.addNode('bling', {url : 'https://secure.gravatar.com/avatar/24a5b6e62e9a486743a71e0a0a4f71af'});
graph.addNode('diyan', {url : 'https://secure.gravatar.com/avatar/01bce7702975191fdc402565bd1045a8?'});
graph.addNode('pocheptsov', {url : 'https://secure.gravatar.com/avatar/13da974fc9716b42f5d62e3c8056c718'});
graph.addNode('dimapasko', {url : 'https://secure.gravatar.com/avatar/8e587a4232502a9f1ca14e2810e3c3dd'});

graph.addLink('anvaka', 'manunt');
graph.addLink('anvaka', 'thlorenz');
graph.addLink('anvaka', 'bling');
graph.addLink('anvaka', 'diyan');
graph.addLink('anvaka', 'pocheptsov');
graph.addLink('anvaka', 'dimapasko');

// Set custom nodes appearance
var graphics = Viva.Graph.View.svgGraphics();
graphics.node(function(node) {
       // The function is called every time renderer needs a ui to display node
       return Viva.Graph.svg('image')
             .attr('width', 24)
             .attr('height', 24)
             .link(node.data.url); // node.data holds custom object passed to graph.addNode();
    })
    .placeNode(function(nodeUI, pos){
        // Shift image to let links go to the center:
        nodeUI.attr('x', pos.x - 12).attr('y', pos.y - 12);
    });

var renderer = Viva.Graph.View.renderer(graph, {
        graphics : graphics
    });
renderer.run();

The result is:

Custom nodes

Tuning layout algorithm

Graphs vary by their nature. Some graphs have hundreds of nodes and few edges (or links), some might connect every node with every other. Tuning the physics often helps get the best layout. Consider the following example:

var graphGenerator = Viva.Graph.generator();
var graph = graphGenerator.grid(3, 3);
var renderer = Viva.Graph.View.renderer(graph);
renderer.run();

Graph generators are part of the library, which can produce classic graphs. grid generator creates a grid with given number of columns and rows. But with default parameters the rendering is pretty ugly:

Grid 3x3 bad

Let's tweak the original code:

var graphGenerator = Viva.Graph.generator();
var graph = graphGenerator.grid(3, 3);

var layout = Viva.Graph.Layout.forceDirected(graph, {
    springLength : 10,
    springCoeff : 0.0005,
    dragCoeff : 0.02,
    gravity : -1.2
});

var renderer = Viva.Graph.View.renderer(graph, {
    layout : layout
});
renderer.run();

Now the result is much better:

Grid 3x3

You can tune values during simulation with layout.simulator.springLength(newValue), layout.simulator.springCoeff(newValue), etc. See all the values that you can tune in this source file.

Tuning layout algorithm is definitely one of the hardest part of using this library. It has to be improved in future to simplify usage. Each of the force directed algorithm parameters are described in the source code.

Design philosophy/roadmap

Until version 0.7.x VivaGraph was a single monolithic code base. Starting from 0.7.x the library is bundled from small npm modules into Viva namespace. All these modules are part of a larger ngraph family. ngraph modules support rendering graphs into images, 3D rendering, integration with gephi, pagerank calculation and many more.

Version 0.7 is a compromise between maximum backward compatibility and ngraph flexibility. Eventually I hope to further simplify API and provide interface for custom builds.

Upgrade guide

Please refer the upgrade guide to see how to update older versions of the library to the latest one.

Local Build

Run the following script:

git clone https://github.com/anvaka/VivaGraphJS.git
cd ./VivaGraphJS
npm install
gulp release

The combined/minified code should be stored in dist folder.

Looking for alternatives?

I'm trying to put up a list of all known graph drawing libraries. Please find it here

I need your feedback

Disclaimer: I wrote this library to learn JavaScript. By no means I pretend to be an expert in the language and chosen approach to design may not be the optimal. I would love to hear your feedback and suggestions.

Though I implemented this library from scratch, I went through many existing libraries to pick the best (at my view) out of them. If you are evaluating libraries for your project make sure to check them out as well.

My goal is to create highly performant javascript library, which serves in the field of graph drawing. To certain extent I achieved it. But I have no doubt there is much more to improve here.

changelog

v0.8.1 date Sep 9, 2015

    - Improved layout performance in some cases
    - Extended WebGL API to transform from/to webgl coordinates space
    - Custom shaders now receive layout's view of node position. This means
    that `y` coordinate needs to be replaced to `-y` in your custom shaders
    code
    - Bug fixes
    - Documentation updates

v0.7.7 date Mar 24, 2015

  - Upgraded to latest `ngraph` modules
    - Bug fixes

v0.7.0 date Feb 4, 2015

  - All files are now CommonJS Modules
    - `Viva.Graph.svg` is replaced with npm module `simplesvg`
    - `Viva.Graph.graph` is replaced with `ngraph.graph`
    - `Viva.Graph.generator` is replaced with `ngraph.generators`. This module
    contains all original graph + new graphs.
    Note: `randomNoLinks` is called `noLinks`.
- `Viva.graph.Layout.forceDirected` is replaced with npm module
    'ngraph.forcelayout'. This module is faster than older one, and has better
    test coverage. Unfortunately this also means breaking changes:
    1. Instead of passing `link` object to `layout.getLinkPosition(link)`, you
    need to pas linkId: `layout.getLinkPosition(link.id)`.
    2. Instead of passing `node` object to `layout.setNodePosition(node, x, y)`
    use `layout.setNodePosition(node.id, x, y)`.
    3. Force based layout settings can be now accessed from `layout.simulator`:
        `layout.drag()` is now known as `simulator.dragCoeff()`
        `layout.springCoeff()` -> `simulator.springCoeff()`
        `layout.springLength()` -> `simulator.springLength()`
        `layout.gravity()` -> `simulator.gravity()`
        `layout.theta()` -> `simulator.theta()`
    - `Viva.Graph.Point2d` is removed. Use plain {x: 42, y: 42} object
    - `Viva.Graph.graph.addEventListener` is replaced with `on` method
    - `Viva.Graph.View.cssGraphcis` is deprecated
    - `Viva.Graph.View.svgNodeFactory` is deprecated
    - `geom.convexHull` is deprecated. Use https://github.com/anvaka/cnvx
    instead.
    - `Viva.Graph.community` is deprecated. Use https://github.com/anvaka/ngraph.slpa
    instead.

v0.6.0 date Dec 27, 2014

 - Migrated to gulp. First step towards commonjs.
 - Fixed spelling, grammar.

v0.5.8 date: Sep 28, 2014

- Graphics object no longer waits `init` method to create container. Fixes
https://github.com/anvaka/VivaGraphJS/issues/82
- When renderer is paused clicking on any node will not reset it. Fixes
https://github.com/anvaka/VivaGraphJS/issues/98
- Calculating stable threshold based on absolute value. Fixes
https://github.com/anvaka/VivaGraphJS/issues/100#issuecomment-55568513
- Minor code style improvements

v0.5.6 date: Apr 05, 2014

- Using Object.create where possible to avoid node id collision with
standard object property names (e.g. `constructor`)
- Fixed bug in constant layout

v0.5.5 date: Feb 22, 2014

- Stable threshold can now be configured via options (Tnanks to @grnadav)

v0.5.4 date: Feb 19, 2014

- Webgl renderer supports centering API (Thanks to @sgerard)

v0.5.3 date: Dec 27, 2013

- Small clean up in renderer
- Added pan/zoom API for SVG

v0.5.2 date: Nov 23, 2013

- Euler integrator now supports custom time step

v0.5.1 date: Nov 20, 2013

- Merged changes from v0.4.2: custom links length + fixed bug in arguments
order

v0.5.0 date: Oct 20, 2013 BREAKING CHANGES:

  • graph.addNode() no longer augments old data model with whatever passed to method. Instead it stores direct reference to passed node's model
  • node/link objects no longer store layout specific properties. Instead you can query all layout properties from layout class itself. This allows the same graph to be layed out by two different layout algorithm, without stepping on toes of each other
  • node/link objects no longer store ui specific properties. Instead you can query them from specific UI provider

v0.4.2 date: Nov 20, 2013 changes:

- Added customization point to force directed layout to allow specify custom links length.
- Fixed a bug with wrong arguments order in physics simulator.

v0.4.1 date: Jul 20, 2013 changes:

  - Layout algorithm now listens to changes from graph directly. Public API
      to add/remove nodes or links is dropped from layout algorithms.
    - Added small performance test for node.js

v0.4.0 date: April 7, 2013 changes:

- Migrated to grunt.js as a build system
- Dropped jslint support in favor of jshint.
- Cleaned up unused code:
    * GEM/ACE layout files are removed from repository. If you need them for
    the reference, please find them in the project's commits history.
    * Runge Kutta integrator is dropped