You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stanbol.apache.org by co...@apache.org on 2011/03/20 18:01:36 UTC
svn commit: r1083505 [3/9] - in /incubator/stanbol/trunk/kres/jersey: ./
src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/stanbol/ src/main/java/org/apache/stanbol/kres/
src/main/java/org/apache/stanbo...
Added: incubator/stanbol/trunk/kres/jersey/src/main/resources/META-INF/static/scripts/jit.js
URL: http://svn.apache.org/viewvc/incubator/stanbol/trunk/kres/jersey/src/main/resources/META-INF/static/scripts/jit.js?rev=1083505&view=auto
==============================================================================
--- incubator/stanbol/trunk/kres/jersey/src/main/resources/META-INF/static/scripts/jit.js (added)
+++ incubator/stanbol/trunk/kres/jersey/src/main/resources/META-INF/static/scripts/jit.js Sun Mar 20 17:01:32 2011
@@ -0,0 +1,9046 @@
+(function () {
+
+/*
+ File: Core.js
+
+ Description:
+
+ Provides common utility functions and the Class object used internally by the library.
+
+ Also provides the <TreeUtil> object for manipulating JSON tree structures
+
+ Some of the Basic utility functions and the Class system are based in the MooTools Framework <http://mootools.net>. Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net/>. MIT license <http://mootools.net/license.txt>.
+
+ Author:
+
+ Nicolas Garcia Belmonte
+
+ Copyright:
+
+ Copyright 2008-2009 by Nicolas Garcia Belmonte.
+
+ Homepage:
+
+ <http://thejit.org>
+
+ Version:
+
+ 1.1.3
+
+ License:
+
+ BSD License
+
+> Redistribution and use in source and binary forms, with or without
+> modification, are permitted provided that the following conditions are met:
+> * Redistributions of source code must retain the above copyright
+> notice, this list of conditions and the following disclaimer.
+> * Redistributions in binary form must reproduce the above copyright
+> notice, this list of conditions and the following disclaimer in the
+> documentation and/or other materials provided with the distribution.
+> * Neither the name of the organization nor the
+> names of its contributors may be used to endorse or promote products
+> derived from this software without specific prior written permission.
+>
+> THIS SOFTWARE IS PROVIDED BY Nicolas Garcia Belmonte ``AS IS'' AND ANY
+> EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+> WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+> DISCLAIMED. IN NO EVENT SHALL Nicolas Garcia Belmonte BE LIABLE FOR ANY
+> DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+> (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+> ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+> SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+function $empty() {};
+
+function $extend(original, extended){
+ for (var key in (extended || {})) original[key] = extended[key];
+ return original;
+};
+
+function $lambda(value){
+ return (typeof value == 'function') ? value : function(){
+ return value;
+ };
+};
+
+var $time = Date.now || function(){
+ return +new Date;
+};
+
+function $splat(obj){
+ var type = $type(obj);
+ return (type) ? ((type != 'array') ? [obj] : obj) : [];
+};
+
+var $type = function(elem) {
+ return $type.s.call(elem).match(/^\[object\s(.*)\]$/)[1].toLowerCase();
+};
+$type.s = Object.prototype.toString;
+
+function $each(iterable, fn){
+ var type = $type(iterable);
+ if(type == 'object') {
+ for (var key in iterable) fn(iterable[key], key);
+ } else {
+ for(var i=0; i < iterable.length; i++) fn(iterable[i], i);
+ }
+};
+
+function $merge(){
+ var mix = {};
+ for (var i = 0, l = arguments.length; i < l; i++){
+ var object = arguments[i];
+ if ($type(object) != 'object') continue;
+ for (var key in object){
+ var op = object[key], mp = mix[key];
+ mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $merge(mp, op) : $unlink(op);
+ }
+ }
+ return mix;
+};
+
+function $unlink(object){
+ var unlinked;
+ switch ($type(object)){
+ case 'object':
+ unlinked = {};
+ for (var p in object) unlinked[p] = $unlink(object[p]);
+ break;
+ case 'array':
+ unlinked = [];
+ for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
+ break;
+ default: return object;
+ }
+ return unlinked;
+};
+
+function $rgbToHex(srcArray, array){
+ if (srcArray.length < 3) return null;
+ if (srcArray.length == 4 && srcArray[3] == 0 && !array) return 'transparent';
+ var hex = [];
+ for (var i = 0; i < 3; i++){
+ var bit = (srcArray[i] - 0).toString(16);
+ hex.push((bit.length == 1) ? '0' + bit : bit);
+ }
+ return (array) ? hex : '#' + hex.join('');
+};
+
+function $destroy(elem) {
+ $clean(elem);
+ if(elem.parentNode) elem.parentNode.removeChild(elem);
+ if(elem.clearAttributes) elem.clearAttributes();
+};
+
+function $clean(elem) {
+ for(var ch = elem.childNodes, i=0; i < ch.length; i++) {
+ $destroy(ch[i]);
+ }
+};
+
+function $addEvent(obj, type, fn) {
+ if (obj.addEventListener)
+ obj.addEventListener(type, fn, false);
+ else
+ obj.attachEvent('on' + type, fn);
+};
+
+function $hasClass(obj, klass) {
+ return (' ' + obj.className + ' ').indexOf(' ' + klass + ' ') > -1;
+};
+
+function $addClass(obj, klass) {
+ if(!$hasClass(obj, klass)) obj.className = (obj.className + " " + klass);
+};
+
+function $removeClass(obj, klass) {
+ obj.className = obj.className.replace(new RegExp('(^|\\s)' + klass + '(?:\\s|$)'), '$1');
+};
+
+function $get(id) {
+ return document.getElementById(id);
+};
+
+var Class = function(properties){
+ properties = properties || {};
+ var klass = function(){
+// not defining any attributes in Class properties.
+// for (var key in this){
+// if (typeof this[key] != 'function') this[key] = $unlink(this[key]);
+// }
+ this.constructor = klass;
+ if (Class.prototyping) return this;
+ var instance = (this.initialize) ? this.initialize.apply(this, arguments) : this;
+ return instance;
+ };
+
+ for (var mutator in Class.Mutators){
+ if (!properties[mutator]) continue;
+ properties = Class.Mutators[mutator](properties, properties[mutator]);
+ delete properties[mutator];
+ }
+
+ $extend(klass, this);
+ klass.constructor = Class;
+ klass.prototype = properties;
+ return klass;
+};
+
+Class.Mutators = {
+
+ Extends: function(self, klass){
+ Class.prototyping = klass.prototype;
+ var subclass = new klass;
+ delete subclass.parent;
+ subclass = Class.inherit(subclass, self);
+ delete Class.prototyping;
+ return subclass;
+ },
+
+ Implements: function(self, klasses){
+ $each($splat(klasses), function(klass){
+ Class.prototying = klass;
+ $extend(self, ($type(klass) == 'function') ? new klass : klass);
+ delete Class.prototyping;
+ });
+ return self;
+ }
+
+};
+
+$extend(Class, {
+
+ inherit: function(object, properties){
+ var caller = arguments.callee.caller;
+ for (var key in properties){
+ var override = properties[key];
+ var previous = object[key];
+ var type = $type(override);
+ if (previous && type == 'function'){
+ if (override != previous){
+ if (caller){
+ override.__parent = previous;
+ object[key] = override;
+ } else {
+ Class.override(object, key, override);
+ }
+ }
+ } else if(type == 'object'){
+ object[key] = $merge(previous, override);
+ } else {
+ object[key] = override;
+ }
+ }
+
+ if (caller) object.parent = function(){
+ return arguments.callee.caller.__parent.apply(this, arguments);
+ };
+
+ return object;
+ },
+
+ override: function(object, name, method){
+ var parent = Class.prototyping;
+ if (parent && object[name] != parent[name]) parent = null;
+ var override = function(){
+ var previous = this.parent;
+ this.parent = parent ? parent[name] : object[name];
+ var value = method.apply(this, arguments);
+ this.parent = previous;
+ return value;
+ };
+ object[name] = override;
+ }
+
+});
+
+
+Class.prototype.implement = function(){
+ var proto = this.prototype;
+ $each(Array.prototype.slice.call(arguments || []), function(properties){
+ Class.inherit(proto, properties);
+ });
+ return this;
+};
+
+/*
+ Object: TreeUtil
+
+ Some common JSON tree manipulation methods.
+*/
+this.TreeUtil = {
+
+ /*
+ Method: prune
+
+ Clears all tree nodes having depth greater than maxLevel.
+
+ Parameters:
+
+ tree - A JSON tree object. For more information please see <Loader.loadJSON>.
+ maxLevel - An integer specifying the maximum level allowed for this tree. All nodes having depth greater than max level will be deleted.
+
+ */
+ prune: function(tree, maxLevel) {
+ this.each(tree, function(elem, i) {
+ if(i == maxLevel && elem.children) {
+ delete elem.children;
+ elem.children = [];
+ }
+ });
+ },
+
+ /*
+ Method: getParent
+
+ Returns the parent node of the node having _id_ as id.
+
+ Parameters:
+
+ tree - A JSON tree object. See also <Loader.loadJSON>.
+ id - The _id_ of the child node whose parent will be returned.
+
+ Returns:
+
+ A tree JSON node if any, or false otherwise.
+
+ */
+ getParent: function(tree, id) {
+ if(tree.id == id) return false;
+ var ch = tree.children;
+ if(ch && ch.length > 0) {
+ for(var i=0; i<ch.length; i++) {
+ if(ch[i].id == id)
+ return tree;
+ else {
+ var ans = this.getParent(ch[i], id);
+ if(ans) return ans;
+ }
+ }
+ }
+ return false;
+ },
+
+ /*
+ Method: getSubtree
+
+ Returns the subtree that matches the given id.
+
+ Parameters:
+
+ tree - A JSON tree object. See also <Loader.loadJSON>.
+ id - A node *unique* identifier.
+
+ Returns:
+
+ A subtree having a root node matching the given id. Returns null if no subtree matching the id is found.
+
+ */
+ getSubtree: function(tree, id) {
+ if(tree.id == id) return tree;
+ for(var i=0, ch=tree.children; i<ch.length; i++) {
+ var t = this.getSubtree(ch[i], id);
+ if(t != null) return t;
+ }
+ return null;
+ },
+
+ /*
+ Method: getLeaves
+
+ Returns the leaves of the tree.
+
+ Parameters:
+
+ node - A JSON tree node. See also <Loader.loadJSON>.
+ maxLevel - _optional_ A subtree's max level.
+
+ Returns:
+
+ An array having objects with two properties.
+
+ - The _node_ property contains the leaf node.
+ - The _level_ property specifies the depth of the node.
+
+ */
+ getLeaves: function (node, maxLevel) {
+ var leaves = [], levelsToShow = maxLevel || Number.MAX_VALUE;
+ this.each(node, function(elem, i) {
+ if(i < levelsToShow &&
+ (!elem.children || elem.children.length == 0 )) {
+ leaves.push({
+ 'node':elem,
+ 'level':levelsToShow - i
+ });
+ }
+ });
+ return leaves;
+ },
+
+
+ /*
+ Method: eachLevel
+
+ Iterates on tree nodes with relative depth less or equal than a specified level.
+
+ Parameters:
+
+ tree - A JSON tree or subtree. See also <Loader.loadJSON>.
+ initLevel - An integer specifying the initial relative level. Usually zero.
+ toLevel - An integer specifying a top level. This method will iterate only through nodes with depth less than or equal this number.
+ action - A function that receives a node and an integer specifying the actual level of the node.
+
+ Example:
+ (start code js)
+ TreeUtil.eachLevel(tree, 0, 3, function(node, depth) {
+ alert(node.name + ' ' + depth);
+ });
+ (end code)
+ */
+ eachLevel: function(tree, initLevel, toLevel, action) {
+ if(initLevel <= toLevel) {
+ action(tree, initLevel);
+ for(var i=0, ch = tree.children; i<ch.length; i++) {
+ this.eachLevel(ch[i], initLevel +1, toLevel, action);
+ }
+ }
+ },
+
+ /*
+ Method: each
+
+ A tree iterator.
+
+ Parameters:
+
+ tree - A JSON tree or subtree. See also <Loader.loadJSON>.
+ action - A function that receives a node.
+
+ Example:
+ (start code js)
+ TreeUtil.each(tree, function(node) {
+ alert(node.name);
+ });
+ (end code)
+
+ */
+ each: function(tree, action) {
+ this.eachLevel(tree, 0, Number.MAX_VALUE, action);
+ },
+
+ /*
+ Method: loadSubtrees
+
+ Appends subtrees to leaves by requesting new subtrees
+ with the _request_ method.
+
+ Parameters:
+
+ tree - A JSON tree node. <Loader.loadJSON>.
+ controller - An object that implements a request method.
+
+ Example:
+ (start code js)
+ TreeUtil.loadSubtrees(leafNode, {
+ request: function(nodeId, level, onComplete) {
+ //Pseudo-code to make an ajax request for a new subtree
+ // that has as root id _nodeId_ and depth _level_ ...
+ Ajax.request({
+ 'url': 'http://subtreerequesturl/',
+
+ onSuccess: function(json) {
+ onComplete.onComplete(nodeId, json);
+ }
+ });
+ }
+ });
+ (end code)
+ */
+ loadSubtrees: function(tree, controller) {
+ var maxLevel = controller.request && controller.levelsToShow;
+ var leaves = this.getLeaves(tree, maxLevel),
+ len = leaves.length,
+ selectedNode = {};
+ if(len == 0) controller.onComplete();
+ for(var i=0, counter=0; i<len; i++) {
+ var leaf = leaves[i], id = leaf.node.id;
+ selectedNode[id] = leaf.node;
+ controller.request(id, leaf.level, {
+ onComplete: function(nodeId, tree) {
+ var ch = tree.children;
+ selectedNode[nodeId].children = ch;
+ if(++counter == len) {
+ controller.onComplete();
+ }
+ }
+ });
+ }
+ }
+};
+
+
+
+/*
+ * File: Canvas.js
+ *
+ * A cross browser Canvas widget.
+ *
+ * Used By:
+ *
+ * <ST>, <Hypertree>, <RGraph>
+ */
+/*
+ Class: Canvas
+
+ A multi-purpose Canvas Class. This Class can be used with the ExCanvas library to provide
+ cross browser Canvas based visualizations.
+
+ Parameters:
+
+ id - The canvas id. This id will be used as prefix for the canvas widget DOM elements ids.
+ options - An object containing multiple options such as
+
+ - _injectInto_ This property is _required_ and it specifies the id of the DOM element
+ to which the Canvas widget will be appended
+ - _width_ The width of the Canvas widget. Default's to 200px
+ - _height_ The height of the Canvas widget. Default's to 200px
+ - _backgroundColor_ Used for compatibility with IE. The canvas' background color.
+ Default's to '#333'
+ - _styles_ A hash containing canvas specific style properties such as _fillStyle_ and _strokeStyle_ among others.
+
+ Example:
+
+ Suppose we have this HTML
+
+ (start code xml)
+ <div id="infovis"></div>
+ (end code)
+
+ Now we create a new Canvas instance
+
+ (start code js)
+ //Create a new canvas instance
+ var canvas = new Canvas('mycanvas', {
+ //Where to inject the canvas. Any div container will do.
+ 'injectInto':'infovis',
+ //width and height for canvas. Default's to 200.
+ 'width': 900,
+ 'height':500,
+ //Canvas styles
+ 'styles': {
+ 'fillStyle': '#ccddee',
+ 'strokeStyle': '#772277'
+ }
+ });
+ (end code)
+
+ The generated HTML will look like this
+
+ (start code xml)
+ <div id="infovis">
+ <div id="mycanvas" style="position:relative;">
+ <canvas id="mycanvas-canvas" width=900 height=500
+ style="position:absolute; top:0; left:0; width:900px; height:500px;" />
+ <div id="mycanvas-label"
+ style="overflow:visible; position:absolute; top:0; left:0; width:900px; height:0px">
+ </div>
+ </div>
+ </div>
+ (end code)
+
+ As you can see, the generated HTML consists of a canvas DOM element of id _mycanvas-canvas_ and a div label container
+ of id _mycanvas-label_, wrapped in a main div container of id _mycanvas_.
+ You can also add a background canvas, for making background drawings.
+ This is how the <RGraph> background concentric circles are drawn
+
+ Example:
+
+ (start code js)
+ //Create a new canvas instance.
+ var canvas = new Canvas('mycanvas', {
+ //Where to inject the canvas. Any div container will do.
+ 'injectInto':'infovis',
+ //width and height for canvas. Default's to 200.
+ 'width': 900,
+ 'height':500,
+ //Canvas styles
+ 'styles': {
+ 'fillStyle': '#ccddee',
+ 'strokeStyle': '#772277'
+ },
+ //Add a background canvas for plotting
+ //concentric circles.
+ 'backgroundCanvas': {
+ //Add Canvas styles for the bck canvas.
+ 'styles': {
+ 'fillStyle': '#444',
+ 'strokeStyle': '#444'
+ },
+ //Add the initialization and plotting functions.
+ 'impl': {
+ 'init': function() {},
+ 'plot': function(canvas, ctx) {
+ var times = 6, d = 100;
+ var pi2 = Math.PI*2;
+ for(var i=1; i<=times; i++) {
+ ctx.beginPath();
+ ctx.arc(0, 0, i * d, 0, pi2, true);
+ ctx.stroke();
+ ctx.closePath();
+ }
+ }
+ }
+ }
+ });
+ (end code)
+
+ The _backgroundCanvas_ object contains a canvas _styles_ property and
+ an _impl_ key to be used for implementing background canvas specific code.
+
+ The _init_ method is only called once, at the instanciation of the background canvas.
+ The _plot_ method is called for plotting a Canvas image.
+ */
+this.Canvas = (function(){
+ var config = {
+ 'injectInto': 'id',
+
+ 'width': 200,
+ 'height': 200,
+ //deprecated
+ 'backgroundColor': '#333333',
+
+ 'styles': {
+ 'fillStyle': '#000000',
+ 'strokeStyle': '#000000'
+ },
+
+ 'backgroundCanvas': false
+ };
+
+ function hasCanvas(){
+ hasCanvas.t = hasCanvas.t || typeof(HTMLCanvasElement);
+ return "function" == hasCanvas.t || "object" == hasCanvas.t;
+ };
+
+ function create(tag, prop, styles){
+ var elem = document.createElement(tag);
+ (function(obj, prop){
+ if (prop) {
+ for (var p in prop) {
+ obj[p] = prop[p];
+ }
+ }
+ return arguments.callee;
+ })(elem, prop)(elem.style, styles);
+ //feature check
+ if (tag == "canvas" && !hasCanvas() && G_vmlCanvasManager) {
+ elem = G_vmlCanvasManager.initElement(document.body.appendChild(elem));
+ }
+
+ return elem;
+ };
+
+ function get(id){
+ return document.getElementById(id);
+ };
+
+ function translateToCenter(canvas, ctx, w, h){
+ var width = w ? (canvas.width - w) : canvas.width;
+ var height = h ? (canvas.height - h) : canvas.height;
+ ctx.translate(width / 2, height / 2);
+ };
+
+ return function(id, opt){
+ var ctx, bkctx, mainContainer, labelContainer, canvas, bkcanvas;
+ if (arguments.length < 1)
+ throw "Arguments missing";
+ var idLabel = id + "-label", idCanvas = id + "-canvas", idBCanvas = id + "-bkcanvas";
+ opt = $merge(config, opt || {});
+ //create elements
+ var dim = {
+ 'width': opt.width,
+ 'height': opt.height
+ };
+ mainContainer = create("div", {
+ 'id': id
+ }, $merge(dim, {
+ 'position': 'relative'
+ }));
+ labelContainer = create("div", {
+ 'id': idLabel
+ }, {
+ 'overflow': 'visible',
+ 'position': 'absolute',
+ 'top': 0,
+ 'left': 0,
+ 'width': dim.width + 'px',
+ 'height': 0
+ });
+ var dimPos = {
+ 'position': 'absolute',
+ 'top': 0,
+ 'left': 0,
+ 'width': dim.width + 'px',
+ 'height': dim.height + 'px'
+ };
+ canvas = create("canvas", $merge({
+ 'id': idCanvas
+ }, dim), dimPos);
+ var bc = opt.backgroundCanvas;
+ if (bc) {
+ bkcanvas = create("canvas", $merge({
+ 'id': idBCanvas
+ }, dim), dimPos);
+ //append elements
+ mainContainer.appendChild(bkcanvas);
+ }
+ mainContainer.appendChild(canvas);
+ mainContainer.appendChild(labelContainer);
+ get(opt.injectInto).appendChild(mainContainer);
+
+ //create contexts
+ ctx = canvas.getContext('2d');
+ translateToCenter(canvas, ctx);
+ var st = opt.styles;
+ var s;
+ for (s in st)
+ ctx[s] = st[s];
+ if (bc) {
+ bkctx = bkcanvas.getContext('2d');
+ st = bc.styles;
+ for (s in st) {
+ bkctx[s] = st[s];
+ }
+ translateToCenter(bkcanvas, bkctx);
+ bc.impl.init(bkcanvas, bkctx);
+ bc.impl.plot(bkcanvas, bkctx);
+ }
+ //create methods
+ return {
+ 'id': id,
+ /*
+ Method: getCtx
+
+ Returns the main canvas context object
+
+ Returns:
+
+ Main canvas context
+
+ Example:
+
+ (start code js)
+ var ctx = canvas.getCtx();
+ //Now I can use the native canvas context
+ //and for example change some canvas styles
+ ctx.globalAlpha = 1;
+ (end code)
+ */
+ getCtx: function(){
+ return ctx;
+ },
+
+ /*
+ Method: getElement
+ Returns the main Canvas DOM wrapper
+
+ Returns:
+ DOM canvas wrapper generated, (i.e the div wrapper element with id _mycanvas_)
+
+ Example:
+ (start code js)
+ var wrapper = canvas.getElement();
+ //Returns <div id="mycanvas" ... >...</div> as element
+ (end code)
+ */
+ getElement: function(){
+ return mainContainer;
+ },
+
+ /*
+ Method: resize
+
+ Resizes the canvas.
+
+ Parameters:
+
+ width - New canvas width.
+ height - New canvas height.
+
+ This method can be used with the <ST>, <Hypertree> or <RGraph> visualizations to resize
+ the visualizations
+
+ Example:
+
+ (start code js)
+ function resizeViz(width, height) {
+ canvas.resize(width, height);
+ rgraph.refresh(); //ht.refresh or st.refresh() also work.
+ rgraph.onAfterCompute();
+ }
+ (end code)
+
+ */
+ resize: function(width, height){
+ var pwidth = canvas.width, pheight = canvas.height;
+ canvas.width = width;
+ canvas.height = height;
+ canvas.style.width = width + "px";
+ canvas.style.height = height + "px";
+ if (bc) {
+ bkcanvas.width = width;
+ bkcanvas.height = height;
+ bkcanvas.style.width = width + "px";
+ bkcanvas.style.height = height + "px";
+ }
+ //small ExCanvas fix
+ if(!hasCanvas()) {
+ translateToCenter(canvas, ctx, pwidth, pheight);
+ } else {
+ translateToCenter(canvas, ctx);
+ }
+
+ var st = opt.styles;
+ var s;
+ for (s in st) {
+ ctx[s] = st[s];
+ }
+ if (bc) {
+ st = bc.styles;
+ for (s in st)
+ bkctx[s] = st[s];
+ //same ExCanvas fix here
+ if(!hasCanvas()) {
+ translateToCenter(bkcanvas, bkctx, pwidth, pheight);
+ } else {
+ translateToCenter(bkcanvas, bkctx);
+ }
+
+ bc.impl.init(bkcanvas, bkctx);
+ bc.impl.plot(bkcanvas, bkctx);
+ }
+ },
+
+ /*
+ Method: getSize
+
+ Returns canvas dimensions.
+
+ Returns:
+
+ An object with _width_ and _height_ properties.
+ Example:
+ (start code js)
+ canvas.getSize(); //returns { width: 900, height: 500 }
+ (end code)
+ */
+ getSize: function(){
+ return {
+ 'width': canvas.width,
+ 'height': canvas.height
+ };
+ },
+
+ path: function(type, action){
+ ctx.beginPath();
+ action(ctx);
+ ctx[type]();
+ ctx.closePath();
+ },
+
+ /*
+ Method: clear
+
+ Clears the canvas object.
+ */
+ clear: function(){
+ var size = this.getSize();
+ ctx.clearRect(-size.width / 2, -size.height / 2, size.width, size.height);
+ },
+
+ /*
+ Method: clearReactangle
+
+ Same as <Canvas.clear> but only clears a section of the canvas.
+
+ Parameters:
+
+ top - An integer specifying the top of the rectangle.
+ right - An integer specifying the right of the rectangle.
+ bottom - An integer specifying the bottom of the rectangle.
+ left - An integer specifying the left of the rectangle.
+ */
+ clearRectangle: function(top, right, bottom, left){
+ //if using excanvas
+ if (!hasCanvas()) {
+ var f0 = ctx.fillStyle;
+ ctx.fillStyle = opt.backgroundColor;
+ ctx.fillRect(left, top, Math.abs(right - left), Math.abs(bottom - top));
+ ctx.fillStyle = f0;
+ }
+ else {
+ ctx.clearRect(left, top, Math.abs(right - left), Math.abs(bottom - top));
+ }
+ }
+ };
+ };
+
+})();
+
+
+
+/*
+ * File: Polar.js
+ *
+ * Defines the <Polar> class.
+ *
+ * Description:
+ *
+ * The <Polar> class, just like the <Complex> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
+ *
+ * See also:
+ *
+ * <http://en.wikipedia.org/wiki/Polar_coordinates>
+ *
+*/
+
+/*
+ Class: Polar
+
+ A multi purpose polar representation.
+
+ Description:
+
+ The <Polar> class, just like the <Complex> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
+
+ See also:
+
+ <http://en.wikipedia.org/wiki/Polar_coordinates>
+
+ Parameters:
+
+ theta - An angle.
+ rho - The norm.
+*/
+
+this.Polar = function(theta, rho) {
+ this.theta = theta;
+ this.rho = rho;
+};
+
+Polar.prototype = {
+ /*
+ Method: getc
+
+ Returns a complex number.
+
+ Parameters:
+
+ simple - _optional_ If *true*, this method will return only an object holding x and y properties and not a <Complex> instance. Default's *false*.
+
+ Returns:
+
+ A complex number.
+ */
+ getc: function(simple) {
+ return this.toComplex(simple);
+ },
+
+ /*
+ Method: getp
+
+ Returns a <Polar> representation.
+
+ Returns:
+
+ A variable in polar coordinates.
+ */
+ getp: function() {
+ return this;
+ },
+
+
+ /*
+ Method: set
+
+ Sets a number.
+
+ Parameters:
+
+ v - A <Complex> or <Polar> instance.
+
+ */
+ set: function(v) {
+ v = v.getp();
+ this.theta = v.theta; this.rho = v.rho;
+ },
+
+ /*
+ Method: setc
+
+ Sets a <Complex> number.
+
+ Parameters:
+
+ x - A <Complex> number real part.
+ y - A <Complex> number imaginary part.
+
+ */
+ setc: function(x, y) {
+ this.rho = Math.sqrt(x * x + y * y);
+ this.theta = Math.atan2(y, x);
+ if(this.theta < 0) this.theta += Math.PI * 2;
+ },
+
+ /*
+ Method: setp
+
+ Sets a polar number.
+
+ Parameters:
+
+ theta - A <Polar> number angle property.
+ rho - A <Polar> number rho property.
+
+ */
+ setp: function(theta, rho) {
+ this.theta = theta;
+ this.rho = rho;
+ },
+
+ /*
+ Method: clone
+
+ Returns a copy of the current object.
+
+ Returns:
+
+ A copy of the real object.
+ */
+ clone: function() {
+ return new Polar(this.theta, this.rho);
+ },
+
+ /*
+ Method: toComplex
+
+ Translates from polar to cartesian coordinates and returns a new <Complex> instance.
+
+ Parameters:
+
+ simple - _optional_ If *true* this method will only return an object with x and y properties (and not the whole <Complex> instance). Default's *false*.
+
+ Returns:
+
+ A new <Complex> instance.
+ */
+ toComplex: function(simple) {
+ var x = Math.cos(this.theta) * this.rho;
+ var y = Math.sin(this.theta) * this.rho;
+ if(simple) return { 'x': x, 'y': y};
+ return new Complex(x, y);
+ },
+
+ /*
+ Method: add
+
+ Adds two <Polar> instances.
+
+ Parameters:
+
+ polar - A <Polar> number.
+
+ Returns:
+
+ A new Polar instance.
+ */
+ add: function(polar) {
+ return new Polar(this.theta + polar.theta, this.rho + polar.rho);
+ },
+
+ /*
+ Method: scale
+
+ Scales a polar norm.
+
+ Parameters:
+
+ number - A scale factor.
+
+ Returns:
+
+ A new Polar instance.
+ */
+ scale: function(number) {
+ return new Polar(this.theta, this.rho * number);
+ },
+
+ /*
+ Method: equals
+
+ Comparison method.
+
+ Returns *true* if the theta and rho properties are equal.
+
+ Parameters:
+
+ c - A <Polar> number.
+
+ Returns:
+
+ *true* if the theta and rho parameters for these objects are equal. *false* otherwise.
+ */
+ equals: function(c) {
+ return this.theta == c.theta && this.rho == c.rho;
+ },
+
+ /*
+ Method: $add
+
+ Adds two <Polar> instances affecting the current object.
+
+ Paramters:
+
+ polar - A <Polar> instance.
+
+ Returns:
+
+ The changed object.
+ */
+ $add: function(polar) {
+ this.theta = this.theta + polar.theta; this.rho += polar.rho;
+ return this;
+ },
+
+ /*
+ Method: $madd
+
+ Adds two <Polar> instances affecting the current object. The resulting theta angle is modulo 2pi.
+
+ Parameters:
+
+ polar - A <Polar> instance.
+
+ Returns:
+
+ The changed object.
+ */
+ $madd: function(polar) {
+ this.theta = (this.theta + polar.theta) % (Math.PI * 2); this.rho += polar.rho;
+ return this;
+ },
+
+
+ /*
+ Method: $scale
+
+ Scales a polar instance affecting the object.
+
+ Parameters:
+
+ number - A scaling factor.
+
+ Returns:
+
+ The changed object.
+ */
+ $scale: function(number) {
+ this.rho *= number;
+ return this;
+ },
+
+ /*
+ Method: interpolate
+
+ Calculates a polar interpolation between two points at a given delta moment.
+
+ Parameters:
+
+ elem - A <Polar> instance.
+ delta - A delta factor ranging [0, 1].
+
+ Returns:
+
+ A new <Polar> instance representing an interpolation between _this_ and _elem_
+ */
+ interpolate: function(elem, delta) {
+ var pi = Math.PI, pi2 = pi * 2;
+ var ch = function(t) {
+ return (t < 0)? (t % pi2) + pi2 : t % pi2;
+ };
+ var tt = this.theta, et = elem.theta;
+ var sum;
+ if(Math.abs(tt - et) > pi) {
+ if(tt > et) {
+ sum =ch((et + ((tt - pi2) - et) * delta)) ;
+ } else {
+ sum =ch((et - pi2 + (tt - (et - pi2)) * delta));
+ }
+ } else {
+ sum =ch((et + (tt - et) * delta)) ;
+ }
+ var r = (this.rho - elem.rho) * delta + elem.rho;
+ return {
+ 'theta': sum,
+ 'rho': r
+ };
+ }
+};
+
+
+var $P = function(a, b) { return new Polar(a, b); };
+
+Polar.KER = $P(0, 0);
+
+
+
+/*
+ * File: Complex.js
+ *
+ * Defines the <Complex> class.
+ *
+ * Description:
+ *
+ * The <Complex> class, just like the <Polar> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
+ *
+ * See also:
+ *
+ * <http://en.wikipedia.org/wiki/Complex_number>
+ *
+*/
+
+/*
+ Class: Complex
+
+ A multi-purpose Complex Class with common methods.
+
+ Description:
+
+ The <Complex> class, just like the <Polar> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
+
+ See also:
+
+ <http://en.wikipedia.org/wiki/Complex_number>
+
+ Parameters:
+
+ x - _optional_ A Complex number real part.
+ y - _optional_ A Complex number imaginary part.
+
+*/
+
+this.Complex = function(x, y) {
+ this.x = x;
+ this.y = y;
+};
+
+Complex.prototype = {
+ /*
+ Method: getc
+
+ Returns a complex number.
+
+ Returns:
+
+ A complex number.
+ */
+ getc: function() {
+ return this;
+ },
+
+ /*
+ Method: getp
+
+ Returns a <Polar> representation of this number.
+
+ Parameters:
+
+ simple - _optional_ If *true*, this method will return only an object holding theta and rho properties and not a <Polar> instance. Default's *false*.
+
+ Returns:
+
+ A variable in <Polar> coordinates.
+ */
+ getp: function(simple) {
+ return this.toPolar(simple);
+ },
+
+
+ /*
+ Method: set
+
+ Sets a number.
+
+ Parameters:
+
+ c - A <Complex> or <Polar> instance.
+
+ */
+ set: function(c) {
+ c = c.getc(true);
+ this.x = c.x;
+ this.y = c.y;
+ },
+
+ /*
+ Method: setc
+
+ Sets a complex number.
+
+ Parameters:
+
+ x - A <Complex> number Real part.
+ y - A <Complex> number Imaginary part.
+
+ */
+ setc: function(x, y) {
+ this.x = x;
+ this.y = y;
+ },
+
+ /*
+ Method: setp
+
+ Sets a polar number.
+
+ Parameters:
+
+ theta - A <Polar> number theta property.
+ rho - A <Polar> number rho property.
+
+ */
+ setp: function(theta, rho) {
+ this.x = Math.cos(theta) * rho;
+ this.y = Math.sin(theta) * rho;
+ },
+
+ /*
+ Method: clone
+
+ Returns a copy of the current object.
+
+ Returns:
+
+ A copy of the real object.
+ */
+ clone: function() {
+ return new Complex(this.x, this.y);
+ },
+
+ /*
+ Method: toPolar
+
+ Transforms cartesian to polar coordinates.
+
+ Parameters:
+
+ simple - _optional_ If *true* this method will only return an object with theta and rho properties (and not the whole <Polar> instance). Default's *false*.
+
+ Returns:
+
+ A new <Polar> instance.
+ */
+
+ toPolar: function(simple) {
+ var rho = this.norm();
+ var atan = Math.atan2(this.y, this.x);
+ if(atan < 0) atan += Math.PI * 2;
+ if(simple) return { 'theta': atan, 'rho': rho };
+ return new Polar(atan, rho);
+ },
+ /*
+ Method: norm
+
+ Calculates a <Complex> number norm.
+
+ Returns:
+
+ A real number representing the complex norm.
+ */
+ norm: function () {
+ return Math.sqrt(this.squaredNorm());
+ },
+
+ /*
+ Method: squaredNorm
+
+ Calculates a <Complex> number squared norm.
+
+ Returns:
+
+ A real number representing the complex squared norm.
+ */
+ squaredNorm: function () {
+ return this.x*this.x + this.y*this.y;
+ },
+
+ /*
+ Method: add
+
+ Returns the result of adding two complex numbers.
+
+ Does not alter the original object.
+
+ Parameters:
+
+ pos - A <Complex> instance.
+
+ Returns:
+
+ The result of adding two complex numbers.
+ */
+ add: function(pos) {
+ return new Complex(this.x + pos.x, this.y + pos.y);
+ },
+
+ /*
+ Method: prod
+
+ Returns the result of multiplying two <Complex> numbers.
+
+ Does not alter the original object.
+
+ Parameters:
+
+ pos - A <Complex> instance.
+
+ Returns:
+
+ The result of multiplying two complex numbers.
+ */
+ prod: function(pos) {
+ return new Complex(this.x*pos.x - this.y*pos.y, this.y*pos.x + this.x*pos.y);
+ },
+
+ /*
+ Method: conjugate
+
+ Returns the conjugate of this <Complex> number.
+
+ Does not alter the original object.
+
+ Returns:
+
+ The conjugate of this <Complex> number.
+ */
+ conjugate: function() {
+ return new Complex(this.x, -this.y);
+ },
+
+
+ /*
+ Method: scale
+
+ Returns the result of scaling a <Complex> instance.
+
+ Does not alter the original object.
+
+ Parameters:
+
+ factor - A scale factor.
+
+ Returns:
+
+ The result of scaling this complex to a factor.
+ */
+ scale: function(factor) {
+ return new Complex(this.x * factor, this.y * factor);
+ },
+
+ /*
+ Method: equals
+
+ Comparison method.
+
+ Returns *true* if both real and imaginary parts are equal.
+
+ Parameters:
+
+ c - A <Complex> instance.
+
+ Returns:
+
+ A boolean instance indicating if both <Complex> numbers are equal.
+ */
+ equals: function(c) {
+ return this.x == c.x && this.y == c.y;
+ },
+
+ /*
+ Method: $add
+
+ Returns the result of adding two <Complex> numbers.
+
+ Alters the original object.
+
+ Parameters:
+
+ pos - A <Complex> instance.
+
+ Returns:
+
+ The result of adding two complex numbers.
+ */
+ $add: function(pos) {
+ this.x += pos.x; this.y += pos.y;
+ return this;
+ },
+
+ /*
+ Method: $prod
+
+ Returns the result of multiplying two <Complex> numbers.
+
+ Alters the original object.
+
+ Parameters:
+
+ pos - A <Complex> instance.
+
+ Returns:
+
+ The result of multiplying two complex numbers.
+ */
+ $prod:function(pos) {
+ var x = this.x, y = this.y;
+ this.x = x*pos.x - y*pos.y;
+ this.y = y*pos.x + x*pos.y;
+ return this;
+ },
+
+ /*
+ Method: $conjugate
+
+ Returns the conjugate for this <Complex>.
+
+ Alters the original object.
+
+ Returns:
+
+ The conjugate for this complex.
+ */
+ $conjugate: function() {
+ this.y = -this.y;
+ return this;
+ },
+
+ /*
+ Method: $scale
+
+ Returns the result of scaling a <Complex> instance.
+
+ Alters the original object.
+
+ Parameters:
+
+ factor - A scale factor.
+
+ Returns:
+
+ The result of scaling this complex to a factor.
+ */
+ $scale: function(factor) {
+ this.x *= factor; this.y *= factor;
+ return this;
+ },
+
+ /*
+ Method: $div
+
+ Returns the division of two <Complex> numbers.
+
+ Alters the original object.
+
+ Parameters:
+
+ pos - A <Complex> number.
+
+ Returns:
+
+ The result of scaling this complex to a factor.
+ */
+ $div: function(pos) {
+ var x = this.x, y = this.y;
+ var sq = pos.squaredNorm();
+ this.x = x * pos.x + y * pos.y; this.y = y * pos.x - x * pos.y;
+ return this.$scale(1 / sq);
+ }
+};
+
+var $C = function(a, b) { return new Complex(a, b); };
+
+Complex.KER = $C(0, 0);
+
+
+
+/*
+ * File: Graph.js
+ *
+ * Generic <Graph>, <Graph.Node> and <Graph.Adjacence> classes.
+ *
+ * Used by:
+ *
+ * <Hypertree>, <RGraph> and <ST>.
+ *
+*/
+
+/*
+ Class: Graph
+
+ A generic Graph class.
+
+ Description:
+
+ When a json graph/tree structure is loaded by <Loader.loadJSON>, an internal <Graph> representation is created.
+
+ In most cases you'll be dealing with an already created <Graph> structure, so methods like <Graph.addNode> or <Graph.addAdjacence> won't
+ be of many use. However methods like <Graph.getNode> and <Graph.hasNode> are pretty useful.
+
+ <Graph.Util> provides also iterators for <Graphs> and advanced and useful graph operations and methods.
+
+ Used by:
+
+ <Loader.loadJSON>, <Hypertree>, <RGraph> and <ST>.
+
+ Access:
+
+ An instance of this class can be accessed by using the _graph_ parameter of a <Hypertree>, <RGraph> or <ST> instance
+
+ Example:
+
+ (start code js)
+ var st = new ST(canvas, config);
+ st.graph.getNode //or any other <Graph> method.
+
+ var ht = new Hypertree(canvas, config);
+ ht.graph.getNode //or any other <Graph> method.
+
+ var rg = new RGraph(canvas, config);
+ rg.graph.getNode //or any other <Graph> method.
+ (end code)
+
+*/
+
+this.Graph = new Class({
+
+ initialize: function(opt) {
+ var innerOptions = {
+ 'complex': false,
+ 'Node': {}
+ };
+ this.opt = $merge(innerOptions, opt || {});
+ this.nodes= {};
+ },
+
+/*
+ Method: getNode
+
+ Returns a <Graph.Node> by _id_.
+
+ Parameters:
+
+ id - A <Graph.Node> id.
+
+ Returns:
+
+ A <Graph.Node> having _id_ as id. Returns *false* otherwise.
+
+ Example:
+
+ (start code js)
+ var node = graph.getNode('someid');
+ (end code)
+*/
+ getNode: function(id) {
+ if(this.hasNode(id)) return this.nodes[id];
+ return false;
+ },
+
+/*
+ Method: getAdjacence
+
+ Returns an array of <Graph.Adjacence> objects connecting nodes with ids _id_ and _id2_.
+
+ Parameters:
+
+ id - A <Graph.Node> id.
+ id2 - A <Graph.Node> id.
+
+ Returns:
+
+ An Array of <Graph.Adjacence> objects. Returns *false* if there's not a <Graph.Adjacence> connecting those two nodes.
+*/
+ getAdjacence: function (id, id2) {
+ var adjs = [];
+ if(this.hasNode(id) && this.hasNode(id2)
+ && this.nodes[id].adjacentTo({ 'id':id2 }) && this.nodes[id2].adjacentTo({ 'id':id })) {
+ adjs.push(this.nodes[id].getAdjacency(id2));
+ adjs.push(this.nodes[id2].getAdjacency(id));
+ return adjs;
+ }
+ return false;
+ },
+
+ /*
+ Method: addNode
+
+ Adds a node.
+
+ Parameters:
+
+ obj - An object containing as properties
+
+ - _id_ node's id
+ - _name_ node's name
+ - _data_ node's data hash
+
+ See also:
+ <Graph.Node>
+
+ */
+ addNode: function(obj) {
+ if(!this.nodes[obj.id]) {
+ this.nodes[obj.id] = new Graph.Node($extend({
+ 'id': obj.id,
+ 'name': obj.name,
+ 'data': obj.data
+ }, this.opt.Node), this.opt.complex);
+ }
+ return this.nodes[obj.id];
+ },
+
+ /*
+ Method: addAdjacence
+
+ Connects nodes specified by _obj_ and _obj2_. If not found, nodes are created.
+
+ Parameters:
+
+ obj - a <Graph.Node> object.
+ obj2 - Another <Graph.Node> object.
+ data - A DataSet object. Used to store some extra information in the <Graph.Adjacence> object created.
+
+ See also:
+
+ <Graph.Node>, <Graph.Adjacence>
+ */
+ addAdjacence: function (obj, obj2, data) {
+ var adjs = [];
+ if(!this.hasNode(obj.id)) { this.addNode(obj); }
+ if(!this.hasNode(obj2.id)) { this.addNode(obj2); }
+ obj = this.nodes[obj.id]; obj2 = this.nodes[obj2.id];
+
+ for(var i in this.nodes) {
+ if(this.nodes[i].id == obj.id) {
+ if(!this.nodes[i].adjacentTo(obj2)) {
+ adjs.push(this.nodes[i].addAdjacency(obj2, data));
+ }
+ }
+
+ if(this.nodes[i].id == obj2.id) {
+ if(!this.nodes[i].adjacentTo(obj)) {
+ adjs.push(this.nodes[i].addAdjacency(obj, data));
+ }
+ }
+ }
+ return adjs;
+ },
+
+ /*
+ Method: removeNode
+
+ Removes a <Graph.Node> matching the specified _id_.
+
+ Parameters:
+
+ id - A node's id.
+
+ */
+ removeNode: function(id) {
+ if(this.hasNode(id)) {
+ var node = this.nodes[id];
+ for(var i=0 in node.adjacencies) {
+ var adj = node.adjacencies[i];
+ this.removeAdjacence(id, adj.nodeTo.id);
+ }
+ delete this.nodes[id];
+ }
+ },
+
+/*
+ Method: removeAdjacence
+
+ Removes a <Graph.Adjacence> matching _id1_ and _id2_.
+
+ Parameters:
+
+ id1 - A <Graph.Node> id.
+ id2 - A <Graph.Node> id.
+*/
+ removeAdjacence: function(id1, id2) {
+ if(this.hasNode(id1)) this.nodes[id1].removeAdjacency(id2);
+ if(this.hasNode(id2)) this.nodes[id2].removeAdjacency(id1);
+ },
+
+ /*
+ Method: hasNode
+
+ Returns a Boolean instance indicating if the node belongs to the <Graph> or not.
+
+ Parameters:
+
+ id - Node id.
+
+ Returns:
+
+ A Boolean instance indicating if the node belongs to the graph or not.
+ */
+ hasNode: function(id) {
+ return id in this.nodes;
+ }
+});
+
+/*
+ Class: Graph.Node
+
+ A <Graph> node.
+
+ Parameters:
+
+ obj - An object containing an 'id', 'name' and 'data' properties as described in <Graph.addNode>.
+ complex - Whether node position properties should contain <Complex> or <Polar> instances.
+
+ See also:
+
+ <Graph>
+
+ Description:
+
+ An instance of <Graph.Node> is usually passed as parameter for most configuration/controller methods in the
+ <Hypertree>, <RGraph> and <ST> classes.
+
+ A <Graph.Node> object has as properties
+
+ id - Node id.
+ name - Node name.
+ data - Node data property containing a hash (i.e {}) with custom options. For more information see <Loader.loadJSON>.
+ selected - Whether the node is selected or not. Used by <ST> for selecting nodes that are between the root node and the selected node.
+ angleSpan - For radial layouts such as the ones performed by the <Hypertree> and the <RGraph>. Contains _begin_ and _end_ properties containing angle values describing the angle span for this subtree.
+ alpha - Current opacity value.
+ startAlpha - Opacity begin value. Used for interpolation.
+ endAlpha - Opacity end value. Used for interpolation.
+ pos - Current position. Can be a <Complex> or <Polar> instance.
+ startPos - Starting position. Used for interpolation.
+ endPos - Ending position. Used for interpolation.
+*/
+Graph.Node = new Class({
+
+ initialize: function(opt, complex) {
+ var innerOptions = {
+ 'id': '',
+ 'name': '',
+ 'data': {},
+ 'adjacencies': {},
+
+ 'selected': false,
+ 'drawn': false,
+ 'exist': false,
+
+ 'angleSpan': {
+ 'begin': 0,
+ 'end' : 0
+ },
+
+ 'alpha': 1,
+ 'startAlpha': 1,
+ 'endAlpha': 1,
+
+ 'pos': (complex && $C(0, 0)) || $P(0, 0),
+ 'startPos': (complex && $C(0, 0)) || $P(0, 0),
+ 'endPos': (complex && $C(0, 0)) || $P(0, 0)
+ };
+
+ $extend(this, $extend(innerOptions, opt));
+ },
+
+ /*
+ Method: adjacentTo
+
+ Indicates if the node is adjacent to the node specified by id
+
+ Parameters:
+
+ id - A node id.
+
+ Returns:
+
+ A Boolean instance indicating whether this node is adjacent to the specified by id or not.
+
+ Example:
+ (start code js)
+ node.adjacentTo('mynodeid');
+ (end code)
+ */
+ adjacentTo: function(node) {
+ return node.id in this.adjacencies;
+ },
+
+ /*
+ Method: getAdjacency
+
+ Returns a <Graph.Adjacence> object connecting the current <Graph.Node> and the node having _id_ as id.
+
+ Parameters:
+
+ id - A node id.
+
+ Returns:
+
+ A <Graph.Adjacence> object or undefined.
+ */
+ getAdjacency: function(id) {
+ return this.adjacencies[id];
+ },
+ /*
+ Method: addAdjacency
+
+ Connects the current node and the given node.
+
+ Parameters:
+
+ node - A <Graph.Node>.
+ data - Some custom hash information.
+ */
+ addAdjacency: function(node, data) {
+ var adj = new Graph.Adjacence(this, node, data);
+ return this.adjacencies[node.id] = adj;
+ },
+
+ /*
+ Method: removeAdjacency
+
+ Removes a <Graph.Adjacence> by _id_.
+
+ Parameters:
+
+ id - A node id.
+ */
+ removeAdjacency: function(id) {
+ delete this.adjacencies[id];
+ }
+});
+
+/*
+ Class: Graph.Adjacence
+
+ A <Graph> adjacence (or edge). Connects two <Graph.Nodes>.
+
+ Parameters:
+
+ nodeFrom - A <Graph.Node>.
+ nodeTo - A <Graph.Node>.
+ data - Some custom hash data.
+
+ See also:
+
+ <Graph>
+
+ Description:
+
+ An instance of <Graph.Adjacence> is usually passed as parameter for some configuration/controller methods in the
+ <Hypertree>, <RGraph> and <ST> classes.
+
+ A <Graph.Adjacence> object has as properties
+
+ nodeFrom - A <Graph.Node> connected by this edge.
+ nodeTo - Another <Graph.Node> connected by this edge.
+ data - Node data property containing a hash (i.e {}) with custom options. For more information see <Loader.loadJSON>.
+ alpha - Current opacity value.
+ startAlpha - Opacity begin value. Used for interpolation.
+ endAlpha - Opacity end value. Used for interpolation.
+*/
+Graph.Adjacence = function(nodeFrom, nodeTo, data) {
+ this.nodeFrom = nodeFrom;
+ this.nodeTo = nodeTo;
+ this.data = data || {};
+ this.alpha = 1;
+ this.startAlpha = 1;
+ this.endAlpha = 1;
+};
+
+/*
+ Object: Graph.Util
+
+ <Graph> traversal and processing utility object.
+*/
+Graph.Util = {
+ /*
+ filter
+
+ For internal use only. Provides a filtering function based on flags.
+ */
+ filter: function(param) {
+ if(!param || !($type(param) == 'string')) return function() { return true; };
+ var props = param.split(" ");
+ return function(elem) {
+ for(var i=0; i<props.length; i++) {
+ if(elem[props[i]]) {
+ return false;
+ }
+ }
+ return true;
+ };
+ },
+ /*
+ Method: getNode
+
+ Returns a <Graph.Node> by _id_.
+
+ Parameters:
+
+ graph - A <Graph> instance.
+ id - A <Graph.Node> id.
+
+ Returns:
+
+ A <Graph> node.
+
+ Example:
+
+ (start code js)
+ Graph.Util.getNode(graph, 'nodeid');
+ (end code)
+ */
+ getNode: function(graph, id) {
+ return graph.getNode(id);
+ },
+
+ /*
+ Method: eachNode
+
+ Iterates over <Graph> nodes performing an _action_.
+
+ Parameters:
+
+ graph - A <Graph> instance.
+ action - A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ Graph.Util.each(graph, function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ eachNode: function(graph, action, flags) {
+ var filter = this.filter(flags);
+ for(var i in graph.nodes) {
+ if(filter(graph.nodes[i])) action(graph.nodes[i]);
+ }
+ },
+
+ /*
+ Method: eachAdjacency
+
+ Iterates over <Graph.Node> adjacencies applying the _action_ function.
+
+ Parameters:
+
+ node - A <Graph.Node>.
+ action - A callback function having <Graph.Adjacence> as first formal parameter.
+
+ Example:
+ (start code js)
+ Graph.Util.eachAdjacency(node, function(adj) {
+ alert(adj.nodeTo.name);
+ });
+ (end code)
+ */
+ eachAdjacency: function(node, action, flags) {
+ var adj = node.adjacencies, filter = this.filter(flags);
+ for(var id in adj) {
+ if(filter(adj[id])) {
+ action(adj[id], id);
+ }
+ }
+ },
+
+ /*
+ Method: computeLevels
+
+ Performs a BFS traversal setting the correct depth for each node.
+
+ The depth of each node can then be accessed by
+ >node._depth
+
+ Parameters:
+
+ graph - A <Graph>.
+ id - A starting node id for the BFS traversal.
+ startDepth - _optional_ A minimum depth value. Default's 0.
+
+ */
+ computeLevels: function(graph, id, startDepth, flags) {
+ startDepth = startDepth || 0;
+ var filter = this.filter(flags);
+ this.eachNode(graph, function(elem) {
+ elem._flag = false;
+ elem._depth = -1;
+ }, flags);
+ var root = graph.getNode(id);
+ root._depth = startDepth;
+ var queue = [root];
+ while(queue.length != 0) {
+ var node = queue.pop();
+ node._flag = true;
+ this.eachAdjacency(node, function(adj) {
+ var n = adj.nodeTo;
+ if(n._flag == false && filter(n)) {
+ if(n._depth < 0) n._depth = node._depth + 1 + startDepth;
+ queue.unshift(n);
+ }
+ }, flags);
+ }
+ },
+
+ /*
+ Method: eachBFS
+
+ Performs a BFS traversal applying _action_ to each <Graph.Node>.
+
+ Parameters:
+
+ graph - A <Graph>.
+ id - A starting node id for the BFS traversal.
+ action - A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ Graph.Util.eachBFS(graph, 'mynodeid', function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ eachBFS: function(graph, id, action, flags) {
+ var filter = this.filter(flags);
+ this.clean(graph);
+ var queue = [graph.getNode(id)];
+ while(queue.length != 0) {
+ var node = queue.pop();
+ node._flag = true;
+ action(node, node._depth);
+ this.eachAdjacency(node, function(adj) {
+ var n = adj.nodeTo;
+ if(n._flag == false && filter(n)) {
+ n._flag = true;
+ queue.unshift(n);
+ }
+ }, flags);
+ }
+ },
+
+ /*
+ Method: eachLevel
+
+ Iterates over a node's subgraph applying _action_ to the nodes of relative depth between _levelBegin_ and _levelEnd_.
+
+ Parameters:
+
+ node - A <Graph.Node>.
+ levelBegin - A relative level value.
+ levelEnd - A relative level value.
+ action - A callback function having a <Graph.Node> as first formal parameter.
+
+ */
+ eachLevel: function(node, levelBegin, levelEnd, action, flags) {
+ var d = node._depth, filter = this.filter(flags), that = this;
+ levelEnd = levelEnd === false? Number.MAX_VALUE -d : levelEnd;
+ (function loopLevel(node, levelBegin, levelEnd) {
+ var d = node._depth;
+ if(d >= levelBegin && d <= levelEnd && filter(node)) action(node, d);
+ if(d < levelEnd) {
+ that.eachAdjacency(node, function(adj) {
+ var n = adj.nodeTo;
+ if(n._depth > d) loopLevel(n, levelBegin, levelEnd);
+ });
+ }
+ })(node, levelBegin + d, levelEnd + d);
+ },
+
+ /*
+ Method: eachSubgraph
+
+ Iterates over a node's children recursively.
+
+ Parameters:
+ node - A <Graph.Node>.
+ action - A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ Graph.Util.eachSubgraph(node, function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ eachSubgraph: function(node, action, flags) {
+ this.eachLevel(node, 0, false, action, flags);
+ },
+
+ /*
+ Method: eachSubnode
+
+ Iterates over a node's children (without deeper recursion).
+
+ Parameters:
+ node - A <Graph.Node>.
+ action - A callback function having a <Graph.Node> as first formal parameter.
+
+ Example:
+ (start code js)
+ Graph.Util.eachSubnode(node, function(node) {
+ alert(node.name);
+ });
+ (end code)
+ */
+ eachSubnode: function(node, action, flags) {
+ this.eachLevel(node, 1, 1, action, flags);
+ },
+
+ /*
+ Method: anySubnode
+
+ Returns *true* if any subnode matches the given condition.
+
+ Parameters:
+ node - A <Graph.Node>.
+ cond - A callback function returning a Boolean instance. This function has as first formal parameter a <Graph.Node>.
+
+ Returns:
+ A boolean value.
+
+ Example:
+ (start code js)
+ Graph.Util.anySubnode(node, function(node) { return node.name == "mynodename"; });
+ (end code)
+ */
+ anySubnode: function(node, cond, flags) {
+ var flag = false;
+ cond = cond || $lambda(true);
+ var c = $type(cond) == 'string'? function(n) { return n[cond]; } : cond;
+ this.eachSubnode(node, function(elem) {
+ if(c(elem)) flag = true;
+ }, flags);
+ return flag;
+ },
+
+ /*
+ Method: getSubnodes
+
+ Collects all subnodes for a specified node. The _level_ parameter filters nodes having relative depth of _level_ from the root node.
+
+ Parameters:
+ node - A <Graph.Node>.
+ level - _optional_ A starting relative depth for collecting nodes. Default's 0.
+
+ Returns:
+ An array of nodes.
+
+ */
+ getSubnodes: function(node, level, flags) {
+ var ans = [], that = this;
+ level = level || 0;
+ var levelStart, levelEnd;
+ if($type(level) == 'array') {
+ levelStart = level[0];
+ levelEnd = level[1];
+ } else {
+ levelStart = level;
+ levelEnd = Number.MAX_VALUE - node._depth;
+ }
+ this.eachLevel(node, levelStart, levelEnd, function(n) {
+ ans.push(n);
+ }, flags);
+ return ans;
+ },
+
+
+ /*
+ Method: getParents
+
+ Returns an Array of <Graph.Nodes> wich are parents of the given node.
+
+ Parameters:
+ node - A <Graph.Node>.
+
+ Returns:
+ An Array of <Graph.Nodes>.
+
+ Example:
+ (start code js)
+ var pars = Graph.Util.getParents(node);
+ if(pars.length > 0) {
+ //do stuff with parents
+ }
+ (end code)
+ */
+ getParents: function(node) {
+ var ans = [];
+ this.eachAdjacency(node, function(adj) {
+ var n = adj.nodeTo;
+ if(n._depth < node._depth) ans.push(n);
+ });
+ return ans;
+ },
+
+ /*
+ Method: isDescendantOf
+
+ Returns a Boolean instance indicating if some node is descendant of the node with the given id.
+
+ Parameters:
+ node - A <Graph.Node>.
+ id - A <Graph.Node> id.
+
+ Returns:
+ Ture if _node_ is descendant of the node with the given _id_. False otherwise.
+
+ Example:
+ (start code js)
+ var pars = Graph.Util.isDescendantOf(node, "nodeid");
+ (end code)
+ */
+ isDescendantOf: function(node, id) {
+ if(node.id == id) return true;
+ var pars = this.getParents(node), ans = false;
+ for ( var i = 0; !ans && i < pars.length; i++) {
+ ans = ans || this.isDescendantOf(pars[i], id);
+ }
+ return ans;
+ },
+
+ /*
+ Method: clean
+
+ Cleans flags from nodes (by setting the _flag_ property to false).
+
+ Parameters:
+ graph - A <Graph> instance.
+ */
+ clean: function(graph) { this.eachNode(graph, function(elem) { elem._flag = false; }); }
+};
+
+
+
+/*
+ * File: Graph.Op.js
+ *
+ * Defines an abstract class for performing <Graph> Operations.
+*/
+
+/*
+ Object: Graph.Op
+
+ Generic <Graph> Operations.
+
+ Description:
+
+ An abstract class holding unary and binary powerful graph operations such as removingNodes, removingEdges, adding two graphs and morphing.
+
+ Implemented by:
+
+ <Hypertree.Op>, <RGraph.Op> and <ST.Op>.
+
+ Access:
+
+ The subclasses for this abstract class can be accessed by using the _op_ property of the <Hypertree>, <RGraph> or <ST> instances created.
+
+ See also:
+
+ <Hypertree.Op>, <RGraph.Op>, <ST.Op>, <Hypertree>, <RGraph>, <ST>, <Graph>.
+*/
+Graph.Op = {
+
+ options: {
+ type: 'nothing',
+ duration: 2000,
+ hideLabels: true,
+ fps:30
+ },
+
+ /*
+ Method: removeNode
+
+ Removes one or more <Graph.Nodes> from the visualization.
+ It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.
+
+ Parameters:
+
+ node - The node's id. Can also be an array having many ids.
+ opt - Animation options. It's an object with optional properties
+
+ - _type_ Type of the animation. Can be "nothing", "replot", "fade:seq", "fade:con" or "iter". Default's "nothing".
+ - _duration_ Duration of the animation in milliseconds. Default's 2000.
+ - _fps_ Frames per second for the animation. Default's 30.
+ - _hideLabels_ Hide labels during the animation. Default's *true*.
+ - _transition_ Transitions defined in the <Animation> class. Default's the default transition option of the
+ <RGraph>, <Hypertree> or <ST> instance created.
+
+ Example:
+ (start code js)
+ var rg = new RGraph(canvas, config); //could be new ST or new Hypertree also.
+ rg.op.removeNode('nodeid', {
+ type: 'fade:seq',
+ duration: 1000,
+ hideLabels: false,
+ transition: Trans.Quart.easeOut
+ });
+ //or also
+ rg.op.removeNode(['someid', 'otherid'], {
+ type: 'fade:con',
+ duration: 1500
+ });
+ (end code)
+ */
+
+ removeNode: function(node, opt) {
+ var viz = this.viz;
+ var options = $merge(this.options, viz.controller, opt);
+ var n = $splat(node);
+ var i, that, nodeObj;
+ switch(options.type) {
+ case 'nothing':
+ for(i=0; i<n.length; i++) viz.graph.removeNode(n[i]);
+ break;
+
+ case 'replot':
+ this.removeNode(n, { type: 'nothing' });
+ viz.fx.clearLabels();
+ viz.refresh(true);
+ break;
+
+ case 'fade:seq': case 'fade':
+ that = this;
+ //set alpha to 0 for nodes to remove.
+ for(i=0; i<n.length; i++) {
+ nodeObj = viz.graph.getNode(n[i]);
+ nodeObj.endAlpha = 0;
+ }
+ viz.fx.animate($merge(options, {
+ modes: ['fade:nodes'],
+ onComplete: function() {
+ that.removeNode(n, { type: 'nothing' });
+ viz.fx.clearLabels();
+ viz.reposition();
+ viz.fx.animate($merge(options, {
+ modes: ['linear']
+ }));
+ }
+ }));
+ break;
+
+ case 'fade:con':
+ that = this;
+ //set alpha to 0 for nodes to remove. Tag them for being ignored on computing positions.
+ for(i=0; i<n.length; i++) {
+ nodeObj = viz.graph.getNode(n[i]);
+ nodeObj.endAlpha = 0;
+ nodeObj.ignore = true;
+ }
+ viz.reposition();
+ viz.fx.animate($merge(options, {
+ modes: ['fade:nodes', 'linear'],
+ onComplete: function() {
+ that.removeNode(n, { type: 'nothing' });
+ }
+ }));
+ break;
+
+ case 'iter':
+ that = this;
+ viz.fx.sequence({
+ condition: function() { return n.length != 0; },
+ step: function() { that.removeNode(n.shift(), { type: 'nothing' }); viz.fx.clearLabels(); },
+ onComplete: function() { options.onComplete(); },
+ duration: Math.ceil(options.duration / n.length)
+ });
+ break;
+
+ default: this.doError();
+ }
+ },
+
+ /*
+ Method: removeEdge
+
+ Removes one or more edges from the visualization.
+ It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.
+
+ Parameters:
+
+ vertex - An array having two strings which are the ids of the nodes connected by this edge (i.e ['id1', 'id2']). Can also be a two dimensional array holding many edges (i.e [['id1', 'id2'], ['id3', 'id4'], ...]).
+ opt - Animation options. It's an object with optional properties
+
+ - _type_ Type of the animation. Can be "nothing", "replot", "fade:seq", "fade:con" or "iter". Default's "nothing".
+ - _duration_ Duration of the animation in milliseconds. Default's 2000.
+ - _fps_ Frames per second for the animation. Default's 30.
+ - _hideLabels_ Hide labels during the animation. Default's *true*.
+ - _transition_ Transitions defined in the <Animation> class. Default's the default transition option of the
+ <RGraph>, <Hypertree> or <ST> instance created.
+
+ Example:
+ (start code js)
+ var rg = new RGraph(canvas, config); //could be new ST or new Hypertree also.
+ rg.op.removeEdge(['nodeid', 'otherid'], {
+ type: 'fade:seq',
+ duration: 1000,
+ hideLabels: false,
+ transition: Trans.Quart.easeOut
+ });
+ //or also
+ rg.op.removeEdge([['someid', 'otherid'], ['id3', 'id4']], {
+ type: 'fade:con',
+ duration: 1500
+ });
+ (end code)
+
+ */
+ removeEdge: function(vertex, opt) {
+ var viz = this.viz;
+ var options = $merge(this.options, viz.controller, opt);
+ var v = ($type(vertex[0]) == 'string')? [vertex] : vertex;
+ var i, that, adjs;
+ switch(options.type) {
+ case 'nothing':
+ for(i=0; i<v.length; i++) viz.graph.removeAdjacence(v[i][0], v[i][1]);
+ break;
+
+ case 'replot':
+ this.removeEdge(v, { type: 'nothing' });
+ viz.refresh(true);
+ break;
+
+ case 'fade:seq': case 'fade':
+ that = this;
+ //set alpha to 0 for edges to remove.
+ for(i=0; i<v.length; i++) {
+ adjs = viz.graph.getAdjacence(v[i][0], v[i][1]);
+ if(adjs) {
+ adjs[0].endAlpha = 0;
+ adjs[1].endAlpha = 0;
+ }
+ }
+ viz.fx.animate($merge(options, {
+ modes: ['fade:vertex'],
+ onComplete: function() {
+ that.removeEdge(v, { type: 'nothing' });
+ viz.reposition();
+ viz.fx.animate($merge(options, {
+ modes: ['linear']
+ }));
+ }
+ }));
+ break;
+
+ case 'fade:con':
+ that = this;
+ //set alpha to 0 for nodes to remove. Tag them for being ignored when computing positions.
+ for(i=0; i<v.length; i++) {
+ adjs = viz.graph.getAdjacence(v[i][0], v[i][1]);
+ if(adjs) {
+ adjs[0].endAlpha = 0;
+ adjs[0].ignore = true;
+ adjs[1].endAlpha = 0;
+ adjs[1].ignore = true;
+ }
+ }
+ viz.reposition();
+ viz.fx.animate($merge(options, {
+ modes: ['fade:vertex', 'linear'],
+ onComplete: function() {
+ that.removeEdge(v, { type: 'nothing' });
+ }
+ }));
+ break;
+
+ case 'iter':
+ that = this;
+ viz.fx.sequence({
+ condition: function() { return v.length != 0; },
+ step: function() { that.removeEdge(v.shift(), { type: 'nothing' }); viz.fx.clearLabels(); },
+ onComplete: function() { options.onComplete(); },
+ duration: Math.ceil(options.duration / v.length)
+ });
+ break;
+
+ default: this.doError();
+ }
+ },
+
+ /*
+ Method: sum
+
+ Adds a new graph to the visualization.
+
+ The json graph (or tree) must at least have a common node with the current graph plotted by the visualization.
+
+ The resulting graph can be defined as follows <http://mathworld.wolfram.com/GraphSum.html>
+
+ Parameters:
+
+ json - A json tree or graph structure. See also <Loader.loadJSON>.
+ opt - Animation options. It's an object with optional properties
+
+ - _type_ Type of the animation. Can be "nothing", "replot", "fade:seq" or "fade:con". Default's "nothing".
+ - _duration_ Duration of the animation in milliseconds. Default's 2000.
+ - _fps_ Frames per second for the animation. Default's 30.
+ - _hideLabels_ Hide labels during the animation. Default's *true*.
+ - _transition_ Transitions defined in the <Animation> class. Default's the default transition option of the
+ <RGraph>, <Hypertree> or <ST> instance created.
+
+ Example:
+ (start code js)
+ //json contains a tree or graph structure.
+
+ var rg = new RGraph(canvas, config); //could be new ST or new Hypertree also.
+ rg.op.sum(json, {
+ type: 'fade:seq',
+ duration: 1000,
+ hideLabels: false,
+ transition: Trans.Quart.easeOut
+ });
+ //or also
+ rg.op.sum(json, {
+ type: 'fade:con',
+ duration: 1500
+ });
+ (end code)
+
+ */
+ sum: function(json, opt) {
+ var viz = this.viz;
+ var options = $merge(this.options, viz.controller, opt), root = viz.root;
+ var GUtil, graph;
+ viz.root = opt.id || viz.root;
+ switch(options.type) {
+ case 'nothing':
+ graph = viz.construct(json);
+ GUtil = Graph.Util;
+ GUtil.eachNode(graph, function(elem) {
+ GUtil.eachAdjacency(elem, function(adj) {
+ viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
+ });
+ });
+ break;
+
+ case 'replot':
+ viz.refresh(true);
+ this.sum(json, { type: 'nothing' });
+ viz.refresh(true);
+ break;
+
+ case 'fade:seq': case 'fade': case 'fade:con':
+ GUtil = Graph.Util;
+ that = this;
+ graph = viz.construct(json);
+
+ //set alpha to 0 for nodes to add.
+ var fadeEdges = this.preprocessSum(graph);
+ var modes = !fadeEdges? ['fade:nodes'] : ['fade:nodes', 'fade:vertex'];
+ viz.reposition();
+ if(options.type != 'fade:con') {
+ viz.fx.animate($merge(options, {
+ modes: ['linear'],
+ onComplete: function() {
+ viz.fx.animate($merge(options, {
+ modes: modes,
+ onComplete: function() {
+ options.onComplete();
+ }
+ }));
+ }
+ }));
+ } else {
+ GUtil.eachNode(viz.graph, function(elem) {
+ if (elem.id != root && elem.pos.getp().equals(Polar.KER)) {
+ elem.pos.set(elem.endPos); elem.startPos.set(elem.endPos);
+ }
+ });
+ viz.fx.animate($merge(options, {
+ modes: ['linear'].concat(modes)
+ }));
+ }
+ break;
+
+ default: this.doError();
+ }
+ },
+
+ /*
+ Method: morph
+
+ This method will _morph_ the current visualized graph into the new _json_ representation passed in the method.
+
+ Can also perform multiple animations. The _json_ object must at least have the root node in common with the current visualized graph.
+
+ Parameters:
+
+ json - A json tree or graph structure. See also <Loader.loadJSON>.
+ opt - Animation options. It's an object with optional properties
+
+ - _type_ Type of the animation. Can be "nothing", "replot", or "fade". Default's "nothing".
+ - _duration_ Duration of the animation in milliseconds. Default's 2000.
+ - _fps_ Frames per second for the animation. Default's 30.
+ - _hideLabels_ Hide labels during the animation. Default's *true*.
+ - _transition_ Transitions defined in the <Animation> class. Default's the default transition option of the
+ <RGraph>, <Hypertree> or <ST> instance created.
+
+ Example:
+ (start code js)
+ //json contains a tree or graph structure.
+
+ var rg = new RGraph(canvas, config); //could be new ST or new Hypertree also.
+ rg.op.morph(json, {
+ type: 'fade',
+ duration: 1000,
+ hideLabels: false,
+ transition: Trans.Quart.easeOut
+ });
+ //or also
+ rg.op.morph(json, {
+ type: 'fade',
+ duration: 1500
+ });
+ (end code)
+
+ */
+ morph: function(json, opt) {
+ var viz = this.viz;
+ var options = $merge(this.options, viz.controller, opt), root = viz.root;
+ var GUtil, graph;
+ viz.root = opt.id || viz.root;
+ switch(options.type) {
+ case 'nothing':
+ graph = viz.construct(json);
+ GUtil = Graph.Util;
+ GUtil.eachNode(graph, function(elem) {
+ GUtil.eachAdjacency(elem, function(adj) {
+ viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
+ });
+ });
+ GUtil.eachNode(viz.graph, function(elem) {
+ GUtil.eachAdjacency(elem, function(adj) {
+ if(!graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id)) {
+ viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
+ }
+ });
+ if(!graph.hasNode(elem.id)) viz.graph.removeNode(elem.id);
+ });
+
+ break;
+
+ case 'replot':
+ viz.fx.clearLabels(true);
+ this.morph(json, { type: 'nothing' });
+ viz.refresh(true);
+ viz.refresh(true);
+ break;
+
+ case 'fade:seq': case 'fade': case 'fade:con':
+ GUtil = Graph.Util;
+ that = this;
+ graph = viz.construct(json);
+ //preprocessing for adding nodes.
+ var fadeEdges = this.preprocessSum(graph);
+ //preprocessing for nodes to delete.
+ GUtil.eachNode(viz.graph, function(elem) {
+ if(!graph.hasNode(elem.id)) {
+ elem.alpha = 1; elem.startAlpha = 1; elem.endAlpha = 0; elem.ignore = true;
+ }
+ });
+ GUtil.eachNode(viz.graph, function(elem) {
+ if(elem.ignore) return;
+ GUtil.eachAdjacency(elem, function(adj) {
+ if(adj.nodeFrom.ignore || adj.nodeTo.ignore) return;
+ var nodeFrom = graph.getNode(adj.nodeFrom.id);
+ var nodeTo = graph.getNode(adj.nodeTo.id);
+ if(!nodeFrom.adjacentTo(nodeTo)) {
+ var adjs = viz.graph.getAdjacence(nodeFrom.id, nodeTo.id);
+ fadeEdges = true;
+ adjs[0].alpha = 1; adjs[0].startAlpha = 1; adjs[0].endAlpha = 0; adjs[0].ignore = true;
+ adjs[1].alpha = 1; adjs[1].startAlpha = 1; adjs[1].endAlpha = 0; adjs[1].ignore = true;
+ }
+ });
+ });
+ var modes = !fadeEdges? ['fade:nodes'] : ['fade:nodes', 'fade:vertex'];
+ viz.reposition();
+ GUtil.eachNode(viz.graph, function(elem) {
+ if (elem.id != root && elem.pos.getp().equals(Polar.KER)) {
+ elem.pos.set(elem.endPos); elem.startPos.set(elem.endPos);
+ }
+ });
+ viz.fx.animate($merge(options, {
+ modes: ['polar'].concat(modes),
+ onComplete: function() {
+ GUtil.eachNode(viz.graph, function(elem) {
+ if(elem.ignore) viz.graph.removeNode(elem.id);
+ });
+ GUtil.eachNode(viz.graph, function(elem) {
+ GUtil.eachAdjacency(elem, function(adj) {
+ if(adj.ignore) viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
+ });
+ });
+ options.onComplete();
+ }
+ }));
+ break;
+
+ default: this.doError();
+ }
+ },
+
+ preprocessSum: function(graph) {
+ var viz = this.viz;
+ var GUtil = Graph.Util;
+ GUtil.eachNode(graph, function(elem) {
+ if(!viz.graph.hasNode(elem.id)) {
+ viz.graph.addNode(elem);
+ var n = viz.graph.getNode(elem.id);
+ n.alpha = 0; n.startAlpha = 0; n.endAlpha = 1;
+ }
+ });
+ var fadeEdges = false;
+ GUtil.eachNode(graph, function(elem) {
+ GUtil.eachAdjacency(elem, function(adj) {
+ var nodeFrom = viz.graph.getNode(adj.nodeFrom.id);
+ var nodeTo = viz.graph.getNode(adj.nodeTo.id);
+ if(!nodeFrom.adjacentTo(nodeTo)) {
+ var adjs = viz.graph.addAdjacence(nodeFrom, nodeTo, adj.data);
+ if(nodeFrom.startAlpha == nodeFrom.endAlpha
+ && nodeTo.startAlpha == nodeTo.endAlpha) {
+ fadeEdges = true;
+ adjs[0].alpha = 0; adjs[0].startAlpha = 0; adjs[0].endAlpha = 1;
+ adjs[1].alpha = 0; adjs[1].startAlpha = 0; adjs[1].endAlpha = 1;
+ }
+ }
+ });
+ });
+ return fadeEdges;
+ }
+};
+
+
+
+/*
+ * File: Graph.Plot.js
+ *
+ * Defines an abstract class for performing <Graph> rendering and animation.
+ *
+ */
+
+
+/*
+ Object: Graph.Plot
+
+ Generic <Graph> rendering and animation methods.
+
+ Description:
+
+ An abstract class for plotting a generic graph structure.
+
+ Implemented by:
+
+ <Hypertree.Plot>, <RGraph.Plot>, <ST.Plot>.
+
+ Access:
+
+ The subclasses for this abstract class can be accessed by using the _fx_ property of the <Hypertree>, <RGraph>, or <ST> instances created.
+
+ See also:
+
+ <Hypertree.Plot>, <RGraph.Plot>, <ST.Plot>, <Hypertree>, <RGraph>, <ST>, <Graph>.
+
+*/
+Graph.Plot = {
+
+ Interpolator: {
+ 'moebius': function(elem, delta, vector) {
+ if(delta <= 1 || vector.norm() <= 1) {
+ var x = vector.x, y = vector.y;
+ var ans = elem.startPos.getc().moebiusTransformation(vector);
+ elem.pos.setc(ans.x, ans.y);
+ vector.x = x; vector.y = y;
+ }
+ },
+
+ 'linear': function(elem, delta) {
+ var from = elem.startPos.getc(true);
+ var to = elem.endPos.getc(true);
+ elem.pos.setc((to.x - from.x) * delta + from.x, (to.y - from.y) * delta + from.y);
+ },
+
+ 'fade:nodes': function(elem, delta) {
+ if(delta <= 1 && (elem.endAlpha != elem.alpha)) {
+ var from = elem.startAlpha;
+ var to = elem.endAlpha;
+ elem.alpha = from + (to - from) * delta;
+ }
+ },
+
+ 'fade:vertex': function(elem, delta) {
+ var adjs = elem.adjacencies;
+ for(var id in adjs) this['fade:nodes'](adjs[id], delta);
+ },
+
+ 'polar': function(elem, delta) {
+ var from = elem.startPos.getp(true);
+ var to = elem.endPos.getp();
+ var ans = to.interpolate(from, delta);
+ elem.pos.setp(ans.theta, ans.rho);
+ }
+ },
+
+ //A flag value indicating if node labels are being displayed or not.
+ labelsHidden: false,
+ //Label DOM element
+ labelContainer: false,
+ //Label DOM elements hash.
+ labels: {},
+
+ /*
+ Method: getLabelContainer
+
+ Lazy fetcher for the label container.
+
+ Returns:
+
+ The label container DOM element.
+
+ Example:
+
+ (start code js)
+ var rg = new RGraph(canvas, config); //can be also Hypertree or ST
+ var labelContainer = rg.fx.getLabelContainer();
+ alert(labelContainer.innerHTML);
+ (end code)
+ */
+ getLabelContainer: function() {
+ return this.labelContainer? this.labelContainer : this.labelContainer = document.getElementById(this.viz.config.labelContainer);
+ },
+
+ /*
+ Method: getLabel
+
+ Lazy fetcher for the label DOM element.
+
+ Parameters:
+
+ id - The label id (which is also a <Graph.Node> id).
+
+ Returns:
+
+ The label DOM element.
+
+ Example:
+
+ (start code js)
+ var rg = new RGraph(canvas, config); //can be also Hypertree or ST
+ var label = rg.fx.getLabel('someid');
+ alert(label.innerHTML);
+ (end code)
+
+ */
+ getLabel: function(id) {
+ return (id in this.labels && this.labels[id] != null)? this.labels[id] : this.labels[id] = document.getElementById(id);
+ },
+
+ /*
+ Method: hideLabels
+
+ Hides all labels (by hiding the label container).
+
+ Parameters:
+
+ hide - A boolean value indicating if the label container must be hidden or not.
+
+ Example:
+ (start code js)
+ var rg = new RGraph(canvas, config); //can be also Hypertree or ST
+ rg.fx.hideLabels(true);
+ (end code)
+
+ */
+ hideLabels: function (hide) {
+ var container = this.getLabelContainer();
+ if(hide) container.style.display = 'none';
+ else container.style.display = '';
+ this.labelsHidden = hide;
+ },
+
+ /*
+ Method: clearLabels
+
+ Clears the label container.
+
+ Useful when using a new visualization with the same canvas element/widget.
+
+ Parameters:
+
+ force - Forces deletion of all labels.
+
+ Example:
+ (start code js)
+ var rg = new RGraph(canvas, config); //can be also Hypertree or ST
+ rg.fx.clearLabels();
+ (end code)
+ */
+ clearLabels: function(force) {
+ for(var id in this.labels) {
+ if (force || !this.viz.graph.hasNode(id)) {
+ this.disposeLabel(id);
+ delete this.labels[id];
+ }
+ }
+ },
+
+ /*
+ Method: disposeLabel
+
+ Removes a label.
+
+ Parameters:
+
+ id - A label id (which generally is also a <Graph.Node> id).
+
+ Example:
+ (start code js)
+ var rg = new RGraph(canvas, config); //can be also Hypertree or ST
+ rg.fx.disposeLabel('labelid');
+ (end code)
+ */
+ disposeLabel: function(id) {
+ var elem = this.getLabel(id);
+ if(elem && elem.parentNode) {
+ elem.parentNode.removeChild(elem);
+ }
+ },
+
+ /*
+ Method: hideLabel
+
+ Hides the corresponding <Graph.Node> label.
+
+ Parameters:
+
+ node - A <Graph.Node>. Can also be an array of <Graph.Nodes>.
+ flag - If *true*, nodes will be shown. Otherwise nodes will be hidden.
+
+ Example:
+ (start code js)
+ var rg = new RGraph(canvas, config); //can be also Hypertree or ST
+ rg.fx.hideLabel(rg.graph.getNode('someid'), false);
+ (end code)
+ */
+ hideLabel: function(node, flag) {
+ node = $splat(node);
+ var st = flag? "" : "none", lab, that = this;
+ $each(node, function(n) {
+ var lab = that.getLabel(n.id);
+ if (lab) {
+ lab.style.display = st;
+ }
+ });
+ },
+
+ /*
+ Method: sequence
+
+ Iteratively performs an action while refreshing the state of the visualization.
+
+ Parameters:
+
+ options - Some sequence options like
+
+ - _condition_ A function returning a boolean instance in order to stop iterations.
+ - _step_ A function to execute on each step of the iteration.
+ - _onComplete_ A function to execute when the sequence finishes.
+ - _duration_ Duration (in milliseconds) of each step.
+
+ Example:
+ (start code js)
+ var rg = new RGraph(canvas, config); //can be also Hypertree or ST
+ var i = 0;
+ rg.fx.sequence({
+ condition: function() {
+ return i == 10;
+ },
+ step: function() {
+ alert(i++);
+ },
+ onComplete: function() {
+ alert('done!');
+ }
+ });
+ (end code)
+
+ */
+ sequence: function(options) {
+ var that = this;
+ options = $merge({
+ condition: $lambda(false),
+ step: $empty,
+ onComplete: $empty,
+ duration: 200
+ }, options || {});
+
+ var interval = setInterval(function() {
+ if(options.condition()) {
+ options.step();
+ } else {
+ clearInterval(interval);
+ options.onComplete();
[... 5942 lines stripped ...]