├── .gitignore
├── Gruntfile.js
├── LICENSE
├── README.md
├── build
├── README.md
└── graph.min.js
├── examples
├── simple_graph
│ ├── index.html
│ └── simple_graph.js
└── sphere_graph
│ ├── index.html
│ └── sphere_graph.js
├── index.html
├── package.json
├── src
├── graph.js
├── layouts
│ └── force-directed-layout.js
└── utils
│ ├── Label.js
│ ├── ObjectSelection.js
│ ├── Stats.js
│ ├── TrackballControls.js
│ └── Vector3.js
└── webgl-frameworks
├── Three.js
└── three.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | grunt.initConfig({
3 | pkg: grunt.file.readJSON('package.json'),
4 | jshint: {
5 | all: ['Gruntfile.js', 'src/graph.js', 'src/layouts/*.js', 'src/utils/Label.js', 'src/utils/ObjectSelection.js']
6 | },
7 | uglify: {
8 | options: {
9 | banner: '/*! <%= pkg.name %> <%= pkg.version %> */\n'
10 | },
11 | graphVisualization: {
12 | files: {
13 | 'build/graph.min.js': ['webgl-frameworks/three.min.js', 'src/graph.js', 'src/utils/*.js', 'src/layouts/*.js']
14 | }
15 | }
16 | }
17 | });
18 |
19 | grunt.loadNpmTasks('grunt-contrib-jshint');
20 | grunt.loadNpmTasks('grunt-contrib-uglify');
21 |
22 | grunt.registerTask('default', ['jshint', 'uglify']);
23 | };
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | /*!
2 | MIT License
3 |
4 | Copyright (c) 2011 David Piegza
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of
11 | the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
16 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 | */
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### Notice: This repo is not maintained anymore but PRs are still welcome.
2 |
3 | # Graph-Visualization
4 |
5 | This project is about 3D graph visualization with WebGL. The aim of this project is to evaluate the possibilities of graph drawing in WebGL.
6 |
7 | It uses [Three.js](https://threejs.org/) for drawing and currently supports a force directed layout.
8 |
9 |
10 | ### Run the example
11 |
12 | You can see the examples at http://davidpiegza.github.io/Graph-Visualization/index.html or:
13 |
14 | 1. Clone or download the project
15 | 2. Open the index.html in a WebGL-compatible browser
16 |
17 | The `examples` folder contains all examples.
18 |
19 | ## Project Description
20 |
21 | The project consists of
22 |
23 | - a graph structure
24 | - a graph layout implementation
25 | - and a graph drawing implementation
26 |
27 | ### Graph Structure
28 |
29 | This is implemented in [src/graph.js](https://github.com/davidpiegza/Graph-Visualization/blob/master/src/graph.js).
30 |
31 | Usage:
32 |
33 | ```js
34 | // create a graph with maximum number of nodes (optional)
35 | var graph = new GRAPHVIS.Graph({limit: 100});
36 | // create nodes with an id
37 | var node1 = new GRAPHVIS.Node(1);
38 | var node2 = new GRAPHVIS.Node(2);
39 | // add nodes to the graph
40 | graph.addNode(node1);
41 | graph.addNode(node2);
42 | // create edge between nodes
43 | graph.addEdge(node1, node2);
44 | ```
45 |
46 | Node:
47 |
48 | A node has the properties
49 |
50 | - `ID`
51 | - `nodesTo`, Array with connected nodes
52 | - `nodesFrom`, Array with connected nodes
53 | - `position`, Object for x, y, z position, default is {}
54 | - `data`, Object with further properties, e.g. properties for a graph layout
55 |
56 | For more details have a look at the [source code](https://github.com/davidpiegza/Graph-Visualization/blob/master/src/graph.js).
57 |
58 | ### Graph Layout
59 |
60 | A graph layout has the basic structure:
61 |
62 | ```js
63 | var Layout = Layout || {};
64 | Layout.ForceDirected = function(graph, options) {
65 | this.init = function() {
66 | ...
67 | };
68 |
69 | this.generate = function() {
70 | ...
71 | };
72 | }
73 | ```
74 |
75 | The `init()` function is called after graph creation, the `generate()` function is called on each render-call.
76 |
77 | The graph layout gets the created graph and calculates new positions for the nodes. The `generate()` function is called repeatedly, so there must be a stop condition after finished calculation.
78 |
79 | The graph layout may extend the nodes and edges with custom properties in the data object.
80 |
81 | See [force-directed-layout.js](https://github.com/davidpiegza/Graph-Visualization/blob/master/src/layouts/force-directed-layout.js) for example usage.
82 |
83 |
84 | ## Contribution
85 |
86 | It would be great to have more examples of force-directed graphs or other 3d graph layouts. To add a new example, just copy one of the existing [examples](https://github.com/davidpiegza/Graph-Visualization/blob/master/examples), add a new `Drawing` object and update the `index.html`.
87 |
88 | ***Check out the [open issues](https://github.com/davidpiegza/Graph-Visualization/issues) for a specific task***.
89 |
90 | This project uses [Grunt](http://gruntjs.com/) to run several tasks in development. You should have `npm` and `grunt` installed. To install `grunt` run
91 |
92 | npm install -g grunt-cli
93 |
94 | And to install all dependencies run
95 |
96 | npm install
97 |
98 | For more info check the [Grunt - Getting started guide](http://gruntjs.com/getting-started).
99 |
100 | If you added some changes, run `grunt` to check the code.
101 |
102 | ## Changelog
103 |
104 | See [releases](https://github.com/davidpiegza/Graph-Visualization/releases).
105 |
--------------------------------------------------------------------------------
/build/README.md:
--------------------------------------------------------------------------------
1 | # Create minified version
2 |
3 | Using `grunt`:
4 |
5 | npm install -g grunt-cli
6 | grunt
7 |
--------------------------------------------------------------------------------
/examples/simple_graph/index.html:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 | Graph Visualization
19 |
20 |
21 |
22 |
28 |
29 |
52 |
53 |
54 |
65 |
66 |
67 | Rotate: Left Mouse Button and Move
68 | Zoom: Press Key S + Left Mouse Button and Move
69 | Drag: Press Key D + Left Mouse Button and Move
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/examples/simple_graph/simple_graph.js:
--------------------------------------------------------------------------------
1 | /**
2 | @author David Piegza
3 |
4 | Implements a simple graph drawing with force-directed placement in 2D and 3D.
5 |
6 | It uses the force-directed-layout implemented in:
7 | https://github.com/davidpiegza/Graph-Visualization/blob/master/layouts/force-directed-layout.js
8 |
9 | Drawing is done with Three.js: http://github.com/mrdoob/three.js
10 |
11 | To use this drawing, include the graph-min.js file and create a SimpleGraph object:
12 |
13 |
14 |
15 |
16 | Graph Visualization
17 |
18 |
19 |
20 |
21 |
22 |
23 | Parameters:
24 | options = {
25 | layout: "2d" or "3d"
26 |
27 | showStats: , displays FPS box
28 | showInfo: , displays some info on the graph and layout
29 | The info box is created as , it must be
30 | styled and positioned with CSS.
31 |
32 |
33 | selection:
, enables selection of nodes on mouse over (it displays some info
34 | when the showInfo flag is set)
35 |
36 |
37 | limit: , maximum number of nodes
38 |
39 | numNodes: - sets the number of nodes to create.
40 | numEdges: - sets the maximum number of edges for a node. A node will have
41 | 1 to numEdges edges, this is set randomly.
42 | }
43 |
44 |
45 | Feel free to contribute a new drawing!
46 |
47 | */
48 |
49 | var Drawing = Drawing || {};
50 |
51 | Drawing.SimpleGraph = function(options) {
52 | options = options || {};
53 |
54 | this.layout = options.layout || "2d";
55 | this.layout_options = options.graphLayout || {};
56 | this.show_stats = options.showStats || false;
57 | this.show_info = options.showInfo || false;
58 | this.show_labels = options.showLabels || false;
59 | this.selection = options.selection || false;
60 | this.limit = options.limit || 10;
61 | this.nodes_count = options.numNodes || 20;
62 | this.edges_count = options.numEdges || 10;
63 |
64 | var camera, controls, scene, renderer, interaction, geometry, object_selection;
65 | var stats;
66 | var info_text = {};
67 | var graph = new GRAPHVIS.Graph({limit: options.limit});
68 |
69 | var geometries = [];
70 |
71 | var that=this;
72 |
73 | init();
74 | createGraph();
75 | animate();
76 |
77 | function init() {
78 | // Three.js initialization
79 | renderer = new THREE.WebGLRenderer({alpha: true, antialias: true});
80 | renderer.setPixelRatio(window.devicePixelRatio);
81 | renderer.setSize(window.innerWidth, window.innerHeight);
82 |
83 |
84 | camera = new THREE.PerspectiveCamera(40, window.innerWidth/window.innerHeight, 1, 1000000);
85 | camera.position.z = 10000;
86 |
87 | controls = new THREE.TrackballControls(camera);
88 |
89 | controls.rotateSpeed = 0.5;
90 | controls.zoomSpeed = 5.2;
91 | controls.panSpeed = 1;
92 |
93 | controls.noZoom = false;
94 | controls.noPan = false;
95 |
96 | controls.staticMoving = false;
97 | controls.dynamicDampingFactor = 0.3;
98 |
99 | controls.keys = [ 65, 83, 68 ];
100 |
101 | controls.addEventListener('change', render);
102 |
103 | scene = new THREE.Scene();
104 |
105 | // Node geometry
106 | if(that.layout === "3d") {
107 | geometry = new THREE.SphereGeometry(30);
108 | } else {
109 | geometry = new THREE.BoxGeometry( 50, 50, 0 );
110 | }
111 |
112 | // Create node selection, if set
113 | if(that.selection) {
114 | object_selection = new THREE.ObjectSelection({
115 | domElement: renderer.domElement,
116 | selected: function(obj) {
117 | // display info
118 | if(obj !== null) {
119 | info_text.select = "Object " + obj.id;
120 | } else {
121 | delete info_text.select;
122 | }
123 | },
124 | clicked: function(obj) {
125 | }
126 | });
127 | }
128 |
129 | document.body.appendChild( renderer.domElement );
130 |
131 | // Stats.js
132 | if(that.show_stats) {
133 | stats = new Stats();
134 | stats.domElement.style.position = 'absolute';
135 | stats.domElement.style.top = '0px';
136 | document.body.appendChild( stats.domElement );
137 | }
138 |
139 | // Create info box
140 | if(that.show_info) {
141 | var info = document.createElement("div");
142 | var id_attr = document.createAttribute("id");
143 | id_attr.nodeValue = "graph-info";
144 | info.setAttributeNode(id_attr);
145 | document.body.appendChild( info );
146 | }
147 | }
148 |
149 |
150 | /**
151 | * Creates a graph with random nodes and edges.
152 | * Number of nodes and edges can be set with
153 | * numNodes and numEdges.
154 | */
155 | function createGraph() {
156 |
157 | var node = new GRAPHVIS.Node(0);
158 | node.data.title = "This is node " + node.id;
159 | graph.addNode(node);
160 | drawNode(node);
161 |
162 | var nodes = [];
163 | nodes.push(node);
164 |
165 | var steps = 1;
166 | while(nodes.length !== 0 && steps < that.nodes_count) {
167 | node = nodes.shift();
168 |
169 | var numEdges = randomFromTo(1, that.edges_count);
170 | for(var i=1; i <= numEdges; i++) {
171 | var target_node = new GRAPHVIS.Node(i*steps);
172 | if(graph.addNode(target_node)) {
173 | target_node.data.title = "This is node " + target_node.id;
174 |
175 | drawNode(target_node);
176 | nodes.push(target_node);
177 | if(graph.addEdge(node, target_node)) {
178 | drawEdge(node, target_node);
179 | }
180 | }
181 | }
182 | steps++;
183 | }
184 |
185 | that.layout_options.width = that.layout_options.width || 2000;
186 | that.layout_options.height = that.layout_options.height || 2000;
187 | that.layout_options.iterations = that.layout_options.iterations || 100000;
188 | that.layout_options.layout = that.layout_options.layout || that.layout;
189 | graph.layout = new Layout.ForceDirected(graph, that.layout_options);
190 | graph.layout.init();
191 | info_text.nodes = "Nodes " + graph.nodes.length;
192 | info_text.edges = "Edges " + graph.edges.length;
193 | }
194 |
195 |
196 | /**
197 | * Create a node object and add it to the scene.
198 | */
199 | function drawNode(node) {
200 | var draw_object = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: Math.random() * 0xe0e0e0, opacity: 0.8 } ) );
201 | var label_object;
202 |
203 | if(that.show_labels) {
204 | if(node.data.title !== undefined) {
205 | label_object = new THREE.Label(node.data.title);
206 | } else {
207 | label_object = new THREE.Label(node.id);
208 | }
209 | node.data.label_object = label_object;
210 | scene.add( node.data.label_object );
211 | }
212 |
213 | var area = 5000;
214 | draw_object.position.x = Math.floor(Math.random() * (area + area + 1) - area);
215 | draw_object.position.y = Math.floor(Math.random() * (area + area + 1) - area);
216 |
217 | if(that.layout === "3d") {
218 | draw_object.position.z = Math.floor(Math.random() * (area + area + 1) - area);
219 | }
220 |
221 | draw_object.id = node.id;
222 | node.data.draw_object = draw_object;
223 | node.position = draw_object.position;
224 | scene.add( node.data.draw_object );
225 | }
226 |
227 |
228 | /**
229 | * Create an edge object (line) and add it to the scene.
230 | */
231 | function drawEdge(source, target) {
232 | material = new THREE.LineBasicMaterial({ color: 0x606060 });
233 |
234 | var tmp_geo = new THREE.Geometry();
235 | tmp_geo.vertices.push(source.data.draw_object.position);
236 | tmp_geo.vertices.push(target.data.draw_object.position);
237 |
238 | line = new THREE.LineSegments( tmp_geo, material );
239 | line.scale.x = line.scale.y = line.scale.z = 1;
240 | line.originalScale = 1;
241 |
242 | // NOTE: Deactivated frustumCulled, otherwise it will not draw all lines (even though
243 | // it looks like the lines are in the view frustum).
244 | line.frustumCulled = false;
245 |
246 | geometries.push(tmp_geo);
247 |
248 | scene.add( line );
249 | }
250 |
251 |
252 | function animate() {
253 | requestAnimationFrame( animate );
254 | controls.update();
255 | render();
256 | if(that.show_info) {
257 | printInfo();
258 | }
259 | }
260 |
261 |
262 | function render() {
263 | var i, length, node;
264 |
265 | // Generate layout if not finished
266 | if(!graph.layout.finished) {
267 | info_text.calc = "Calculating layout...";
268 | graph.layout.generate();
269 | } else {
270 | info_text.calc = "";
271 | }
272 |
273 | // Update position of lines (edges)
274 | for(i=0; i
5 |
6 |
7 | Graph Visualization
8 |
9 |
10 |
11 |
12 |
13 | -->
14 |
15 |
16 |
17 |
18 | Graph Visualization
19 |
20 |
21 |
22 |
28 |
29 |
52 |
53 |
54 |
65 |
66 |
67 | Rotate: Left Mouse Button and Move
68 | Zoom: Press Key S + Left Mouse Button and Move
69 | Drag: Press Key D + Left Mouse Button and Move
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/examples/sphere_graph/sphere_graph.js:
--------------------------------------------------------------------------------
1 | /**
2 | @author David Piegza
3 |
4 | Implements a sphere graph drawing with force-directed placement.
5 |
6 | It uses the force-directed-layout implemented in:
7 | https://github.com/davidpiegza/Graph-Visualization/blob/master/layouts/force-directed-layout.js
8 |
9 | Drawing is done with Three.js: http://github.com/mrdoob/three.js
10 |
11 | To use this drawing, include the graph-min.js file and create a SphereGraph object:
12 |
13 |
14 |
15 |
16 | Graph Visualization
17 |
18 |
19 |
20 |
21 |
22 |
23 | Parameters:
24 | options = {
25 | layout: "2d" or "3d"
26 |
27 | showStats: , displays FPS box
28 | showInfo: , displays some info on the graph and layout
29 | The info box is created as , it must be
30 | styled and positioned with CSS.
31 |
32 |
33 | selection:
, enables selection of nodes on mouse over (it displays some info
34 | when the showInfo flag is set)
35 |
36 |
37 | limit: , maximum number of nodes
38 |
39 | numNodes: - sets the number of nodes to create.
40 | numEdges: - sets the maximum number of edges for a node. A node will have
41 | 1 to numEdges edges, this is set randomly.
42 | }
43 |
44 |
45 | Feel free to contribute a new drawing!
46 |
47 | */
48 |
49 |
50 | var Drawing = Drawing || {};
51 |
52 | Drawing.SphereGraph = function(options) {
53 | options = options || {};
54 |
55 | this.layout = options.layout || "2d";
56 | this.show_stats = options.showStats || false;
57 | this.show_info = options.showInfo || false;
58 | this.selection = options.selection || false;
59 | this.limit = options.limit || 10;
60 | this.nodes_count = options.numNodes || 20;
61 | this.edges_count = options.numEdges || 10;
62 |
63 | var camera, controls, scene, renderer, interaction, geometry, object_selection;
64 | var stats;
65 | var info_text = {};
66 | var graph = new GRAPHVIS.Graph({limit: options.limit});
67 |
68 | var geometries = [];
69 |
70 | var sphere_radius = 4900;
71 | var max_X = sphere_radius;
72 | var min_X = -sphere_radius;
73 | var max_Y = sphere_radius;
74 | var min_Y = -sphere_radius;
75 |
76 | var that=this;
77 |
78 | init();
79 | createGraph();
80 | animate();
81 |
82 | function init() {
83 | // Three.js initialization
84 | renderer = new THREE.WebGLRenderer({alpha: true});
85 | renderer.setSize( window.innerWidth, window.innerHeight );
86 |
87 | camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 100000);
88 | camera.position.z = 20000;
89 |
90 | controls = new THREE.TrackballControls(camera);
91 |
92 | controls.rotateSpeed = 0.5;
93 | controls.zoomSpeed = 5.2;
94 | controls.panSpeed = 1;
95 |
96 | controls.noZoom = false;
97 | controls.noPan = false;
98 |
99 | controls.staticMoving = false;
100 | controls.dynamicDampingFactor = 0.3;
101 |
102 | controls.keys = [ 65, 83, 68 ];
103 |
104 | controls.addEventListener('change', render);
105 |
106 | scene = new THREE.Scene();
107 |
108 | // Create sphere geometry and add it to the scene
109 | var sphere_geometry = new THREE.SphereGeometry(sphere_radius, 110, 100);
110 | material = new THREE.MeshBasicMaterial({ color: 0x000000, opacity: 0.8 });
111 | mesh = new THREE.Mesh(sphere_geometry, material);
112 | scene.add(mesh);
113 |
114 | // Create node geometry (will be used in drawNode())
115 | geometry = new THREE.SphereGeometry( 25, 25, 0 );
116 |
117 | // Create node selection, if set
118 | if(that.selection) {
119 | object_selection = new THREE.ObjectSelection({
120 | domElement: renderer.domElement,
121 | selected: function(obj) {
122 | // display info
123 | if(obj !== null) {
124 | info_text.select = "Object " + obj.id;
125 | } else {
126 | delete info_text.select;
127 | }
128 | }
129 | });
130 | }
131 |
132 | document.body.appendChild( renderer.domElement );
133 |
134 | // Stats.js
135 | if(that.show_stats) {
136 | stats = new Stats();
137 | stats.domElement.style.position = 'absolute';
138 | stats.domElement.style.top = '0px';
139 | document.body.appendChild( stats.domElement );
140 | }
141 |
142 | // Create info box
143 | if(that.show_info) {
144 | var info = document.createElement("div");
145 | var id_attr = document.createAttribute("id");
146 | id_attr.nodeValue = "graph-info";
147 | info.setAttributeNode(id_attr);
148 | document.body.appendChild( info );
149 | }
150 | }
151 |
152 |
153 | /**
154 | * Creates a graph with random nodes and edges.
155 | * Number of nodes and edges can be set with
156 | * numNodes and numEdges.
157 | */
158 | function createGraph() {
159 | var node = new GRAPHVIS.Node(0);
160 | graph.addNode(node);
161 | drawNode(node);
162 |
163 | var nodes = [];
164 | nodes.push(node);
165 |
166 | var steps = 1;
167 | while(nodes.length !== 0 && steps < that.nodes_count) {
168 | node = nodes.shift();
169 |
170 | var numEdges = randomFromTo(1, that.edges_count);
171 | for(var i=1; i <= numEdges; i++) {
172 | var target_node = new GRAPHVIS.Node(i*steps);
173 | if(graph.addNode(target_node)) {
174 | drawNode(target_node);
175 | nodes.push(target_node);
176 | if(graph.addEdge(node, target_node)) {
177 | drawEdge(node, target_node);
178 | }
179 | }
180 | }
181 | steps++;
182 | }
183 |
184 | // Transform a lat, lng-position to x,y.
185 | graph.layout = new Layout.ForceDirected(graph, {width: 2000, height: 2000, iterations: 1000, positionUpdated: function(node) {
186 | max_X = Math.max(max_X, node.position.x);
187 | min_X = Math.min(min_X, node.position.x);
188 | max_Y = Math.max(max_Y, node.position.y);
189 | min_Y = Math.min(min_Y, node.position.y);
190 |
191 | var lat, lng;
192 | if(node.position.x < 0) {
193 | lat = (-90/min_X) * node.position.x;
194 | } else {
195 | lat = (90/max_X) * node.position.x;
196 | }
197 | if(node.position.y < 0) {
198 | lng = (-180/min_Y) * node.position.y;
199 | } else {
200 | lng = (180/max_Y) * node.position.y;
201 | }
202 |
203 | var area = 5000;
204 | var phi = (90 - lat) * Math.PI / 180;
205 | var theta = (180 - lng) * Math.PI / 180;
206 | node.data.draw_object.position.x = area * Math.sin(phi) * Math.cos(theta);
207 | node.data.draw_object.position.y = area * Math.cos(phi);
208 | node.data.draw_object.position.z = area * Math.sin(phi) * Math.sin(theta);
209 |
210 | }});
211 | graph.layout.init();
212 | info_text.nodes = "Nodes " + graph.nodes.length;
213 | info_text.edges = "Edges " + graph.edges.length;
214 | }
215 |
216 |
217 | /**
218 | * Create a node object and add it to the scene.
219 | */
220 | function drawNode(node) {
221 | var draw_object = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ) );
222 |
223 | var area = 2000;
224 | draw_object.position.x = Math.floor(Math.random() * (area + area + 1) - area);
225 | draw_object.position.y = Math.floor(Math.random() * (area + area + 1) - area);
226 |
227 | node.position.x = Math.floor(Math.random() * (area + area + 1) - area);
228 | node.position.y = Math.floor(Math.random() * (area + area + 1) - area);
229 |
230 | draw_object.id = node.id;
231 | node.data.draw_object = draw_object;
232 | node.layout = {};
233 | node.layout.max_X = 90;
234 | node.layout.min_X = -90;
235 | node.layout.max_Y = 180;
236 | node.layout.min_Y = -180;
237 |
238 | // node.position = draw_object.position;
239 | scene.add( node.data.draw_object );
240 | }
241 |
242 |
243 | /**
244 | * Create an edge object (line) and add it to the scene.
245 | */
246 | function drawEdge(source, target) {
247 | material = new THREE.LineBasicMaterial( { color: 0xCCCCCC, opacity: 0.5, linewidth: 0.5 } );
248 | var tmp_geo = new THREE.Geometry();
249 |
250 | tmp_geo.vertices.push(source.data.draw_object.position);
251 | tmp_geo.vertices.push(target.data.draw_object.position);
252 |
253 | line = new THREE.LineSegments( tmp_geo, material );
254 | line.scale.x = line.scale.y = line.scale.z = 1;
255 | line.originalScale = 1;
256 |
257 | geometries.push(tmp_geo);
258 |
259 | scene.add( line );
260 | }
261 |
262 |
263 | function animate() {
264 | requestAnimationFrame( animate );
265 | controls.update();
266 | render();
267 | if(that.show_info) {
268 | printInfo();
269 | }
270 | }
271 |
272 |
273 | function render() {
274 | var i;
275 |
276 | // Generate layout if not finished
277 | if(!graph.layout.finished) {
278 | info_text.calc = "Calculating layout...";
279 | graph.layout.generate();
280 | } else {
281 | info_text.calc = "";
282 | }
283 |
284 | // Update position of lines (edges)
285 | for(i=0; i
2 |
3 |
4 |
5 | Graph Visualization
6 |
7 |
53 |
54 |
55 |
56 |