Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ericdrowell/ElGrapho
https://github.com/ericdrowell/ElGrapho
Last synced: 5 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/ericdrowell/ElGrapho
- Owner: ericdrowell
- License: other
- Created: 2018-11-22T06:22:21.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2020-01-27T11:06:05.000Z (almost 5 years ago)
- Last Synced: 2024-04-26T09:22:28.636Z (7 months ago)
- Language: JavaScript
- Homepage:
- Size: 37.5 MB
- Stars: 1,683
- Watchers: 36
- Forks: 153
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: license.js
Awesome Lists containing this project
- awesome-starred - ericdrowell/ElGrapho - (others)
README
# El Grapho
## What is El Grapho?
El Grapho is a high performance WebGL graph data visualization engine. El Grapho can support millions of interactive nodes and edges in any modern browser.
https://www.elgrapho.com/
## Why Would I Use This?
If you need to build a graph visualization for the web of any kind, such as a tree, force directed graph, network graph, etc., and scale and performance are important to you, then El Grapho is a great option. El Grapho was built to push the limits of modern browsers.
## Live Examples
* [Custom Layout](https://codepen.io/ericdrowell/pen/dLpNvK)
* [Miserables Force Directed Graph](https://codepen.io/ericdrowell/pen/wNRyoZ)
* [Tree](https://codepen.io/ericdrowell/pen/qLYrEm)
* [Radial Tree](https://codepen.io/ericdrowell/pen/bJwgRG)
* [Hairball](https://codepen.io/ericdrowell/pen/eodgGW)
* [Chord](https://codepen.io/ericdrowell/pen/dLpNzj)
* [Cluster](https://codepen.io/ericdrowell/pen/JVREJp)## Getting Started
To get started, you can install El Grapho from npm like this
```npm install --save elgrapho```
or you can download the latest El Grapho distribution file found here
https://github.com/ericdrowell/ElGrapho/blob/master/engine/dist/ElGrapho.min.js
## API
To create a simple El Grapho data visualization, you can instantiate a new graph like this
```
let graph = new ElGrapho({
container: document.getElementById('container'),
model: {
nodes: [
{x: 0, y: 0.6, group: 0, label: 0},
{x: -0.4, y: 0, group: 1, label: 1},
{x: 0.4, y: 0, group: 1, label: 2},
{x: -0.6, y: -0.6, group: 2, label: 3},
{x: -0.2, y: -0.6, group: 2, label: 4},
{x: 0.2, y: -0.6, group: 2, label: 5},
{x: 0.6, y: -0.6, group: 2, label: 6}
],
edges: [
{from: 0, to: 1},
{from: 0, to: 2},
{from: 1, to: 3},
{from: 1, to: 4},
{from: 2, to: 5},
{from: 2, to: 6}
]
},
width: 500,
height: 500
});
```* ```container``` - DOM element that will contain the El Grapho graph.
* ```model.nodes``` - object that defines the nodes in the graph. Each node is defined by a position (x and y), and also a group. El Grapho x and y ranges are between -1 and 1. If x is -1, then the node position is on the very left of the viewport. If x is 0 it is in the center, and if x is 1 it is on the very right of the viewport. Groups are integer values, and El Grapho automatically assigns colors to each unique grouping. To add labels, simply add a ```label``` key and value pair to each node.
* ```model.edges``` - object that defines the edges between nodes based on their indices. Each edge is defined by a from-node-index and a to-node-index. In the example above, the first edge begins at node ```0``` and ends at node ```1```. For non directed graphs, or bi-directional graphs, ```from``` and ```to``` are interchangeable.
* ```width``` - number that defines the width of the El Grapho viewport in pixels. The default is ```500```.
* ```height``` - number defines the height of the El Grapho viewport in pixels. The default is ```500```.
* ```nodeSize``` - number between 0 and 1 which defines the node size. The default is ```1```.
* ```nodeOutline``` - boolean that enables or disables node outlines. The default is ```true```.
* ```edgeSize``` - number between 0 and 1 which defines the edge size. Edge sizes are relative to the connecting node size. The default is ```0.25```.
* ```darkMode``` - boolean that enables or disables dark mode. The default is ```false```.
* ```glowBlend``` - number between 0 and 1 that defines the glow blending of nodes and edges. A value of 0 has no glow blending, and a value of 1 has full glow blending. Glow blending can be used as a visual treatment to emphasize node clustering or edge bundling. It is most effective when used in conjunction with dark mode. The default is ```0```.
* ```fillContainer``` - boolean that enables or disables auto filling the container. When true, El Grapho will automatically detect anytime its container has changed shape, and will auto resize itself. The default is ```false```.
* ```tooltips``` - boolean that enables or disables tooltips. The default is ```true```.
* ```arrows``` - boolean that enables or disables edge arrows. For non directed or bi-directional graphs, you should keep ```arrows``` as ```false```. The default is ```false```.
* ```animations``` - boolean that defines animation strategy. When animations is true, zoom and pan transitions will be animated. Otherwise the transitions will be immediate. Although animations utilize requestAnimationFrame for dynamic frame rates, in some situations you may prefer to set animations to false to improve transition performance for very high cardinality graphs with millions of nodes and edges. The default is ```true```.
* ```debug``` - boolean that can be used to enable debug mode. Debug mode will show the node and edge count in the bottom right corner of the visualization. The default is ```false```.
### Layouts
Determining the positions of the nodes for your graph can be a lot of work! While it's nice to have the power to construct custom graph layouts, most El Grapho users will want to leverage the provided El Grapho layouts which will generate node positions for you. Currently, El Grapho supports ```ForceDirected```, ```Tree```, ```RadialTree```, ```Hairball```, ```Chord```, and ```Cluster```
#### ForceDirected Layout
```
let model = {
nodes: [
{group: 0},
{group: 1},
{group: 1},
{group: 2},
{group: 2},
{group: 3}
],
edges: [
{from: 0, to: 1},
{from: 0, to: 2},
{from: 1, to: 3},
{from: 1, to: 4},
{from: 2, to: 5},
],
steps: 30
};graph = new ElGrapho({
container: document.getElementById('container'),
model: ElGrapho.layouts.ForceDirected(model),
width: 500,
height: 500
});
```The ```ForceDirected``` layout uses d3-force to reduce edge crossing and optimize node spacing. Although the algorithm is fairly efficient with a runtime of O(nlog(n)) via the Barnes-Hut approximation which uses quad trees, this can still be slow for very large graphs of 50k nodes or more. If it's possible to build your models in advance, it's a good idea to build the force directed graph model on the server and then cache it. If you require your models to be constructed at execution time, and the number of nodes is very high, you may consider using an O(n) model substitude such as ```HairBall``` or ```Cluster```
The ```ForceDirected``` layout accepts a ```steps``` property from the model config which can be used to define the accuracy of the result. This is because force directed graphs require multiple passes to obtain a final result. The default is 30. Lowering this number will result in faster model construction but less accurate results. Increasing this number will result in slower model construction but more accurate results.
#### Tree Layout
```
let model = {
nodes: [
{group: 0},
{group: 1},
{group: 1},
{group: 2},
{group: 2},
{group: 3},
{group: 3}
],
edges: [
{from: 0, to: 1},
{from: 0, to: 2},
{from: 1, to: 3},
{from: 1, to: 4},
{from: 2, to: 5},
{from: 2, to: 6}
]
};let graph = new ElGrapho({
container: document.getElementById('container'),
model: ElGrapho.layouts.Tree(model),
width: 500,
height: 500
});
```#### RadialTree Layout
```
let model = {
nodes: [
{group: 0},
{group: 1},
{group: 1},
{group: 2},
{group: 2},
{group: 3},
{group: 3}
],
edges: [
{from: 0, to: 1},
{from: 0, to: 2},
{from: 1, to: 3},
{from: 1, to: 4},
{from: 2, to: 5},
{from: 2, to: 6}
]
};let graph = new ElGrapho({
container: document.getElementById('container'),
model: ElGrapho.layouts.RadialTree(model),
width: 500,
height: 500
});
```#### Hairball Layout
```
let model = {
nodes: [
{group: 0},
{group: 1},
{group: 1},
{group: 2},
{group: 2},
{group: 3},
{group: 3}
],
edges: [
{from: 0, to: 1},
{from: 0, to: 2},
{from: 1, to: 3},
{from: 1, to: 4},
{from: 2, to: 5},
{from: 2, to: 6}
]
};let graph = new ElGrapho({
container: document.getElementById('container'),
model: ElGrapho.layouts.Hairball(model),
width: 500,
height: 500
});
```The ```Hairball``` layout is an excellent alternative to ```ForceDirected``` layouts when the number of nodes is very high, for example in the millions. This is because it runs in O(n) time, i.e. linear time. Essentially, nodes with lots of edges are forced towards the center, and nodes with few edges are pushed out to the perimeter, creating a hairball effect.
#### Cluster Layout
```
let model = {
nodes: [
{group: 0},
{group: 1},
{group: 1},
{group: 2},
{group: 2},
{group: 3},
{group: 3}
],
edges: [
{from: 0, to: 1},
{from: 0, to: 2},
{from: 1, to: 3},
{from: 1, to: 4},
{from: 2, to: 5},
{from: 2, to: 6}
]
};let graph = new ElGrapho({
container: document.getElementById('container'),
model: ElGrapho.layouts.Cluster(model),
arrows: true,
width: 500,
height: 500
});
```The ```Cluster``` layout clusters nodes by group. If a single group is used for all of the nodes, El Grapho will generate a single centered cluster. If there are several groups used, El Grapho will render distinct clusters. Because Cluster layouts can be generated in ```O(n)``` time, i.e. linear time, they are another great alternative to ```ForceDirected``` if performance becomes an issue.
#### Chord Layout
```
let model = {
nodes: [
{group: 0},
{group: 1},
{group: 1},
{group: 2},
{group: 2},
{group: 3},
{group: 3}
],
edges: [
{from: 0, to: 1},
{from: 0, to: 2},
{from: 1, to: 3},
{from: 1, to: 4},
{from: 2, to: 5},
{from: 2, to: 6}
]
};let graph = new ElGrapho({
container: document.getElementById('container'),
model: ElGrapho.layouts.Chord(model),
width: 500,
height: 500
});
```## Layout Polymorphism
You may have noticed that the layout config schema is identical for all layouts. As a result, El Grapho visualizations are polymorphic, meaning you can pass the same data structure into different layouts and get different graphs. Pretty cool!
## Server Side Model Generation
Because the El Grapho layouts are fully decoupled from the rendering engine itself, they can be executed on the client or on the server, depending on your needs. For really complex layouts, it may be best to build the model on the server, deliver the output over http to the browser, and pass it directly into the El Grapho config.
## Controls
El Grapho has controls in the upper right corner of the visualization that enable users to navigate large and complex graphs. These controls appear when you mouseover the visualization. There are three modes:
* __select__ - use this mode to select nodes
* __zoom__ - use this mode to draw zoom boxes around areas of interest or to zoom into a particular region of the graph
* __pan__ - use this mode to pan the visualization aroundAnd there are three action buttons:
* __reset__
* __zoom in__
* __zoom out__## Tooltips
El Grapho ships with a default template and default content. It is assumed however that you will be providing your own tooltip content (at the end of the day, most people want something custom anyways). To set the tooltip template, simply do the following:
```
let graph = new ElGrapho(config);graph.tooltipTemplate = function(index, el) {
el.innerHTML = 'node index: ' + index;
};
```This means that your tooltips can be anything! You can show lots of information about the node, insert images, etc. The tooltip template is decoupled from the El Grapho config in order to ensure that the config is serializable and thus transferable over http.
To disable tooltips entirely, you can set the ```tooltips``` property to false in the graph config.
## Events
El Grapho also has a built in event bus. Currently, the supported events are:
* ```idle```
* ```node-mouseover```
* ```node-mouseout```
* ```node-click```and you can use these events like this:
```
let graph = new ElGrapho(config);graph.on('idle', function() {
console.log('idle');
});graph.on('node-mouseover', function(evt) {
console.log('node-mouseover: ' + evt.dataIndex);
});
```## Methods
* ```graph.selectGroup(index)``` - select a group by index, where ```index``` is an ```integer```
* ```graph.deselectGroup()``` - deselect the currently selected group
* ```graph.setSize(width, height)``` - set the graph size in pixels, where ```width``` and ```height``` is a ```number```
* ```graph.setDarkMode(mode)``` - enable or disable dark mode, where ```mode``` is a ```boolean```
* ```graph.selectNode(index)``` - select node by index, where ```index``` is an ```integer```
* ```graph.deselectNode()``` - deselect a selected node
## About the Name and Logo
Why is this called El Grapho? - *Why not?*
Okay... and why is the logo a skeleton with a rose in his mouth? - *Why not?*