jsmetric4java 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +7 -0
- data/.rvmrc +1 -0
- data/Gemfile +8 -0
- data/README +16 -0
- data/Rakefile +37 -0
- data/bin/jsmetric4java +20 -0
- data/boot.rb +5 -0
- data/build +1 -0
- data/features/cyclometric_complexity/boolean_complexity_counting.feature +46 -0
- data/features/cyclometric_complexity/case_complexity_counting.feature +117 -0
- data/features/cyclometric_complexity/exception_complexity_counting.feature +81 -0
- data/features/cyclometric_complexity/function_detection.feature +128 -0
- data/features/cyclometric_complexity/if_else_complexity_counting.feature +178 -0
- data/features/cyclometric_complexity/loop_complexity_counting.feature +81 -0
- data/features/graphing/draw_basic_graph.feature +14 -0
- data/features/reporting/report.feature +13 -0
- data/features/sample_js_files_for_test/foobar.js +30 -0
- data/features/step_definitions/cyclometric_complexity_steps.rb +31 -0
- data/features/step_definitions/graph_steps.rb +10 -0
- data/features/step_definitions/reporting_steps.rb +14 -0
- data/features/support/env.rb +1 -0
- data/jsgraphlib/Curry-1.0.1.js +29 -0
- data/jsgraphlib/dracula_algorithms.js +599 -0
- data/jsgraphlib/dracula_graffle.js +106 -0
- data/jsgraphlib/dracula_graph.js +534 -0
- data/jsgraphlib/graphtest.html +57 -0
- data/jsgraphlib/jquery-1.4.2.min.js +154 -0
- data/jsgraphlib/jsgraphsource.js +12 -0
- data/jsgraphlib/raphael-min.js +7 -0
- data/jsgraphlib/seedrandom.js +266 -0
- data/jsmetric.gemspec +23 -0
- data/lib/cc_report.rb +24 -0
- data/lib/complexity_analyser.rb +90 -0
- data/lib/fulljslint.js +6100 -0
- data/lib/graphing/graph_analyser.rb +19 -0
- data/lib/js_lint.rb +23 -0
- data/lib/json2.js +480 -0
- data/lib/options.js +24 -0
- data/lib/report.rb +26 -0
- data/lib/utils.rb +18 -0
- data/lib/version.rb +3 -0
- data/spec/spec_helper.rb +1 -0
- data/tasks/dev.rb +4 -0
- data/tasks/run.rb +55 -0
- metadata +129 -0
| @@ -0,0 +1,534 @@ | |
| 1 | 
            +
            /*
         | 
| 2 | 
            +
             *  Dracula Graph Layout and Drawing Framework 0.0.3alpha
         | 
| 3 | 
            +
             *  (c) 2010 Philipp Strathausen <strathausen@gmail.com>, http://strathausen.eu
         | 
| 4 | 
            +
             *
         | 
| 5 | 
            +
             *  based on the Graph JavaScript framework, version 0.0.1
         | 
| 6 | 
            +
             *  (c) 2006 Aslak Hellesoy <aslak.hellesoy@gmail.com>
         | 
| 7 | 
            +
             *  (c) 2006 Dave Hoover <dave.hoover@gmail.com>
         | 
| 8 | 
            +
             *
         | 
| 9 | 
            +
             *  Ported from Graph::Layouter::Spring in
         | 
| 10 | 
            +
             *    http://search.cpan.org/~pasky/Graph-Layderer-0.02/
         | 
| 11 | 
            +
             *  The algorithm is based on a spring-style layouter of a Java-based social
         | 
| 12 | 
            +
             *  network tracker PieSpy written by Paul Mutton E<lt>paul@jibble.orgE<gt>.
         | 
| 13 | 
            +
             *
         | 
| 14 | 
            +
             *  This code is freely distributable under the terms of an MIT-style license.
         | 
| 15 | 
            +
             *  For details, see the Graph web site: http://dev.buildpatternd.com/trac
         | 
| 16 | 
            +
             *
         | 
| 17 | 
            +
             *  Links:
         | 
| 18 | 
            +
             *
         | 
| 19 | 
            +
             *  Graph Dracula JavaScript Framework:
         | 
| 20 | 
            +
             *      http://graphdracula.net
         | 
| 21 | 
            +
             *
         | 
| 22 | 
            +
             *  Demo of the original applet:
         | 
| 23 | 
            +
             *      http://redsquirrel.com/dave/work/webdep/
         | 
| 24 | 
            +
             *
         | 
| 25 | 
            +
             *  Mirrored original source code at snipplr:
         | 
| 26 | 
            +
             *      http://snipplr.com/view/1950/graph-javascript-framework-version-001/
         | 
| 27 | 
            +
             *
         | 
| 28 | 
            +
             *  Original usage example:
         | 
| 29 | 
            +
             *      http://ajaxian.com/archives/new-javascriptcanvas-graph-library
         | 
| 30 | 
            +
             *
         | 
| 31 | 
            +
             /*--------------------------------------------------------------------------*/
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            // Branched by Jake Stothard <stothardj@gmail.com>.
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            /*
         | 
| 36 | 
            +
             * Edge Factory
         | 
| 37 | 
            +
             */
         | 
| 38 | 
            +
            var AbstractEdge = function() {
         | 
| 39 | 
            +
            }
         | 
| 40 | 
            +
            AbstractEdge.prototype = {
         | 
| 41 | 
            +
                hide: function() {
         | 
| 42 | 
            +
            	this.connection.fg.hide();
         | 
| 43 | 
            +
            	this.connection.bg && this.bg.connection.hide();
         | 
| 44 | 
            +
                }
         | 
| 45 | 
            +
            };
         | 
| 46 | 
            +
            var EdgeFactory = function() {
         | 
| 47 | 
            +
                this.template = new AbstractEdge();
         | 
| 48 | 
            +
                this.template.style = new Object();
         | 
| 49 | 
            +
                this.template.style.directed = false;
         | 
| 50 | 
            +
                this.template.weight = 1;
         | 
| 51 | 
            +
            };
         | 
| 52 | 
            +
            EdgeFactory.prototype = {
         | 
| 53 | 
            +
                build: function(source, target) {
         | 
| 54 | 
            +
            	var e = jQuery.extend(true, {}, this.template);
         | 
| 55 | 
            +
            	e.source = source;
         | 
| 56 | 
            +
            	e.target = target;
         | 
| 57 | 
            +
            	return e;
         | 
| 58 | 
            +
                }
         | 
| 59 | 
            +
            };
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            /*
         | 
| 62 | 
            +
             * Graph
         | 
| 63 | 
            +
             */
         | 
| 64 | 
            +
            var Graph = function() {
         | 
| 65 | 
            +
                this.nodes = new Object();
         | 
| 66 | 
            +
                this.edges = [];
         | 
| 67 | 
            +
                this.snapshots = []; // previous graph states TODO to be implemented
         | 
| 68 | 
            +
                this.edgeFactory = new EdgeFactory();
         | 
| 69 | 
            +
            };
         | 
| 70 | 
            +
            Graph.prototype = {
         | 
| 71 | 
            +
                /* 
         | 
| 72 | 
            +
                 * add a node
         | 
| 73 | 
            +
                 * @id          the node's ID (string or number)
         | 
| 74 | 
            +
                 * @content     (optional, dictionary) can contain any information that is
         | 
| 75 | 
            +
                 *              being interpreted by the layout algorithm or the graph
         | 
| 76 | 
            +
                 *              representation
         | 
| 77 | 
            +
                 */
         | 
| 78 | 
            +
                addNode: function(id, content) {
         | 
| 79 | 
            +
                    /* testing if node is already existing in the graph */
         | 
| 80 | 
            +
                    if(this.nodes[id] == undefined) {
         | 
| 81 | 
            +
            	    this.nodes[id] = new Graph.Node(id, content);
         | 
| 82 | 
            +
                    }
         | 
| 83 | 
            +
                    return this.nodes[id];
         | 
| 84 | 
            +
                },
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                addEdge: function(source, target, style) {
         | 
| 87 | 
            +
                    var s = this.addNode(source);
         | 
| 88 | 
            +
                    var t = this.addNode(target);
         | 
| 89 | 
            +
            	var edge = this.edgeFactory.build(s, t);
         | 
| 90 | 
            +
            	jQuery.extend(edge.style,style);
         | 
| 91 | 
            +
                    s.edges.push(edge);
         | 
| 92 | 
            +
                    this.edges.push(edge);
         | 
| 93 | 
            +
            	// NOTE: Even directed edges are added to both nodes.
         | 
| 94 | 
            +
            	t.edges.push(edge);
         | 
| 95 | 
            +
                },
         | 
| 96 | 
            +
                
         | 
| 97 | 
            +
                /* TODO to be implemented
         | 
| 98 | 
            +
                 * Preserve a copy of the graph state (nodes, positions, ...)
         | 
| 99 | 
            +
                 * @comment     a comment describing the state
         | 
| 100 | 
            +
                 */
         | 
| 101 | 
            +
                snapShot: function(comment) {
         | 
| 102 | 
            +
            	/* FIXME
         | 
| 103 | 
            +
                    var graph = new Graph();
         | 
| 104 | 
            +
            	graph.nodes = jQuery.extend(true, {}, this.nodes);
         | 
| 105 | 
            +
            	graph.edges = jQuery.extend(true, {}, this.edges);
         | 
| 106 | 
            +
                    this.snapshots.push({comment: comment, graph: graph});
         | 
| 107 | 
            +
            	*/
         | 
| 108 | 
            +
                },
         | 
| 109 | 
            +
                removeNode: function(id) {
         | 
| 110 | 
            +
            	delete this.nodes[id];
         | 
| 111 | 
            +
                    for(var i = 0; i < this.edges.length; i++) {
         | 
| 112 | 
            +
                        if (this.edges[i].source.id == id || this.edges[i].target.id == id) {
         | 
| 113 | 
            +
            		this.edges.splice(i, 1);
         | 
| 114 | 
            +
            		i--;
         | 
| 115 | 
            +
            	    }
         | 
| 116 | 
            +
            	}
         | 
| 117 | 
            +
                }
         | 
| 118 | 
            +
            };
         | 
| 119 | 
            +
             | 
| 120 | 
            +
            /*
         | 
| 121 | 
            +
             * Node
         | 
| 122 | 
            +
             */
         | 
| 123 | 
            +
            Graph.Node = function(id, node){
         | 
| 124 | 
            +
                node = node || {};
         | 
| 125 | 
            +
                node.id = id;
         | 
| 126 | 
            +
                node.edges = [];
         | 
| 127 | 
            +
                node.hide = function() {
         | 
| 128 | 
            +
                    this.hidden = true;
         | 
| 129 | 
            +
                    this.shape && this.shape.hide(); /* FIXME this is representation specific code and should be elsewhere */
         | 
| 130 | 
            +
                    for(i in this.edges)
         | 
| 131 | 
            +
                        (this.edges[i].source.id == id || this.edges[i].target == id) && this.edges[i].hide && this.edges[i].hide();
         | 
| 132 | 
            +
                };
         | 
| 133 | 
            +
                node.show = function() {
         | 
| 134 | 
            +
                    this.hidden = false;
         | 
| 135 | 
            +
                    this.shape && this.shape.show();
         | 
| 136 | 
            +
                    for(i in this.edges)
         | 
| 137 | 
            +
                        (this.edges[i].source.id == id || this.edges[i].target == id) && this.edges[i].show && this.edges[i].show();
         | 
| 138 | 
            +
                };
         | 
| 139 | 
            +
                return node;
         | 
| 140 | 
            +
            };
         | 
| 141 | 
            +
            Graph.Node.prototype = {
         | 
| 142 | 
            +
            };
         | 
| 143 | 
            +
             | 
| 144 | 
            +
            /*
         | 
| 145 | 
            +
             * Renderer base class
         | 
| 146 | 
            +
             */
         | 
| 147 | 
            +
            Graph.Renderer = {};
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            /*
         | 
| 150 | 
            +
             * Renderer implementation using RaphaelJS
         | 
| 151 | 
            +
             */
         | 
| 152 | 
            +
            Graph.Renderer.Raphael = function(element, graph, width, height) {
         | 
| 153 | 
            +
                this.width = width || 400;
         | 
| 154 | 
            +
                this.height = height || 400;
         | 
| 155 | 
            +
                var selfRef = this;
         | 
| 156 | 
            +
                this.r = Raphael(element, this.width, this.height);
         | 
| 157 | 
            +
                this.radius = 40; /* max dimension of a node */
         | 
| 158 | 
            +
                this.graph = graph;
         | 
| 159 | 
            +
                this.mouse_in = false;
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                /* TODO default node rendering function */
         | 
| 162 | 
            +
                if(!this.graph.render) {
         | 
| 163 | 
            +
                    this.graph.render = function() {
         | 
| 164 | 
            +
                        return;
         | 
| 165 | 
            +
                    }
         | 
| 166 | 
            +
                }
         | 
| 167 | 
            +
                
         | 
| 168 | 
            +
                /*
         | 
| 169 | 
            +
                 * Dragging
         | 
| 170 | 
            +
                 */
         | 
| 171 | 
            +
                this.isDrag = false;
         | 
| 172 | 
            +
                this.dragger = function (e) {
         | 
| 173 | 
            +
                    this.dx = e.clientX;
         | 
| 174 | 
            +
                    this.dy = e.clientY;
         | 
| 175 | 
            +
                    selfRef.isDrag = this;
         | 
| 176 | 
            +
                    this.set && this.set.animate({"fill-opacity": .1}, 200) && this.set.toFront();
         | 
| 177 | 
            +
                    e.preventDefault && e.preventDefault();
         | 
| 178 | 
            +
                };
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                document.onmousemove = function (e) {
         | 
| 181 | 
            +
                    e = e || window.event;
         | 
| 182 | 
            +
                    if (selfRef.isDrag) {
         | 
| 183 | 
            +
                        var bBox = selfRef.isDrag.set.getBBox();
         | 
| 184 | 
            +
                        // TODO round the coordinates here (eg. for proper image representation)
         | 
| 185 | 
            +
                        var newX = e.clientX - selfRef.isDrag.dx + (bBox.x + bBox.width / 2);
         | 
| 186 | 
            +
                        var newY = e.clientY - selfRef.isDrag.dy + (bBox.y + bBox.height / 2);
         | 
| 187 | 
            +
                        /* prevent shapes from being dragged out of the canvas */
         | 
| 188 | 
            +
                        var clientX = e.clientX - (newX < 20 ? newX - 20 : newX > selfRef.width - 20 ? newX - selfRef.width + 20 : 0);
         | 
| 189 | 
            +
                        var clientY = e.clientY - (newY < 20 ? newY - 20 : newY > selfRef.height - 20 ? newY - selfRef.height + 20 : 0);
         | 
| 190 | 
            +
                        selfRef.isDrag.set.translate(clientX - Math.round(selfRef.isDrag.dx), clientY - Math.round(selfRef.isDrag.dy));
         | 
| 191 | 
            +
            	    //            console.log(clientX - Math.round(selfRef.isDrag.dx), clientY - Math.round(selfRef.isDrag.dy));
         | 
| 192 | 
            +
                        for (var i in selfRef.graph.edges) {
         | 
| 193 | 
            +
                            selfRef.graph.edges[i].connection && selfRef.graph.edges[i].connection.draw();
         | 
| 194 | 
            +
                        }
         | 
| 195 | 
            +
                        //selfRef.r.safari();
         | 
| 196 | 
            +
                        selfRef.isDrag.dx = clientX;
         | 
| 197 | 
            +
                        selfRef.isDrag.dy = clientY;
         | 
| 198 | 
            +
                    }
         | 
| 199 | 
            +
                };
         | 
| 200 | 
            +
                document.onmouseup = function () {
         | 
| 201 | 
            +
                    selfRef.isDrag && selfRef.isDrag.set.animate({"fill-opacity": .6}, 500);
         | 
| 202 | 
            +
                    selfRef.isDrag = false;
         | 
| 203 | 
            +
                };
         | 
| 204 | 
            +
                this.draw();
         | 
| 205 | 
            +
            };
         | 
| 206 | 
            +
            Graph.Renderer.Raphael.prototype = {
         | 
| 207 | 
            +
                translate: function(point) {
         | 
| 208 | 
            +
                    return [
         | 
| 209 | 
            +
                        (point[0] - this.graph.layoutMinX) * this.factorX + this.radius,
         | 
| 210 | 
            +
                        (point[1] - this.graph.layoutMinY) * this.factorY + this.radius
         | 
| 211 | 
            +
                    ];
         | 
| 212 | 
            +
                },
         | 
| 213 | 
            +
             | 
| 214 | 
            +
                rotate: function(point, length, angle) {
         | 
| 215 | 
            +
                    var dx = length * Math.cos(angle);
         | 
| 216 | 
            +
                    var dy = length * Math.sin(angle);
         | 
| 217 | 
            +
                    return [point[0]+dx, point[1]+dy];
         | 
| 218 | 
            +
                },
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                draw: function() {
         | 
| 221 | 
            +
                    this.factorX = (this.width - 2 * this.radius) / (this.graph.layoutMaxX - this.graph.layoutMinX);
         | 
| 222 | 
            +
                    this.factorY = (this.height - 2 * this.radius) / (this.graph.layoutMaxY - this.graph.layoutMinY);
         | 
| 223 | 
            +
                    for (i in this.graph.nodes) {
         | 
| 224 | 
            +
                        this.drawNode(this.graph.nodes[i]);
         | 
| 225 | 
            +
                    }
         | 
| 226 | 
            +
                    for (var i = 0; i < this.graph.edges.length; i++) {
         | 
| 227 | 
            +
                        this.drawEdge(this.graph.edges[i]);
         | 
| 228 | 
            +
                    }
         | 
| 229 | 
            +
                },
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                drawNode: function(node) {
         | 
| 232 | 
            +
                    var point = this.translate([node.layoutPosX, node.layoutPosY]);
         | 
| 233 | 
            +
                    node.point = point;
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                    /* if node has already been drawn, move the nodes */
         | 
| 236 | 
            +
                    if(node.shape) {
         | 
| 237 | 
            +
                        var oBBox = node.shape.getBBox();
         | 
| 238 | 
            +
                        var opoint = { x: oBBox.x + oBBox.width / 2, y: oBBox.y + oBBox.height / 2};
         | 
| 239 | 
            +
                        node.shape.translate(Math.round(point[0] - opoint.x), Math.round(point[1] - opoint.y));
         | 
| 240 | 
            +
                        this.r.safari();
         | 
| 241 | 
            +
                        return node;
         | 
| 242 | 
            +
                    }/* else, draw new nodes */
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                    var shape;
         | 
| 245 | 
            +
             | 
| 246 | 
            +
                    /* if a node renderer function is provided by the user, then use it 
         | 
| 247 | 
            +
                       or the default render function instead */
         | 
| 248 | 
            +
                    if(!node.render) {
         | 
| 249 | 
            +
                        node.render = function(r, node) {
         | 
| 250 | 
            +
                            /* the default node drawing */
         | 
| 251 | 
            +
                            var color = Raphael.getColor();
         | 
| 252 | 
            +
                            var ellipse = r.ellipse(0, 0, 30, 20).attr({fill: color, stroke: color, "stroke-width": 2});
         | 
| 253 | 
            +
                            /* set DOM node ID */
         | 
| 254 | 
            +
                            ellipse.node.id = node.label || node.id;
         | 
| 255 | 
            +
                            shape = r.set().
         | 
| 256 | 
            +
                                push(ellipse).
         | 
| 257 | 
            +
                                push(r.text(0, 30, node.label || node.id));
         | 
| 258 | 
            +
                            return shape;
         | 
| 259 | 
            +
                        }
         | 
| 260 | 
            +
                    }
         | 
| 261 | 
            +
                    /* or check for an ajax representation of the nodes */
         | 
| 262 | 
            +
                    if(node.shapes) {
         | 
| 263 | 
            +
                        // TODO ajax representation evaluation
         | 
| 264 | 
            +
                    }
         | 
| 265 | 
            +
             | 
| 266 | 
            +
                    shape = node.render(this.r, node).hide();
         | 
| 267 | 
            +
             | 
| 268 | 
            +
                    shape.attr({"fill-opacity": .6});
         | 
| 269 | 
            +
                    /* re-reference to the node an element belongs to, needed for dragging all elements of a node */
         | 
| 270 | 
            +
                    shape.items.forEach(function(item){ item.set = shape; item.node.style.cursor = "move"; });
         | 
| 271 | 
            +
                    shape.mousedown(this.dragger);
         | 
| 272 | 
            +
             | 
| 273 | 
            +
                    var box = shape.getBBox();
         | 
| 274 | 
            +
                    shape.translate(Math.round(point[0]-(box.x+box.width/2)),Math.round(point[1]-(box.y+box.height/2)))
         | 
| 275 | 
            +
                    //console.log(box,point);
         | 
| 276 | 
            +
                    node.hidden || shape.show();
         | 
| 277 | 
            +
                    node.shape = shape;
         | 
| 278 | 
            +
                },
         | 
| 279 | 
            +
                drawEdge: function(edge) {
         | 
| 280 | 
            +
                    /* if this edge already exists the other way around and is undirected */
         | 
| 281 | 
            +
                    if(edge.backedge)
         | 
| 282 | 
            +
                        return;
         | 
| 283 | 
            +
                    if(edge.source.hidden || edge.target.hidden) {
         | 
| 284 | 
            +
                        edge.connection && edge.connection.fg.hide() | edge.connection.bg && edge.connection.bg.hide();
         | 
| 285 | 
            +
                        return;
         | 
| 286 | 
            +
                    }
         | 
| 287 | 
            +
                    /* if edge already has been drawn, only refresh the edge */
         | 
| 288 | 
            +
                    if(!edge.connection) {
         | 
| 289 | 
            +
                        edge.style && edge.style.callback && edge.style.callback(edge); // TODO move this somewhere else
         | 
| 290 | 
            +
                        edge.connection = this.r.connection(edge.source.shape, edge.target.shape, edge.style);
         | 
| 291 | 
            +
                        return;
         | 
| 292 | 
            +
                    }
         | 
| 293 | 
            +
                    //FIXME showing doesn't work well
         | 
| 294 | 
            +
                    edge.connection.fg.show();
         | 
| 295 | 
            +
                    edge.connection.bg && edge.connection.bg.show();
         | 
| 296 | 
            +
                    edge.connection.draw();
         | 
| 297 | 
            +
                }
         | 
| 298 | 
            +
            };
         | 
| 299 | 
            +
            Graph.Layout = {};
         | 
| 300 | 
            +
            Graph.Layout.Spring = function(graph) {
         | 
| 301 | 
            +
                this.graph = graph;
         | 
| 302 | 
            +
                this.iterations = 500;
         | 
| 303 | 
            +
                this.maxRepulsiveForceDistance = 6;
         | 
| 304 | 
            +
                this.k = 2;
         | 
| 305 | 
            +
                this.c = 0.01;
         | 
| 306 | 
            +
                this.maxVertexMovement = 0.5;
         | 
| 307 | 
            +
                this.layout();
         | 
| 308 | 
            +
            };
         | 
| 309 | 
            +
            Graph.Layout.Spring.prototype = {
         | 
| 310 | 
            +
                layout: function() {
         | 
| 311 | 
            +
                    this.layoutPrepare();
         | 
| 312 | 
            +
                    for (var i = 0; i < this.iterations; i++) {
         | 
| 313 | 
            +
                        this.layoutIteration();
         | 
| 314 | 
            +
                    }
         | 
| 315 | 
            +
                    this.layoutCalcBounds();
         | 
| 316 | 
            +
                },
         | 
| 317 | 
            +
                
         | 
| 318 | 
            +
                layoutPrepare: function() {
         | 
| 319 | 
            +
                    for (i in this.graph.nodes) {
         | 
| 320 | 
            +
                        var node = this.graph.nodes[i];
         | 
| 321 | 
            +
                        node.layoutPosX = 0;
         | 
| 322 | 
            +
                        node.layoutPosY = 0;
         | 
| 323 | 
            +
                        node.layoutForceX = 0;
         | 
| 324 | 
            +
                        node.layoutForceY = 0;
         | 
| 325 | 
            +
                    }
         | 
| 326 | 
            +
                    
         | 
| 327 | 
            +
                },
         | 
| 328 | 
            +
                
         | 
| 329 | 
            +
                layoutCalcBounds: function() {
         | 
| 330 | 
            +
                    var minx = Infinity, maxx = -Infinity, miny = Infinity, maxy = -Infinity;
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                    for (i in this.graph.nodes) {
         | 
| 333 | 
            +
                        var x = this.graph.nodes[i].layoutPosX;
         | 
| 334 | 
            +
                        var y = this.graph.nodes[i].layoutPosY;
         | 
| 335 | 
            +
                        
         | 
| 336 | 
            +
                        if(x > maxx) maxx = x;
         | 
| 337 | 
            +
                        if(x < minx) minx = x;
         | 
| 338 | 
            +
                        if(y > maxy) maxy = y;
         | 
| 339 | 
            +
                        if(y < miny) miny = y;
         | 
| 340 | 
            +
                    }
         | 
| 341 | 
            +
             | 
| 342 | 
            +
                    this.graph.layoutMinX = minx;
         | 
| 343 | 
            +
                    this.graph.layoutMaxX = maxx;
         | 
| 344 | 
            +
                    this.graph.layoutMinY = miny;
         | 
| 345 | 
            +
                    this.graph.layoutMaxY = maxy;
         | 
| 346 | 
            +
                },
         | 
| 347 | 
            +
                
         | 
| 348 | 
            +
                layoutIteration: function() {
         | 
| 349 | 
            +
                    // Forces on nodes due to node-node repulsions
         | 
| 350 | 
            +
             | 
| 351 | 
            +
            	var prev = new Array();
         | 
| 352 | 
            +
            	for(var c in this.graph.nodes) {
         | 
| 353 | 
            +
            	    var node1 = this.graph.nodes[c];
         | 
| 354 | 
            +
                        for (var d in prev) {
         | 
| 355 | 
            +
                            var node2 = this.graph.nodes[prev[d]];
         | 
| 356 | 
            +
                            this.layoutRepulsive(node1, node2);
         | 
| 357 | 
            +
            		
         | 
| 358 | 
            +
                        }
         | 
| 359 | 
            +
            	    prev.push(c);
         | 
| 360 | 
            +
            	}
         | 
| 361 | 
            +
            	
         | 
| 362 | 
            +
                    // Forces on nodes due to edge attractions
         | 
| 363 | 
            +
                    for (var i = 0; i < this.graph.edges.length; i++) {
         | 
| 364 | 
            +
                        var edge = this.graph.edges[i];
         | 
| 365 | 
            +
                        this.layoutAttractive(edge);             
         | 
| 366 | 
            +
                    }
         | 
| 367 | 
            +
                    
         | 
| 368 | 
            +
                    // Move by the given force
         | 
| 369 | 
            +
                    for (i in this.graph.nodes) {
         | 
| 370 | 
            +
                        var node = this.graph.nodes[i];
         | 
| 371 | 
            +
                        var xmove = this.c * node.layoutForceX;
         | 
| 372 | 
            +
                        var ymove = this.c * node.layoutForceY;
         | 
| 373 | 
            +
             | 
| 374 | 
            +
                        var max = this.maxVertexMovement;
         | 
| 375 | 
            +
                        if(xmove > max) xmove = max;
         | 
| 376 | 
            +
                        if(xmove < -max) xmove = -max;
         | 
| 377 | 
            +
                        if(ymove > max) ymove = max;
         | 
| 378 | 
            +
                        if(ymove < -max) ymove = -max;
         | 
| 379 | 
            +
                        
         | 
| 380 | 
            +
                        node.layoutPosX += xmove;
         | 
| 381 | 
            +
                        node.layoutPosY += ymove;
         | 
| 382 | 
            +
                        node.layoutForceX = 0;
         | 
| 383 | 
            +
                        node.layoutForceY = 0;
         | 
| 384 | 
            +
                    }
         | 
| 385 | 
            +
                },
         | 
| 386 | 
            +
             | 
| 387 | 
            +
                layoutRepulsive: function(node1, node2) {
         | 
| 388 | 
            +
                    var dx = node2.layoutPosX - node1.layoutPosX;
         | 
| 389 | 
            +
                    var dy = node2.layoutPosY - node1.layoutPosY;
         | 
| 390 | 
            +
                    var d2 = dx * dx + dy * dy;
         | 
| 391 | 
            +
                    if(d2 < 0.01) {
         | 
| 392 | 
            +
                        dx = 0.1 * Math.random() + 0.1;
         | 
| 393 | 
            +
                        dy = 0.1 * Math.random() + 0.1;
         | 
| 394 | 
            +
                        var d2 = dx * dx + dy * dy;
         | 
| 395 | 
            +
                    }
         | 
| 396 | 
            +
                    var d = Math.sqrt(d2);
         | 
| 397 | 
            +
                    if(d < this.maxRepulsiveForceDistance) {
         | 
| 398 | 
            +
                        var repulsiveForce = this.k * this.k / d;
         | 
| 399 | 
            +
                        node2.layoutForceX += repulsiveForce * dx / d;
         | 
| 400 | 
            +
                        node2.layoutForceY += repulsiveForce * dy / d;
         | 
| 401 | 
            +
                        node1.layoutForceX -= repulsiveForce * dx / d;
         | 
| 402 | 
            +
                        node1.layoutForceY -= repulsiveForce * dy / d;
         | 
| 403 | 
            +
                    }
         | 
| 404 | 
            +
                },
         | 
| 405 | 
            +
             | 
| 406 | 
            +
                layoutAttractive: function(edge) {
         | 
| 407 | 
            +
                    var node1 = edge.source;
         | 
| 408 | 
            +
                    var node2 = edge.target;
         | 
| 409 | 
            +
                    
         | 
| 410 | 
            +
                    var dx = node2.layoutPosX - node1.layoutPosX;
         | 
| 411 | 
            +
                    var dy = node2.layoutPosY - node1.layoutPosY;
         | 
| 412 | 
            +
                    var d2 = dx * dx + dy * dy;
         | 
| 413 | 
            +
                    if(d2 < 0.01) {
         | 
| 414 | 
            +
                        dx = 0.1 * Math.random() + 0.1;
         | 
| 415 | 
            +
                        dy = 0.1 * Math.random() + 0.1;
         | 
| 416 | 
            +
                        var d2 = dx * dx + dy * dy;
         | 
| 417 | 
            +
                    }
         | 
| 418 | 
            +
                    var d = Math.sqrt(d2);
         | 
| 419 | 
            +
                    if(d > this.maxRepulsiveForceDistance) {
         | 
| 420 | 
            +
                        d = this.maxRepulsiveForceDistance;
         | 
| 421 | 
            +
                        d2 = d * d;
         | 
| 422 | 
            +
                    }
         | 
| 423 | 
            +
                    var attractiveForce = (d2 - this.k * this.k) / this.k;
         | 
| 424 | 
            +
                    if(edge.attraction == undefined) edge.attraction = 1;
         | 
| 425 | 
            +
                    attractiveForce *= Math.log(edge.attraction) * 0.5 + 1;
         | 
| 426 | 
            +
                    
         | 
| 427 | 
            +
                    node2.layoutForceX -= attractiveForce * dx / d;
         | 
| 428 | 
            +
                    node2.layoutForceY -= attractiveForce * dy / d;
         | 
| 429 | 
            +
                    node1.layoutForceX += attractiveForce * dx / d;
         | 
| 430 | 
            +
                    node1.layoutForceY += attractiveForce * dy / d;
         | 
| 431 | 
            +
                }
         | 
| 432 | 
            +
            };
         | 
| 433 | 
            +
             | 
| 434 | 
            +
            Graph.Layout.Ordered = function(graph, order) {
         | 
| 435 | 
            +
                this.graph = graph;
         | 
| 436 | 
            +
                this.order = order;
         | 
| 437 | 
            +
                this.layout();
         | 
| 438 | 
            +
            };
         | 
| 439 | 
            +
            Graph.Layout.Ordered.prototype = {
         | 
| 440 | 
            +
                layout: function() {
         | 
| 441 | 
            +
                    this.layoutPrepare();
         | 
| 442 | 
            +
                    this.layoutCalcBounds();
         | 
| 443 | 
            +
                },
         | 
| 444 | 
            +
                
         | 
| 445 | 
            +
                layoutPrepare: function(order) {
         | 
| 446 | 
            +
                    for (i in this.graph.nodes) {
         | 
| 447 | 
            +
                        var node = this.graph.nodes[i];
         | 
| 448 | 
            +
                        node.layoutPosX = 0;
         | 
| 449 | 
            +
                        node.layoutPosY = 0;
         | 
| 450 | 
            +
                    }
         | 
| 451 | 
            +
            	var counter = 0;
         | 
| 452 | 
            +
            	for (i in this.order) {
         | 
| 453 | 
            +
            	    var node = this.order[i];
         | 
| 454 | 
            +
            	    node.layoutPosX = counter;
         | 
| 455 | 
            +
            	    node.layoutPosY = Math.random();
         | 
| 456 | 
            +
            	    counter++;
         | 
| 457 | 
            +
            	}
         | 
| 458 | 
            +
                },
         | 
| 459 | 
            +
                
         | 
| 460 | 
            +
                layoutCalcBounds: function() {
         | 
| 461 | 
            +
                    var minx = Infinity, maxx = -Infinity, miny = Infinity, maxy = -Infinity;
         | 
| 462 | 
            +
             | 
| 463 | 
            +
                    for (i in this.graph.nodes) {
         | 
| 464 | 
            +
                        var x = this.graph.nodes[i].layoutPosX;
         | 
| 465 | 
            +
                        var y = this.graph.nodes[i].layoutPosY;
         | 
| 466 | 
            +
                        
         | 
| 467 | 
            +
                        if(x > maxx) maxx = x;
         | 
| 468 | 
            +
                        if(x < minx) minx = x;
         | 
| 469 | 
            +
                        if(y > maxy) maxy = y;
         | 
| 470 | 
            +
                        if(y < miny) miny = y;
         | 
| 471 | 
            +
                    }
         | 
| 472 | 
            +
             | 
| 473 | 
            +
                    this.graph.layoutMinX = minx;
         | 
| 474 | 
            +
                    this.graph.layoutMaxX = maxx;
         | 
| 475 | 
            +
             | 
| 476 | 
            +
                    this.graph.layoutMinY = miny;
         | 
| 477 | 
            +
                    this.graph.layoutMaxY = maxy;
         | 
| 478 | 
            +
                },
         | 
| 479 | 
            +
            };
         | 
| 480 | 
            +
             | 
| 481 | 
            +
            /*
         | 
| 482 | 
            +
             * usefull JavaScript extensions, 
         | 
| 483 | 
            +
             */
         | 
| 484 | 
            +
             | 
| 485 | 
            +
            function log(a) {console.log&&console.log(a);}
         | 
| 486 | 
            +
             | 
| 487 | 
            +
            /*
         | 
| 488 | 
            +
             * Raphael Tooltip Plugin
         | 
| 489 | 
            +
             * - attaches an element as a tooltip to another element
         | 
| 490 | 
            +
             *
         | 
| 491 | 
            +
             * Usage example, adding a rectangle as a tooltip to a circle:
         | 
| 492 | 
            +
             *
         | 
| 493 | 
            +
             *      paper.circle(100,100,10).tooltip(paper.rect(0,0,20,30));
         | 
| 494 | 
            +
             *
         | 
| 495 | 
            +
             * If you want to use more shapes, you'll have to put them into a set.
         | 
| 496 | 
            +
             *
         | 
| 497 | 
            +
             */
         | 
| 498 | 
            +
            Raphael.el.tooltip = function (tp) {
         | 
| 499 | 
            +
                this.tp = tp;
         | 
| 500 | 
            +
                this.tp.o = {x: 0, y: 0};
         | 
| 501 | 
            +
                this.tp.hide();
         | 
| 502 | 
            +
                this.hover(
         | 
| 503 | 
            +
                    function(event){ 
         | 
| 504 | 
            +
                        this.mousemove(function(event){ 
         | 
| 505 | 
            +
                            this.tp.translate(event.clientX - 
         | 
| 506 | 
            +
            				  this.tp.o.x,event.clientY - this.tp.o.y);
         | 
| 507 | 
            +
                            this.tp.o = {x: event.clientX, y: event.clientY};
         | 
| 508 | 
            +
                        });
         | 
| 509 | 
            +
                        this.tp.show().toFront();
         | 
| 510 | 
            +
                    }, 
         | 
| 511 | 
            +
                    function(event){
         | 
| 512 | 
            +
                        this.tp.hide();
         | 
| 513 | 
            +
                        this.unmousemove();
         | 
| 514 | 
            +
                    });
         | 
| 515 | 
            +
                return this;
         | 
| 516 | 
            +
            };
         | 
| 517 | 
            +
             | 
| 518 | 
            +
            /* For IE */
         | 
| 519 | 
            +
            if (!Array.prototype.forEach)
         | 
| 520 | 
            +
            {
         | 
| 521 | 
            +
              Array.prototype.forEach = function(fun /*, thisp*/)
         | 
| 522 | 
            +
              {
         | 
| 523 | 
            +
                var len = this.length;
         | 
| 524 | 
            +
                if (typeof fun != "function")
         | 
| 525 | 
            +
                  throw new TypeError();
         | 
| 526 | 
            +
             | 
| 527 | 
            +
                var thisp = arguments[1];
         | 
| 528 | 
            +
                for (var i = 0; i < len; i++)
         | 
| 529 | 
            +
                {
         | 
| 530 | 
            +
                  if (i in this)
         | 
| 531 | 
            +
                    fun.call(thisp, this[i], i, this);
         | 
| 532 | 
            +
                }
         | 
| 533 | 
            +
              };
         | 
| 534 | 
            +
            }
         | 
| @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            <html>
         | 
| 2 | 
            +
            <head>
         | 
| 3 | 
            +
                <title>Graphing JavaScript with JavaScript</title>
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            </head>
         | 
| 6 | 
            +
            <body>
         | 
| 7 | 
            +
            <div id='canvas'></div>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            <script type="text/javascript" src="raphael-min.js"></script>
         | 
| 10 | 
            +
            <script type="text/javascript" src="dracula_graffle.js"></script>
         | 
| 11 | 
            +
            <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
         | 
| 12 | 
            +
            <script type="text/javascript" src="dracula_graph.js"></script>
         | 
| 13 | 
            +
            <script type="text/javascript" src="dracula_algorithms.js"></script>
         | 
| 14 | 
            +
            <script type="text/javascript" src="jsgraphsource.js"></script>
         | 
| 15 | 
            +
            <script type="text/javascript">
         | 
| 16 | 
            +
                $(document).ready(function() {
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    for (var js_class in graphdata) {
         | 
| 19 | 
            +
                        if (graphdata.hasOwnProperty(js_class)) {
         | 
| 20 | 
            +
                            process_class(graphdata[js_class]);
         | 
| 21 | 
            +
                        }
         | 
| 22 | 
            +
                    }
         | 
| 23 | 
            +
                });
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                function process_class(js_class) {
         | 
| 26 | 
            +
                    var width = 300;
         | 
| 27 | 
            +
                    var height = 300;
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    var g = new Graph();
         | 
| 30 | 
            +
                    g.edgeFactory.template.style.directed = true;
         | 
| 31 | 
            +
                    for (js_method in js_class) {
         | 
| 32 | 
            +
                        if (js_class.hasOwnProperty(js_method)) {
         | 
| 33 | 
            +
                            process_method(g, js_method, js_class[js_method]);
         | 
| 34 | 
            +
                        }
         | 
| 35 | 
            +
                    }
         | 
| 36 | 
            +
                    var layouter = new Graph.Layout.Ordered(g, topological_sort(g));
         | 
| 37 | 
            +
                    var renderer = new Graph.Renderer.Raphael('canvas', g, width, height);
         | 
| 38 | 
            +
                }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                function process_method(graph, js_method_name, js_calls) {
         | 
| 41 | 
            +
                    var i;
         | 
| 42 | 
            +
                    for (i = 0; i < js_calls.length; i++) {
         | 
| 43 | 
            +
                        graph.addEdge(js_method_name, js_calls[i]);
         | 
| 44 | 
            +
                    }
         | 
| 45 | 
            +
                }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
             | 
| 48 | 
            +
            </script>
         | 
| 49 | 
            +
             | 
| 50 | 
            +
             | 
| 51 | 
            +
            </body>
         | 
| 52 | 
            +
            </html>
         | 
| 53 | 
            +
            <!-- Ideas - to do
         | 
| 54 | 
            +
            Initial load produces a list of classes
         | 
| 55 | 
            +
            click a link to view a graph for that class instead of all graphs on one page
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            -->
         |