├── .gitignore ├── README.md ├── example.png ├── example ├── example.jsx └── index.html ├── index.js ├── index.jsx └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dagre-react is a JavaScript library which provides a Graph React component and does automatic layout, 2 | so you can render directed graphs just from vertex and edge data: 3 | 4 | ``` .javascript 5 | var Example = React.createClass({ 6 | render: function() { 7 | var toVertex = function(name) { 8 | return ( 9 | 11 | 12 | 13 | {name} 14 | 15 | 16 | ); 17 | }; 18 | 19 | var arrow = " \ 21 | \ 22 | "; 23 | 24 | return ( 25 | 26 | 27 | 28 | 29 | {["bar", "baz"].map(toVertex)} 30 | 33 | 34 | 35 | {"foo"} 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ); 44 | } 45 | }); 46 | ``` 47 | 48 | produces something like this (with styles): 49 | 50 | 51 | 52 | You can make the vertices' children arbitrary React components; 53 | at the moment, edges are just SVG paths. 54 | 55 | It uses the dagre library to lay out your graph. 56 | 57 | Make sure you compile JSX files back to JS if you change them. 58 | -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osnr/dagre-react/7e0eaff7939f43376a2cd41ac917710d06d0cd4d/example.png -------------------------------------------------------------------------------- /example/example.jsx: -------------------------------------------------------------------------------- 1 | var Graph = DagreReact.Graph; 2 | var Vertex = DagreReact.Vertex; 3 | var Edge = DagreReact.Edge; 4 | 5 | var Example = React.createClass({ 6 | render: function() { 7 | var toVertex = function(name) { 8 | return ( 9 | 11 | 12 | 13 | {name} 14 | 15 | 16 | ); 17 | }; 18 | 19 | var arrow = " \ 21 | \ 22 | "; 23 | 24 | return ( 25 | 26 | 27 | 28 | 29 | {["bar", "baz"].map(toVertex)} 30 | 33 | 34 | 35 | {"foo"} 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ); 44 | } 45 | }); 46 | 47 | React.render( 48 | , 49 | document.getElementById('dagre-graph-example') 50 | ); 51 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Dagre React Example 6 | 7 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (function(root, modules, factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | // AMD. 4 | var carry = function(React, dagre) { 5 | return factory(root, React, dagre); 6 | }; 7 | define(['react', 'dagre'], carry); 8 | } else { 9 | // Browser globals 10 | root.DagreReact = factory(root, modules[0], modules[1]); 11 | } 12 | })(this, 13 | (typeof require === 'function' ? 14 | [require('react'), require('dagre')] : 15 | [React, dagre] 16 | ), 17 | function(window, React, dagre) { 18 | 'use strict'; 19 | 20 | var Graph = React.createClass({displayName: 'Graph', 21 | render: function() { 22 | // construct a new graph from scratch 23 | // because dagre mutates g for the layout 24 | var g = new dagre.graphlib.Graph(); 25 | 26 | g.setGraph({}); 27 | 28 | React.Children.forEach(this.props.children, function(child) { 29 | if (child.type === Vertex) { 30 | g.setNode(child.key, { label: child, width: child.props.width, height: child.props.height }); 31 | 32 | } else if (child.type === Edge) { 33 | g.setEdge(child.props.source, child.props.target, { label: child }); 34 | } 35 | }); 36 | 37 | dagre.layout(g); 38 | 39 | // now render 40 | // node svg elements 41 | var nodes = g.nodes().map(function(v) { 42 | var node = g.node(v); 43 | return React.cloneElement(node.label, { 44 | x: node.x, 45 | y: node.y 46 | }); 47 | 48 | }); 49 | var edges = g.edges().map(function(e) { 50 | var edge = g.edge(e); 51 | return React.cloneElement(edge.label, { 52 | points: edge.points 53 | }); 54 | }); 55 | 56 | return ( 57 | React.createElement("g", React.__spread({}, this.props), 58 | nodes, 59 | edges 60 | ) 61 | ); 62 | } 63 | }); 64 | 65 | var Vertex = React.createClass({displayName: 'Vertex', 66 | render: function() { 67 | return ( 68 | React.createElement("g", React.__spread({transform: "translate("+ 69 | (this.props.x-(this.props.width/2))+","+ 70 | (this.props.y-(this.props.height/2))+")"}, 71 | this.props), 72 | 73 | this.props.children 74 | ) 75 | ); 76 | } 77 | }); 78 | 79 | var Edge = React.createClass({displayName: 'Edge', 80 | render: function() { 81 | var points = this.props.points; 82 | 83 | var path = "M" + points[0].x + " " + points[0].y + " "; 84 | for (var i = 1; i < points.length; i++) { 85 | path += "L" + points[i].x + " " + points[i].y + " "; 86 | } 87 | 88 | return React.createElement("path", React.__spread({}, this.props, {d: path})); 89 | } 90 | }); 91 | 92 | var exports = { 93 | Graph: Graph, 94 | Vertex: Vertex, 95 | Edge: Edge 96 | }; 97 | 98 | if (typeof module === 'undefined') { 99 | window.DagreReact = exports; 100 | } else { 101 | module.exports = exports; 102 | } 103 | 104 | return exports; 105 | }); 106 | -------------------------------------------------------------------------------- /index.jsx: -------------------------------------------------------------------------------- 1 | (function(root, modules, factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | // AMD. 4 | var carry = function(React, dagre) { 5 | return factory(root, React, dagre); 6 | }; 7 | define(['react', 'dagre'], carry); 8 | } else { 9 | // Browser globals 10 | root.DagreReact = factory(root, modules[0], modules[1]); 11 | } 12 | })(this, 13 | (typeof require === 'function' ? 14 | [require('react'), require('dagre')] : 15 | [React, dagre] 16 | ), 17 | function(window, React, dagre) { 18 | 'use strict'; 19 | 20 | var Graph = React.createClass({ 21 | render: function() { 22 | // construct a new graph from scratch 23 | // because dagre mutates g for the layout 24 | var g = new dagre.graphlib.Graph(); 25 | 26 | g.setGraph({}); 27 | 28 | React.Children.forEach(this.props.children, function(child) { 29 | if (child.type === Vertex) { 30 | g.setNode(child.key, { label: child, width: child.props.width, height: child.props.height }); 31 | 32 | } else if (child.type === Edge) { 33 | g.setEdge(child.props.source, child.props.target, { label: child }); 34 | } 35 | }); 36 | 37 | dagre.layout(g); 38 | 39 | // now render 40 | // node svg elements 41 | var nodes = g.nodes().map(function(v) { 42 | var node = g.node(v); 43 | return React.cloneElement(node.label, { 44 | x: node.x, 45 | y: node.y 46 | }); 47 | 48 | }); 49 | var edges = g.edges().map(function(e) { 50 | var edge = g.edge(e); 51 | return React.cloneElement(edge.label, { 52 | points: edge.points 53 | }); 54 | }); 55 | 56 | return ( 57 | 58 | {nodes} 59 | {edges} 60 | 61 | ); 62 | } 63 | }); 64 | 65 | var Vertex = React.createClass({ 66 | render: function() { 67 | return ( 68 | 72 | 73 | {this.props.children} 74 | 75 | ); 76 | } 77 | }); 78 | 79 | var Edge = React.createClass({ 80 | render: function() { 81 | var points = this.props.points; 82 | 83 | var path = "M" + points[0].x + " " + points[0].y + " "; 84 | for (var i = 1; i < points.length; i++) { 85 | path += "L" + points[i].x + " " + points[i].y + " "; 86 | } 87 | 88 | return ; 89 | } 90 | }); 91 | 92 | var exports = { 93 | Graph: Graph, 94 | Vertex: Vertex, 95 | Edge: Edge 96 | }; 97 | 98 | if (typeof module === 'undefined') { 99 | window.DagreReact = exports; 100 | } else { 101 | module.exports = exports; 102 | } 103 | 104 | return exports; 105 | }); 106 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dagre-react", 3 | "version": "0.0.1", 4 | "description": "React component that renders directed graphs.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Omar Rizwan", 10 | "license": "MIT", 11 | "dependencies": { 12 | "dagre": "^0.7.1", 13 | "react": "^0.13.2" 14 | }, 15 | "devDependencies": { 16 | "react-tools": "^0.13.2" 17 | } 18 | } 19 | --------------------------------------------------------------------------------