├── .all-contributorsrc ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── CHANGELOG.md ├── Jakefile.js ├── LICENCE.txt ├── README.md ├── lib ├── deps │ ├── attributs.js │ ├── core_ext │ │ ├── fs-ext.js │ │ └── hash.js │ ├── edge.js │ ├── graph.js │ └── node.js ├── ext │ └── gvpr │ │ └── dot2js.g └── graphviz.js ├── package-lock.json ├── package.json └── tests ├── cluster.dot ├── cluster.js ├── compound.js ├── fdpclust.js ├── hello.js ├── hello_world.js ├── memory.js ├── parse.js ├── remove_node.js ├── server ├── app.js ├── static │ └── dotgraph.js └── views │ ├── index.ejs │ └── layout.ejs └── switch.js /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "node-graphviz", 3 | "projectOwner": "glejeune", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": false, 11 | "contributors": [ 12 | { 13 | "login": "glejeune", 14 | "name": "Gregoire Lejeune", 15 | "avatar_url": "https://avatars1.githubusercontent.com/u/15168?v=4", 16 | "profile": "http://lejeun.es", 17 | "contributions": [ 18 | "code", 19 | "doc", 20 | "example" 21 | ] 22 | }, 23 | { 24 | "login": "dariusk", 25 | "name": "Darius Kazemi", 26 | "avatar_url": "https://avatars3.githubusercontent.com/u/266454?v=4", 27 | "profile": "https://tinysubversions.com", 28 | "contributions": [ 29 | "code" 30 | ] 31 | }, 32 | { 33 | "login": "SebastienElet", 34 | "name": "Sébastien ELET", 35 | "avatar_url": "https://avatars0.githubusercontent.com/u/541937?v=4", 36 | "profile": "https://github.com/SebastienElet", 37 | "contributions": [ 38 | "code" 39 | ] 40 | }, 41 | { 42 | "login": "papandreou", 43 | "name": "Andreas Lind", 44 | "avatar_url": "https://avatars3.githubusercontent.com/u/373545?v=4", 45 | "profile": "https://github.com/papandreou", 46 | "contributions": [ 47 | "code" 48 | ] 49 | }, 50 | { 51 | "login": "blakmatrix", 52 | "name": "Farrin Reid", 53 | "avatar_url": "https://avatars3.githubusercontent.com/u/91209?v=4", 54 | "profile": "http://www.blakmatrix.com", 55 | "contributions": [ 56 | "code" 57 | ] 58 | }, 59 | { 60 | "login": "pahen", 61 | "name": "Patrik Henningsson", 62 | "avatar_url": "https://avatars3.githubusercontent.com/u/353888?v=4", 63 | "profile": "https://pahen.se", 64 | "contributions": [ 65 | "code" 66 | ] 67 | }, 68 | { 69 | "login": "pooriaazimi", 70 | "name": "Pooria Azimi", 71 | "avatar_url": "https://avatars2.githubusercontent.com/u/814637?v=4", 72 | "profile": "https://github.com/pooriaazimi", 73 | "contributions": [ 74 | "code" 75 | ] 76 | }, 77 | { 78 | "login": "BridgeAR", 79 | "name": "Ruben Bridgewater", 80 | "avatar_url": "https://avatars2.githubusercontent.com/u/8822573?v=4", 81 | "profile": "https://twitter.com/BridgeAR", 82 | "contributions": [ 83 | "code" 84 | ] 85 | }, 86 | { 87 | "login": "mathieuravaux", 88 | "name": "Mathieu Ravaux", 89 | "avatar_url": "https://avatars1.githubusercontent.com/u/38495?v=4", 90 | "profile": "https://github.com/mathieuravaux", 91 | "contributions": [ 92 | "code" 93 | ] 94 | } 95 | ], 96 | "contributorsPerLine": 7 97 | } 98 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/data 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "extends": ["airbnb-base", "prettier", "plugin:promise/recommended", "plugin:node/recommended"], 4 | "env": { 5 | "node": true 6 | }, 7 | "plugins": ["promise"], 8 | "rules": { 9 | "global-require": "off", 10 | "vars-on-top": "off", 11 | "dot-notation": "off", 12 | "guard-for-in": "off", 13 | "func-names": "off", 14 | "one-var": "off", 15 | "no-underscore-dangle": "off", 16 | "no-plusplus": "off", 17 | "no-process-exit": "off", 18 | "no-bitwise": "off", 19 | "no-extend-native": "off", 20 | "handle-callback-err": ["error", "^(err|error)$"], 21 | "camelcase": ["error", { "properties": "never" }], 22 | "no-use-before-define": ["error", "nofunc"], 23 | "no-mixed-requires": ["warn", { "grouping": true }], 24 | "id-length": ["warn", { "min": 2, "exceptions": ["i", "_"] }], 25 | "no-unused-expressions": ["error", { "allowShortCircuit": true }], 26 | "no-param-reassign": ["warn"], 27 | "no-unused-vars": ["error", { "varsIgnorePattern": "^_.+", "argsIgnorePattern": "^_" }] 28 | }, 29 | "parserOptions": { 30 | "ecmaVersion": 2018 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | doc 3 | pkg 4 | test/output/ 5 | documentation.html 6 | node_modules/ 7 | test/*.png 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "printWidth": 120, 5 | "semi": true 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [0.0.9](https://github.com/glejeune/node-graphviz/tree/0.0.9) (2019-04-03) 4 | [Full Changelog](https://github.com/glejeune/node-graphviz/compare/0.0.8...0.0.9) 5 | 6 | **Closed issues:** 7 | 8 | - Is it possible to create a stripped down version for browsers that only generates dot code? [\#15](https://github.com/glejeune/node-graphviz/issues/15) 9 | - Is there a way to tell this library to ignore duplicate edges? [\#13](https://github.com/glejeune/node-graphviz/issues/13) 10 | - How to get x,y coords for a node? [\#11](https://github.com/glejeune/node-graphviz/issues/11) 11 | 12 | **Merged pull requests:** 13 | 14 | - Fix missing error handling [\#26](https://github.com/glejeune/node-graphviz/pull/26) ([BridgeAR](https://github.com/BridgeAR)) 15 | - Fixing `for in` loops [\#17](https://github.com/glejeune/node-graphviz/pull/17) ([dariusk](https://github.com/dariusk)) 16 | - Node setter is now fluent. [\#16](https://github.com/glejeune/node-graphviz/pull/16) ([SebastienElet](https://github.com/SebastienElet)) 17 | 18 | ## [0.0.8](https://github.com/glejeune/node-graphviz/tree/0.0.8) (2012-08-04) 19 | [Full Changelog](https://github.com/glejeune/node-graphviz/compare/0.0.7...0.0.8) 20 | 21 | **Closed issues:** 22 | 23 | - Clickable Nodes [\#10](https://github.com/glejeune/node-graphviz/issues/10) 24 | 25 | **Merged pull requests:** 26 | 27 | - `npm install node-graphviz` --\> `npm install graphviz` [\#9](https://github.com/glejeune/node-graphviz/pull/9) ([pooriaazimi](https://github.com/pooriaazimi)) 28 | 29 | ## [0.0.7](https://github.com/glejeune/node-graphviz/tree/0.0.7) (2012-07-01) 30 | [Full Changelog](https://github.com/glejeune/node-graphviz/compare/0.0.6...0.0.7) 31 | 32 | **Closed issues:** 33 | 34 | - Publish 0.0.6 with correct dependency on 'temp' to the npm repo? [\#5](https://github.com/glejeune/node-graphviz/issues/5) 35 | 36 | **Merged pull requests:** 37 | 38 | - Fixed so it can be installed on v0.8. Please bump version & update the NPM repo :\) [\#7](https://github.com/glejeune/node-graphviz/pull/7) ([pahen](https://github.com/pahen)) 39 | - Hi! I fixed some calls to "sys" for you! [\#6](https://github.com/glejeune/node-graphviz/pull/6) ([node-migrator-bot](https://github.com/node-migrator-bot)) 40 | 41 | ## [0.0.6](https://github.com/glejeune/node-graphviz/tree/0.0.6) (2012-01-27) 42 | [Full Changelog](https://github.com/glejeune/node-graphviz/compare/0.0.5...0.0.6) 43 | 44 | **Closed issues:** 45 | 46 | - Error: EPIPE, Broken pipe [\#3](https://github.com/glejeune/node-graphviz/issues/3) 47 | - Graph.prototype.getNodeAttribut [\#2](https://github.com/glejeune/node-graphviz/issues/2) 48 | 49 | ## [0.0.5](https://github.com/glejeune/node-graphviz/tree/0.0.5) (2011-12-14) 50 | [Full Changelog](https://github.com/glejeune/node-graphviz/compare/0.0.4...0.0.5) 51 | 52 | **Merged pull requests:** 53 | 54 | - graphviz.js: Don't require the 'sys' module. [\#4](https://github.com/glejeune/node-graphviz/pull/4) ([papandreou](https://github.com/papandreou)) 55 | 56 | ## [0.0.4](https://github.com/glejeune/node-graphviz/tree/0.0.4) (2010-11-16) 57 | [Full Changelog](https://github.com/glejeune/node-graphviz/compare/0.0.3...0.0.4) 58 | 59 | ## [0.0.3](https://github.com/glejeune/node-graphviz/tree/0.0.3) (2010-10-04) 60 | [Full Changelog](https://github.com/glejeune/node-graphviz/compare/0.0.2...0.0.3) 61 | 62 | ## [0.0.2](https://github.com/glejeune/node-graphviz/tree/0.0.2) (2010-09-29) 63 | 64 | 65 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* -------------------------------------------------------------------------------- /Jakefile.js: -------------------------------------------------------------------------------- 1 | // This file is a node-jake file -- http://github.com/mde/node-jake 2 | 3 | var util = require('util'), 4 | exec = require('child_process').exec, 5 | child; 6 | 7 | var docTitle = 'node-graphviz' 8 | var docFiles = 'lib/graphviz.js lib/deps/graph.js lib/deps/node.js lib/deps/edge.js' 9 | var outputDocFile = 'documentation.json' 10 | var docRibbon = 'http://github.com/glejeune/node-graphviz' 11 | var docDesc = '[Node.js](http://nodejs.org) interface to the [GraphViz](http://graphviz.org) graphing tool' 12 | 13 | desc('Generate node-graphviz documentation.'); 14 | task('doc', [], function () { 15 | child = exec('dox -r ' + docRibbon + ' -d "' + docDesc + '" -t "' + docTitle + '" < ' + docFiles + ' > ' + outputDocFile, 16 | function (error, stdout, stderr) { 17 | if (error !== null) { 18 | console.log('exec error: ' + error); 19 | } 20 | }); 21 | }); 22 | 23 | desc('Install'); 24 | task('install', [], function() { 25 | child = exec('npm install .', 26 | function(error, stdout, stderr) { 27 | if (error !== null) { 28 | console.log('exec error: ' + error); 29 | } 30 | } 31 | ); 32 | }); 33 | 34 | desc('Publish'); 35 | task('publish', [], function() { 36 | child = exec('npm publish .', 37 | function(error, stdout, stderr) { 38 | if (error !== null) { 39 | console.log('exec error: ' + error); 40 | } 41 | } 42 | ); 43 | }); 44 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Gregoire Lejeune 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.js GraphViz Module 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors) 4 | 5 | Copyright (C) 2010-2019 Gregoire Lejeune 6 | 7 | * Sources : http://github.com/glejeune/node-graphviz 8 | 9 | ## DESCRIPTION 10 | 11 | Interface to the GraphViz graphing tool 12 | 13 | ## SYNOPSIS 14 | 15 | A basic example 16 | 17 | ```javascript 18 | var util = require('util'), 19 | graphviz = require('graphviz'); 20 | 21 | // Create digraph G 22 | var g = graphviz.digraph("G"); 23 | 24 | // Add node (ID: Hello) 25 | var n1 = g.addNode( "Hello", {"color" : "blue"} ); 26 | n1.set( "style", "filled" ); 27 | 28 | // Add node (ID: World) 29 | g.addNode( "World" ); 30 | 31 | // Add edge between the two nodes 32 | var e = g.addEdge( n1, "World" ); 33 | e.set( "color", "red" ); 34 | 35 | // Print the dot script 36 | console.log( g.to_dot() ); 37 | 38 | // Set GraphViz path (if not in your path) 39 | g.setGraphVizPath( "/usr/local/bin" ); 40 | // Generate a PNG output 41 | g.output( "png", "test01.png" ); 42 | ``` 43 | 44 | ## INSTALLATION 45 | 46 | ``` 47 | $ npm install graphviz 48 | ``` 49 | 50 | You also need to install [GraphViz](http://www.graphviz.org) 51 | 52 | ## DOCUMENTATION 53 | 54 | To build the documentation: 55 | 56 | ```bash 57 | npm install -g jake dox 58 | jake doc & open documentation.json 59 | ``` 60 | 61 | ## AUTHORS 62 | 63 | * Gregoire Lejeune (http://algorithmique.net) 64 | * Mathieu Ravaux (http://mathieuravaux.com) 65 | 66 | ## LICENCES 67 | 68 | Copyright (c) 2010 Gregoire Lejeune 69 | 70 | Permission is hereby granted, free of charge, to any person obtaining a copy 71 | of this software and associated documentation files (the "Software"), to deal 72 | in the Software without restriction, including without limitation the rights 73 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 74 | copies of the Software, and to permit persons to whom the Software is 75 | furnished to do so, subject to the following conditions: 76 | 77 | The above copyright notice and this permission notice shall be included in 78 | all copies or substantial portions of the Software. 79 | 80 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 81 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 82 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 83 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 84 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 85 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 86 | THE SOFTWARE. 87 | 88 | 89 | ## Contributors 90 | 91 | Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)): 92 | 93 | 94 | 95 |
Gregoire Lejeune
Gregoire Lejeune

💻 📖 💡
Darius Kazemi
Darius Kazemi

💻
Sébastien ELET
Sébastien ELET

💻
Andreas Lind
Andreas Lind

💻
Farrin Reid
Farrin Reid

💻
Patrik Henningsson
Patrik Henningsson

💻
Pooria Azimi
Pooria Azimi

💻
Ruben Bridgewater
Ruben Bridgewater

💻
Mathieu Ravaux
Mathieu Ravaux

💻
96 | 97 | 98 | 99 | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! 100 | -------------------------------------------------------------------------------- /lib/deps/attributs.js: -------------------------------------------------------------------------------- 1 | var Hash = require('./core_ext/hash').Hash, 2 | util = require('util'); 3 | 4 | var attrs = { 5 | Damping: { usage: 'G', type: 'double' }, 6 | K: { usage: 'GC', type: 'double' }, 7 | URL: { usage: 'ENGC', type: 'escString' }, 8 | area: { usage: 'NC', type: 'double' }, 9 | arrowhead: { usage: 'E', type: 'arrowType' }, 10 | arrowsize: { usage: 'E', type: 'double' }, 11 | arrowtail: { usage: 'E', type: 'arrowType' }, 12 | aspect: { usage: 'G', type: 'aspectType' }, 13 | bb: { usage: 'G', type: 'rect' }, 14 | bgcolor: { usage: 'GC', type: 'color' }, 15 | center: { usage: 'G', type: 'bool' }, 16 | charset: { usage: 'G', type: 'string' }, 17 | clusterrank: { usage: 'G', type: 'clusterMode' }, 18 | color: { usage: 'ENC', type: 'color' }, 19 | colorscheme: { usage: 'ENCG', type: 'string' }, 20 | comment: { usage: 'ENG', type: 'string' }, 21 | compound: { usage: 'G', type: 'bool' }, 22 | concentrate: { usage: 'G', type: 'bool' }, 23 | constraint: { usage: 'E', type: 'bool' }, 24 | decorate: { usage: 'E', type: 'bool' }, 25 | defaultdist: { usage: 'G', type: 'double' }, 26 | dim: { usage: 'G', type: 'int' }, 27 | dimen: { usage: 'G', type: 'int' }, 28 | dir: { usage: 'E', type: 'dirType' }, 29 | diredgeconstraints: { usage: 'G', type: 'string' }, 30 | distortion: { usage: 'N', type: 'double' }, 31 | dpi: { usage: 'G', type: 'double' }, 32 | edgeURL: { usage: 'E', type: 'escString' }, 33 | edgehref: { usage: 'E', type: 'escString' }, 34 | edgetarget: { usage: 'E', type: 'escString' }, 35 | edgetooltip: { usage: 'E', type: 'escString' }, 36 | epsilon: { usage: 'G', type: 'double' }, 37 | esep: { usage: 'G', type: 'double' }, 38 | fillcolor: { usage: 'NEC', type: 'color' }, 39 | fixedsize: { usage: 'N', type: 'bool' }, 40 | fontcolor: { usage: 'ENGC', type: 'color' }, 41 | fontname: { usage: 'ENGC', type: 'string' }, 42 | fontnames: { usage: 'G', type: 'string' }, 43 | fontpath: { usage: 'G', type: 'string' }, 44 | fontsize: { usage: 'ENGC', type: 'double' }, 45 | group: { usage: 'N', type: 'string' }, 46 | headURL: { usage: 'E', type: 'escString' }, 47 | headclip: { usage: 'E', type: 'bool' }, 48 | headhref: { usage: 'E', type: 'escString' }, 49 | headlabel: { usage: 'E', type: 'lblString' }, 50 | headport: { usage: 'E', type: 'portPos' }, 51 | headtarget: { usage: 'E', type: 'escString' }, 52 | headtooltip: { usage: 'E', type: 'escString' }, 53 | height: { usage: 'N', type: 'double' }, 54 | href: { usage: 'ENGC', type: 'escString' }, 55 | id: { usage: 'GNE', type: 'lblString' }, 56 | image: { usage: 'N', type: 'string' }, 57 | imagepath: { usage: 'G', type: 'string' }, 58 | imagescale: { usage: 'N', type: 'string' }, 59 | label: { usage: 'ENGC', type: 'lblString' }, 60 | labelURL: { usage: 'E', type: 'escString' }, 61 | labelangle: { usage: 'E', type: 'double' }, 62 | labeldistance: { usage: 'E', type: 'double' }, 63 | labelfloat: { usage: 'E', type: 'bool' }, 64 | labelfontcolor: { usage: 'E', type: 'color' }, 65 | labelfontname: { usage: 'E', type: 'string' }, 66 | labelfontsize: { usage: 'E', type: 'double' }, 67 | labelhref: { usage: 'E', type: 'escString' }, 68 | labeljust: { usage: 'GC', type: 'string' }, 69 | labelloc: { usage: 'NGC', type: 'string' }, 70 | labeltarget: { usage: 'E', type: 'escString' }, 71 | labeltooltip: { usage: 'E', type: 'escString' }, 72 | landscape: { usage: 'G', type: 'bool' }, 73 | layer: { usage: 'ENC', type: 'layerRange' }, 74 | layerlistsep: { usage: 'G', type: 'string' }, 75 | layers: { usage: 'G', type: 'layerList' }, 76 | layerselect: { usage: 'G', type: 'layerRange' }, 77 | layersep: { usage: 'G', type: 'string' }, 78 | layout: { usage: 'G', type: 'string' }, 79 | len: { usage: 'E', type: 'double' }, 80 | levels: { usage: 'G', type: 'int' }, 81 | levelsgap: { usage: 'G', type: 'double' }, 82 | lhead: { usage: 'E', type: 'string' }, 83 | lheight: { usage: 'GC', type: 'double' }, 84 | lp: { usage: 'EGC', type: 'point' }, 85 | ltail: { usage: 'E', type: 'string' }, 86 | lwidth: { usage: 'GC', type: 'double' }, 87 | margin: { usage: 'NGC', type: 'pointf' }, 88 | maxiter: { usage: 'G', type: 'int' }, 89 | mclimit: { usage: 'G', type: 'double' }, 90 | mindist: { usage: 'G', type: 'double' }, 91 | minlen: { usage: 'E', type: 'int' }, 92 | mode: { usage: 'G', type: 'string' }, 93 | model: { usage: 'G', type: 'string' }, 94 | mosek: { usage: 'G', type: 'bool' }, 95 | nodesep: { usage: 'G', type: 'double' }, 96 | nojustify: { usage: 'GCNE', type: 'bool' }, 97 | normalize: { usage: 'G', type: 'bool' }, 98 | nslimit: { usage: 'G', type: 'double' }, 99 | nslimit1: { usage: 'G', type: 'double' }, 100 | ordering: { usage: 'GN', type: 'string' }, 101 | orientation: { usage: 'GN', type: 'string' }, 102 | outputorder: { usage: 'G', type: 'outputMode' }, 103 | overlap: { usage: 'G', type: 'string' }, 104 | overlap_scaling: { usage: 'G', type: 'double' }, 105 | pack: { usage: 'G', type: 'int' }, 106 | packmode: { usage: 'G', type: 'packMode' }, 107 | pad: { usage: 'G', type: 'pointf' }, 108 | page: { usage: 'G', type: 'pointf' }, 109 | pagedir: { usage: 'G', type: 'pagedir' }, 110 | pencolor: { usage: 'C', type: 'color' }, 111 | penwidth: { usage: 'CNE', type: 'double' }, 112 | peripheries: { usage: 'NC', type: 'int' }, 113 | pin: { usage: 'N', type: 'bool' }, 114 | pos: { usage: 'EN', type: 'point' }, 115 | quadtree: { usage: 'G', type: 'quadType' }, 116 | quantum: { usage: 'G', type: 'double' }, 117 | rank: { usage: 'S', type: 'rankType' }, 118 | rankdir: { usage: 'G', type: 'rankdir' }, 119 | ranksep: { usage: 'G', type: 'double' }, 120 | ratio: { usage: 'G', type: 'string' }, 121 | rects: { usage: 'N', type: 'rect' }, 122 | regular: { usage: 'N', type: 'bool' }, 123 | remincross: { usage: 'G', type: 'bool' }, 124 | repulsiveforce: { usage: 'G', type: 'double' }, 125 | resolution: { usage: 'G', type: 'double' }, 126 | root: { usage: 'GN', type: 'string' }, 127 | rotate: { usage: 'G', type: 'int' }, 128 | rotation: { usage: 'G', type: 'double' }, 129 | samehead: { usage: 'E', type: 'string' }, 130 | sametail: { usage: 'E', type: 'string' }, 131 | samplepoints: { usage: 'N', type: 'int' }, 132 | scale: { usage: 'G', type: 'double' }, 133 | searchsize: { usage: 'G', type: 'int' }, 134 | sep: { usage: 'G', type: 'double' }, 135 | shape: { usage: 'N', type: 'shape' }, 136 | shapefile: { usage: 'N', type: 'string' }, 137 | showboxes: { usage: 'ENG', type: 'int' }, 138 | sides: { usage: 'N', type: 'int' }, 139 | size: { usage: 'G', type: 'pointf' }, 140 | skew: { usage: 'N', type: 'double' }, 141 | smoothing: { usage: 'G', type: 'smoothType' }, 142 | sortv: { usage: 'GCN', type: 'int' }, 143 | splines: { usage: 'G', type: 'string' }, 144 | start: { usage: 'G', type: 'startType' }, 145 | style: { usage: 'ENCG', type: 'style' }, 146 | stylesheet: { usage: 'G', type: 'string' }, 147 | tail_lp: { usage: 'E', type: 'pointf' }, 148 | tailURL: { usage: 'E', type: 'escString' }, 149 | tailclip: { usage: 'E', type: 'bool' }, 150 | tailhref: { usage: 'E', type: 'escString' }, 151 | taillabel: { usage: 'E', type: 'lblString' }, 152 | tailport: { usage: 'E', type: 'portPos' }, 153 | tailtarget: { usage: 'E', type: 'escString' }, 154 | tailtooltip: { usage: 'E', type: 'escString' }, 155 | target: { usage: 'ENGC', type: 'escString' }, 156 | tooltip: { usage: 'NEC', type: 'escString' }, 157 | truecolor: { usage: 'G', type: 'bool' }, 158 | vertices: { usage: 'N', type: 'pointfList' }, 159 | viewport: { usage: 'G', type: 'viewPort' }, 160 | voro_margin: { usage: 'G', type: 'double' }, 161 | weight: { usage: 'E', type: 'double' }, 162 | width: { usage: 'N', type: 'double' }, 163 | xlabel: { usage: 'EN', type: 'lblString' }, 164 | z: { usage: 'N', type: 'double' }, 165 | }; 166 | 167 | var gType = { 168 | E: 'edge', 169 | N: 'node', 170 | G: 'graph', 171 | C: 'cluster', 172 | }; 173 | 174 | var quotedTypes = [ 175 | 'escString', 176 | 'rect', 177 | 'color', 178 | 'colorList', 179 | 'string', 180 | 'lblString', 181 | 'portPos', 182 | 'point', 183 | 'pointf', 184 | 'pointfList', 185 | 'splineType', 186 | 'style', 187 | 'viewPort', 188 | ]; 189 | 190 | function mustBeQuoted(data) { 191 | return quotedTypes.indexOf(attrs[data].type) !== -1; 192 | } 193 | 194 | function quoteMe(attr, value) { 195 | if (value[0] === '!') { 196 | return '<' + value.substr(1, 1000) + '>'; 197 | } else if (mustBeQuoted(attr)) { 198 | return ' "' + value + '"'; 199 | } else { 200 | return value; 201 | } 202 | } 203 | 204 | function validateAttribut(name, type) { 205 | if (attrs[name]) { 206 | return attrs[name].usage.indexOf(type) > -1; 207 | } else { 208 | return false; 209 | } 210 | } 211 | 212 | exports.isValid = function(name, type) { 213 | return validateAttribut(name, type); 214 | }; 215 | 216 | var Attributs = (exports.Attributs = function(t) { 217 | this._type = t; 218 | this.attributs = new Hash(); 219 | }); 220 | 221 | Attributs.prototype.length = function() { 222 | return this.attributs.length; 223 | }; 224 | 225 | Attributs.prototype.set = function(name, value) { 226 | if (validateAttribut(name, this._type) === false) { 227 | console.error('Warning : Invalid attribut `' + name + "' for a " + gType[this._type]); 228 | // throw "Invalid attribut `"+name+"' for a "+gType[this._type] 229 | } 230 | this.attributs.setItem(name, value); 231 | }; 232 | 233 | Attributs.prototype.get = function(name) { 234 | return this.attributs.items[name]; 235 | }; 236 | 237 | Attributs.prototype.to_dot = function(link) { 238 | var attrsOutput = '', 239 | sep = ''; 240 | 241 | if (this.attributs.length > 0) { 242 | attrsOutput = attrsOutput + ' [ '; 243 | for (var name in this.attributs.items) { 244 | if (this.attributs.items.hasOwnProperty(name)) { 245 | attrsOutput = attrsOutput + sep + name + ' =' + quoteMe(name, this.attributs.items[name]); 246 | sep = ', '; 247 | } 248 | } 249 | attrsOutput = attrsOutput + ' ]'; 250 | } 251 | 252 | return attrsOutput; 253 | }; 254 | -------------------------------------------------------------------------------- /lib/deps/core_ext/fs-ext.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | exports.exist = function(path) { 4 | try { 5 | fs.statSync(path); 6 | } catch (e) { 7 | return false; 8 | } 9 | return true; 10 | }; 11 | -------------------------------------------------------------------------------- /lib/deps/core_ext/hash.js: -------------------------------------------------------------------------------- 1 | var Hash = (exports.Hash = function() { 2 | this.length = 0; 3 | this.items = new Array(); 4 | for (var i = 0; i < arguments.length; i += 2) { 5 | if (typeof arguments[i + 1] != 'undefined') { 6 | this.items[arguments[i]] = arguments[i + 1]; 7 | this.length++; 8 | } 9 | } 10 | }); 11 | 12 | Hash.prototype.removeItem = function(in_key) { 13 | var tmp_previous; 14 | if (typeof this.items[in_key] != 'undefined') { 15 | this.length--; 16 | var tmp_previous = this.items[in_key]; 17 | delete this.items[in_key]; 18 | } 19 | 20 | return tmp_previous; 21 | }; 22 | 23 | Hash.prototype.getItem = function(in_key) { 24 | return this.items[in_key]; 25 | }; 26 | 27 | Hash.prototype.setItem = function(in_key, in_value) { 28 | var tmp_previous; 29 | if (typeof in_value != 'undefined') { 30 | if (typeof this.items[in_key] == 'undefined') { 31 | this.length++; 32 | } else { 33 | tmp_previous = this.items[in_key]; 34 | } 35 | 36 | this.items[in_key] = in_value; 37 | } 38 | 39 | return tmp_previous; 40 | }; 41 | 42 | Hash.prototype.hasItem = function(in_key) { 43 | return typeof this.items[in_key] != 'undefined'; 44 | }; 45 | 46 | Hash.prototype.clear = function() { 47 | for (var i in this.items) { 48 | delete this.items[i]; 49 | } 50 | 51 | this.length = 0; 52 | }; 53 | -------------------------------------------------------------------------------- /lib/deps/edge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies 3 | */ 4 | var Hash = require('./core_ext/hash').Hash, 5 | Attributs = require('./attributs').Attributs; 6 | 7 | /** 8 | * Create a new edge 9 | * @constructor 10 | * @param {Graph} graph Parent Graph 11 | * @param {String|Node} nodeOne The first node 12 | * @param {String|Node} nodeTwo The second node 13 | * @return {Edge} 14 | * @api public 15 | */ 16 | var Edge = (exports.Edge = function(graph, nodeOne, nodeTwo) { 17 | this.relativeGraph = graph; 18 | this.nodeOne = nodeOne; 19 | this.nodeTwo = nodeTwo; 20 | this.attributs = new Attributs('E'); 21 | }); 22 | 23 | /** 24 | * Set an edge attribut 25 | * 26 | * @param {String} name The attribut name 27 | * @param {Void} value The attribut value 28 | * @api public 29 | */ 30 | Edge.prototype.set = function(name, value) { 31 | this.attributs.set(name, value); 32 | return this; 33 | }; 34 | 35 | /** 36 | * Get an edge attribut 37 | * 38 | * @param {String} name The attribut name 39 | * @return {Void} 40 | * @api public 41 | */ 42 | Edge.prototype.get = function(name) { 43 | return this.attributs.get(name); 44 | }; 45 | 46 | /** 47 | * @api private 48 | */ 49 | Edge.prototype.to_dot = function() { 50 | var edgeLink = '->'; 51 | if (this.relativeGraph.type === 'graph') { 52 | edgeLink = '--'; 53 | } 54 | 55 | var edgeOutput = '"' + this.nodeOne.id + '"' + ' ' + edgeLink + ' ' + '"' + this.nodeTwo.id + '"'; 56 | edgeOutput = edgeOutput + this.attributs.to_dot(); 57 | return edgeOutput; 58 | }; 59 | -------------------------------------------------------------------------------- /lib/deps/graph.js: -------------------------------------------------------------------------------- 1 | var which = require('which'); 2 | 3 | /** 4 | * Module dependencies 5 | */ 6 | var Hash = require('./core_ext/hash').Hash, 7 | Node = require('./node').Node, 8 | Edge = require('./edge').Edge, 9 | gvattrs = require('./attributs'), 10 | Attributs = gvattrs.Attributs, 11 | util = require('util'), 12 | path = require('path'), 13 | spawn = require('child_process').spawn; 14 | 15 | /** 16 | * Create a new graph 17 | * @constructor 18 | * @param {Graph} graph Parent Graph 19 | * @param {String} id The graphID 20 | * @return {Graph} 21 | * @api public 22 | */ 23 | var Graph = (exports.Graph = function(graph, id) { 24 | this.relativeGraph = graph; 25 | this.id = id; 26 | this.type = 'graph'; 27 | this.isStrict = false; 28 | this.gvPath = ''; 29 | this.nodes = new Hash(); 30 | this.edges = new Array(); 31 | this.clusters = new Hash(); 32 | if (this.relativeGraph == null) { 33 | this.graphAttributs = new Attributs('G'); 34 | } else { 35 | this.graphAttributs = new Attributs('C'); 36 | } 37 | this.nodesAttributs = new Attributs('N'); 38 | this.edgesAttributs = new Attributs('E'); 39 | this.use = 'dot'; 40 | }); 41 | 42 | /** 43 | * Create a new node 44 | * 45 | * @param {String} id The node ID 46 | * @param {Object} attrs Node attributs 47 | * @return {Node} 48 | * @api public 49 | */ 50 | Graph.prototype.addNode = function(id, attrs) { 51 | this.nodes.setItem(id, new Node(this, id)); 52 | if (attrs) { 53 | for (k in attrs) { 54 | this.nodes.items[id].set(k, attrs[k]); 55 | } 56 | } 57 | 58 | return this.nodes.items[id]; 59 | }; 60 | 61 | /** 62 | * Remove a node 63 | * 64 | * @param {String} id The node ID 65 | * @param {Boolean} force Remove edges related to node 66 | * @api public 67 | */ 68 | Graph.prototype.removeNode = function(id, force) { 69 | if (force === true) { 70 | for (i = 0; i < this.edges.length; ++i) { 71 | if (this.edges[i].nodeOne.id == id || this.edges[i].nodeTwo.id == id) { 72 | delete this.edges[i]; 73 | } 74 | } 75 | } 76 | this.nodes.removeItem(id); 77 | }; 78 | 79 | /** 80 | * Return a node for a given ID 81 | * 82 | * @param {String} id The node ID 83 | * @return {Node} 84 | * @api public 85 | */ 86 | Graph.prototype.getNode = function(id) { 87 | return this.nodes.items[id]; 88 | }; 89 | 90 | Graph.prototype.from = function(id) { 91 | if (this.nodes.items[id] == undefined) { 92 | this.addNode(id); 93 | } 94 | return this.nodes.items[id]; 95 | }; 96 | 97 | /** 98 | * Return the number of nodes in the current graph 99 | * 100 | * @return {Integer} 101 | * @api public 102 | */ 103 | Graph.prototype.nodeCount = function() { 104 | return this.nodes.length; 105 | }; 106 | 107 | /** 108 | * Create a new edge 109 | * 110 | * @param {String|Node} nodeOne 111 | * @param {String|Node} nodeTwo 112 | * @param {Object} attrs Node attributs 113 | * @return {Edge} 114 | * @api public 115 | */ 116 | Graph.prototype.addEdge = function(nodeOne, nodeTwo, attrs) { 117 | var _nodeOne = nodeOne; 118 | var _nodeTwo = nodeTwo; 119 | if (typeof nodeOne == 'string') { 120 | _nodeOne = this.nodes.items[nodeOne]; 121 | if (_nodeOne == null) { 122 | _nodeOne = this.addNode(nodeOne); 123 | } 124 | } 125 | if (typeof nodeTwo == 'string') { 126 | _nodeTwo = this.nodes.items[nodeTwo]; 127 | if (_nodeTwo == null) { 128 | _nodeTwo = this.addNode(nodeTwo); 129 | } 130 | } 131 | 132 | var edge = new Edge(this, _nodeOne, _nodeTwo); 133 | if (attrs) { 134 | for (k in attrs) { 135 | edge.set(k, attrs[k]); 136 | } 137 | } 138 | this.edges.push(edge); 139 | 140 | return edge; 141 | }; 142 | 143 | /** 144 | * Return the number of edges in the current graph 145 | * 146 | * @return {Integer} 147 | * @api public 148 | */ 149 | Graph.prototype.edgeCount = function() { 150 | return this.edges.length; 151 | }; 152 | 153 | /** 154 | * Create a new subgraph 155 | * 156 | * @param {String} id The subgraph ID 157 | * @return {Graph} 158 | * @api public 159 | */ 160 | Graph.prototype.addCluster = function(id) { 161 | var cluster = new Graph(this, id); 162 | cluster.type = this.type; 163 | this.clusters.setItem(id, cluster); 164 | return cluster; 165 | }; 166 | 167 | /** 168 | * Return a subgraph for a given ID 169 | * 170 | * @param {String} id The subgraph ID 171 | * @return {Graph} 172 | * @api public 173 | */ 174 | Graph.prototype.getCluster = function(id) { 175 | return this.clusters.items[id]; 176 | }; 177 | 178 | /** 179 | * Return the number of subgraphs in the current graph 180 | * 181 | * @return {Integer} 182 | * @api public 183 | */ 184 | Graph.prototype.clusterCount = function() { 185 | return this.clusters.length; 186 | }; 187 | 188 | /** 189 | * Set a graph attribut 190 | * 191 | * @param {String} name The attribut name 192 | * @param {Void} value The attribut value 193 | * @api public 194 | */ 195 | Graph.prototype.set = function(name, value) { 196 | this.graphAttributs.set(name, value); 197 | }; 198 | 199 | /** 200 | * Get a graph attribut 201 | * 202 | * @param {String} name The attribut name 203 | * @return {Void} 204 | * @api public 205 | */ 206 | Graph.prototype.get = function(name) { 207 | return this.graphAttributs.get(name); 208 | }; 209 | 210 | /** 211 | * Set a global node attribut 212 | * 213 | * @param {String} name The attribut name 214 | * @param {Void} value The attribut value 215 | * @api public 216 | */ 217 | Graph.prototype.setNodeAttribut = function(name, value) { 218 | this.nodesAttributs.set(name, value); 219 | }; 220 | 221 | /** 222 | * Get a global node attribut 223 | * 224 | * @param {String} name The attribut name 225 | * @return {Void} 226 | * @api public 227 | */ 228 | Graph.prototype.getNodeAttribut = function(name) { 229 | return this.nodesAttributs.get(name); 230 | }; 231 | 232 | /** 233 | * Set a global edge attribut 234 | * 235 | * @param {String} name The attribut name 236 | * @param {Void} value The attribut value 237 | * @api public 238 | */ 239 | Graph.prototype.setEdgeAttribut = function(name, value) { 240 | this.edgesAttributs.set(name, value); 241 | }; 242 | 243 | /** 244 | * Get a global edge attribut 245 | * 246 | * @param {String} name The attribut name 247 | * @return {Void} 248 | * @api public 249 | */ 250 | Graph.prototype.getEdgeAttribut = function(name) { 251 | return this.edgesAttributs.get(name); 252 | }; 253 | 254 | /** 255 | * Generate the GraphViz script 256 | * 257 | * @return {String} 258 | * @api public 259 | */ 260 | Graph.prototype.to_dot = function() { 261 | var dotScript = ''; 262 | if (this.relativeGraph == null) { 263 | dotScript = this.type + ' "' + this.id + '" {\n'; 264 | if(this.isStrict){ 265 | dotScript = 'strict '+dotScript 266 | } 267 | } else { 268 | dotScript = 'subgraph "' + this.id + '" {\n'; 269 | } 270 | 271 | // Graph attributs 272 | if (this.graphAttributs.length() > 0) { 273 | dotScript = dotScript + ' graph' + this.graphAttributs.to_dot() + ';\n'; 274 | } 275 | 276 | // Nodes attributs 277 | if (this.nodesAttributs.length() > 0) { 278 | dotScript = dotScript + ' node' + this.nodesAttributs.to_dot() + ';\n'; 279 | } 280 | 281 | // Edges attributs 282 | if (this.edgesAttributs.length() > 0) { 283 | dotScript = dotScript + ' edge' + this.edgesAttributs.to_dot() + ';\n'; 284 | } 285 | 286 | // Each clusters 287 | for (var id in this.clusters.items) { 288 | if (this.clusters.items.hasOwnProperty(id)) { 289 | dotScript = dotScript + this.clusters.items[id].to_dot() + '\n'; 290 | } 291 | } 292 | 293 | // Each nodes 294 | for (var id in this.nodes.items) { 295 | if (this.nodes.items.hasOwnProperty(id)) { 296 | dotScript = dotScript + ' ' + this.nodes.items[id].to_dot() + ';\n'; 297 | } 298 | } 299 | 300 | // Each edges 301 | for (var i in this.edges) { 302 | if (this.edges.hasOwnProperty(i)) { 303 | dotScript = dotScript + ' ' + this.edges[i].to_dot() + ';\n'; 304 | } 305 | } 306 | 307 | dotScript = dotScript + '}\n'; 308 | 309 | return dotScript; 310 | }; 311 | 312 | /** 313 | * Generate an output in file or memory 314 | * 315 | * @param {String|Object} type The output file type (png, jpeg, ps, ...) or options 316 | * @param {String|Function} name_or_callback The output file name or callback 317 | * @param {Function} errback Error callback 318 | * @api public 319 | * 320 | * Options : 321 | * - type : output file type (png, jpeg, ps, ...) 322 | * - use : Graphviz command to use (dot, neato, ...) 323 | * - path : GraphViz path 324 | * - G : 325 | * - N : 326 | * - E : 327 | */ 328 | Graph.prototype.render = function(type_or_options, name_or_callback, errback) { 329 | var parameters = []; 330 | 331 | // Get output type 332 | var type = type_or_options; 333 | if (typeof type_or_options == 'object') { 334 | type = type_or_options.type; 335 | 336 | // Get use 337 | if (type_or_options.use != undefined) { 338 | this.use = type_or_options.use; 339 | } 340 | 341 | // Get path 342 | if (type_or_options.path != undefined) { 343 | this.gvPath = type_or_options.path; 344 | } 345 | 346 | // Get extra Graph Options 347 | if (type_or_options.G != undefined) { 348 | for (attr in type_or_options.G) { 349 | if (gvattrs.isValid(attr, 'G') == false) { 350 | console.error('Warning : Invalid attribut `' + attr + "' for a graph"); 351 | } 352 | parameters.push('-G' + attr + '=' + type_or_options.G[attr]); 353 | } 354 | } 355 | // Get extra Node Options 356 | if (type_or_options.N != undefined) { 357 | for (attr in type_or_options.N) { 358 | if (gvattrs.isValid(attr, 'N') == false) { 359 | console.error('Warning : Invalid attribut `' + attr + "' for a node"); 360 | } 361 | parameters.push('-N' + attr + '=' + type_or_options.N[attr]); 362 | } 363 | } 364 | // Get extra Edge Options 365 | if (type_or_options.E != undefined) { 366 | for (attr in type_or_options.E) { 367 | if (gvattrs.isValid(attr, 'E') == false) { 368 | console.error('Warning : Invalid attribut `' + attr + "' for an edge"); 369 | } 370 | parameters.push('-E' + attr + '=' + type_or_options.E[attr]); 371 | } 372 | } 373 | } 374 | parameters.push('-T' + type); 375 | 376 | var dotScript = this.to_dot(); 377 | 378 | var cmd = this.use; 379 | if (this.gvPath != '') { 380 | cmd = path.join(this.gvPath, this.use); 381 | } 382 | 383 | var rendered = null; 384 | var out = ''; 385 | var err = ''; 386 | var outcallback = function(data) { 387 | if (rendered == null) { 388 | rendered = data; 389 | } else { 390 | __b = new Buffer(rendered.length + data.length); 391 | rendered.copy(__b, 0, 0); 392 | data.copy(__b, rendered.length, 0); 393 | rendered = __b; 394 | } 395 | }; 396 | 397 | if (typeof name_or_callback == 'string') { 398 | parameters.push('-o' + name_or_callback); 399 | outcallback = function(data) { 400 | out += data; 401 | }; 402 | } 403 | 404 | var self = this; 405 | 406 | which(cmd, function(err, cmdPath) { 407 | if (err) { 408 | if (errback) { 409 | errback(-1, out, 'Command ' + cmd + ' not found'); 410 | } 411 | } else { 412 | graphviz = spawn(cmdPath, parameters); 413 | graphviz.stdout.on('data', outcallback); 414 | graphviz.stderr.on('data', function(data) { 415 | err += data; 416 | }); 417 | graphviz.on('exit', function(code) { 418 | if (code !== 0) { 419 | if (errback) { 420 | errback(code, out, err); 421 | } 422 | } else { 423 | if (typeof name_or_callback == 'function') name_or_callback(rendered); 424 | else if (errback) errback(code, out, err) 425 | } 426 | }); 427 | graphviz.stdin.write(self.to_dot()); 428 | graphviz.stdin.end(); 429 | } 430 | }); 431 | }; 432 | // Compatibility 433 | Graph.prototype.output = function(type, name_or_callback, errback) { 434 | this.render(type, name_or_callback, errback); 435 | }; 436 | 437 | /** 438 | * Set the GraphViz path 439 | * 440 | * @param {String} path The GraphViz path 441 | * @api public 442 | */ 443 | Graph.prototype.setGraphVizPath = function(path) { 444 | this.gvPath = path; 445 | }; 446 | -------------------------------------------------------------------------------- /lib/deps/node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies 3 | */ 4 | var Hash = require('./core_ext/hash').Hash, 5 | Attributs = require('./attributs').Attributs; 6 | 7 | /** 8 | * Create a new node 9 | * @constructor 10 | * @param {Graph} graph Parent Graph 11 | * @param {String} id The node ID 12 | * @return {Node} 13 | * @api public 14 | */ 15 | var Node = (exports.Node = function(graph, id) { 16 | this.relativeGraph = graph; 17 | this.id = id; 18 | this.attributs = new Attributs('N'); 19 | }); 20 | 21 | /** 22 | * 23 | */ 24 | Node.prototype.to = function(id, attrs) { 25 | this.relativeGraph.addEdge(this, id, attrs); 26 | return this.relativeGraph.from(id); 27 | }; 28 | 29 | /** 30 | * Set a node attribut 31 | * 32 | * @param {String} name The attribut name 33 | * @param {Void} value The attribut value 34 | * @api public 35 | */ 36 | Node.prototype.set = function(name, value) { 37 | this.attributs.set(name, value); 38 | return this; 39 | }; 40 | 41 | /** 42 | * Get a node attribut 43 | * 44 | * @param {String} name The attribut name 45 | * @return {Void} 46 | * @api public 47 | */ 48 | Node.prototype.get = function(name) { 49 | return this.attributs.get(name); 50 | }; 51 | 52 | /** 53 | * @api private 54 | */ 55 | Node.prototype.to_dot = function() { 56 | var nodeOutput = '"' + this.id + '"' + this.attributs.to_dot(); 57 | return nodeOutput; 58 | }; 59 | -------------------------------------------------------------------------------- /lib/ext/gvpr/dot2js.g: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2010 Gregoire Lejeune 2 | // 3 | // This program is free software; you can redistribute it and/or modify 4 | // it under the terms of the GNU General Public License as published by 5 | // the Free Software Foundation; either version 2 of the License, or 6 | // (at your option) any later version. 7 | // 8 | // This program is distributed in the hope that it will be useful, 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | // GNU General Public License for more details. 12 | // 13 | // You should have received a copy of the GNU General Public License 14 | // along with this program; if not, write to the Free Software 15 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 | // 17 | // Usage : 18 | // gvpr -f dot2js.g [-a ] 19 | 20 | BEGIN { 21 | int g_strict; int g_direct; 22 | graph_t cluster; 23 | node_t cnode; 24 | edge_t cedge; 25 | string attr; string attrv; 26 | graph_t subgraph; graph_t pgraph; 27 | graph_t ofgraph; 28 | 29 | string xOut; 30 | if( ARGC == 0 ) { 31 | xOut = "_"; 32 | } else { 33 | xOut = tolower(ARGV[0]); 34 | } 35 | 36 | printf( "// This code was generated by dot2js.g\n\n" ); 37 | 38 | string rubyfy( string s ) { 39 | string out; 40 | out = tolower( s ); 41 | out = gsub( out, " ", "__" ); 42 | out = gsub( out, "'", "" ); 43 | out = gsub( out, "-", "_" ); 44 | out = gsub( out, ".", "" ); 45 | out = gsub( out, "%", "u" ); 46 | out = gsub( out, "+", "" ); 47 | out = gsub( out, "/", "_" ); 48 | return( out ); 49 | } 50 | } 51 | 52 | BEG_G { 53 | printf( "var util = require('util'),\n graphviz = require('graphviz');\n\n"); 54 | // Directed 55 | g_direct = isDirect($); 56 | if( g_direct == 0 ) { 57 | printf( "var graph_%s = graphviz.graph( \"%s\" );\n", rubyfy($.name), rubyfy($.name) ); 58 | } else { 59 | printf( "var graph_%s = graphviz.digraph( \"%s\" );\n", rubyfy($.name), rubyfy($.name) ); 60 | } 61 | // Strict 62 | g_strict = isStrict($); 63 | if( g_strict != 0 ) { 64 | // printf( ", :strict => true" ); ///////////////////////// TODO 65 | } 66 | 67 | // Attributs of G 68 | attr = fstAttr($, "G"); 69 | while( attr != "" ) { 70 | attrv = aget( $, attr ); 71 | if( attrv != "" ) { 72 | printf( "graph_%s.set( \"%s\", \"%s\" );\n", rubyfy($.name), attr, attrv ); 73 | } 74 | attr = nxtAttr( $, "G", attr ); 75 | } 76 | 77 | // Subgraph 78 | subgraph = fstsubg( $ ); 79 | while( subgraph != NULL ) { 80 | pgraph = subgraph.parent; 81 | printf ( "var graph_%s = graph_%s.addCluster( \"%s\" )\n", rubyfy(subgraph.name), rubyfy(pgraph.name), rubyfy(subgraph.name) ); 82 | 83 | // ATTRS 84 | attr = fstAttr(subgraph, "G"); 85 | while( attr != "" ) { 86 | attrv = aget( subgraph, attr ); 87 | if( attrv != "" ) { 88 | printf( "graph_%s.set( \"%s\", \"%s\" );\n", rubyfy(subgraph.name), attr, attrv ); 89 | } 90 | attr = nxtAttr( subgraph, "G", attr ); 91 | } 92 | 93 | subgraph = nxtsubg( subgraph ); 94 | } 95 | } 96 | 97 | N { 98 | pgraph = $.root; 99 | ofgraph = pgraph; 100 | 101 | subgraph = fstsubg( pgraph ); 102 | while( subgraph != NULL ) { 103 | if( isSubnode( subgraph, $ ) != 0 ) { 104 | ofgraph = subgraph; 105 | } 106 | subgraph = nxtsubg( subgraph ); 107 | } 108 | 109 | printf( "var node_%s = graph_%s.addNode( \"%s\", {", rubyfy($.name), rubyfy(ofgraph.name), $.name ); 110 | 111 | // Attributs of N 112 | attr = fstAttr($G, "N"); 113 | while( attr != "" ) { 114 | attrv = aget( $, attr ); 115 | if( attrv != "" ) { 116 | printf( "\"%s\" : \"%s\", ", attr, gsub( attrv, "'", "\\'" ) ); 117 | // } else { 118 | // printf( "\"%s\" : \"\", ", attr ); 119 | } 120 | attr = nxtAttr( $G, "N", attr ); 121 | } 122 | 123 | printf( "} );\n" ); 124 | } 125 | 126 | E { 127 | pgraph = $.root; 128 | ofgraph = pgraph; 129 | 130 | subgraph = fstsubg( pgraph ); 131 | while( subgraph != NULL ) { 132 | if( isSubedge( subgraph, $ ) != 0 ) { 133 | ofgraph = subgraph; 134 | } 135 | subgraph = nxtsubg( subgraph ); 136 | } 137 | 138 | printf( "graph_%s.addEdge( \"%s\", \"%s\", {", rubyfy(ofgraph.name), $.tail.name, $.head.name ); 139 | 140 | // Attributs of E 141 | attr = fstAttr($G, "E"); 142 | while( attr != "" ) { 143 | attrv = aget( $, attr ); 144 | if( attrv != "" ) { 145 | printf( "\"%s\" : \"%s\", ", attr, gsub( attrv, "'", "\\'" ) ); 146 | // } else { 147 | // printf( "\"%s\" : \"\", ", attr ); 148 | } 149 | attr = nxtAttr( $G, "E", attr ); 150 | } 151 | 152 | printf( "} );\n" ); 153 | } 154 | 155 | END_G { 156 | printf( "__graph_eval = graph_%s;\n", rubyfy($.name) ); 157 | } 158 | -------------------------------------------------------------------------------- /lib/graphviz.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module dependencies. 3 | */ 4 | var path = require('path'), 5 | spawn = require('child_process').spawn, 6 | temp = require('temp'), 7 | which = require('which'), 8 | fs = require('fs'), 9 | fsExt = require('./deps/core_ext/fs-ext'), 10 | Graph = require('./deps/graph').Graph; 11 | 12 | /** 13 | * Create a new undirected graph 14 | * @constructor 15 | * @param {String} id The graphID 16 | * @return {Graph} 17 | * @api public 18 | */ 19 | exports.graph = function(id) { 20 | var graph = new Graph(null, id); 21 | graph.type = 'graph'; 22 | return graph; 23 | }; 24 | 25 | /** 26 | * Create a new directed graph 27 | * @constructor 28 | * @param {String} id The graphID 29 | * @param {Boolean} isStrict if the Graph is strict 30 | * @return {Graph} 31 | * @api public 32 | */ 33 | exports.digraph = function(id, isStrict = false) { 34 | var graph = new Graph(null, id); 35 | graph.type = 'digraph'; 36 | graph.isStrict = isStrict; 37 | return graph; 38 | }; 39 | 40 | function _parse(file, callback, errback) { 41 | which('gvpr', function(err, cmdPath) { 42 | if (err) { 43 | if (errback) { 44 | errback(-1, '', 'Command gvpr not found'); 45 | } 46 | } else { 47 | var gvprScript = path.join(__dirname, 'ext', 'gvpr', 'dot2js.g'), 48 | parameters = ['-f' + gvprScript, file], 49 | __graph_eval, 50 | err = '', 51 | out = '', 52 | graphviz = spawn(cmdPath, parameters); 53 | 54 | graphviz.stdout.on('data', function(data) { 55 | out += data; 56 | }); 57 | graphviz.stderr.on('data', function(data) { 58 | err += data; 59 | }); 60 | graphviz.stdin.end(); 61 | graphviz.on('exit', function(code) { 62 | if (code !== 0) { 63 | if (errback) { 64 | errback(code, out, err); 65 | } 66 | } else { 67 | eval(out.toString()); 68 | if (typeof __graph_eval == 'undefined') { 69 | if (errback) { 70 | errback(code, out, '__graph_eval is not defined in call to graphviz'); 71 | } 72 | } else { 73 | callback(__graph_eval); 74 | } 75 | } 76 | }); 77 | } 78 | }); 79 | } 80 | /** 81 | * Create a new graph from a dot script 82 | * @constructor 83 | * @param {String} file_or_script The DOT script or file 84 | * @param {Function} callback 85 | * @param {Function} errback 86 | * @api public 87 | */ 88 | exports.parse = function(file_or_script, callback, errback) { 89 | if (fsExt.exist(file_or_script)) { 90 | _parse(file_or_script, callback, errback); 91 | } else { 92 | temp.open('node-graphviz', function(err, info) { 93 | if (err) { 94 | return errback(err); 95 | } 96 | fs.write(info.fd, file_or_script, function(err) { 97 | if (err) { 98 | return errback(err); 99 | } 100 | fs.close(info.fd, function(err) { 101 | if (err) { 102 | return errback(err); 103 | } 104 | _parse(info.path, callback, errback); 105 | }); 106 | }); 107 | }); 108 | } 109 | }; 110 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphviz", 3 | "version": "0.0.9", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "isexe": { 8 | "version": "2.0.0", 9 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 10 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 11 | }, 12 | "temp": { 13 | "version": "0.4.0", 14 | "resolved": "https://registry.npmjs.org/temp/-/temp-0.4.0.tgz", 15 | "integrity": "sha1-ZxrWPVe+D+nXKUZks/xABjZnimA=" 16 | }, 17 | "which": { 18 | "version": "1.3.1", 19 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 20 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 21 | "requires": { 22 | "isexe": "^2.0.0" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphviz", 3 | "version": "0.0.9", 4 | "author": "Gregoire Lejeune (http://algorithmique.net/)", 5 | "description": "Node.js interface to the GraphViz graphing tool", 6 | "homepage": "http://algorithmique.net/", 7 | "license": "MIT", 8 | "contributors": [ 9 | "Gregoire Lejeune (http://algorithmique.net)", 10 | "Mathieu Ravaux (http://mathieuravaux.com)" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "http://github.com/glejeune/node-graphviz.git" 15 | }, 16 | "keywords": [ 17 | "graphviz", 18 | "dot" 19 | ], 20 | "directories": { 21 | "lib": "./lib" 22 | }, 23 | "main": "lib/graphviz", 24 | "engines": { 25 | "node": ">=0.6.8" 26 | }, 27 | "dependencies": { 28 | "temp": "~0.4.0", 29 | "which": "^1.3.1" 30 | }, 31 | "devDependencies": {} 32 | } 33 | -------------------------------------------------------------------------------- /tests/cluster.dot: -------------------------------------------------------------------------------- 1 | digraph G { 2 | subgraph cluster_0 { 3 | style=filled; 4 | color=lightgrey; 5 | node [style=filled,color=white]; 6 | a0 -> a1; 7 | a1 -> a2; 8 | a2 -> a3; 9 | label = "process #1"; 10 | } 11 | 12 | subgraph cluster_1 { 13 | node [style=filled]; 14 | b0 -> b1; 15 | b1 -> b2; 16 | b2 -> b3; 17 | label = "process #2"; 18 | color=blue; 19 | } 20 | start -> a0; 21 | start -> b0; 22 | a1 -> b3; 23 | b2 -> a3; 24 | a3 -> a0; 25 | a3 -> end; 26 | b3 -> end; 27 | 28 | start [shape=Mdiamond]; 29 | end [shape=Msquare]; 30 | } -------------------------------------------------------------------------------- /tests/cluster.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | graphviz = require('../lib/graphviz'); 3 | 4 | // digraph G { 5 | var g = graphviz.digraph('G'); 6 | // subgraph cluster_0 { 7 | var cluster_0 = g.addCluster('cluster_0'); 8 | // style=filled; 9 | cluster_0.set('style', 'filled'); 10 | // color=lightgrey; 11 | cluster_0.set('color', 'lightgrey'); 12 | // node [style=filled,color=white]; 13 | cluster_0.setNodeAttribut('style', 'filled'); 14 | cluster_0.setNodeAttribut('color', 'white'); 15 | 16 | // a0 -> a1 -> a2 -> a3; 17 | cluster_0.addEdge('a0', 'a1'); 18 | cluster_0.addEdge('a1', 'a2'); 19 | cluster_0.addEdge('a2', 'a3'); 20 | // label = "process #1"; 21 | cluster_0.set('label', 'process #1'); 22 | // } 23 | 24 | // subgraph cluster_1 { 25 | var cluster_1 = g.addCluster('cluster_1'); 26 | // node [style=filled]; 27 | cluster_1.setNodeAttribut('style', 'filled'); 28 | 29 | // b0 -> b1 -> b2 -> b3; 30 | cluster_1.addEdge('b0', 'b1'); 31 | cluster_1.addEdge('b1', 'b2'); 32 | cluster_1.addEdge('b2', 'b3'); 33 | // label = "process #2"; 34 | cluster_1.set('label', 'process #2'); 35 | // color = blue 36 | cluster_1.set('color', 'blue'); 37 | // } 38 | 39 | // start -> a0; 40 | g.addEdge('start', cluster_0.getNode('a0')); 41 | // start -> b0; 42 | g.addEdge('start', cluster_1.getNode('b0')); 43 | // a1 -> b3; 44 | g.addEdge(cluster_0.getNode('a1'), cluster_1.getNode('b3')); 45 | // b2 -> a3; 46 | g.addEdge(cluster_1.getNode('b2'), cluster_0.getNode('a3')); 47 | // a3 -> a0; 48 | g.addEdge(cluster_0.getNode('a3'), cluster_0.getNode('a0')); 49 | // a3 -> end; 50 | g.addEdge(cluster_0.getNode('a3'), 'end'); 51 | // b3 -> end; 52 | g.addEdge(cluster_1.getNode('b3'), 'end'); 53 | // 54 | // start [shape=Mdiamond]; 55 | g.getNode('start').set('shape', 'Mdiamond'); 56 | // end [shape=Msquare]; 57 | g.getNode('end').set('shape', 'Msquare'); 58 | // } 59 | 60 | g.output('png', 'cluster.png', function(code, out, err) { 61 | console.log(err); 62 | }); 63 | -------------------------------------------------------------------------------- /tests/compound.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | graphviz = require('../lib/graphviz'); 3 | 4 | // Create digraph G 5 | var g = graphviz.digraph("G"); 6 | g.set( "splines", "compound"); 7 | g.from( "A" ).to( "B" ).to( "F" ); 8 | g.from( "A" ).to( "C" ).to( "D" ).to( "F" ); 9 | g.from( "A" ).to( "D" ); 10 | g.from( "A" ).to( "F" ); 11 | g.from( "C" ).to( "F" ); 12 | g.from( "E" ).to( "F" ); 13 | 14 | g.render( "png", "compound.png" ); 15 | -------------------------------------------------------------------------------- /tests/fdpclust.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | graphviz = require('../lib/graphviz'); 3 | 4 | // graph G { 5 | var g = graphviz.graph("G"); 6 | // e 7 | var e = g.addNode( "e" ) 8 | // subgraph clusterA { 9 | var clusterA = g.addCluster( "clusterA" ) 10 | // a -- b; 11 | clusterA.addEdge( "a", "b" ) 12 | // subgraph clusterC { 13 | var clusterC = clusterA.addCluster( "clusterC" ) 14 | // C -- D; 15 | clusterC.addEdge( "C", "D" ) 16 | // } 17 | // } 18 | // subgraph clusterB { 19 | var clusterB = g.addCluster( "clusterB" ) 20 | clusterB.addEdge( "d", "f" ) 21 | // d -- f 22 | // } 23 | // d -- D 24 | g.addEdge( clusterB.getNode("d"), clusterC.getNode("D") ) 25 | // e -- clusterB 26 | g.addEdge( e, clusterB ) 27 | // clusterC -- clusterB 28 | g.addEdge( clusterC, clusterB ) 29 | // } 30 | 31 | g.use = "fdp" 32 | g.output( "png", "fdpclust.png" ); 33 | -------------------------------------------------------------------------------- /tests/hello.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | graphviz = require('../lib/graphviz'); 3 | 4 | // Create digraph G 5 | var g = graphviz.digraph("G"); 6 | 7 | // Add node (ID: Hello) 8 | var n1 = g.addNode( "Hello" ); 9 | 10 | // Add node (ID: World) 11 | g.addNode( "World" ); 12 | 13 | // Add edge between the two nodes 14 | var e = g.addEdge( n1, "World" ); 15 | 16 | // Generate a PNG output 17 | g.output( { 18 | "type":"png", 19 | "use":"dot", 20 | "N" : { 21 | "color":"blue", 22 | "shape":"Mdiamond" 23 | }, 24 | "E" : { 25 | "color" : "red", 26 | "label" : "Say" 27 | }, 28 | "G" : { 29 | "label" : "Example" 30 | } 31 | }, "hello.png" ); 32 | -------------------------------------------------------------------------------- /tests/hello_world.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | graphviz = require('../lib/graphviz'); 3 | 4 | // Create digraph G 5 | var g = graphviz.digraph("G"); 6 | 7 | // Add node (ID: Hello) 8 | var n1 = g.addNode( "Hello", {"color" : "blue", "shape" : "Mdiamond"} ); 9 | //n1.set( "color", "blue" ); 10 | n1.set( "style", "filled" ); 11 | 12 | // Add node (ID: World) 13 | g.addNode( "World" ); 14 | 15 | // Add edge between the two nodes 16 | g.addEdge(n1, "World") 17 | .set("color", "red") 18 | .set("label", "A label") 19 | .set("fontsize", "10"); 20 | 21 | // Generate a PNG output 22 | g.output( "png", "hello_world.png" ); 23 | -------------------------------------------------------------------------------- /tests/memory.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | graphviz = require('../lib/graphviz'); 3 | 4 | // Create digraph G 5 | var g = graphviz.digraph("G"); 6 | 7 | // Add node (ID: Hello) 8 | var n1 = g.addNode( "Hello" ); 9 | n1.set( "color", "blue" ) 10 | .set( "style", "filled" ); 11 | 12 | // Add node (ID: World) 13 | g.addNode( "World" ); 14 | 15 | // Add edge between the two nodes 16 | var e = g.addEdge( n1, "World" ); 17 | e.set( "color", "red" ); 18 | 19 | // Generate a dot output in-memory 20 | g.render( "png", function(render) { 21 | process.stdout.write( render ); 22 | } ); 23 | 24 | // Generate a PNG output in-file 25 | g.output( "png", "memory.png" ); 26 | -------------------------------------------------------------------------------- /tests/parse.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | graphviz = require('../lib/graphviz'); 3 | 4 | graphviz.parse( "cluster.dot", function(graph) { 5 | graph.render( "png", "cluster.png" ); 6 | }) 7 | 8 | graphviz.parse( "cluster.dot", function(graph) { 9 | graph.render( "png", function(render) { 10 | process.stdout.write( render ); 11 | }, function(code, out, err) { 12 | console.log("RENDER ERROR") 13 | console.log(""+err) 14 | console.log(""+out) 15 | }); 16 | }, function(code, out, err) { 17 | console.log("PARSE ERROR") 18 | console.log(""+err) 19 | console.log(""+out) 20 | }); 21 | -------------------------------------------------------------------------------- /tests/remove_node.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | graphviz = require('../lib/graphviz'); 3 | 4 | 5 | //create a graph 6 | var g = graphviz.digraph("G"); 7 | 8 | //add some nodes 9 | g.addNode("a"); 10 | g.addNode("b"); 11 | g.addNode("c"); 12 | g.addNode("d"); 13 | g.addNode("e"); 14 | 15 | 16 | //add relations 17 | g.addEdge("a", "b"); 18 | g.addEdge("a", "c"); 19 | g.addEdge("c", "b"); 20 | g.addEdge("a", "d"); 21 | 22 | g.output( "png", "remove_node_original.png" ); 23 | 24 | 25 | //soft removeNode 26 | //will remove the node, but not the edges 27 | g.removeNode("e"); 28 | g.output( "png", "remove_node_soft.png" ); 29 | 30 | //hard removeNode 31 | //removes the node and the edgesfrom and to the node 32 | g.removeNode("c", true); 33 | g.output( "png", "remove_node_hard.png" ); 34 | 35 | console.log(g.to_dot()) 36 | -------------------------------------------------------------------------------- /tests/server/app.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var util = require('util'); 3 | var http = require('http'); 4 | var url = require('url'); 5 | 6 | // npm install express 7 | var express = require('express'), 8 | app = express.createServer(); 9 | // nom install temp 10 | var temp = require('temp'); 11 | // npm install graphviz 12 | var graphviz = require('../../lib/graphviz'); 13 | // npm install jsmin 14 | var jsmin = require('jsmin').jsmin; 15 | 16 | // Configuration -------------------------------------------------------------- 17 | 18 | app.set('views', __dirname + '/views'); 19 | app.configure(function(){ 20 | app.use(express.bodyParser()); 21 | app.use(express.static(__dirname + '/static')); 22 | }) 23 | 24 | // Site ----------------------------------------------------------------------- 25 | 26 | app.get('/', function(req, res){ 27 | res.render('index.ejs', {}); 28 | }); 29 | 30 | // APIs ----------------------------------------------------------------------- 31 | 32 | app.get('/dotgraph.min.js', function(req,res) { 33 | fs.readFile(__dirname+'/static/dotgraph.js', function (err, data) { 34 | if (err) throw err; 35 | res.contentType('text/javascript'); 36 | res.send( jsmin(data.toString('utf8') ) ); 37 | }); 38 | }) 39 | 40 | function __do( req, res, data ) { 41 | graphviz.parse( data, function(graph) { 42 | graph.render( "png", function(render) { 43 | img = '' 44 | res.send(img) 45 | }, function(code, out, err) { 46 | img = '

Render error (code '+code+')

'; 47 | img += '

STDOUT : '+out+'

'; 48 | img += '

STDERR : '+err+'

'; 49 | res.send(img) 50 | }); 51 | }, function(code, out, err){ 52 | img = '

Parser error (code '+code+')

'; 53 | img += '

STDERR : '+err+'

'; 54 | img += '

STDOUT : '+out+'

'; 55 | res.send(img) 56 | }); 57 | } 58 | 59 | app.post('/script', function(req,res){ 60 | __do(req, res, req.body.data) 61 | }) 62 | 63 | app.get('/file/*', function(req,res){ 64 | var urlData = url.parse(req.params[0]); 65 | 66 | var urlPort = urlData.port; 67 | if( urlPort == undefined ) { 68 | urlPort = 80; 69 | } 70 | var urlHost = urlData.host; 71 | var urlPath = urlData.pathname; 72 | 73 | var client = http.createClient(urlPort, urlHost); 74 | var request = client.request('GET', urlPath, 75 | {'host': urlHost}); 76 | request.end(); 77 | request.on('response', function (response) { 78 | response.setEncoding('utf8'); 79 | if(response.statusCode == 404 ) { 80 | res.send('

'+req.params[0]+' does not exist (404 error)

'); 81 | } else { 82 | response.on('data', function (chunk) { 83 | __do(req, res, chunk) 84 | }); 85 | } 86 | }); 87 | }) 88 | 89 | app.listen(3000); 90 | -------------------------------------------------------------------------------- /tests/server/static/dotgraph.js: -------------------------------------------------------------------------------- 1 | var DotGraphClient = { 2 | version: '0.0.1', 3 | host: 'http://localhost:3000', 4 | 5 | require: function(libraryName) { 6 | try{ 7 | document.write(' 21 | 22 | 27 | 28 | -------------------------------------------------------------------------------- /tests/server/views/layout.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 13 | <%- body %> 14 | 15 | -------------------------------------------------------------------------------- /tests/switch.js: -------------------------------------------------------------------------------- 1 | // This code was generated by dot2js.g 2 | 3 | var util = require('util'), 4 | graphviz = require('../lib/graphviz'); 5 | 6 | var graph_g = graphviz.digraph( "g" ); 7 | graph_g.set( "bgcolor", "#808080" ); 8 | graph_g.set( "rankdir", "LR" ); 9 | var graph_u1 = graph_g.addCluster( "u1" ) 10 | graph_u1.set( "bgcolor", "#808080" ); 11 | graph_u1.set( "rankdir", "LR" ); 12 | var graph_u3 = graph_g.addCluster( "u3" ) 13 | graph_u3.set( "bgcolor", "#808080" ); 14 | graph_u3.set( "rankdir", "LR" ); 15 | var graph_u5 = graph_g.addCluster( "u5" ) 16 | graph_u5.set( "bgcolor", "#808080" ); 17 | graph_u5.set( "rankdir", "LR" ); 18 | var graph_u7 = graph_g.addCluster( "u7" ) 19 | graph_u7.set( "bgcolor", "#808080" ); 20 | graph_u7.set( "rankdir", "LR" ); 21 | var graph_u15 = graph_g.addCluster( "u15" ) 22 | graph_u15.set( "bgcolor", "#808080" ); 23 | graph_u15.set( "rankdir", "LR" ); 24 | var graph_u23 = graph_g.addCluster( "u23" ) 25 | graph_u23.set( "bgcolor", "#808080" ); 26 | graph_u23.set( "rankdir", "LR" ); 27 | var graph_u31 = graph_g.addCluster( "u31" ) 28 | graph_u31.set( "bgcolor", "#808080" ); 29 | graph_u31.set( "rankdir", "LR" ); 30 | var graph_u39 = graph_g.addCluster( "u39" ) 31 | graph_u39.set( "bgcolor", "#808080" ); 32 | graph_u39.set( "rankdir", "LR" ); 33 | var graph_u47 = graph_g.addCluster( "u47" ) 34 | graph_u47.set( "bgcolor", "#808080" ); 35 | graph_u47.set( "rankdir", "LR" ); 36 | var graph_u55 = graph_g.addCluster( "u55" ) 37 | graph_u55.set( "bgcolor", "#808080" ); 38 | graph_u55.set( "rankdir", "LR" ); 39 | var graph_u63 = graph_g.addCluster( "u63" ) 40 | graph_u63.set( "bgcolor", "#808080" ); 41 | graph_u63.set( "rankdir", "LR" ); 42 | var graph_u71 = graph_g.addCluster( "u71" ) 43 | graph_u71.set( "bgcolor", "#808080" ); 44 | graph_u71.set( "rankdir", "LR" ); 45 | var graph_u89 = graph_g.addCluster( "u89" ) 46 | graph_u89.set( "bgcolor", "#808080" ); 47 | graph_u89.set( "rankdir", "LR" ); 48 | var graph_u107 = graph_g.addCluster( "u107" ) 49 | graph_u107.set( "bgcolor", "#808080" ); 50 | graph_u107.set( "rankdir", "LR" ); 51 | var graph_u125 = graph_g.addCluster( "u125" ) 52 | graph_u125.set( "bgcolor", "#808080" ); 53 | graph_u125.set( "rankdir", "LR" ); 54 | var graph_u143 = graph_g.addCluster( "u143" ) 55 | graph_u143.set( "bgcolor", "#808080" ); 56 | graph_u143.set( "rankdir", "LR" ); 57 | var graph_u177 = graph_g.addCluster( "u177" ) 58 | graph_u177.set( "bgcolor", "#808080" ); 59 | graph_u177.set( "rankdir", "LR" ); 60 | var graph_u211 = graph_g.addCluster( "u211" ) 61 | graph_u211.set( "bgcolor", "#808080" ); 62 | graph_u211.set( "rankdir", "LR" ); 63 | var node_1 = graph_u1.addNode( "1", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 64 | graph_g.addEdge( "1", "a", {"color" : "#0000ff", "dir" : "none", } ); 65 | var node_2 = graph_u1.addNode( "2", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 66 | graph_g.addEdge( "2", "b", {"color" : "#ff0000", "dir" : "none", } ); 67 | var node_3 = graph_u1.addNode( "3", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 68 | graph_g.addEdge( "3", "c", {"color" : "#ffff00", "dir" : "none", } ); 69 | var node_4 = graph_u1.addNode( "4", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 70 | graph_g.addEdge( "4", "d", {"color" : "#00ff00", "dir" : "none", } ); 71 | var node_5 = graph_u1.addNode( "5", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 72 | graph_g.addEdge( "5", "e", {"color" : "#000000", "dir" : "none", } ); 73 | var node_6 = graph_u1.addNode( "6", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 74 | graph_g.addEdge( "6", "f", {"color" : "#00ffff", "dir" : "none", } ); 75 | var node_7 = graph_u1.addNode( "7", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 76 | graph_g.addEdge( "7", "g", {"color" : "#ffffff", "dir" : "none", } ); 77 | var node_8 = graph_u1.addNode( "8", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 78 | graph_g.addEdge( "8", "h", {"color" : "#ff00ff", "dir" : "none", } ); 79 | var node_10 = graph_u211.addNode( "10", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 80 | var node_20 = graph_u211.addNode( "20", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 81 | var node_30 = graph_u211.addNode( "30", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 82 | var node_40 = graph_u211.addNode( "40", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 83 | var node_50 = graph_u211.addNode( "50", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 84 | var node_60 = graph_u211.addNode( "60", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 85 | var node_70 = graph_u211.addNode( "70", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 86 | var node_80 = graph_u211.addNode( "80", {"height" : "0.3", "shape" : "circle", "style" : "invis", "width" : "0.3", } ); 87 | var node_a = graph_u3.addNode( "a", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 88 | graph_g.addEdge( "a", "A", {"color" : "#0000ff", "dir" : "none", } ); 89 | graph_g.addEdge( "a", "B", {"color" : "#0000ff", "dir" : "none", } ); 90 | var node_b = graph_u3.addNode( "b", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 91 | graph_g.addEdge( "b", "A", {"color" : "#ff0000", "dir" : "none", } ); 92 | graph_g.addEdge( "b", "B", {"color" : "#ff0000", "dir" : "none", } ); 93 | var node_c = graph_u3.addNode( "c", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 94 | graph_g.addEdge( "c", "C", {"color" : "#ffff00", "dir" : "none", } ); 95 | graph_g.addEdge( "c", "D", {"color" : "#ffff00", "dir" : "none", } ); 96 | var node_d = graph_u3.addNode( "d", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 97 | graph_g.addEdge( "d", "C", {"color" : "#00ff00", "dir" : "none", } ); 98 | graph_g.addEdge( "d", "D", {"color" : "#00ff00", "dir" : "none", } ); 99 | var node_e = graph_u3.addNode( "e", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 100 | graph_g.addEdge( "e", "E", {"color" : "#000000", "dir" : "none", } ); 101 | graph_g.addEdge( "e", "F", {"color" : "#000000", "dir" : "none", } ); 102 | var node_f = graph_u3.addNode( "f", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 103 | graph_g.addEdge( "f", "E", {"color" : "#00ffff", "dir" : "none", } ); 104 | graph_g.addEdge( "f", "F", {"color" : "#00ffff", "dir" : "none", } ); 105 | var node_g = graph_u3.addNode( "g", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 106 | graph_g.addEdge( "g", "G", {"color" : "#ffffff", "dir" : "none", } ); 107 | graph_g.addEdge( "g", "H", {"color" : "#ffffff", "dir" : "none", } ); 108 | var node_h = graph_u3.addNode( "h", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 109 | graph_g.addEdge( "h", "G", {"color" : "#ff00ff", "dir" : "none", } ); 110 | graph_g.addEdge( "h", "H", {"color" : "#ff00ff", "dir" : "none", } ); 111 | var node_i = graph_u71.addNode( "i", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 112 | graph_u71.addEdge( "i", "I", {"color" : "#ff0000:#0000ff", "dir" : "none", } ); 113 | graph_u71.addEdge( "i", "K", {"color" : "#ff0000:#0000ff", "dir" : "none", } ); 114 | var node_j = graph_u71.addNode( "j", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 115 | graph_u71.addEdge( "j", "J", {"color" : "#ff0000:#0000ff", "dir" : "none", } ); 116 | graph_u71.addEdge( "j", "L", {"color" : "#ff0000:#0000ff", "dir" : "none", } ); 117 | var node_k = graph_u89.addNode( "k", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 118 | graph_u89.addEdge( "k", "I", {"color" : "#00ff00:#ffff00", "dir" : "none", } ); 119 | graph_u89.addEdge( "k", "K", {"color" : "#00ff00:#ffff00", "dir" : "none", } ); 120 | var node_l = graph_u89.addNode( "l", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 121 | graph_u89.addEdge( "l", "J", {"color" : "#00ff00:#ffff00", "dir" : "none", } ); 122 | graph_u89.addEdge( "l", "L", {"color" : "#00ff00:#ffff00", "dir" : "none", } ); 123 | var node_m = graph_u107.addNode( "m", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 124 | graph_u107.addEdge( "m", "M", {"color" : "#00ffff:#000000", "dir" : "none", } ); 125 | graph_u107.addEdge( "m", "O", {"color" : "#00ffff:#000000", "dir" : "none", } ); 126 | var node_n = graph_u107.addNode( "n", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 127 | graph_u107.addEdge( "n", "N", {"color" : "#00ffff:#000000", "dir" : "none", } ); 128 | graph_u107.addEdge( "n", "P", {"color" : "#00ffff:#000000", "dir" : "none", } ); 129 | var node_o = graph_u125.addNode( "o", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 130 | graph_u125.addEdge( "o", "M", {"color" : "#ff00ff:#ffffff", "dir" : "none", } ); 131 | graph_u125.addEdge( "o", "O", {"color" : "#ff00ff:#ffffff", "dir" : "none", } ); 132 | var node_p = graph_u125.addNode( "p", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 133 | graph_u125.addEdge( "p", "N", {"color" : "#ff00ff:#ffffff", "dir" : "none", } ); 134 | graph_u125.addEdge( "p", "P", {"color" : "#ff00ff:#ffffff", "dir" : "none", } ); 135 | var node_q = graph_u143.addNode( "q", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 136 | graph_u143.addEdge( "q", "Q", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 137 | graph_u143.addEdge( "q", "U", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 138 | var node_r = graph_u143.addNode( "r", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 139 | graph_u143.addEdge( "r", "R", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 140 | graph_u143.addEdge( "r", "V", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 141 | var node_s = graph_u143.addNode( "s", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 142 | graph_u143.addEdge( "s", "S", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 143 | graph_u143.addEdge( "s", "W", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 144 | var node_t = graph_u143.addNode( "t", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 145 | graph_u143.addEdge( "t", "T", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 146 | graph_u143.addEdge( "t", "X", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 147 | var node_u = graph_u177.addNode( "u", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 148 | graph_u177.addEdge( "u", "Q", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 149 | graph_u177.addEdge( "u", "U", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 150 | var node_v = graph_u177.addNode( "v", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 151 | graph_u177.addEdge( "v", "R", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 152 | graph_u177.addEdge( "v", "V", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 153 | var node_w = graph_u177.addNode( "w", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 154 | graph_u177.addEdge( "w", "S", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 155 | graph_u177.addEdge( "w", "W", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 156 | var node_x = graph_u177.addNode( "x", {"height" : "0.3", "shape" : "circle", "width" : "0.3", } ); 157 | graph_u177.addEdge( "x", "T", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 158 | graph_u177.addEdge( "x", "X", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 159 | var node_a = graph_u71.addNode( "A", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 160 | graph_u71.addEdge( "A", "i", {"color" : "#ff0000:#0000ff", "dir" : "none", } ); 161 | var node_b = graph_u71.addNode( "B", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 162 | graph_u71.addEdge( "B", "j", {"color" : "#ff0000:#0000ff", "dir" : "none", } ); 163 | var node_c = graph_u89.addNode( "C", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 164 | graph_u89.addEdge( "C", "k", {"color" : "#00ff00:#ffff00", "dir" : "none", } ); 165 | var node_d = graph_u89.addNode( "D", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 166 | graph_u89.addEdge( "D", "l", {"color" : "#00ff00:#ffff00", "dir" : "none", } ); 167 | var node_e = graph_u107.addNode( "E", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 168 | graph_u107.addEdge( "E", "m", {"color" : "#00ffff:#000000", "dir" : "none", } ); 169 | var node_f = graph_u107.addNode( "F", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 170 | graph_u107.addEdge( "F", "n", {"color" : "#00ffff:#000000", "dir" : "none", } ); 171 | var node_g = graph_u125.addNode( "G", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 172 | graph_u125.addEdge( "G", "o", {"color" : "#ff00ff:#ffffff", "dir" : "none", } ); 173 | var node_h = graph_u125.addNode( "H", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 174 | graph_u125.addEdge( "H", "p", {"color" : "#ff00ff:#ffffff", "dir" : "none", } ); 175 | var node_i = graph_u143.addNode( "I", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 176 | graph_u143.addEdge( "I", "q", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 177 | var node_j = graph_u143.addNode( "J", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 178 | graph_u143.addEdge( "J", "r", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 179 | var node_k = graph_u143.addNode( "K", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 180 | graph_u143.addEdge( "K", "s", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 181 | var node_l = graph_u143.addNode( "L", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 182 | graph_u143.addEdge( "L", "t", {"color" : "#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 183 | var node_m = graph_u177.addNode( "M", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 184 | graph_u177.addEdge( "M", "u", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 185 | var node_n = graph_u177.addNode( "N", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 186 | graph_u177.addEdge( "N", "v", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 187 | var node_o = graph_u177.addNode( "O", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 188 | graph_u177.addEdge( "O", "w", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 189 | var node_p = graph_u177.addNode( "P", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 190 | graph_u177.addEdge( "P", "x", {"color" : "#ff00ff:#ffffff:#00ffff:#000000", "dir" : "none", } ); 191 | var node_q = graph_u211.addNode( "Q", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 192 | graph_u211.addEdge( "Q", "10", {"color" : "#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 193 | var node_r = graph_u211.addNode( "R", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 194 | graph_u211.addEdge( "R", "20", {"color" : "#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 195 | var node_s = graph_u211.addNode( "S", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 196 | graph_u211.addEdge( "S", "30", {"color" : "#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 197 | var node_t = graph_u211.addNode( "T", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 198 | graph_u211.addEdge( "T", "40", {"color" : "#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 199 | var node_u = graph_u211.addNode( "U", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 200 | graph_u211.addEdge( "U", "50", {"color" : "#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 201 | var node_v = graph_u211.addNode( "V", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 202 | graph_u211.addEdge( "V", "60", {"color" : "#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 203 | var node_w = graph_u211.addNode( "W", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 204 | graph_u211.addEdge( "W", "70", {"color" : "#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 205 | var node_x = graph_u211.addNode( "X", {"height" : "0.3", "shape" : "diamond", "width" : "0.3", } ); 206 | graph_u211.addEdge( "X", "80", {"color" : "#ff00ff:#ffffff:#00ffff:#000000:#00ff00:#ffff00:#ff0000:#0000ff", "dir" : "none", } ); 207 | __graph_eval = graph_g; 208 | 209 | __graph_eval.render( "png", "switch.png" ); 210 | --------------------------------------------------------------------------------