0f9ef03304948dadcbaf6fc47db6fb21b6658eac
[controller.git] / opendaylight / web / root / src / main / resources / js / jit.js
1 /*
2 Copyright (c) 2012 Sencha Inc. - Author: Nicolas Garcia Belmonte (http://philogb.github.com/)
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21
22  */
23  (function () { 
24
25 /*
26   File: Core.js
27
28  */
29
30 /*
31  Object: $jit
32
33  Defines the namespace for all library Classes and Objects.
34  This variable is the *only* global variable defined in the Toolkit.
35  There are also other interesting properties attached to this variable described below.
36  */
37 this.$jit = function(w) {
38   w = w || window;
39   for(var k in $jit) {
40     if($jit[k].$extend) {
41       w[k] = $jit[k];
42     }
43   }
44 };
45
46 $jit.version = '2.0.1';
47 /*
48   Object: $jit.id
49
50   Works just like *document.getElementById*
51
52   Example:
53   (start code js)
54   var element = $jit.id('elementId');
55   (end code)
56
57 */
58
59 /*
60  Object: $jit.util
61
62  Contains utility functions.
63
64  Some of the utility functions and the Class system were based in the MooTools Framework
65  <http://mootools.net>. Copyright (c) 2006-2010 Valerio Proietti, <http://mad4milk.net/>.
66  MIT license <http://mootools.net/license.txt>.
67
68  These methods are generally also implemented in DOM manipulation frameworks like JQuery, MooTools and Prototype.
69  I'd suggest you to use the functions from those libraries instead of using these, since their functions
70  are widely used and tested in many different platforms/browsers. Use these functions only if you have to.
71
72  */
73 var $ = function(d) {
74   return document.getElementById(d);
75 };
76
77 $.empty = function() {
78 };
79
80 /*
81   Method: extend
82
83   Augment an object by appending another object's properties.
84
85   Parameters:
86
87   original - (object) The object to be extended.
88   extended - (object) An object which properties are going to be appended to the original object.
89
90   Example:
91   (start code js)
92   $jit.util.extend({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 4 }); //{ 'a':1, 'b': 3, 'c': 4 }
93   (end code)
94 */
95 $.extend = function(original, extended) {
96   for ( var key in (extended || {}))
97     original[key] = extended[key];
98   return original;
99 };
100
101 $.lambda = function(value) {
102   return (typeof value == 'function') ? value : function() {
103     return value;
104   };
105 };
106
107 $.time = Date.now || function() {
108   return +new Date;
109 };
110
111 /*
112   Method: splat
113
114   Returns an array wrapping *obj* if *obj* is not an array. Returns *obj* otherwise.
115
116   Parameters:
117
118   obj - (mixed) The object to be wrapped in an array.
119
120   Example:
121   (start code js)
122   $jit.util.splat(3);   //[3]
123   $jit.util.splat([3]); //[3]
124   (end code)
125 */
126 $.splat = function(obj) {
127   var type = $.type(obj);
128   return type ? ((type != 'array') ? [ obj ] : obj) : [];
129 };
130
131 $.type = function(elem) {
132   var type = $.type.s.call(elem).match(/^\[object\s(.*)\]$/)[1].toLowerCase();
133   if(type != 'object') return type;
134   if(elem && elem.$$family) return elem.$$family;
135   if(elem && elem.nodeType == 9) return 'htmldocument';
136   return (elem && elem.nodeName && elem.nodeType == 1)? 'element' : type;
137 };
138 $.type.s = Object.prototype.toString;
139
140 /*
141   Method: each
142
143   Iterates through an iterable applying *f*.
144
145   Parameters:
146
147   iterable - (array) The original array.
148   fn - (function) The function to apply to the array elements.
149
150   Example:
151   (start code js)
152   $jit.util.each([3, 4, 5], function(n) { alert('number ' + n); });
153   (end code)
154 */
155 $.each = function(iterable, fn) {
156   var type = $.type(iterable);
157   if (type == 'object') {
158     for ( var key in iterable)
159       fn(iterable[key], key);
160   } else {
161     for ( var i = 0, l = iterable.length; i < l; i++)
162       fn(iterable[i], i);
163   }
164 };
165
166 $.indexOf = function(array, item) {
167   if(array.indexOf) return array.indexOf(item);
168   for(var i=0,l=array.length; i<l; i++) {
169     if(array[i] === item) return i;
170   }
171   return -1;
172 };
173
174 /*
175   Method: map
176
177   Maps or collects an array by applying *f*.
178
179   Parameters:
180
181   array - (array) The original array.
182   f - (function) The function to apply to the array elements.
183
184   Example:
185   (start code js)
186   $jit.util.map([3, 4, 5], function(n) { return n*n; }); //[9, 16, 25]
187   (end code)
188 */
189 $.map = function(array, f) {
190   var ans = [];
191   $.each(array, function(elem, i) {
192     ans.push(f(elem, i));
193   });
194   return ans;
195 };
196
197 /*
198   Method: reduce
199
200   Iteratively applies the binary function *f* storing the result in an accumulator.
201
202   Parameters:
203
204   array - (array) The original array.
205   f - (function) The function to apply to the array elements.
206   opt - (optional|mixed) The starting value for the acumulator.
207
208   Example:
209   (start code js)
210   $jit.util.reduce([3, 4, 5], function(x, y) { return x + y; }, 0); //12
211   (end code)
212 */
213 $.reduce = function(array, f, opt) {
214   var l = array.length;
215   if(l==0) return opt;
216   var acum = arguments.length == 3? opt : array[--l];
217   while(l--) {
218     acum = f(acum, array[l]);
219   }
220   return acum;
221 };
222
223 /*
224   Method: merge
225
226   Merges n-objects and their sub-objects creating a new, fresh object.
227
228   Parameters:
229
230   An arbitrary number of objects.
231
232   Example:
233   (start code js)
234   $jit.util.merge({ 'a': 1, 'b': 2 }, { 'b': 3, 'c': 4 }); //{ 'a':1, 'b': 3, 'c': 4 }
235   (end code)
236 */
237 $.merge = function() {
238   var mix = {};
239   for ( var i = 0, l = arguments.length; i < l; i++) {
240     var object = arguments[i];
241     if ($.type(object) != 'object')
242       continue;
243     for ( var key in object) {
244       var op = object[key], mp = mix[key];
245       mix[key] = (mp && $.type(op) == 'object' && $.type(mp) == 'object') ? $
246           .merge(mp, op) : $.unlink(op);
247     }
248   }
249   return mix;
250 };
251
252 $.unlink = function(object) {
253   var unlinked;
254   switch ($.type(object)) {
255   case 'object':
256     unlinked = {};
257     for ( var p in object)
258       unlinked[p] = $.unlink(object[p]);
259     break;
260   case 'array':
261     unlinked = [];
262     for ( var i = 0, l = object.length; i < l; i++)
263       unlinked[i] = $.unlink(object[i]);
264     break;
265   default:
266     return object;
267   }
268   return unlinked;
269 };
270
271 $.zip = function() {
272   if(arguments.length === 0) return [];
273   for(var j=0, ans=[], l=arguments.length, ml=arguments[0].length; j<ml; j++) {
274     for(var i=0, row=[]; i<l; i++) {
275       row.push(arguments[i][j]);
276     }
277     ans.push(row);
278   }
279   return ans;
280 };
281
282 /*
283   Method: rgbToHex
284
285   Converts an RGB array into a Hex string.
286
287   Parameters:
288
289   srcArray - (array) An array with R, G and B values
290
291   Example:
292   (start code js)
293   $jit.util.rgbToHex([255, 255, 255]); //'#ffffff'
294   (end code)
295 */
296 $.rgbToHex = function(srcArray, array) {
297   if (srcArray.length < 3)
298     return null;
299   if (srcArray.length == 4 && srcArray[3] == 0 && !array)
300     return 'transparent';
301   var hex = [];
302   for ( var i = 0; i < 3; i++) {
303     var bit = (srcArray[i] - 0).toString(16);
304     hex.push(bit.length == 1 ? '0' + bit : bit);
305   }
306   return array ? hex : '#' + hex.join('');
307 };
308
309 /*
310   Method: hexToRgb
311
312   Converts an Hex color string into an RGB array.
313
314   Parameters:
315
316   hex - (string) A color hex string.
317
318   Example:
319   (start code js)
320   $jit.util.hexToRgb('#fff'); //[255, 255, 255]
321   (end code)
322 */
323 $.hexToRgb = function(hex) {
324   if (hex.length != 7) {
325     hex = hex.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
326     hex.shift();
327     if (hex.length != 3)
328       return null;
329     var rgb = [];
330     for ( var i = 0; i < 3; i++) {
331       var value = hex[i];
332       if (value.length == 1)
333         value += value;
334       rgb.push(parseInt(value, 16));
335     }
336     return rgb;
337   } else {
338     hex = parseInt(hex.slice(1), 16);
339     return [ hex >> 16, hex >> 8 & 0xff, hex & 0xff ];
340   }
341 };
342
343 $.destroy = function(elem) {
344   $.clean(elem);
345   if (elem.parentNode)
346     elem.parentNode.removeChild(elem);
347   if (elem.clearAttributes)
348     elem.clearAttributes();
349 };
350
351 $.clean = function(elem) {
352   for (var ch = elem.childNodes, i = 0, l = ch.length; i < l; i++) {
353     $.destroy(ch[i]);
354   }
355 };
356
357 /*
358   Method: addEvent
359
360   Cross-browser add event listener.
361
362   Parameters:
363
364   obj - (obj) The Element to attach the listener to.
365   type - (string) The listener type. For example 'click', or 'mousemove'.
366   fn - (function) The callback function to be used when the event is fired.
367
368   Example:
369   (start code js)
370   $jit.util.addEvent(elem, 'click', function(){ alert('hello'); });
371   (end code)
372 */
373 $.addEvent = function(obj, type, fn) {
374   if (obj.addEventListener)
375     obj.addEventListener(type, fn, false);
376   else
377     obj.attachEvent('on' + type, fn);
378 };
379
380 $.addEvents = function(obj, typeObj) {
381   for(var type in typeObj) {
382     $.addEvent(obj, type, typeObj[type]);
383   }
384 };
385
386 $.hasClass = function(obj, klass) {
387   return (' ' + obj.className + ' ').indexOf(' ' + klass + ' ') > -1;
388 };
389
390 $.addClass = function(obj, klass) {
391   if (!$.hasClass(obj, klass))
392     obj.className = (obj.className + " " + klass);
393 };
394
395 $.removeClass = function(obj, klass) {
396   obj.className = obj.className.replace(new RegExp(
397       '(^|\\s)' + klass + '(?:\\s|$)'), '$1');
398 };
399
400 $.getPos = function(elem) {
401   var offset = getOffsets(elem);
402   var scroll = getScrolls(elem);
403   return {
404     x: offset.x - scroll.x,
405     y: offset.y - scroll.y
406   };
407
408   function getOffsets(elem) {
409     var position = {
410       x: 0,
411       y: 0
412     };
413     while (elem && !isBody(elem)) {
414       position.x += elem.offsetLeft;
415       position.y += elem.offsetTop;
416       elem = elem.offsetParent;
417     }
418     return position;
419   }
420
421   function getScrolls(elem) {
422     var position = {
423       x: 0,
424       y: 0
425     };
426     while (elem && !isBody(elem)) {
427       position.x += elem.scrollLeft;
428       position.y += elem.scrollTop;
429       elem = elem.parentNode;
430     }
431     return position;
432   }
433
434   function isBody(element) {
435     return (/^(?:body|html)$/i).test(element.tagName);
436   }
437 };
438
439 $.event = {
440   get: function(e, win) {
441     win = win || window;
442     return e || win.event;
443   },
444   getWheel: function(e) {
445     return e.wheelDelta? e.wheelDelta / 120 : -(e.detail || 0) / 3;
446   },
447   isRightClick: function(e) {
448     return (e.which == 3 || e.button == 2);
449   },
450   getPos: function(e, win) {
451     // get mouse position
452     win = win || window;
453     e = e || win.event;
454     var doc = win.document;
455     doc = doc.documentElement || doc.body;
456     //TODO(nico): make touch event handling better
457     if(e.touches && e.touches.length) {
458       e = e.touches[0];
459     }
460     var page = {
461       x: e.pageX || (e.clientX + doc.scrollLeft),
462       y: e.pageY || (e.clientY + doc.scrollTop)
463     };
464     return page;
465   },
466   stop: function(e) {
467     if (e.stopPropagation) e.stopPropagation();
468     e.cancelBubble = true;
469     if (e.preventDefault) e.preventDefault();
470     else e.returnValue = false;
471   }
472 };
473
474 $jit.util = $jit.id = $;
475
476 var Class = function(properties) {
477   properties = properties || {};
478   var klass = function() {
479     for ( var key in this) {
480       if (typeof this[key] != 'function')
481         this[key] = $.unlink(this[key]);
482     }
483     this.constructor = klass;
484     if (Class.prototyping)
485       return this;
486     var instance = this.initialize ? this.initialize.apply(this, arguments)
487         : this;
488     //typize
489     this.$$family = 'class';
490     return instance;
491   };
492
493   for ( var mutator in Class.Mutators) {
494     if (!properties[mutator])
495       continue;
496     properties = Class.Mutators[mutator](properties, properties[mutator]);
497     delete properties[mutator];
498   }
499
500   $.extend(klass, this);
501   klass.constructor = Class;
502   klass.prototype = properties;
503   return klass;
504 };
505
506 Class.Mutators = {
507
508   Implements: function(self, klasses) {
509     $.each($.splat(klasses), function(klass) {
510       Class.prototyping = klass;
511       var instance = (typeof klass == 'function') ? new klass : klass;
512       for ( var prop in instance) {
513         if (!(prop in self)) {
514           self[prop] = instance[prop];
515         }
516       }
517       delete Class.prototyping;
518     });
519     return self;
520   }
521
522 };
523
524 $.extend(Class, {
525
526   inherit: function(object, properties) {
527     for ( var key in properties) {
528       var override = properties[key];
529       var previous = object[key];
530       var type = $.type(override);
531       if (previous && type == 'function') {
532         if (override != previous) {
533           Class.override(object, key, override);
534         }
535       } else if (type == 'object') {
536         object[key] = $.merge(previous, override);
537       } else {
538         object[key] = override;
539       }
540     }
541     return object;
542   },
543
544   override: function(object, name, method) {
545     var parent = Class.prototyping;
546     if (parent && object[name] != parent[name])
547       parent = null;
548     var override = function() {
549       var previous = this.parent;
550       this.parent = parent ? parent[name] : object[name];
551       var value = method.apply(this, arguments);
552       this.parent = previous;
553       return value;
554     };
555     object[name] = override;
556   }
557
558 });
559
560 Class.prototype.implement = function() {
561   var proto = this.prototype;
562   $.each(Array.prototype.slice.call(arguments || []), function(properties) {
563     Class.inherit(proto, properties);
564   });
565   return this;
566 };
567
568 $jit.Class = Class;
569
570 /*
571   Object: $jit.json
572
573   Provides JSON utility functions.
574
575   Most of these functions are JSON-tree traversal and manipulation functions.
576 */
577 $jit.json = {
578   /*
579      Method: prune
580
581      Clears all tree nodes having depth greater than maxLevel.
582
583      Parameters:
584
585         tree - (object) A JSON tree object. For more information please see <Loader.loadJSON>.
586         maxLevel - (number) An integer specifying the maximum level allowed for this tree. All nodes having depth greater than max level will be deleted.
587
588   */
589   prune: function(tree, maxLevel) {
590     this.each(tree, function(elem, i) {
591       if (i == maxLevel && elem.children) {
592         delete elem.children;
593         elem.children = [];
594       }
595     });
596   },
597   /*
598      Method: getParent
599
600      Returns the parent node of the node having _id_ as id.
601
602      Parameters:
603
604         tree - (object) A JSON tree object. See also <Loader.loadJSON>.
605         id - (string) The _id_ of the child node whose parent will be returned.
606
607     Returns:
608
609         A tree JSON node if any, or false otherwise.
610
611   */
612   getParent: function(tree, id) {
613     if (tree.id == id)
614       return false;
615     var ch = tree.children;
616     if (ch && ch.length > 0) {
617       for ( var i = 0; i < ch.length; i++) {
618         if (ch[i].id == id)
619           return tree;
620         else {
621           var ans = this.getParent(ch[i], id);
622           if (ans)
623             return ans;
624         }
625       }
626     }
627     return false;
628   },
629   /*
630      Method: getSubtree
631
632      Returns the subtree that matches the given id.
633
634      Parameters:
635
636         tree - (object) A JSON tree object. See also <Loader.loadJSON>.
637         id - (string) A node *unique* identifier.
638
639      Returns:
640
641         A subtree having a root node matching the given id. Returns null if no subtree matching the id is found.
642
643   */
644   getSubtree: function(tree, id) {
645     if (tree.id == id)
646       return tree;
647     for ( var i = 0, ch = tree.children; ch && i < ch.length; i++) {
648       var t = this.getSubtree(ch[i], id);
649       if (t != null)
650         return t;
651     }
652     return null;
653   },
654   /*
655      Method: eachLevel
656
657       Iterates on tree nodes with relative depth less or equal than a specified level.
658
659      Parameters:
660
661         tree - (object) A JSON tree or subtree. See also <Loader.loadJSON>.
662         initLevel - (number) An integer specifying the initial relative level. Usually zero.
663         toLevel - (number) An integer specifying a top level. This method will iterate only through nodes with depth less than or equal this number.
664         action - (function) A function that receives a node and an integer specifying the actual level of the node.
665
666     Example:
667    (start code js)
668      $jit.json.eachLevel(tree, 0, 3, function(node, depth) {
669         alert(node.name + ' ' + depth);
670      });
671    (end code)
672   */
673   eachLevel: function(tree, initLevel, toLevel, action) {
674     if (initLevel <= toLevel) {
675       action(tree, initLevel);
676       if(!tree.children) return;
677       for ( var i = 0, ch = tree.children; i < ch.length; i++) {
678         this.eachLevel(ch[i], initLevel + 1, toLevel, action);
679       }
680     }
681   },
682   /*
683      Method: each
684
685       A JSON tree iterator.
686
687      Parameters:
688
689         tree - (object) A JSON tree or subtree. See also <Loader.loadJSON>.
690         action - (function) A function that receives a node.
691
692     Example:
693     (start code js)
694       $jit.json.each(tree, function(node) {
695         alert(node.name);
696       });
697     (end code)
698
699   */
700   each: function(tree, action) {
701     this.eachLevel(tree, 0, Number.MAX_VALUE, action);
702   }
703 };
704
705
706 /*
707      An object containing multiple type of transformations. 
708 */
709
710 $jit.Trans = {
711   $extend: true,
712   
713   linear: function(p){
714     return p;
715   }
716 };
717
718 var Trans = $jit.Trans;
719
720 (function(){
721
722   var makeTrans = function(transition, params){
723     params = $.splat(params);
724     return $.extend(transition, {
725       easeIn: function(pos){
726         return transition(pos, params);
727       },
728       easeOut: function(pos){
729         return 1 - transition(1 - pos, params);
730       },
731       easeInOut: function(pos){
732         return (pos <= 0.5)? transition(2 * pos, params) / 2 : (2 - transition(
733             2 * (1 - pos), params)) / 2;
734       }
735     });
736   };
737
738   var transitions = {
739
740     Pow: function(p, x){
741       return Math.pow(p, x[0] || 6);
742     },
743
744     Expo: function(p){
745       return Math.pow(2, 8 * (p - 1));
746     },
747
748     Circ: function(p){
749       return 1 - Math.sin(Math.acos(p));
750     },
751
752     Sine: function(p){
753       return 1 - Math.sin((1 - p) * Math.PI / 2);
754     },
755
756     Back: function(p, x){
757       x = x[0] || 1.618;
758       return Math.pow(p, 2) * ((x + 1) * p - x);
759     },
760
761     Bounce: function(p){
762       var value;
763       for ( var a = 0, b = 1; 1; a += b, b /= 2) {
764         if (p >= (7 - 4 * a) / 11) {
765           value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
766           break;
767         }
768       }
769       return value;
770     },
771
772     Elastic: function(p, x){
773       return Math.pow(2, 10 * --p)
774           * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
775     }
776
777   };
778
779   $.each(transitions, function(val, key){
780     Trans[key] = makeTrans(val);
781   });
782
783   $.each( [
784       'Quad', 'Cubic', 'Quart', 'Quint'
785   ], function(elem, i){
786     Trans[elem] = makeTrans(function(p){
787       return Math.pow(p, [
788         i + 2
789       ]);
790     });
791   });
792
793 })();
794
795 /*
796    A Class that can perform animations for generic objects.
797
798    If you are looking for animation transitions please take a look at the <Trans> object.
799
800    Used by:
801
802    <Graph.Plot>
803    
804    Based on:
805    
806    The Animation class is based in the MooTools Framework <http://mootools.net>. Copyright (c) 2006-2009 Valerio Proietti, <http://mad4milk.net/>. MIT license <http://mootools.net/license.txt>.
807
808 */
809
810 var Animation = new Class( {
811
812   initialize: function(options){
813     this.setOptions(options);
814   },
815
816   setOptions: function(options){
817     var opt = {
818       duration: 2500,
819       fps: 40,
820       transition: Trans.Quart.easeInOut,
821       compute: $.empty,
822       complete: $.empty,
823       link: 'ignore'
824     };
825     this.opt = $.merge(opt, options || {});
826     return this;
827   },
828
829   step: function(){
830     var time = $.time(), opt = this.opt;
831     if (time < this.time + opt.duration) {
832       var delta = opt.transition((time - this.time) / opt.duration);
833       opt.compute(delta);
834     } else {
835       this.timer = clearInterval(this.timer);
836       opt.compute(1);
837       opt.complete();
838     }
839   },
840
841   start: function(){
842     if (!this.check())
843       return this;
844     this.time = 0;
845     this.startTimer();
846     return this;
847   },
848
849   startTimer: function(){
850     var that = this, fps = this.opt.fps;
851     if (this.timer)
852       return false;
853     this.time = $.time() - this.time;
854     this.timer = setInterval((function(){
855       that.step();
856     }), Math.round(1000 / fps));
857     return true;
858   },
859
860   pause: function(){
861     this.stopTimer();
862     return this;
863   },
864
865   resume: function(){
866     this.startTimer();
867     return this;
868   },
869
870   stopTimer: function(){
871     if (!this.timer)
872       return false;
873     this.time = $.time() - this.time;
874     this.timer = clearInterval(this.timer);
875     return true;
876   },
877
878   check: function(){
879     if (!this.timer)
880       return true;
881     if (this.opt.link == 'cancel') {
882       this.stopTimer();
883       return true;
884     }
885     return false;
886   }
887 });
888
889
890 var Options = function() {
891   var args = arguments;
892   for(var i=0, l=args.length, ans={}; i<l; i++) {
893     var opt = Options[args[i]];
894     if(opt.$extend) {
895       $.extend(ans, opt);
896     } else {
897       ans[args[i]] = opt;  
898     }
899   }
900   return ans;
901 };
902
903 /*
904  * File: Options.Canvas.js
905  *
906 */
907
908 /*
909   Object: Options.Canvas
910   
911   These are Canvas general options, like where to append it in the DOM, its dimensions, background, 
912   and other more advanced options.
913   
914   Syntax:
915   
916   (start code js)
917
918   Options.Canvas = {
919     injectInto: 'id',
920     type: '2D', //'3D'
921     width: false,
922     height: false,
923     useCanvas: false,
924     withLabels: true,
925     background: false
926   };  
927   (end code)
928   
929   Example:
930   
931   (start code js)
932   var viz = new $jit.Viz({
933     injectInto: 'someContainerId',
934     width: 500,
935     height: 700
936   });
937   (end code)
938   
939   Parameters:
940   
941   injectInto - *required* (string|element) The id of the DOM container for the visualization. It can also be an Element provided that it has an id.
942   type - (string) Context type. Default's 2D but can be 3D for webGL enabled browsers.
943   width - (number) Default's to the *container's offsetWidth*. The width of the canvas.
944   height - (number) Default's to the *container's offsetHeight*. The height of the canvas.
945   useCanvas - (boolean|object) Default's *false*. You can pass another <Canvas> instance to be used by the visualization.
946   withLabels - (boolean) Default's *true*. Whether to use a label container for the visualization.
947   background - (boolean|object) Default's *false*. An object containing information about the rendering of a background canvas.
948 */
949
950 Options.Canvas = {
951     $extend: true,
952     
953     injectInto: 'id',
954     type: '2D',
955     width: false,
956     height: false,
957     useCanvas: false,
958     withLabels: true,
959     background: false,
960     
961     Scene: {
962       Lighting: {
963         enable: false,
964         ambient: [1, 1, 1],
965         directional: {
966           direction: { x: -100, y: -100, z: -100 },
967           color: [0.5, 0.3, 0.1]
968         }
969       }
970     }
971 };
972
973 /*
974  * File: Options.Node.js
975  *
976 */
977
978 /*
979   Object: Options.Node
980
981   Provides Node rendering options for Tree and Graph based visualizations.
982
983   Syntax:
984     
985   (start code js)
986   Options.Node = {
987     overridable: false,
988     type: 'circle',
989     color: '#ccb',
990     alpha: 1,
991     dim: 3,
992     height: 20,
993     width: 90,
994     autoHeight: false,
995     autoWidth: false,
996     lineWidth: 1,
997     transform: true,
998     align: "center",
999     angularWidth:1,
1000     span:1,
1001     CanvasStyles: {}
1002   };
1003   (end code)
1004   
1005   Example:
1006   
1007   (start code js)
1008   var viz = new $jit.Viz({
1009     Node: {
1010       overridable: true,
1011       width: 30,
1012       autoHeight: true,
1013       type: 'rectangle'
1014     }
1015   });
1016   (end code)
1017   
1018   Parameters:
1019
1020   overridable - (boolean) Default's *false*. Determine whether or not general node properties can be overridden by a particular <Graph.Node>.
1021   type - (string) Default's *circle*. Node's shape. Node built-in types include 'circle', 'rectangle', 'square', 'ellipse', 'triangle', 'star'. The default Node type might vary in each visualization. You can also implement (non built-in) custom Node types into your visualizations.
1022   color - (string) Default's *#ccb*. Node color.
1023   alpha - (number) Default's *1*. The Node's alpha value. *1* is for full opacity.
1024   dim - (number) Default's *3*. An extra parameter used by 'circle', 'square', 'triangle' and 'star' node types. Depending on each shape, this parameter can set the radius of a circle, half the length of the side of a square, half the base and half the height of a triangle or the length of a side of a star (concave decagon).
1025   height - (number) Default's *20*. Used by 'rectangle' and 'ellipse' node types. The height of the node shape.
1026   width - (number) Default's *90*. Used by 'rectangle' and 'ellipse' node types. The width of the node shape.
1027   autoHeight - (boolean) Default's *false*. Whether to set an auto height for the node depending on the content of the Node's label.
1028   autoWidth - (boolean) Default's *false*. Whether to set an auto width for the node depending on the content of the Node's label.
1029   lineWidth - (number) Default's *1*. Used only by some Node shapes. The line width of the strokes of a node.
1030   transform - (boolean) Default's *true*. Only used by the <Hypertree> visualization. Whether to scale the nodes according to the moebius transformation.
1031   align - (string) Default's *center*. Possible values are 'center', 'left' or 'right'. Used only by the <ST> visualization, these parameters are used for aligning nodes when some of they dimensions vary.
1032   angularWidth - (number) Default's *1*. Used in radial layouts (like <RGraph> or <Sunburst> visualizations). The amount of relative 'space' set for a node.
1033   span - (number) Default's *1*. Used in radial layouts (like <RGraph> or <Sunburst> visualizations). The angle span amount set for a node.
1034   CanvasStyles - (object) Default's an empty object (i.e. {}). Attach any other canvas specific property that you'd set to the canvas context before plotting a Node.
1035
1036 */
1037 Options.Node = {
1038   $extend: false,
1039   
1040   overridable: false,
1041   type: 'circle',
1042   color: '#ccb',
1043   alpha: 1,
1044   dim: 3,
1045   height: 20,
1046   width: 90,
1047   autoHeight: false,
1048   autoWidth: false,
1049   lineWidth: 1,
1050   transform: true,
1051   align: "center",
1052   angularWidth:1,
1053   span:1,
1054   //Raw canvas styles to be
1055   //applied to the context instance
1056   //before plotting a node
1057   CanvasStyles: {}
1058 };
1059
1060
1061 /*
1062  * File: Options.Edge.js
1063  *
1064 */
1065
1066 /*
1067   Object: Options.Edge
1068
1069   Provides Edge rendering options for Tree and Graph based visualizations.
1070
1071   Syntax:
1072     
1073   (start code js)
1074   Options.Edge = {
1075     overridable: false,
1076     type: 'line',
1077     color: '#ccb',
1078     lineWidth: 1,
1079     dim:15,
1080     alpha: 1,
1081     CanvasStyles: {}
1082   };
1083   (end code)
1084   
1085   Example:
1086   
1087   (start code js)
1088   var viz = new $jit.Viz({
1089     Edge: {
1090       overridable: true,
1091       type: 'line',
1092       color: '#fff',
1093       CanvasStyles: {
1094         shadowColor: '#ccc',
1095         shadowBlur: 10
1096       }
1097     }
1098   });
1099   (end code)
1100   
1101   Parameters:
1102     
1103    overridable - (boolean) Default's *false*. Determine whether or not general edges properties can be overridden by a particular <Graph.Adjacence>.
1104    type - (string) Default's 'line'. Edge styles include 'line', 'hyperline', 'arrow'. The default Edge type might vary in each visualization. You can also implement custom Edge types.
1105    color - (string) Default's '#ccb'. Edge color.
1106    lineWidth - (number) Default's *1*. Line/Edge width.
1107    alpha - (number) Default's *1*. The Edge's alpha value. *1* is for full opacity.
1108    dim - (number) Default's *15*. An extra parameter used by other complex shapes such as quadratic, bezier or arrow, to determine the shape's diameter.
1109    epsilon - (number) Default's *7*. Only used when using *enableForEdges* in <Options.Events>. This dimension is used to create an area for the line where the contains method for the edge returns *true*.
1110    CanvasStyles - (object) Default's an empty object (i.e. {}). Attach any other canvas specific property that you'd set to the canvas context before plotting an Edge.
1111
1112   See also:
1113    
1114    If you want to know more about how to customize Node/Edge data per element, in the JSON or programmatically, take a look at this article.
1115 */
1116 Options.Edge = {
1117   $extend: false,
1118   
1119   overridable: false,
1120   type: 'line',
1121   color: '#ccb',
1122   lineWidth: 1,
1123   dim:15,
1124   alpha: 1,
1125   epsilon: 7,
1126
1127   //Raw canvas styles to be
1128   //applied to the context instance
1129   //before plotting an edge
1130   CanvasStyles: {}
1131 };
1132
1133
1134 /*
1135  * File: Options.Fx.js
1136  *
1137 */
1138
1139 /*
1140   Object: Options.Fx
1141
1142   Provides animation options like duration of the animations, frames per second and animation transitions.  
1143
1144   Syntax:
1145   
1146   (start code js)
1147     Options.Fx = {
1148       fps:40,
1149       duration: 2500,
1150       transition: $jit.Trans.Quart.easeInOut,
1151       clearCanvas: true
1152     };
1153   (end code)
1154   
1155   Example:
1156   
1157   (start code js)
1158   var viz = new $jit.Viz({
1159     duration: 1000,
1160     fps: 35,
1161     transition: $jit.Trans.linear
1162   });
1163   (end code)
1164   
1165   Parameters:
1166   
1167   clearCanvas - (boolean) Default's *true*. Whether to clear the frame/canvas when the viz is plotted or animated.
1168   duration - (number) Default's *2500*. Duration of the animation in milliseconds.
1169   fps - (number) Default's *40*. Frames per second.
1170   transition - (object) Default's *$jit.Trans.Quart.easeInOut*. The transition used for the animations. See below for a more detailed explanation.
1171   
1172   Object: $jit.Trans
1173   
1174   This object is used for specifying different animation transitions in all visualizations.
1175
1176   There are many different type of animation transitions.
1177
1178   linear:
1179
1180   Displays a linear transition
1181
1182   >Trans.linear
1183   
1184   (see Linear.png)
1185
1186   Quad:
1187
1188   Displays a Quadratic transition.
1189
1190   >Trans.Quad.easeIn
1191   >Trans.Quad.easeOut
1192   >Trans.Quad.easeInOut
1193   
1194  (see Quad.png)
1195
1196  Cubic:
1197
1198  Displays a Cubic transition.
1199
1200  >Trans.Cubic.easeIn
1201  >Trans.Cubic.easeOut
1202  >Trans.Cubic.easeInOut
1203
1204  (see Cubic.png)
1205
1206  Quart:
1207
1208  Displays a Quartetic transition.
1209
1210  >Trans.Quart.easeIn
1211  >Trans.Quart.easeOut
1212  >Trans.Quart.easeInOut
1213
1214  (see Quart.png)
1215
1216  Quint:
1217
1218  Displays a Quintic transition.
1219
1220  >Trans.Quint.easeIn
1221  >Trans.Quint.easeOut
1222  >Trans.Quint.easeInOut
1223
1224  (see Quint.png)
1225
1226  Expo:
1227
1228  Displays an Exponential transition.
1229
1230  >Trans.Expo.easeIn
1231  >Trans.Expo.easeOut
1232  >Trans.Expo.easeInOut
1233
1234  (see Expo.png)
1235
1236  Circ:
1237
1238  Displays a Circular transition.
1239
1240  >Trans.Circ.easeIn
1241  >Trans.Circ.easeOut
1242  >Trans.Circ.easeInOut
1243
1244  (see Circ.png)
1245
1246  Sine:
1247
1248  Displays a Sineousidal transition.
1249
1250  >Trans.Sine.easeIn
1251  >Trans.Sine.easeOut
1252  >Trans.Sine.easeInOut
1253
1254  (see Sine.png)
1255
1256  Back:
1257
1258  >Trans.Back.easeIn
1259  >Trans.Back.easeOut
1260  >Trans.Back.easeInOut
1261
1262  (see Back.png)
1263
1264  Bounce:
1265
1266  Bouncy transition.
1267
1268  >Trans.Bounce.easeIn
1269  >Trans.Bounce.easeOut
1270  >Trans.Bounce.easeInOut
1271
1272  (see Bounce.png)
1273
1274  Elastic:
1275
1276  Elastic curve.
1277
1278  >Trans.Elastic.easeIn
1279  >Trans.Elastic.easeOut
1280  >Trans.Elastic.easeInOut
1281
1282  (see Elastic.png)
1283  
1284  Based on:
1285      
1286  Easing and Transition animation methods are based in the MooTools Framework <http://mootools.net>. Copyright (c) 2006-2010 Valerio Proietti, <http://mad4milk.net/>. MIT license <http://mootools.net/license.txt>.
1287
1288
1289 */
1290 Options.Fx = {
1291   $extend: true,
1292   
1293   fps:40,
1294   duration: 2500,
1295   transition: $jit.Trans.Quart.easeInOut,
1296   clearCanvas: true
1297 };
1298
1299 /*
1300  * File: Options.Label.js
1301  *
1302 */
1303 /*
1304   Object: Options.Label
1305
1306   Provides styling for Labels such as font size, family, etc. Also sets Node labels as HTML, SVG or Native canvas elements.  
1307
1308   Syntax:
1309   
1310   (start code js)
1311     Options.Label = {
1312       overridable: false,
1313       type: 'HTML', //'SVG', 'Native'
1314       style: ' ',
1315       size: 10,
1316       family: 'sans-serif',
1317       textAlign: 'center',
1318       textBaseline: 'alphabetic',
1319       color: '#fff'
1320     };
1321   (end code)
1322   
1323   Example:
1324   
1325   (start code js)
1326   var viz = new $jit.Viz({
1327     Label: {
1328       type: 'Native',
1329       size: 11,
1330       color: '#ccc'
1331     }
1332   });
1333   (end code)
1334   
1335   Parameters:
1336     
1337   overridable - (boolean) Default's *false*. Determine whether or not general label properties can be overridden by a particular <Graph.Node>.
1338   type - (string) Default's *HTML*. The type for the labels. Can be 'HTML', 'SVG' or 'Native' canvas labels.
1339   style - (string) Default's *empty string*. Can be 'italic' or 'bold'. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.
1340   size - (number) Default's *10*. The font's size. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.
1341   family - (string) Default's *sans-serif*. The font's family. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.
1342   color - (string) Default's *#fff*. The font's color. This parameter is only taken into account when using 'Native' canvas labels. For DOM based labels the className *node* is added to the DOM element for styling via CSS. You can also use <Options.Controller> methods to style individual labels.
1343 */
1344 Options.Label = {
1345   $extend: false,
1346   
1347   overridable: false,
1348   type: 'HTML', //'SVG', 'Native'
1349   style: ' ',
1350   size: 10,
1351   family: 'sans-serif',
1352   textAlign: 'center',
1353   textBaseline: 'alphabetic',
1354   color: '#fff'
1355 };
1356
1357
1358 /*
1359  * File: Options.Tips.js
1360  *
1361  */
1362
1363 /*
1364   Object: Options.Tips
1365   
1366   Tips options
1367   
1368   Syntax:
1369     
1370   (start code js)
1371   Options.Tips = {
1372     enable: false,
1373     type: 'auto',
1374     offsetX: 20,
1375     offsetY: 20,
1376     onShow: $.empty,
1377     onHide: $.empty
1378   };
1379   (end code)
1380   
1381   Example:
1382   
1383   (start code js)
1384   var viz = new $jit.Viz({
1385     Tips: {
1386       enable: true,
1387       type: 'Native',
1388       offsetX: 10,
1389       offsetY: 10,
1390       onShow: function(tip, node) {
1391         tip.innerHTML = node.name;
1392       }
1393     }
1394   });
1395   (end code)
1396
1397   Parameters:
1398
1399   enable - (boolean) Default's *false*. If *true*, a tooltip will be shown when a node is hovered. The tooltip is a div DOM element having "tip" as CSS class. 
1400   type - (string) Default's *auto*. Defines where to attach the MouseEnter/Leave tooltip events. Possible values are 'Native' to attach them to the canvas or 'HTML' to attach them to DOM label elements (if defined). 'auto' sets this property to the value of <Options.Label>'s *type* property.
1401   offsetX - (number) Default's *20*. An offset added to the current tooltip x-position (which is the same as the current mouse position). Default's 20.
1402   offsetY - (number) Default's *20*. An offset added to the current tooltip y-position (which is the same as the current mouse position). Default's 20.
1403   onShow(tip, node) - This callack is used right before displaying a tooltip. The first formal parameter is the tip itself (which is a DivElement). The second parameter may be a <Graph.Node> for graph based visualizations or an object with label, value properties for charts.
1404   onHide() - This callack is used when hiding a tooltip.
1405
1406 */
1407 Options.Tips = {
1408   $extend: false,
1409   
1410   enable: false,
1411   type: 'auto',
1412   offsetX: 20,
1413   offsetY: 20,
1414   force: false,
1415   onShow: $.empty,
1416   onHide: $.empty
1417 };
1418
1419
1420 /*
1421  * File: Options.NodeStyles.js
1422  *
1423  */
1424
1425 /*
1426   Object: Options.NodeStyles
1427   
1428   Apply different styles when a node is hovered or selected.
1429   
1430   Syntax:
1431     
1432   (start code js)
1433   Options.NodeStyles = {
1434     enable: false,
1435     type: 'auto',
1436     stylesHover: false,
1437     stylesClick: false
1438   };
1439   (end code)
1440   
1441   Example:
1442   
1443   (start code js)
1444   var viz = new $jit.Viz({
1445     NodeStyles: {
1446       enable: true,
1447       type: 'Native',
1448       stylesHover: {
1449         dim: 30,
1450         color: '#fcc'
1451       },
1452       duration: 600
1453     }
1454   });
1455   (end code)
1456
1457   Parameters:
1458   
1459   enable - (boolean) Default's *false*. Whether to enable this option.
1460   type - (string) Default's *auto*. Use this to attach the hover/click events in the nodes or the nodes labels (if they have been defined as DOM elements: 'HTML' or 'SVG', see <Options.Label> for more details). The default 'auto' value will set NodeStyles to the same type defined for <Options.Label>.
1461   stylesHover - (boolean|object) Default's *false*. An object with node styles just like the ones defined for <Options.Node> or *false* otherwise.
1462   stylesClick - (boolean|object) Default's *false*. An object with node styles just like the ones defined for <Options.Node> or *false* otherwise.
1463 */
1464
1465 Options.NodeStyles = {
1466   $extend: false,
1467   
1468   enable: false,
1469   type: 'auto',
1470   stylesHover: false,
1471   stylesClick: false
1472 };
1473
1474
1475 /*
1476  * File: Options.Events.js
1477  *
1478 */
1479
1480 /*
1481   Object: Options.Events
1482   
1483   Configuration for adding mouse/touch event handlers to Nodes.
1484   
1485   Syntax:
1486   
1487   (start code js)
1488   Options.Events = {
1489     enable: false,
1490     enableForEdges: false,
1491     type: 'auto',
1492     onClick: $.empty,
1493     onRightClick: $.empty,
1494     onMouseMove: $.empty,
1495     onMouseEnter: $.empty,
1496     onMouseLeave: $.empty,
1497     onDragStart: $.empty,
1498     onDragMove: $.empty,
1499     onDragCancel: $.empty,
1500     onDragEnd: $.empty,
1501     onTouchStart: $.empty,
1502     onTouchMove: $.empty,
1503     onTouchEnd: $.empty,
1504     onTouchCancel: $.empty,
1505     onMouseWheel: $.empty
1506   };
1507   (end code)
1508   
1509   Example:
1510   
1511   (start code js)
1512   var viz = new $jit.Viz({
1513     Events: {
1514       enable: true,
1515       onClick: function(node, eventInfo, e) {
1516         viz.doSomething();
1517       },
1518       onMouseEnter: function(node, eventInfo, e) {
1519         viz.canvas.getElement().style.cursor = 'pointer';
1520       },
1521       onMouseLeave: function(node, eventInfo, e) {
1522         viz.canvas.getElement().style.cursor = '';
1523       }
1524     }
1525   });
1526   (end code)
1527   
1528   Parameters:
1529   
1530   enable - (boolean) Default's *false*. Whether to enable the Event system.
1531   enableForEdges - (boolean) Default's *false*. Whether to track events also in arcs. If *true* the same callbacks -described below- are used for nodes *and* edges. A simple duck type check for edges is to check for *node.nodeFrom*.
1532   type - (string) Default's 'auto'. Whether to attach the events onto the HTML labels (via event delegation) or to use the custom 'Native' canvas Event System of the library. 'auto' is set when you let the <Options.Label> *type* parameter decide this.
1533   onClick(node, eventInfo, e) - Triggered when a user performs a click in the canvas. *node* is the <Graph.Node> clicked or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. 
1534   onRightClick(node, eventInfo, e) - Triggered when a user performs a right click in the canvas. *node* is the <Graph.Node> right clicked or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. 
1535   onMouseMove(node, eventInfo, e) - Triggered when the user moves the mouse. *node* is the <Graph.Node> under the cursor as it's moving over the canvas or false if no node has been clicked. *e* is the grabbed event (should return the native event in a cross-browser manner).  *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas.
1536   onMouseEnter(node, eventInfo, e) - Triggered when a user moves the mouse over a node. *node* is the <Graph.Node> that the mouse just entered. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. 
1537   onMouseLeave(node, eventInfo, e) - Triggered when the user mouse-outs a node. *node* is the <Graph.Node> 'mouse-outed'. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. 
1538   onDragStart(node, eventInfo, e) - Triggered when the user mouse-downs over a node. *node* is the <Graph.Node> being pressed. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. 
1539   onDragMove(node, eventInfo, e) - Triggered when a user, after pressing the mouse button over a node, moves the mouse around. *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. 
1540   onDragEnd(node, eventInfo, e) - Triggered when a user finished dragging a node. *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. 
1541   onDragCancel(node, eventInfo, e) - Triggered when the user releases the mouse button over a <Graph.Node> that wasn't dragged (i.e. the user didn't perform any mouse movement after pressing the mouse button). *node* is the <Graph.Node> being dragged. *e* is the grabbed event (should return the native event in a cross-browser manner). *eventInfo* is an object containing useful methods like *getPos* to get the mouse position relative to the canvas. 
1542   onTouchStart(node, eventInfo, e) - Behaves just like onDragStart. 
1543   onTouchMove(node, eventInfo, e) - Behaves just like onDragMove. 
1544   onTouchEnd(node, eventInfo, e) - Behaves just like onDragEnd. 
1545   onTouchCancel(node, eventInfo, e) - Behaves just like onDragCancel.
1546   onMouseWheel(delta, e) - Triggered when the user uses the mouse scroll over the canvas. *delta* is 1 or -1 depending on the sense of the mouse scroll.
1547 */
1548
1549 Options.Events = {
1550   $extend: false,
1551   
1552   enable: false,
1553   enableForEdges: false,
1554   type: 'auto',
1555   onClick: $.empty,
1556   onRightClick: $.empty,
1557   onMouseMove: $.empty,
1558   onMouseEnter: $.empty,
1559   onMouseLeave: $.empty,
1560   onDragStart: $.empty,
1561   onDragMove: $.empty,
1562   onDragCancel: $.empty,
1563   onDragEnd: $.empty,
1564   onTouchStart: $.empty,
1565   onTouchMove: $.empty,
1566   onTouchEnd: $.empty,
1567   onMouseWheel: $.empty
1568 };
1569
1570 /*
1571  * File: Options.Navigation.js
1572  *
1573 */
1574
1575 /*
1576   Object: Options.Navigation
1577   
1578   Panning and zooming options for Graph/Tree based visualizations. These options are implemented 
1579   by all visualizations except charts (<AreaChart>, <BarChart> and <PieChart>).
1580   
1581   Syntax:
1582   
1583   (start code js)
1584
1585   Options.Navigation = {
1586     enable: false,
1587     type: 'auto',
1588     panning: false, //true, 'avoid nodes'
1589     zooming: false
1590   };
1591   
1592   (end code)
1593   
1594   Example:
1595     
1596   (start code js)
1597   var viz = new $jit.Viz({
1598     Navigation: {
1599       enable: true,
1600       panning: 'avoid nodes',
1601       zooming: 20
1602     }
1603   });
1604   (end code)
1605   
1606   Parameters:
1607   
1608   enable - (boolean) Default's *false*. Whether to enable Navigation capabilities.
1609   type - (string) Default's 'auto'. Whether to attach the navigation events onto the HTML labels (via event delegation) or to use the custom 'Native' canvas Event System of the library. When 'auto' set when you let the <Options.Label> *type* parameter decide this.
1610   panning - (boolean|string) Default's *false*. Set this property to *true* if you want to add Drag and Drop panning support to the visualization. You can also set this parameter to 'avoid nodes' to enable DnD panning but disable it if the DnD is taking place over a node. This is useful when some other events like Drag & Drop for nodes are added to <Graph.Nodes>.
1611   zooming - (boolean|number) Default's *false*. Set this property to a numeric value to turn mouse-scroll zooming on. The number will be proportional to the mouse-scroll sensitivity.
1612   
1613 */
1614
1615 Options.Navigation = {
1616   $extend: false,
1617   
1618   enable: false,
1619   type: 'auto',
1620   panning: false, //true | 'avoid nodes'
1621   zooming: false
1622 };
1623
1624 /*
1625  * File: Options.Controller.js
1626  *
1627 */
1628
1629 /*
1630   Object: Options.Controller
1631   
1632   Provides controller methods. Controller methods are callback functions that get called at different stages 
1633   of the animation, computing or plotting of the visualization.
1634   
1635   Implemented by:
1636     
1637   All visualizations except charts (<AreaChart>, <BarChart> and <PieChart>).
1638   
1639   Syntax:
1640   
1641   (start code js)
1642
1643   Options.Controller = {
1644     onBeforeCompute: $.empty,
1645     onAfterCompute:  $.empty,
1646     onCreateLabel:   $.empty,
1647     onPlaceLabel:    $.empty,
1648     onComplete:      $.empty,
1649     onBeforePlotLine:$.empty,
1650     onAfterPlotLine: $.empty,
1651     onBeforePlotNode:$.empty,
1652     onAfterPlotNode: $.empty,
1653     request:         false
1654   };
1655   
1656   (end code)
1657   
1658   Example:
1659     
1660   (start code js)
1661   var viz = new $jit.Viz({
1662     onBeforePlotNode: function(node) {
1663       if(node.selected) {
1664         node.setData('color', '#ffc');
1665       } else {
1666         node.removeData('color');
1667       }
1668     },
1669     onBeforePlotLine: function(adj) {
1670       if(adj.nodeFrom.selected && adj.nodeTo.selected) {
1671         adj.setData('color', '#ffc');
1672       } else {
1673         adj.removeData('color');
1674       }
1675     },
1676     onAfterCompute: function() {
1677       alert("computed!");
1678     }
1679   });
1680   (end code)
1681   
1682   Parameters:
1683
1684    onBeforeCompute(node) - This method is called right before performing all computations and animations. The selected <Graph.Node> is passed as parameter.
1685    onAfterCompute() - This method is triggered after all animations or computations ended.
1686    onCreateLabel(domElement, node) - This method receives a new label DIV element as first parameter, and the corresponding <Graph.Node> as second parameter. This method will only be called once for each label. This method is useful when adding events or styles to the labels used by the JIT.
1687    onPlaceLabel(domElement, node) - This method receives a label DIV element as first parameter and the corresponding <Graph.Node> as second parameter. This method is called each time a label has been placed in the visualization, for example at each step of an animation, and thus it allows you to update the labels properties, such as size or position. Note that onPlaceLabel will be triggered after updating the labels positions. That means that, for example, the left and top css properties are already updated to match the nodes positions. Width and height properties are not set however.
1688    onBeforePlotNode(node) - This method is triggered right before plotting each <Graph.Node>. This method is useful for changing a node style right before plotting it.
1689    onAfterPlotNode(node) - This method is triggered right after plotting each <Graph.Node>.
1690    onBeforePlotLine(adj) - This method is triggered right before plotting a <Graph.Adjacence>. This method is useful for adding some styles to a particular edge before being plotted.
1691    onAfterPlotLine(adj) - This method is triggered right after plotting a <Graph.Adjacence>.
1692    onBeforeRemoveNode(node) - This method is triggered right before removing each <Graph.Node>.
1693    
1694     *Used in <ST>, <TM.Base> and <Icicle> visualizations*
1695     
1696     request(nodeId, level, onComplete) - This method is used for buffering information into the visualization. When clicking on an empty node, the visualization will make a request for this node's subtrees, specifying a given level for this subtree (defined by _levelsToShow_). Once the request is completed, the onComplete callback should be called with the given result. This is useful to provide on-demand information into the visualizations withought having to load the entire information from start. The parameters used by this method are _nodeId_, which is the id of the root of the subtree to request, _level_ which is the depth of the subtree to be requested (0 would mean just the root node). _onComplete_ is an object having the callback method _onComplete.onComplete(json)_ that should be called once the json has been retrieved.  
1697  
1698  */
1699 Options.Controller = {
1700   $extend: true,
1701   
1702   onBeforeCompute:   $.empty,
1703   onAfterCompute:    $.empty,
1704   onCreateLabel:     $.empty,
1705   onPlaceLabel:      $.empty,
1706   onComplete:        $.empty,
1707   onBeforePlotLine:  $.empty,
1708   onAfterPlotLine:   $.empty,
1709   onBeforePlotNode:  $.empty,
1710   onAfterPlotNode:   $.empty,
1711   onBeforeRemoveNode:$.empty,
1712   request:         false
1713 };
1714
1715
1716 /*
1717  * File: Extras.js
1718  * 
1719  * Provides Extras such as Tips and Style Effects.
1720  * 
1721  * Description:
1722  * 
1723  * Provides the <Tips> and <NodeStyles> classes and functions.
1724  *
1725  */
1726
1727 /*
1728  * Manager for mouse events (clicking and mouse moving).
1729  * 
1730  * This class is used for registering objects implementing onClick
1731  * and onMousemove methods. These methods are called when clicking or
1732  * moving the mouse around  the Canvas.
1733  * For now, <Tips> and <NodeStyles> are classes implementing these methods.
1734  * 
1735  */
1736 var MultiExtrasInitializer = {
1737   initialize: function(className, viz) {
1738     this.viz = viz;
1739     this.canvas = viz.canvas;
1740     this.config = viz.config[className];
1741     this.nodeTypes = viz.fx.nodeTypes;
1742     var type = this.config.type;
1743     this.dom = type == 'auto'? (viz.config.Label.type != 'Native') : (type != 'Native');
1744     this.labelContainer = this.dom && viz.labels.getLabelContainer();
1745     this.isEnabled() && this.initializePost();
1746   },
1747   initializePost: $.empty,
1748   setAsProperty: $.lambda(false),
1749   isEnabled: function() {
1750     return this.config.enable;
1751   },
1752   isLabel: function(e, win, group) {
1753     e = $.event.get(e, win);
1754     var labelContainer = this.labelContainer,
1755         target = e.target || e.srcElement,
1756         related = e.relatedTarget;
1757     if(group) {
1758       return related && related == this.viz.canvas.getCtx().canvas 
1759           && !!target && this.isDescendantOf(target, labelContainer);
1760     } else {
1761       return this.isDescendantOf(target, labelContainer);
1762     }
1763   },
1764   isDescendantOf: function(elem, par) {
1765     while(elem && elem.parentNode) {
1766       if(elem.parentNode == par)
1767         return elem;
1768       elem = elem.parentNode;
1769     }
1770     return false;
1771   }
1772 };
1773
1774 var MultiEventsInterface = {
1775   onMouseUp: $.empty,
1776   onMouseDown: $.empty,
1777   onMouseMove: $.empty,
1778   onMouseOver: $.empty,
1779   onMouseOut: $.empty,
1780   onMouseWheel: $.empty,
1781   onTouchStart: $.empty,
1782   onTouchMove: $.empty,
1783   onTouchEnd: $.empty,
1784   onTouchCancel: $.empty
1785 };
1786
1787 var MouseEventsManager = new Class({
1788   initialize: function(viz) {
1789     this.viz = viz;
1790     this.canvas = viz.canvas;
1791     this.node = false;
1792     this.edge = false;
1793     this.registeredObjects = [];
1794     this.attachEvents();
1795   },
1796   
1797   attachEvents: function() {
1798     var htmlCanvas = this.canvas.getElement(), 
1799         that = this;
1800     htmlCanvas.oncontextmenu = $.lambda(false);
1801     $.addEvents(htmlCanvas, {
1802       'mouseup': function(e, win) {
1803         var event = $.event.get(e, win);
1804         that.handleEvent('MouseUp', e, win, 
1805             that.makeEventObject(e, win), 
1806             $.event.isRightClick(event));
1807       },
1808       'mousedown': function(e, win) {
1809         var event = $.event.get(e, win);
1810         that.handleEvent('MouseDown', e, win, that.makeEventObject(e, win), 
1811             $.event.isRightClick(event));
1812       },
1813       'mousemove': function(e, win) {
1814         that.handleEvent('MouseMove', e, win, that.makeEventObject(e, win));
1815       },
1816       'mouseover': function(e, win) {
1817         that.handleEvent('MouseOver', e, win, that.makeEventObject(e, win));
1818       },
1819       'mouseout': function(e, win) {
1820         that.handleEvent('MouseOut', e, win, that.makeEventObject(e, win));
1821       },
1822       'touchstart': function(e, win) {
1823         that.handleEvent('TouchStart', e, win, that.makeEventObject(e, win));
1824       },
1825       'touchmove': function(e, win) {
1826         that.handleEvent('TouchMove', e, win, that.makeEventObject(e, win));
1827       },
1828       'touchend': function(e, win) {
1829         that.handleEvent('TouchEnd', e, win, that.makeEventObject(e, win));
1830       }
1831     });
1832     //attach mousewheel event
1833     var handleMouseWheel = function(e, win) {
1834       var event = $.event.get(e, win);
1835       var wheel = $.event.getWheel(event);
1836       that.handleEvent('MouseWheel', e, win, wheel);
1837     };
1838     //TODO(nico): this is a horrible check for non-gecko browsers!
1839     if(!document.getBoxObjectFor && window.mozInnerScreenX == null) {
1840       $.addEvent(htmlCanvas, 'mousewheel', handleMouseWheel);
1841     } else {
1842       htmlCanvas.addEventListener('DOMMouseScroll', handleMouseWheel, false);
1843     }
1844   },
1845   
1846   register: function(obj) {
1847     this.registeredObjects.push(obj);
1848   },
1849   
1850   handleEvent: function() {
1851     var args = Array.prototype.slice.call(arguments),
1852         type = args.shift();
1853     for(var i=0, regs=this.registeredObjects, l=regs.length; i<l; i++) {
1854       regs[i]['on' + type].apply(regs[i], args);
1855     }
1856   },
1857   
1858   makeEventObject: function(e, win) {
1859     var that = this,
1860         graph = this.viz.graph,
1861         fx = this.viz.fx,
1862         ntypes = fx.nodeTypes,
1863         etypes = fx.edgeTypes;
1864     return {
1865       pos: false,
1866       node: false,
1867       edge: false,
1868       contains: false,
1869       getNodeCalled: false,
1870       getEdgeCalled: false,
1871       getPos: function() {
1872         //TODO(nico): check why this can't be cache anymore when using edge detection
1873         //if(this.pos) return this.pos;
1874         var canvas = that.viz.canvas,
1875             s = canvas.getSize(),
1876             p = canvas.getPos(),
1877             ox = canvas.translateOffsetX,
1878             oy = canvas.translateOffsetY,
1879             sx = canvas.scaleOffsetX,
1880             sy = canvas.scaleOffsetY,
1881             pos = $.event.getPos(e, win);
1882         this.pos = {
1883           x: (pos.x - p.x - s.width/2 - ox) * 1/sx,
1884           y: (pos.y - p.y - s.height/2 - oy) * 1/sy
1885         };
1886         return this.pos;
1887       },
1888       getNode: function() {
1889         if(this.getNodeCalled) return this.node;
1890         this.getNodeCalled = true;
1891         for(var id in graph.nodes) {
1892           var n = graph.nodes[id],
1893               geom = n && ntypes[n.getData('type')],
1894               contains = geom && geom.contains && geom.contains.call(fx, n, this.getPos());
1895           if(contains) {
1896             this.contains = contains;
1897             return that.node = this.node = n;
1898           }
1899         }
1900         return that.node = this.node = false;
1901       },
1902       getEdge: function() {
1903                 if(this.getEdgeCalled) return this.edge;
1904                 this.getEdgeCalled = true;
1905
1906                   var checkDupEdge = function(e) {
1907                         var skip = false;
1908                         for(var d in graph.dup) {
1909                                 var ee = graph.dup[d];
1910                                 if(e.nodeTo.id == ee.nodeTo.id && e.nodeFrom.id == ee.nodeFrom.id) {
1911                                         if(e.portTo == ee.portTo && e.portFrom == ee.portFrom) {
1912                                                 skip = true;
1913                                                 break; // NOTE: does this break the outer for loop?
1914                                         }
1915                                 }
1916                         }
1917                         return skip;
1918                   };
1919   
1920                 // you want to go through all the edges in this graph
1921                 for(var id in graph.edges) {
1922                         var edgeFrom = graph.edges[id];
1923
1924                         for(var edgeId in edgeFrom) {
1925                                 // proceed with contains check
1926                                 var total = edgeFrom[edgeId].length;
1927                                 if (total == 1) {
1928                                         var e = edgeFrom[edgeId][0];
1929
1930                                         if(checkDupEdge(e)) continue; // skip this edge if it is a dup
1931
1932                                         var geom = e && etypes[e.getData('type')],
1933                                                 contains = geom && geom.contains && geom.contains.call(fx, e, 0, this.getPos(), that.canvas);
1934
1935                                         if (contains) {
1936                                                 this.contains = contains;
1937                                                 return that.edge = this.edge = e;
1938                                         }
1939                                 } else {
1940                                         for(var idj in edgeFrom[edgeId]) {
1941                                                 var e = edgeFrom[edgeId][idj];
1942
1943                                                 if(checkDupEdge(e)) continue; // skip this edge if it is a dup
1944
1945                                                 var alpha = parseInt(idj,10);
1946                                                 var start = (0.5-(total/2));
1947                                                 alpha += start;
1948
1949                                                 var geom = e && etypes[e.getData('type')],
1950                                                         contains = geom && geom.contains && geom.contains.call(fx, e, alpha, this.getPos(), that.canvas);
1951                                                 if (contains) {
1952                                                         this.contains = contains;
1953                                                         return that.edge = this.edge = e;
1954                                                 }
1955                                         }
1956                                 }
1957                         }
1958                 }
1959                 return that.edge = this.edge = false;
1960
1961                 /*
1962         if(this.getEdgeCalled) return this.edge;
1963         this.getEdgeCalled = true;
1964         var hashset = {};
1965         for(var id in graph.edges) {
1966           var edgeFrom = graph.edges[id];
1967           hashset[id] = true;
1968           for(var edgeId in edgeFrom) {
1969             if(edgeId in hashset) continue;
1970             var e = edgeFrom[edgeId],
1971                 geom = e && etypes[e.getData('type')],
1972                 contains = geom && geom.contains && geom.contains.call(fx, e, this.getPos());
1973             if(contains) {
1974               this.contains = contains;
1975               return that.edge = this.edge = e;
1976             }
1977           }
1978         }
1979         return that.edge = this.edge = false;
1980                 */
1981       },
1982       getContains: function() {
1983         if(this.getNodeCalled) return this.contains;
1984         this.getNode();
1985         return this.contains;
1986       }
1987     };
1988   }
1989 });
1990
1991 /* 
1992  * Provides the initialization function for <NodeStyles> and <Tips> implemented 
1993  * by all main visualizations.
1994  *
1995  */
1996 var MultiExtras = {
1997   initializeExtras: function() {
1998     var mem = new MouseEventsManager(this), that = this;
1999     $.each(['NodeStyles', 'Tips', 'Navigation', 'Events'], function(k) {
2000       var obj = new MultiExtras.Classes[k](k, that);
2001       if(obj.isEnabled()) {
2002         mem.register(obj);
2003       }
2004       if(obj.setAsProperty()) {
2005         that[k.toLowerCase()] = obj;
2006       }
2007     });
2008   }   
2009 };
2010
2011 MultiExtras.Classes = {};
2012 /*
2013   Class: Events
2014    
2015   This class defines an Event API to be accessed by the user.
2016   The methods implemented are the ones defined in the <Options.Events> object.
2017 */
2018
2019 MultiExtras.Classes.Events = new Class({
2020   Implements: [MultiExtrasInitializer, MultiEventsInterface],
2021   
2022   initializePost: function() {
2023     this.fx = this.viz.fx;
2024     this.ntypes = this.viz.fx.nodeTypes;
2025     this.etypes = this.viz.fx.edgeTypes;
2026     
2027     this.hovered = false;
2028     this.pressed = false;
2029     this.touched = false;
2030
2031     this.touchMoved = false;
2032     this.moved = false;
2033     
2034   },
2035   
2036   setAsProperty: $.lambda(true),
2037
2038   onMouseUp: function(e, win, event, isRightClick) {
2039     var evt = $.event.get(e, win);
2040     if(!this.moved) {
2041       if(isRightClick) {
2042         this.config.onRightClick(this.hovered, event, evt);
2043       } else {
2044         this.config.onClick(this.pressed, event, evt);
2045       }
2046     }
2047     if(this.pressed) {
2048       if(this.moved) {
2049         this.config.onDragEnd(this.pressed, event, evt);
2050       } else {
2051         this.config.onDragCancel(this.pressed, event, evt);
2052       }
2053       this.pressed = this.moved = false;
2054     }
2055   },
2056
2057   onMouseOut: function(e, win, event) {
2058    //mouseout a label
2059    var evt = $.event.get(e, win), label;
2060    if(this.dom && (label = this.isLabel(e, win, true))) {
2061      this.config.onMouseLeave(this.viz.graph.getNode(label.id),
2062                               event, evt);
2063      this.hovered = false;
2064      return;
2065    }
2066    //mouseout canvas
2067    var rt = evt.relatedTarget,
2068        canvasWidget = this.canvas.getElement();
2069    while(rt && rt.parentNode) {
2070      if(canvasWidget == rt.parentNode) return;
2071      rt = rt.parentNode;
2072    }
2073    if(this.hovered) {
2074      this.config.onMouseLeave(this.hovered,
2075          event, evt);
2076      this.hovered = false;
2077    }
2078   },
2079   
2080   onMouseOver: function(e, win, event) {
2081     //mouseover a label
2082     var evt = $.event.get(e, win), label;
2083     if(this.dom && (label = this.isLabel(e, win, true))) {
2084       this.hovered = this.viz.graph.getNode(label.id);
2085       this.config.onMouseEnter(this.hovered,
2086                                event, evt);
2087     }
2088   },
2089   
2090   onMouseMove: function(e, win, event) {
2091    var label, evt = $.event.get(e, win);
2092    if(this.pressed) {
2093      this.moved = true;
2094      this.config.onDragMove(this.pressed, event, evt);
2095      return;
2096    }
2097    if(this.dom) {
2098      this.config.onMouseMove(this.hovered, event, evt);
2099    } else {
2100      if(this.hovered) { // if there is a hovered element
2101                 if(this.hovered.id == undefined) { // if this is an edge
2102                         var hn = this.hovered;
2103                         var geom = this.etypes[hn.getData('type')];
2104                         var contains = false;
2105
2106                         // find alpha and total
2107                         var list = this.viz.graph.edges[hn.nodeFrom.id][hn.nodeTo.id];
2108                         if (list != undefined || list.length != 0) {
2109                                 var total = list.length;
2110                                 for(var idj = 0; idj < total; idj++) {
2111                                         var e = list[idj];
2112
2113                                         // check if we need to skip this dup edge
2114                                         // NOTE: is this even needed, if getEdge() already fulfills this action?
2115                                         var skip = false;
2116                                         for(var d in this.viz.graph.dup) {
2117                                                 var ee = this.viz.graph.dup[d];
2118                                                 if(e.nodeTo.id == ee.nodeTo.id && e.nodeFrom.id == ee.nodeFrom.id) {
2119                                                         if(e.portTo == ee.portTo && e.portFrom == ee.portFrom) {
2120                                                                 skip = true;
2121                                                                 break;
2122                                                         }
2123                                                 }
2124                                         }
2125                                         if(skip) continue; // skip this edge if it is a dup
2126
2127                                         var alpha = parseInt(idj,10);
2128                                         var start = (0.5-(total/2));
2129                                         alpha += start;
2130
2131                                         if(list[idj].portFrom == hn.portFrom
2132                                         && list[idj].portTo == hn.portTo) {
2133                                                 contains = geom.contains.call(this.fx, hn, alpha, event.getPos(), this.canvas);
2134                                                 break;
2135                                         }
2136                                 }
2137                         }
2138
2139                         if (contains) {
2140                                 this.config.onMouseEnter(this.hovered, event, evt);
2141                                 return;
2142                         } else {
2143                                 this.config.onMouseLeave(hn, event, evt);
2144                                 this.hovered = false;
2145                         }
2146                 } else { // if this is a node
2147                    var hn = this.hovered;
2148                    var geom = hn.nodeFrom? this.etypes[hn.getData('type')] : this.ntypes[hn.getData('type')];
2149                    var contains = geom && geom.contains 
2150                          && geom.contains.call(this.fx, hn, event.getPos());
2151                    if(contains) {
2152                          this.config.onMouseMove(hn, event, evt);
2153                          return;
2154                    } else {
2155                          this.config.onMouseLeave(hn, event, evt);
2156                          this.hovered = false;
2157                    }
2158                  }
2159          }
2160
2161      if(this.hovered = event.getNode()) {
2162        this.config.onMouseEnter(this.hovered, event, evt);
2163          } else if (this.hovered = event.getEdge()) { // event for edges
2164                 this.config.onMouseEnter(this.hovered, event, evt);
2165      } else {
2166        this.config.onMouseMove(false, event, evt);
2167      }
2168    }
2169   },
2170   
2171   onMouseWheel: function(e, win, delta) {
2172     this.config.onMouseWheel(delta, $.event.get(e, win));
2173   },
2174   
2175   onMouseDown: function(e, win, event) {
2176     var evt = $.event.get(e, win), label;
2177     if(this.dom) {
2178       if(label = this.isLabel(e, win)) {
2179         this.pressed = this.viz.graph.getNode(label.id);
2180       }
2181     } else {
2182       this.pressed = event.getNode() || (this.config.enableForEdges && event.getEdge());
2183     }
2184     this.pressed && this.config.onDragStart(this.pressed, event, evt);
2185   },
2186   
2187   onTouchStart: function(e, win, event) {
2188     var evt = $.event.get(e, win), label;
2189     if(this.dom && (label = this.isLabel(e, win))) {
2190       this.touched = this.viz.graph.getNode(label.id);
2191     } else {
2192       this.touched = event.getNode() || (this.config.enableForEdges && event.getEdge());
2193     }
2194     this.touched && this.config.onTouchStart(this.touched, event, evt);
2195   },
2196   
2197   onTouchMove: function(e, win, event) {
2198     var evt = $.event.get(e, win);
2199     if(this.touched) {
2200       this.touchMoved = true;
2201       this.config.onTouchMove(this.touched, event, evt);
2202     }
2203   },
2204   
2205   onTouchEnd: function(e, win, event) {
2206     var evt = $.event.get(e, win);
2207     if(this.touched) {
2208       if(this.touchMoved) {
2209         this.config.onTouchEnd(this.touched, event, evt);
2210       } else {
2211         this.config.onTouchCancel(this.touched, event, evt);
2212       }
2213       this.touched = this.touchMoved = false;
2214     }
2215   }
2216 });
2217
2218 /*
2219    Class: Tips
2220     
2221    A class containing tip related functions. This class is used internally.
2222    
2223    Used by:
2224    
2225    <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle>
2226    
2227    See also:
2228    
2229    <Options.Tips>
2230 */
2231
2232 MultiExtras.Classes.Tips = new Class({
2233   Implements: [MultiExtrasInitializer, MultiEventsInterface],
2234   
2235   initializePost: function() {
2236     //add DOM tooltip
2237     if(document.body) {
2238       var tip = $('_tooltip') || document.createElement('div');
2239       tip.id = '_tooltip';
2240       tip.className = 'tip';
2241       $.extend(tip.style, {
2242         position: 'absolute',
2243         display: 'none',
2244         zIndex: 13000
2245       });
2246       document.body.appendChild(tip);
2247       this.tip = tip;
2248       this.node = false;
2249     }
2250   },
2251   
2252   setAsProperty: $.lambda(true),
2253   
2254   onMouseOut: function(e, win) {
2255     //mouseout a label
2256     var evt = $.event.get(e, win);
2257     if(this.dom && this.isLabel(e, win, true)) {
2258       this.hide(true);
2259       return;
2260     }
2261     //mouseout canvas
2262     var rt = e.relatedTarget,
2263         canvasWidget = this.canvas.getElement();
2264     while(rt && rt.parentNode) {
2265       if(canvasWidget == rt.parentNode) return;
2266       rt = rt.parentNode;
2267     }
2268     this.hide(false);
2269   },
2270   
2271   onMouseOver: function(e, win) {
2272     //mouseover a label
2273     var label;
2274     if(this.dom && (label = this.isLabel(e, win, false))) {
2275       this.node = this.viz.graph.getNode(label.id);
2276       this.config.onShow(this.tip, this.node, label);
2277     }
2278   },
2279   
2280   onMouseMove: function(e, win, opt) {
2281     if(this.dom && this.isLabel(e, win)) {
2282       this.setTooltipPosition($.event.getPos(e, win));
2283     }
2284     if(!this.dom) {
2285       var node = opt.getNode();
2286           var edge = opt.getEdge();
2287       if(!node && !edge) { // additionally for edge
2288         this.hide(true);
2289         return;
2290       }
2291       /*if(this.config.force || !this.node || this.node.id != node.id) {
2292         this.node = node;
2293         this.config.onShow(this.tip, node, opt.getContains());
2294       }*/
2295                 if (node != false) {    
2296                         if (this.config.force || !this.node || this.node.id != node.id) {
2297                                 this.node = node;
2298                                 this.edge = false;
2299                                 this.config.onShow(this.tip, node, opt.getContains());
2300                         }
2301                 } else if (edge != false) {
2302                         this.edge = edge;
2303                         this.node = false;
2304                         this.config.onShow(this.tip, edge, opt.getContains());
2305                 }
2306       this.setTooltipPosition($.event.getPos(e, win));
2307     }
2308   },
2309   
2310   setTooltipPosition: function(pos) {
2311     var tip = this.tip, 
2312         style = tip.style, 
2313         cont = this.config;
2314     style.display = '';
2315     //get viewport dimensions
2316     var elem = document.compatMode === "CSS1Compat" && document.documentElement ||
2317                document.body ||
2318                document.documentElement;
2319     var view = {
2320       'width': elem.clientWidth,
2321       'height': elem.clientHeight,
2322       'x': window.pageXOffset ||
2323            document.documentElement && document.documentElement.scrollLeft ||
2324            document.body && document.body.scrollLeft ||
2325            0,
2326       'y': window.pageYOffset ||
2327            document.documentElement && document.documentElement.scrollTop ||
2328            document.body && document.body.scrollTop ||
2329            0
2330     };
2331     //get tooltip dimensions
2332     var obj = {
2333       'width': tip.offsetWidth,
2334       'height': tip.offsetHeight  
2335     };
2336     //set tooltip position
2337     var x = cont.offsetX, y = cont.offsetY;
2338     style.top = ((pos.y + obj.height + y > view.height + view.y)?
2339         (pos.y - obj.height - y) : pos.y + y) + 'px';
2340     style.left = ((pos.x + obj.width + x > view.width + view.x)?
2341         (pos.x - obj.width - x) : pos.x + x) + 'px';
2342   },
2343   
2344   hide: function(triggerCallback) {
2345     this.tip.style.display = 'none';
2346     triggerCallback && this.config.onHide();
2347   }
2348 });
2349
2350 /*
2351   Class: NodeStyles
2352    
2353   Change node styles when clicking or hovering a node. This class is used internally.
2354   
2355   Used by:
2356   
2357   <ST>, <Sunburst>, <Hypertree>, <RGraph>, <TM>, <ForceDirected>, <Icicle>
2358   
2359   See also:
2360   
2361   <Options.NodeStyles>
2362 */
2363 MultiExtras.Classes.NodeStyles = new Class({
2364   Implements: [MultiExtrasInitializer, MultiEventsInterface],
2365   
2366   initializePost: function() {
2367     this.fx = this.viz.fx;
2368     this.types = this.viz.fx.nodeTypes;
2369     this.nStyles = this.config;
2370     this.nodeStylesOnHover = this.nStyles.stylesHover;
2371     this.nodeStylesOnClick = this.nStyles.stylesClick;
2372     this.hoveredNode = false;
2373     this.fx.nodeFxAnimation = new Animation();
2374     
2375     this.down = false;
2376     this.move = false;
2377   },
2378   
2379   onMouseOut: function(e, win) {
2380     this.down = this.move = false;
2381     if(!this.hoveredNode) return;
2382     //mouseout a label
2383     if(this.dom && this.isLabel(e, win, true)) {
2384       this.toggleStylesOnHover(this.hoveredNode, false);
2385     }
2386     //mouseout canvas
2387     var rt = e.relatedTarget,
2388         canvasWidget = this.canvas.getElement();
2389     while(rt && rt.parentNode) {
2390       if(canvasWidget == rt.parentNode) return;
2391       rt = rt.parentNode;
2392     }
2393     this.toggleStylesOnHover(this.hoveredNode, false);
2394     this.hoveredNode = false;
2395   },
2396   
2397   onMouseOver: function(e, win) {
2398     //mouseover a label
2399     var label;
2400     if(this.dom && (label = this.isLabel(e, win, true))) {
2401       var node = this.viz.graph.getNode(label.id);
2402       if(node.selected) return;
2403       this.hoveredNode = node;
2404       this.toggleStylesOnHover(this.hoveredNode, true);
2405     }
2406   },
2407   
2408   onMouseDown: function(e, win, event, isRightClick) {
2409     if(isRightClick) return;
2410     var label;
2411     if(this.dom && (label = this.isLabel(e, win))) {
2412       this.down = this.viz.graph.getNode(label.id);
2413     } else if(!this.dom) {
2414       this.down = event.getNode();
2415     }
2416     this.move = false;
2417   },
2418   
2419   onMouseUp: function(e, win, event, isRightClick) {
2420     if(isRightClick) return;
2421     if(!this.move) {
2422       this.onClick(event.getNode());
2423     }
2424     this.down = this.move = false;
2425   },
2426   
2427   getRestoredStyles: function(node, type) {
2428     var restoredStyles = {}, 
2429         nStyles = this['nodeStylesOn' + type];
2430     for(var prop in nStyles) {
2431       restoredStyles[prop] = node.styles['$' + prop];
2432     }
2433     return restoredStyles;
2434   },
2435   
2436   toggleStylesOnHover: function(node, set) {
2437     if(this.nodeStylesOnHover) {
2438       this.toggleStylesOn('Hover', node, set);
2439     }
2440   },
2441
2442   toggleStylesOnClick: function(node, set) {
2443     if(this.nodeStylesOnClick) {
2444       this.toggleStylesOn('Click', node, set);
2445     }
2446   },
2447   
2448   toggleStylesOn: function(type, node, set) {
2449     var viz = this.viz;
2450     var nStyles = this.nStyles;
2451     if(set) {
2452       var that = this;
2453       if(!node.styles) {
2454         node.styles = $.merge(node.data, {});
2455       }
2456       for(var s in this['nodeStylesOn' + type]) {
2457         var $s = '$' + s;
2458         if(!($s in node.styles)) {
2459             node.styles[$s] = node.getData(s); 
2460         }
2461       }
2462       viz.fx.nodeFx($.extend({
2463         'elements': {
2464           'id': node.id,
2465           'properties': that['nodeStylesOn' + type]
2466          },
2467          transition: Trans.Quart.easeOut,
2468          duration:300,
2469          fps:40
2470       }, this.config));
2471     } else {
2472       var restoredStyles = this.getRestoredStyles(node, type);
2473       viz.fx.nodeFx($.extend({
2474         'elements': {
2475           'id': node.id,
2476           'properties': restoredStyles
2477          },
2478          transition: Trans.Quart.easeOut,
2479          duration:300,
2480          fps:40
2481       }, this.config));
2482     }
2483   },
2484
2485   onClick: function(node) {
2486     if(!node) return;
2487     var nStyles = this.nodeStylesOnClick;
2488     if(!nStyles) return;
2489     //if the node is selected then unselect it
2490     if(node.selected) {
2491       this.toggleStylesOnClick(node, false);
2492       delete node.selected;
2493     } else {
2494       //unselect all selected nodes...
2495       this.viz.graph.eachNode(function(n) {
2496         if(n.selected) {
2497           for(var s in nStyles) {
2498             n.setData(s, n.styles['$' + s], 'end');
2499           }
2500           delete n.selected;
2501         }
2502       });
2503       //select clicked node
2504       this.toggleStylesOnClick(node, true);
2505       node.selected = true;
2506       delete node.hovered;
2507       this.hoveredNode = false;
2508     }
2509   },
2510   
2511   onMouseMove: function(e, win, event) {
2512     //if mouse button is down and moving set move=true
2513     if(this.down) this.move = true;
2514     //already handled by mouseover/out
2515     if(this.dom && this.isLabel(e, win)) return;
2516     var nStyles = this.nodeStylesOnHover;
2517     if(!nStyles) return;
2518     
2519     if(!this.dom) {
2520       if(this.hoveredNode) {
2521         var geom = this.types[this.hoveredNode.getData('type')];
2522         var contains = geom && geom.contains && geom.contains.call(this.fx, 
2523             this.hoveredNode, event.getPos());
2524         if(contains) return;
2525       }
2526       var node = event.getNode();
2527       //if no node is being hovered then just exit
2528       if(!this.hoveredNode && !node) return;
2529       //if the node is hovered then exit
2530       if(node.hovered) return;
2531       //select hovered node
2532       if(node && !node.selected) {
2533         //check if an animation is running and exit it
2534         this.fx.nodeFxAnimation.stopTimer();
2535         //unselect all hovered nodes...
2536         this.viz.graph.eachNode(function(n) {
2537           if(n.hovered && !n.selected) {
2538             for(var s in nStyles) {
2539               n.setData(s, n.styles['$' + s], 'end');
2540             }
2541             delete n.hovered;
2542           }
2543         });
2544         //select hovered node
2545         node.hovered = true;
2546         this.hoveredNode = node;
2547         this.toggleStylesOnHover(node, true);
2548       } else if(this.hoveredNode && !this.hoveredNode.selected) {
2549         //check if an animation is running and exit it
2550         this.fx.nodeFxAnimation.stopTimer();
2551         //unselect hovered node
2552         this.toggleStylesOnHover(this.hoveredNode, false);
2553         delete this.hoveredNode.hovered;
2554         this.hoveredNode = false;
2555       }
2556     }
2557   }
2558 });
2559
2560 MultiExtras.Classes.Navigation = new Class({
2561   Implements: [MultiExtrasInitializer, MultiEventsInterface],
2562   
2563   initializePost: function() {
2564     this.pos = false;
2565     this.pressed = false;
2566   },
2567   
2568   onMouseWheel: function(e, win, scroll) {
2569     if(!this.config.zooming) return;
2570     $.event.stop($.event.get(e, win));
2571     var val = this.config.zooming / 1000,
2572         ans = 1 + scroll * val;
2573     this.canvas.scale(ans, ans);
2574   },
2575   
2576   onMouseDown: function(e, win, eventInfo) {
2577     if(!this.config.panning) return;
2578     e.preventDefault ? e.preventDefault() : e.returnValue = false;
2579     $.addClass(this.canvas.getElement(), 'grabbing');
2580     if(this.config.panning == 'avoid nodes' && (this.dom? this.isLabel(e, win) : eventInfo.getNode())) return;
2581     this.pressed = true;
2582     this.pos = eventInfo.getPos();
2583     var canvas = this.canvas,
2584         ox = canvas.translateOffsetX,
2585         oy = canvas.translateOffsetY,
2586         sx = canvas.scaleOffsetX,
2587         sy = canvas.scaleOffsetY;
2588     this.pos.x *= sx;
2589     this.pos.x += ox;
2590     this.pos.y *= sy;
2591     this.pos.y += oy;
2592   },
2593   
2594   onMouseMove: function(e, win, eventInfo) {
2595     if(!this.config.panning) return;
2596     if(!this.pressed) return;
2597     if(this.config.panning == 'avoid nodes' && (this.dom? this.isLabel(e, win) : eventInfo.getNode())) return;
2598     var thispos = this.pos, 
2599         currentPos = eventInfo.getPos(),
2600         canvas = this.canvas,
2601         ox = canvas.translateOffsetX,
2602         oy = canvas.translateOffsetY,
2603         sx = canvas.scaleOffsetX,
2604         sy = canvas.scaleOffsetY;
2605     currentPos.x *= sx;
2606     currentPos.y *= sy;
2607     currentPos.x += ox;
2608     currentPos.y += oy;
2609     var x = currentPos.x - thispos.x,
2610         y = currentPos.y - thispos.y;
2611     this.pos = currentPos;
2612     this.canvas.translate(x * 1/sx, y * 1/sy);
2613   },
2614   
2615   onMouseUp: function(e, win, eventInfo, isRightClick) {
2616     if(!this.config.panning) return;
2617     $.removeClass(this.canvas.getElement(), 'grabbing');
2618     this.pressed = false;
2619   }
2620 });
2621
2622
2623 /*
2624  * File: Canvas.js
2625  *
2626  */
2627
2628 /*
2629  Class: Canvas
2630  
2631         A canvas widget used by all visualizations. The canvas object can be accessed by doing *viz.canvas*. If you want to 
2632         know more about <Canvas> options take a look at <Options.Canvas>.
2633  
2634  A canvas widget is a set of DOM elements that wrap the native canvas DOM Element providing a consistent API and behavior 
2635  across all browsers. It can also include Elements to add DOM (SVG or HTML) label support to all visualizations.
2636  
2637  Example:
2638  
2639  Suppose we have this HTML
2640  
2641  (start code xml)
2642         <div id="infovis"></div>
2643  (end code)
2644  
2645  Now we create a new Visualization
2646  
2647  (start code js)
2648         var viz = new $jit.Viz({
2649                 //Where to inject the canvas. Any div container will do.
2650                 'injectInto':'infovis',
2651                  //width and height for canvas. 
2652                  //Default's to the container offsetWidth and Height.
2653                  'width': 900,
2654                  'height':500
2655          });
2656  (end code)
2657
2658  The generated HTML will look like this
2659  
2660  (start code xml)
2661  <div id="infovis">
2662         <div id="infovis-canvaswidget" style="position:relative;">
2663         <canvas id="infovis-canvas" width=900 height=500
2664         style="position:absolute; top:0; left:0; width:900px; height:500px;" />
2665         <div id="infovis-label"
2666         style="overflow:visible; position:absolute; top:0; left:0; width:900px; height:0px">
2667         </div>
2668         </div>
2669  </div>
2670  (end code)
2671  
2672  As you can see, the generated HTML consists of a canvas DOM Element of id *infovis-canvas* and a div label container
2673  of id *infovis-label*, wrapped in a main div container of id *infovis-canvaswidget*.
2674  */
2675
2676 var Canvas;
2677 (function() {
2678   //check for native canvas support
2679   var canvasType = typeof HTMLCanvasElement,
2680       supportsCanvas = (canvasType == 'object' || canvasType == 'function');
2681   //create element function
2682   function $E(tag, props) {
2683     var elem = document.createElement(tag);
2684     for(var p in props) {
2685       if(typeof props[p] == "object") {
2686         $.extend(elem[p], props[p]);
2687       } else {
2688         elem[p] = props[p];
2689       }
2690     }
2691     if (tag == "canvas" && !supportsCanvas && G_vmlCanvasManager) {
2692       elem = G_vmlCanvasManager.initElement(document.body.appendChild(elem));
2693     }
2694     return elem;
2695   }
2696   //canvas widget which we will call just Canvas
2697   $jit.Canvas = Canvas = new Class({
2698     canvases: [],
2699     pos: false,
2700     element: false,
2701     labelContainer: false,
2702     translateOffsetX: 0,
2703     translateOffsetY: 0,
2704     scaleOffsetX: 1,
2705     scaleOffsetY: 1,
2706     
2707     initialize: function(viz, opt) {
2708       this.viz = viz;
2709       this.opt = this.config = opt;
2710       var id = $.type(opt.injectInto) == 'string'? 
2711           opt.injectInto:opt.injectInto.id,
2712           type = opt.type,
2713           idLabel = id + "-label", 
2714           wrapper = $(id),
2715           width = opt.width || wrapper.offsetWidth,
2716           height = opt.height || wrapper.offsetHeight;
2717       this.id = id;
2718       //canvas options
2719       var canvasOptions = {
2720         injectInto: id,
2721         width: width,
2722         height: height
2723       };
2724       //create main wrapper
2725       this.element = $E('div', {
2726         'id': id + '-canvaswidget',
2727         'style': {
2728           'position': 'relative',
2729           'width': width + 'px',
2730           'height': height + 'px'
2731         }
2732       });
2733       //create label container
2734       this.labelContainer = this.createLabelContainer(opt.Label.type, 
2735           idLabel, canvasOptions);
2736       //create primary canvas
2737       this.canvases.push(new Canvas.Base[type]({
2738         config: $.extend({idSuffix: '-canvas'}, canvasOptions),
2739         plot: function(base) {
2740           viz.fx.plot();
2741         },
2742         resize: function() {
2743           viz.refresh();
2744         }
2745       }));
2746       //create secondary canvas
2747       var back = opt.background;
2748       if(back) {
2749         var backCanvas = new Canvas.Background[back.type](viz, $.extend(back, canvasOptions));
2750         this.canvases.push(new Canvas.Base[type](backCanvas));
2751       }
2752       //insert canvases
2753       var len = this.canvases.length;
2754       while(len--) {
2755         this.element.appendChild(this.canvases[len].canvas);
2756         if(len > 0) {
2757           this.canvases[len].plot();
2758         }
2759       }
2760       this.element.appendChild(this.labelContainer);
2761       wrapper.appendChild(this.element);
2762       //Update canvas position when the page is scrolled.
2763       var timer = null, that = this;
2764       $.addEvent(window, 'scroll', function() {
2765         clearTimeout(timer);
2766         timer = setTimeout(function() {
2767           that.getPos(true); //update canvas position
2768         }, 500);
2769       });
2770     },
2771     /*
2772       Method: getCtx
2773       
2774       Returns the main canvas context object
2775       
2776       Example:
2777       
2778       (start code js)
2779        var ctx = canvas.getCtx();
2780        //Now I can use the native canvas context
2781        //and for example change some canvas styles
2782        ctx.globalAlpha = 1;
2783       (end code)
2784     */
2785     getCtx: function(i) {
2786       return this.canvases[i || 0].getCtx();
2787     },
2788     /*
2789       Method: getConfig
2790       
2791       Returns the current Configuration for this Canvas Widget.
2792       
2793       Example:
2794       
2795       (start code js)
2796        var config = canvas.getConfig();
2797       (end code)
2798     */
2799     getConfig: function() {
2800       return this.opt;
2801     },
2802     /*
2803       Method: getElement
2804
2805       Returns the main Canvas DOM wrapper
2806       
2807       Example:
2808       
2809       (start code js)
2810        var wrapper = canvas.getElement();
2811        //Returns <div id="infovis-canvaswidget" ... >...</div> as element
2812       (end code)
2813     */
2814     getElement: function() {
2815       return this.element;
2816     },
2817     /*
2818       Method: getSize
2819       
2820       Returns canvas dimensions.
2821       
2822       Returns:
2823       
2824       An object with *width* and *height* properties.
2825       
2826       Example:
2827       (start code js)
2828       canvas.getSize(); //returns { width: 900, height: 500 }
2829       (end code)
2830     */
2831     getSize: function(i) {
2832       return this.canvases[i || 0].getSize();
2833     },
2834     /*
2835       Method: resize
2836       
2837       Resizes the canvas.
2838       
2839       Parameters:
2840       
2841       width - New canvas width.
2842       height - New canvas height.
2843       
2844       Example:
2845       
2846       (start code js)
2847        canvas.resize(width, height);
2848       (end code)
2849     
2850     */
2851     resize: function(width, height) {
2852       this.getPos(true);
2853       this.translateOffsetX = this.translateOffsetY = 0;
2854       this.scaleOffsetX = this.scaleOffsetY = 1;
2855       for(var i=0, l=this.canvases.length; i<l; i++) {
2856         this.canvases[i].resize(width, height);
2857       }
2858       var style = this.element.style;
2859       style.width = width + 'px';
2860       style.height = height + 'px';
2861       if(this.labelContainer)
2862         this.labelContainer.style.width = width + 'px';
2863     },
2864     /*
2865       Method: translate
2866       
2867       Applies a translation to the canvas.
2868       
2869       Parameters:
2870       
2871       x - (number) x offset.
2872       y - (number) y offset.
2873       disablePlot - (boolean) Default's *false*. Set this to *true* if you don't want to refresh the visualization.
2874       
2875       Example:
2876       
2877       (start code js)
2878        canvas.translate(30, 30);
2879       (end code)
2880     
2881     */
2882     translate: function(x, y, disablePlot) {
2883       this.translateOffsetX += x*this.scaleOffsetX;
2884       this.translateOffsetY += y*this.scaleOffsetY;
2885       for(var i=0, l=this.canvases.length; i<l; i++) {
2886         this.canvases[i].translate(x, y, disablePlot);
2887       }
2888     },
2889     /*
2890       Method: scale
2891       
2892       Scales the canvas.
2893       
2894       Parameters:
2895       
2896       x - (number) scale value.
2897       y - (number) scale value.
2898       disablePlot - (boolean) Default's *false*. Set this to *true* if you don't want to refresh the visualization.
2899       
2900       Example:
2901       
2902       (start code js)
2903        canvas.scale(0.5, 0.5);
2904       (end code)
2905     
2906     */
2907     scale: function(x, y, disablePlot) {
2908       var px = this.scaleOffsetX * x,
2909           py = this.scaleOffsetY * y;
2910       var dx = this.translateOffsetX * (x -1) / px,
2911           dy = this.translateOffsetY * (y -1) / py;
2912       this.scaleOffsetX = px;
2913       this.scaleOffsetY = py;
2914       for(var i=0, l=this.canvases.length; i<l; i++) {
2915         this.canvases[i].scale(x, y, true);
2916       }
2917       this.translate(dx, dy, false);
2918     },
2919     /*
2920       Method: getZoom
2921
2922       Returns canvas zooming factors. *1* means initial zoom.
2923
2924       Returns:
2925
2926       An object with *x* and *y* properties.
2927     */
2928     getZoom: function() {
2929       return new Complex(this.scaleOffsetX, this.scaleOffsetY);
2930     },
2931     /*
2932       Method: setZoom
2933
2934       Sets the zoom to given factors. *1* means initial zoom.
2935
2936       Parameters:
2937
2938       x - (number) zooming factor
2939       y - (number) zooming factor
2940       disablePlot - (boolean) Default's *false*. Set this to *true* if you don't want to refresh the visualization.
2941
2942       Example:
2943       (start code js)
2944       canvas.setZoom(2, 2); //sets 2x zoom
2945       (end code)
2946     */
2947     setZoom: function(x, y, disablePlot) {
2948       var cur = this.getZoom(),
2949           px = x / cur.x,
2950           py = y / cur.y;
2951       this.scale(px, py, disablePlot);
2952     },
2953     /*
2954       Method: getPos
2955       
2956       Returns the canvas position as an *x, y* object.
2957       
2958       Parameters:
2959       
2960       force - (boolean) Default's *false*. Set this to *true* if you want to recalculate the position without using any cache information.
2961       
2962       Returns:
2963       
2964       An object with *x* and *y* properties.
2965       
2966       Example:
2967       (start code js)
2968       canvas.getPos(true); //returns { x: 900, y: 500 }
2969       (end code)
2970     */
2971     getPos: function(force){
2972       if(force || !this.pos) {
2973         return this.pos = $.getPos(this.getElement());
2974       }
2975       return this.pos;
2976     },
2977     /*
2978        Method: clear
2979        
2980        Clears the canvas.
2981     */
2982     clear: function(i){
2983       this.canvases[i||0].clear();
2984     },
2985     
2986     path: function(type, action){
2987       var ctx = this.canvases[0].getCtx();
2988       ctx.beginPath();
2989       action(ctx);
2990       ctx[type]();
2991       ctx.closePath();
2992     },
2993     
2994     createLabelContainer: function(type, idLabel, dim) {
2995       var NS = 'http://www.w3.org/2000/svg';
2996       if(type == 'HTML' || type == 'Native') {
2997         return $E('div', {
2998           'id': idLabel,
2999           'style': {
3000             'overflow': 'visible',
3001             'position': 'absolute',
3002             'top': 0,
3003             'left': 0,
3004             'width': dim.width + 'px',
3005             'height': 0
3006           }
3007         });
3008       } else if(type == 'SVG') {
3009         var svgContainer = document.createElementNS(NS, 'svg:svg');
3010         svgContainer.setAttribute("width", dim.width);
3011         svgContainer.setAttribute('height', dim.height);
3012         var style = svgContainer.style;
3013         style.position = 'absolute';
3014         style.left = style.top = '0px';
3015         var labelContainer = document.createElementNS(NS, 'svg:g');
3016         labelContainer.setAttribute('width', dim.width);
3017         labelContainer.setAttribute('height', dim.height);
3018         labelContainer.setAttribute('x', 0);
3019         labelContainer.setAttribute('y', 0);
3020         labelContainer.setAttribute('id', idLabel);
3021         svgContainer.appendChild(labelContainer);
3022         return svgContainer;
3023       }
3024     }
3025   });
3026   //base canvas wrapper
3027   Canvas.Base = {};
3028   Canvas.Base['2D'] = new Class({
3029     translateOffsetX: 0,
3030     translateOffsetY: 0,
3031     scaleOffsetX: 1,
3032     scaleOffsetY: 1,
3033
3034     initialize: function(viz) {
3035       this.viz = viz;
3036       this.opt = viz.config;
3037       this.size = false;
3038       this.createCanvas();
3039       this.translateToCenter();
3040     },
3041     createCanvas: function() {
3042       var opt = this.opt,
3043           width = opt.width,
3044           height = opt.height;
3045       this.canvas = $E('canvas', {
3046         'id': opt.injectInto + opt.idSuffix,
3047         'width': width,
3048         'height': height,
3049         'style': {
3050           'position': 'absolute',
3051           'top': 0,
3052           'left': 0,
3053           'width': width + 'px',
3054           'height': height + 'px'
3055         }
3056       });
3057     },
3058     getCtx: function() {
3059       if(!this.ctx) 
3060         return this.ctx = this.canvas.getContext('2d');
3061       return this.ctx;
3062     },
3063     getSize: function() {
3064       if(this.size) return this.size;
3065       var canvas = this.canvas;
3066       return this.size = {
3067         width: canvas.width,
3068         height: canvas.height
3069       };
3070     },
3071     translateToCenter: function(ps) {
3072       var size = this.getSize(),
3073           width = ps? (size.width - ps.width - this.translateOffsetX*2) : size.width;
3074           height = ps? (size.height - ps.height - this.translateOffsetY*2) : size.height;
3075       var ctx = this.getCtx();
3076       ps && ctx.scale(1/this.scaleOffsetX, 1/this.scaleOffsetY);
3077       ctx.translate(width/2, height/2);
3078     },
3079     resize: function(width, height) {
3080       var size = this.getSize(),
3081           canvas = this.canvas,
3082           styles = canvas.style;
3083       this.size = false;
3084       canvas.width = width;
3085       canvas.height = height;
3086       styles.width = width + "px";
3087       styles.height = height + "px";
3088       //small ExCanvas fix
3089       if(!supportsCanvas) {
3090         this.translateToCenter(size);
3091       } else {
3092         this.translateToCenter();
3093       }
3094       this.translateOffsetX =
3095         this.translateOffsetY = 0;
3096       this.scaleOffsetX = 
3097         this.scaleOffsetY = 1;
3098       this.clear();
3099       this.viz.resize(width, height, this);
3100     },
3101     translate: function(x, y, disablePlot) {
3102       var sx = this.scaleOffsetX,
3103           sy = this.scaleOffsetY;
3104       this.translateOffsetX += x*sx;
3105       this.translateOffsetY += y*sy;
3106       this.getCtx().translate(x, y);
3107       !disablePlot && this.plot();
3108     },
3109     scale: function(x, y, disablePlot) {
3110       this.scaleOffsetX *= x;
3111       this.scaleOffsetY *= y;
3112       this.getCtx().scale(x, y);
3113       !disablePlot && this.plot();
3114     },
3115     clear: function(){
3116       var size = this.getSize(),
3117           ox = this.translateOffsetX,
3118           oy = this.translateOffsetY,
3119           sx = this.scaleOffsetX,
3120           sy = this.scaleOffsetY;
3121       this.getCtx().clearRect((-size.width / 2 - ox) * 1/sx, 
3122                               (-size.height / 2 - oy) * 1/sy, 
3123                               size.width * 1/sx, size.height * 1/sy);
3124     },
3125     plot: function() {
3126       this.clear();
3127       this.viz.plot(this);
3128     }
3129   });
3130   //background canvases
3131   //TODO(nico): document this!
3132   Canvas.Background = {};
3133   Canvas.Background.Circles = new Class({
3134     initialize: function(viz, options) {
3135       this.viz = viz;
3136       this.config = $.merge({
3137         idSuffix: '-bkcanvas',
3138         levelDistance: 100,
3139         numberOfCircles: 6,
3140         CanvasStyles: {},
3141         offset: 0
3142       }, options);
3143     },
3144     resize: function(width, height, base) {
3145       this.plot(base);
3146     },
3147     plot: function(base) {
3148       var canvas = base.canvas,
3149           ctx = base.getCtx(),
3150           conf = this.config,
3151           styles = conf.CanvasStyles;
3152       //set canvas styles
3153       for(var s in styles) ctx[s] = styles[s];
3154       var n = conf.numberOfCircles,
3155           rho = conf.levelDistance;
3156       for(var i=1; i<=n; i++) {
3157         ctx.beginPath();
3158         ctx.arc(0, 0, rho * i, 0, 2 * Math.PI, false);
3159         ctx.stroke();
3160         ctx.closePath();
3161       }
3162       //TODO(nico): print labels too!
3163     }
3164   });
3165 })();
3166
3167
3168 /*
3169  * File: Polar.js
3170  * 
3171  * Defines the <Polar> class.
3172  *
3173  * Description:
3174  *
3175  * The <Polar> class, just like the <Complex> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
3176  *
3177  * See also:
3178  *
3179  * <http://en.wikipedia.org/wiki/Polar_coordinates>
3180  *
3181 */
3182
3183 /*
3184    Class: Polar
3185
3186    A multi purpose polar representation.
3187
3188    Description:
3189  
3190    The <Polar> class, just like the <Complex> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
3191  
3192    See also:
3193  
3194    <http://en.wikipedia.org/wiki/Polar_coordinates>
3195  
3196    Parameters:
3197
3198       theta - An angle.
3199       rho - The norm.
3200 */
3201
3202 var Polar = function(theta, rho) {
3203   this.theta = theta || 0;
3204   this.rho = rho || 0;
3205 };
3206
3207 $jit.Polar = Polar;
3208
3209 Polar.prototype = {
3210     /*
3211        Method: getc
3212     
3213        Returns a complex number.
3214     
3215        Parameters:
3216
3217        simple - _optional_ If *true*, this method will return only an object holding x and y properties and not a <Complex> instance. Default's *false*.
3218
3219       Returns:
3220     
3221           A complex number.
3222     */
3223     getc: function(simple) {
3224         return this.toComplex(simple);
3225     },
3226
3227     /*
3228        Method: getp
3229     
3230        Returns a <Polar> representation.
3231     
3232        Returns:
3233     
3234           A variable in polar coordinates.
3235     */
3236     getp: function() {
3237         return this;
3238     },
3239
3240
3241     /*
3242        Method: set
3243     
3244        Sets a number.
3245
3246        Parameters:
3247
3248        v - A <Complex> or <Polar> instance.
3249     
3250     */
3251     set: function(v) {
3252         v = v.getp();
3253         this.theta = v.theta; this.rho = v.rho;
3254     },
3255
3256     /*
3257        Method: setc
3258     
3259        Sets a <Complex> number.
3260
3261        Parameters:
3262
3263        x - A <Complex> number real part.
3264        y - A <Complex> number imaginary part.
3265     
3266     */
3267     setc: function(x, y) {
3268         this.rho = Math.sqrt(x * x + y * y);
3269         this.theta = Math.atan2(y, x);
3270         if(this.theta < 0) this.theta += Math.PI * 2;
3271     },
3272
3273     /*
3274        Method: setp
3275     
3276        Sets a polar number.
3277
3278        Parameters:
3279
3280        theta - A <Polar> number angle property.
3281        rho - A <Polar> number rho property.
3282     
3283     */
3284     setp: function(theta, rho) {
3285         this.theta = theta; 
3286         this.rho = rho;
3287     },
3288
3289     /*
3290        Method: clone
3291     
3292        Returns a copy of the current object.
3293     
3294        Returns:
3295     
3296           A copy of the real object.
3297     */
3298     clone: function() {
3299         return new Polar(this.theta, this.rho);
3300     },
3301
3302     /*
3303        Method: toComplex
3304     
3305         Translates from polar to cartesian coordinates and returns a new <Complex> instance.
3306     
3307         Parameters:
3308
3309         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*.
3310  
3311         Returns:
3312     
3313           A new <Complex> instance.
3314     */
3315     toComplex: function(simple) {
3316         var x = Math.cos(this.theta) * this.rho;
3317         var y = Math.sin(this.theta) * this.rho;
3318         if(simple) return { 'x': x, 'y': y};
3319         return new Complex(x, y);
3320     },
3321
3322     /*
3323        Method: add
3324     
3325         Adds two <Polar> instances.
3326     
3327        Parameters:
3328
3329        polar - A <Polar> number.
3330
3331        Returns:
3332     
3333           A new Polar instance.
3334     */
3335     add: function(polar) {
3336         return new Polar(this.theta + polar.theta, this.rho + polar.rho);
3337     },
3338     
3339     /*
3340        Method: scale
3341     
3342         Scales a polar norm.
3343     
3344         Parameters:
3345
3346         number - A scale factor.
3347         
3348         Returns:
3349     
3350           A new Polar instance.
3351     */
3352     scale: function(number) {
3353         return new Polar(this.theta, this.rho * number);
3354     },
3355     
3356     /*
3357        Method: equals
3358     
3359        Comparison method.
3360
3361        Returns *true* if the theta and rho properties are equal.
3362
3363        Parameters:
3364
3365        c - A <Polar> number.
3366
3367        Returns:
3368
3369        *true* if the theta and rho parameters for these objects are equal. *false* otherwise.
3370     */
3371     equals: function(c) {
3372         return this.theta == c.theta && this.rho == c.rho;
3373     },
3374     
3375     /*
3376        Method: $add
3377     
3378         Adds two <Polar> instances affecting the current object.
3379     
3380        Paramters:
3381
3382        polar - A <Polar> instance.
3383
3384        Returns:
3385     
3386           The changed object.
3387     */
3388     $add: function(polar) {
3389         this.theta = this.theta + polar.theta; this.rho += polar.rho;
3390         return this;
3391     },
3392
3393     /*
3394        Method: $madd
3395     
3396         Adds two <Polar> instances affecting the current object. The resulting theta angle is modulo 2pi.
3397     
3398        Parameters:
3399
3400        polar - A <Polar> instance.
3401
3402        Returns:
3403     
3404           The changed object.
3405     */
3406     $madd: function(polar) {
3407         this.theta = (this.theta + polar.theta) % (Math.PI * 2); this.rho += polar.rho;
3408         return this;
3409     },
3410
3411     
3412     /*
3413        Method: $scale
3414     
3415         Scales a polar instance affecting the object.
3416     
3417       Parameters:
3418
3419       number - A scaling factor.
3420
3421       Returns:
3422     
3423           The changed object.
3424     */
3425     $scale: function(number) {
3426         this.rho *= number;
3427         return this;
3428     },
3429     
3430     /*
3431       Method: isZero
3432    
3433       Returns *true* if the number is zero.
3434    
3435    */
3436     isZero: function () {
3437       var almostZero = 0.0001, abs = Math.abs;
3438       return abs(this.theta) < almostZero && abs(this.rho) < almostZero;
3439     },
3440
3441     /*
3442        Method: interpolate
3443     
3444         Calculates a polar interpolation between two points at a given delta moment.
3445
3446         Parameters:
3447       
3448         elem - A <Polar> instance.
3449         delta - A delta factor ranging [0, 1].
3450     
3451        Returns:
3452     
3453           A new <Polar> instance representing an interpolation between _this_ and _elem_
3454     */
3455     interpolate: function(elem, delta) {
3456         var pi = Math.PI, pi2 = pi * 2;
3457         var ch = function(t) {
3458             var a =  (t < 0)? (t % pi2) + pi2 : t % pi2;
3459             return a;
3460         };
3461         var tt = this.theta, et = elem.theta;
3462         var sum, diff = Math.abs(tt - et);
3463         if(diff == pi) {
3464           if(tt > et) {
3465             sum = ch((et + ((tt - pi2) - et) * delta)) ;
3466           } else {
3467             sum = ch((et - pi2 + (tt - (et)) * delta));
3468           }
3469         } else if(diff >= pi) {
3470           if(tt > et) {
3471             sum = ch((et + ((tt - pi2) - et) * delta)) ;
3472           } else {
3473             sum = ch((et - pi2 + (tt - (et - pi2)) * delta));
3474           }
3475         } else {  
3476           sum = ch((et + (tt - et) * delta)) ;
3477         }
3478         var r = (this.rho - elem.rho) * delta + elem.rho;
3479         return {
3480           'theta': sum,
3481           'rho': r
3482         };
3483     }
3484 };
3485
3486
3487 var $P = function(a, b) { return new Polar(a, b); };
3488
3489 Polar.KER = $P(0, 0);
3490
3491
3492
3493 /*
3494  * File: Complex.js
3495  * 
3496  * Defines the <Complex> class.
3497  *
3498  * Description:
3499  *
3500  * The <Complex> class, just like the <Polar> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
3501  *
3502  * See also:
3503  *
3504  * <http://en.wikipedia.org/wiki/Complex_number>
3505  *
3506 */
3507
3508 /*
3509    Class: Complex
3510     
3511    A multi-purpose Complex Class with common methods.
3512  
3513    Description:
3514  
3515    The <Complex> class, just like the <Polar> class, is used by the <Hypertree>, <ST> and <RGraph> as a 2D point representation.
3516  
3517    See also:
3518  
3519    <http://en.wikipedia.org/wiki/Complex_number>
3520
3521    Parameters:
3522
3523    x - _optional_ A Complex number real part.
3524    y - _optional_ A Complex number imaginary part.
3525  
3526 */
3527
3528 var Complex = function(x, y) {
3529   this.x = x || 0;
3530   this.y = y || 0;
3531 };
3532
3533 $jit.Complex = Complex;
3534
3535 Complex.prototype = {
3536     /*
3537        Method: getc
3538     
3539        Returns a complex number.
3540     
3541        Returns:
3542     
3543           A complex number.
3544     */
3545     getc: function() {
3546         return this;
3547     },
3548
3549     /*
3550        Method: getp
3551     
3552        Returns a <Polar> representation of this number.
3553     
3554        Parameters:
3555
3556        simple - _optional_ If *true*, this method will return only an object holding theta and rho properties and not a <Polar> instance. Default's *false*.
3557
3558        Returns:
3559     
3560           A variable in <Polar> coordinates.
3561     */
3562     getp: function(simple) {
3563         return this.toPolar(simple);
3564     },
3565
3566
3567     /*
3568        Method: set
3569     
3570        Sets a number.
3571
3572        Parameters:
3573
3574        c - A <Complex> or <Polar> instance.
3575     
3576     */
3577     set: function(c) {
3578       c = c.getc(true);
3579       this.x = c.x; 
3580       this.y = c.y;
3581     },
3582
3583     /*
3584        Method: setc
3585     
3586        Sets a complex number.
3587
3588        Parameters:
3589
3590        x - A <Complex> number Real part.
3591        y - A <Complex> number Imaginary part.
3592     
3593     */
3594     setc: function(x, y) {
3595         this.x = x; 
3596         this.y = y;
3597     },
3598
3599     /*
3600        Method: setp
3601     
3602        Sets a polar number.
3603
3604        Parameters:
3605
3606        theta - A <Polar> number theta property.
3607        rho - A <Polar> number rho property.
3608     
3609     */
3610     setp: function(theta, rho) {
3611         this.x = Math.cos(theta) * rho;
3612         this.y = Math.sin(theta) * rho;
3613     },
3614
3615     /*
3616        Method: clone
3617     
3618        Returns a copy of the current object.
3619     
3620        Returns:
3621     
3622           A copy of the real object.
3623     */
3624     clone: function() {
3625         return new Complex(this.x, this.y);
3626     },
3627
3628     /*
3629        Method: toPolar
3630     
3631        Transforms cartesian to polar coordinates.
3632     
3633        Parameters:
3634
3635        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*.
3636        
3637        Returns:
3638     
3639           A new <Polar> instance.
3640     */
3641     
3642     toPolar: function(simple) {
3643         var rho = this.norm();
3644         var atan = Math.atan2(this.y, this.x);
3645         if(atan < 0) atan += Math.PI * 2;
3646         if(simple) return { 'theta': atan, 'rho': rho };
3647         return new Polar(atan, rho);
3648     },
3649     /*
3650        Method: norm
3651     
3652        Calculates a <Complex> number norm.
3653     
3654        Returns:
3655     
3656           A real number representing the complex norm.
3657     */
3658     norm: function () {
3659         return Math.sqrt(this.squaredNorm());
3660     },
3661     
3662     /*
3663        Method: squaredNorm
3664     
3665        Calculates a <Complex> number squared norm.
3666     
3667        Returns:
3668     
3669           A real number representing the complex squared norm.
3670     */
3671     squaredNorm: function () {
3672         return this.x*this.x + this.y*this.y;
3673     },
3674
3675     /*
3676        Method: add
3677     
3678        Returns the result of adding two complex numbers.
3679        
3680        Does not alter the original object.
3681
3682        Parameters:
3683     
3684           pos - A <Complex> instance.
3685     
3686        Returns:
3687     
3688          The result of adding two complex numbers.
3689     */
3690     add: function(pos) {
3691         return new Complex(this.x + pos.x, this.y + pos.y);
3692     },
3693
3694     /*
3695        Method: prod
3696     
3697        Returns the result of multiplying two <Complex> numbers.
3698        
3699        Does not alter the original object.
3700
3701        Parameters:
3702     
3703           pos - A <Complex> instance.
3704     
3705        Returns:
3706     
3707          The result of multiplying two complex numbers.
3708     */
3709     prod: function(pos) {
3710         return new Complex(this.x*pos.x - this.y*pos.y, this.y*pos.x + this.x*pos.y);
3711     },
3712
3713     /*
3714        Method: conjugate
3715     
3716        Returns the conjugate of this <Complex> number.
3717
3718        Does not alter the original object.
3719
3720        Returns:
3721     
3722          The conjugate of this <Complex> number.
3723     */
3724     conjugate: function() {
3725         return new Complex(this.x, -this.y);
3726     },
3727
3728
3729     /*
3730        Method: scale
3731     
3732        Returns the result of scaling a <Complex> instance.
3733        
3734        Does not alter the original object.
3735
3736        Parameters:
3737     
3738           factor - A scale factor.
3739     
3740        Returns:
3741     
3742          The result of scaling this complex to a factor.
3743     */
3744     scale: function(factor) {
3745         return new Complex(this.x * factor, this.y * factor);
3746     },
3747
3748     /*
3749        Method: equals
3750     
3751        Comparison method.
3752
3753        Returns *true* if both real and imaginary parts are equal.
3754
3755        Parameters:
3756
3757        c - A <Complex> instance.
3758
3759        Returns:
3760
3761        A boolean instance indicating if both <Complex> numbers are equal.
3762     */
3763     equals: function(c) {
3764         return this.x == c.x && this.y == c.y;
3765     },
3766
3767     /*
3768        Method: $add
3769     
3770        Returns the result of adding two <Complex> numbers.
3771        
3772        Alters the original object.
3773
3774        Parameters:
3775     
3776           pos - A <Complex> instance.
3777     
3778        Returns:
3779     
3780          The result of adding two complex numbers.
3781     */
3782     $add: function(pos) {
3783         this.x += pos.x; this.y += pos.y;
3784         return this;    
3785     },
3786     
3787     /*
3788        Method: $prod
3789     
3790        Returns the result of multiplying two <Complex> numbers.
3791        
3792        Alters the original object.
3793
3794        Parameters:
3795     
3796           pos - A <Complex> instance.
3797     
3798        Returns:
3799     
3800          The result of multiplying two complex numbers.
3801     */
3802     $prod:function(pos) {
3803         var x = this.x, y = this.y;
3804         this.x = x*pos.x - y*pos.y;
3805         this.y = y*pos.x + x*pos.y;
3806         return this;
3807     },
3808     
3809     /*
3810        Method: $conjugate
3811     
3812        Returns the conjugate for this <Complex>.
3813        
3814        Alters the original object.
3815
3816        Returns:
3817     
3818          The conjugate for this complex.
3819     */
3820     $conjugate: function() {
3821         this.y = -this.y;
3822         return this;
3823     },
3824     
3825     /*
3826        Method: $scale
3827     
3828        Returns the result of scaling a <Complex> instance.
3829        
3830        Alters the original object.
3831
3832        Parameters:
3833     
3834           factor - A scale factor.
3835     
3836        Returns:
3837     
3838          The result of scaling this complex to a factor.
3839     */
3840     $scale: function(factor) {
3841         this.x *= factor; this.y *= factor;
3842         return this;
3843     },
3844     
3845     /*
3846        Method: $div
3847     
3848        Returns the division of two <Complex> numbers.
3849        
3850        Alters the original object.
3851
3852        Parameters:
3853     
3854           pos - A <Complex> number.
3855     
3856        Returns:
3857     
3858          The result of scaling this complex to a factor.
3859     */
3860     $div: function(pos) {
3861         var x = this.x, y = this.y;
3862         var sq = pos.squaredNorm();
3863         this.x = x * pos.x + y * pos.y; this.y = y * pos.x - x * pos.y;
3864         return this.$scale(1 / sq);
3865     },
3866
3867     /*
3868       Method: isZero
3869    
3870       Returns *true* if the number is zero.
3871    
3872    */
3873     isZero: function () {
3874       var almostZero = 0.0001, abs = Math.abs;
3875       return abs(this.x) < almostZero && abs(this.y) < almostZero;
3876     }
3877 };
3878
3879 var $C = function(a, b) { return new Complex(a, b); };
3880
3881 Complex.KER = $C(0, 0);
3882 Complex.IM = $C(0, 1);
3883
3884
3885
3886 /*
3887  * File: Graph.js
3888  *
3889 */
3890
3891 /*
3892  Class: Graph
3893
3894  A Graph Class that provides useful manipulation functions. You can find more manipulation methods in the <Graph.Util> object.
3895
3896  An instance of this class can be accessed by using the *graph* parameter of any tree or graph visualization.
3897  
3898  Example:
3899
3900  (start code js)
3901    //create new visualization
3902    var viz = new $jit.Viz(options);
3903    //load JSON data
3904    viz.loadJSON(json);
3905    //access model
3906    viz.graph; //<Graph> instance
3907  (end code)
3908  
3909  Implements:
3910  
3911  The following <Graph.Util> methods are implemented in <Graph>
3912  
3913   - <Graph.Util.getNode>
3914   - <Graph.Util.eachNode>
3915   - <Graph.Util.computeLevels>
3916   - <Graph.Util.eachBFS>
3917   - <Graph.Util.clean>
3918   - <Graph.Util.getClosestNodeToPos>
3919   - <Graph.Util.getClosestNodeToOrigin>
3920  
3921 */  
3922
3923 $jit.MultiGraph = new Class({
3924
3925   initialize: function(opt, Node, Edge, Label) {
3926     var innerOptions = {
3927     'klass': Complex,
3928     'Node': {}
3929     };
3930     this.Node = Node;
3931     this.Edge = Edge;
3932     this.Label = Label;
3933     this.opt = $.merge(innerOptions, opt || {});
3934     this.nodes = {};
3935     this.edges = {};
3936         this.dup = []; // duplicate (bidirectional) edges
3937     
3938     //add nodeList methods
3939     var that = this;
3940     this.nodeList = {};
3941     for(var p in Accessors) {
3942       that.nodeList[p] = (function(p) {
3943         return function() {
3944           var args = Array.prototype.slice.call(arguments);
3945           that.eachNode(function(n) {
3946             n[p].apply(n, args);
3947           });
3948         };
3949       })(p);
3950     }
3951
3952  },
3953
3954 /*
3955      Method: getNode
3956     
3957      Returns a <Graph.Node> by *id*.
3958
3959      Parameters:
3960
3961      id - (string) A <Graph.Node> id.
3962
3963      Example:
3964
3965      (start code js)
3966        var node = graph.getNode('nodeId');
3967      (end code)
3968 */  
3969  getNode: function(id) {
3970     if(this.hasNode(id)) return this.nodes[id];
3971     return false;
3972  },
3973
3974  /*
3975      Method: get
3976     
3977      An alias for <Graph.Util.getNode>. Returns a node by *id*.
3978     
3979      Parameters:
3980     
3981      id - (string) A <Graph.Node> id.
3982     
3983      Example:
3984     
3985      (start code js)
3986        var node = graph.get('nodeId');
3987      (end code)
3988 */  
3989   get: function(id) {
3990     return this.getNode(id);
3991   },
3992
3993  /*
3994    Method: getByName
3995   
3996    Returns a <Graph.Node> by *name*.
3997   
3998    Parameters:
3999   
4000    name - (string) A <Graph.Node> name.
4001   
4002    Example:
4003   
4004    (start code js)
4005      var node = graph.getByName('someName');
4006    (end code)
4007   */  
4008   getByName: function(name) {
4009     for(var id in this.nodes) {
4010       var n = this.nodes[id];
4011       if(n.name == name) return n;
4012     }
4013     return false;
4014   },
4015
4016 /*
4017    Method: getAdjacence
4018   
4019    Returns a <Graph.Adjacence> object connecting nodes with ids *id* and *id2*.
4020
4021    Parameters:
4022
4023    id - (string) A <Graph.Node> id.
4024    id2 - (string) A <Graph.Node> id.
4025 */  
4026   getAdjacence: function (id, id2) {
4027     if(id in this.edges) {
4028       return this.edges[id][id2];
4029     }
4030     return false;
4031  },
4032
4033     /*
4034      Method: addNode
4035     
4036      Adds a node.
4037      
4038      Parameters:
4039     
4040       obj - An object with the properties described below
4041
4042       id - (string) A node id
4043       name - (string) A node's name
4044       data - (object) A node's data hash
4045
4046     See also:
4047     <Graph.Node>
4048
4049   */  
4050   addNode: function(obj) { 
4051    if(!this.nodes[obj.id]) {  
4052      var edges = this.edges[obj.id] = {};
4053      this.nodes[obj.id] = new MultiGraph.Node($.extend({
4054         'id': obj.id,
4055         'name': obj.name,
4056         'data': $.merge(obj.data || {}, {}),
4057         'adjacencies': edges 
4058       }, this.opt.Node), 
4059       this.opt.klass, 
4060       this.Node, 
4061       this.Edge,
4062       this.Label);
4063     }
4064     return this.nodes[obj.id];
4065   },
4066   
4067     /*
4068      Method: addAdjacence
4069     
4070      Connects nodes specified by *obj* and *obj2*. If not found, nodes are created.
4071      
4072      Parameters:
4073     
4074       obj - (object) A <Graph.Node> object.
4075       obj2 - (object) Another <Graph.Node> object.
4076       data - (object) A data object. Used to store some extra information in the <Graph.Adjacence> object created.
4077
4078     See also:
4079
4080     <Graph.Node>, <Graph.Adjacence>
4081     */  
4082   addAdjacence: function (obj, obj2, data) {
4083         if (obj.id == obj2.id) return null; // skip if node loops back to itself
4084
4085         var portFrom = data["$nodeFromPort"];
4086         var portTo = data["$nodeToPort"];
4087
4088     if(!this.hasNode(obj.id)) { this.addNode(obj); }
4089     if(!this.hasNode(obj2.id)) { this.addNode(obj2); }
4090     obj = this.nodes[obj.id]; obj2 = this.nodes[obj2.id];
4091     if(!obj.adjacentTo(obj2, portTo)) {
4092       var adjsObj = this.edges[obj.id] = this.edges[obj.id] || {};
4093       var adjsObj2 = this.edges[obj2.id] = this.edges[obj2.id] || {};
4094           
4095           adjsObj[obj2.id] = adjsObj[obj2.id] || [];
4096           adjsObj2[obj.id] = adjsObj2[obj.id] || [];
4097
4098           var adj = new MultiGraph.Adjacence(obj, obj2, portFrom, portTo, data, this.Edge, this.Label);
4099
4100           // if dup, then add to dup list
4101           for(var edge in adjsObj2[obj.id]) { // iterate through the adj for the other node
4102                 var e = adjsObj2[obj.id][edge];
4103                 if(e.nodeFrom.id == adj.nodeTo.id && e.nodeTo.id == adj.nodeFrom.id) {
4104                         if(e.portFrom == adj.portTo && e.portTo == adj.portFrom) {
4105                                 this.dup.push(adj); // if the other node contains the edge, then add it to the dup list for later filtering
4106                         }
4107                 }
4108           }
4109
4110           // add this adjacency into the current edges object
4111           adjsObj[obj2.id].push(adj);
4112           if (adj.nodeFrom.data["$type"] != "swtch") {
4113                 // if this is not a switch (e.g. host), then add it to the switch because it will never be added by itself
4114                 adjsObj2[obj.id].push(adj);
4115           }
4116
4117           return adj;
4118       //adjsObj[obj2.id] = adjsObj2[obj.id] = new MultiGraph.Adjacence(obj, obj2, data["$nodeFromPort"], data["$nodeToPort"], data, this.Edge, this.Label);
4119       //return adjsObj[obj2.id];
4120     }
4121     return this.edges[obj.id][obj2.id];
4122  },
4123
4124     /*
4125      Method: removeNode
4126     
4127      Removes a <Graph.Node> matching the specified *id*.
4128
4129      Parameters:
4130
4131      id - (string) A node's id.
4132
4133     */  
4134   removeNode: function(id) {
4135     if(this.hasNode(id)) {
4136       delete this.nodes[id];
4137       var adjs = this.edges[id];
4138       for(var to in adjs) {
4139         delete this.edges[to][id];
4140       }
4141       delete this.edges[id];
4142     }
4143   },
4144   
4145 /*
4146      Method: removeAdjacence
4147     
4148      Removes a <Graph.Adjacence> matching *id1* and *id2*.
4149
4150      Parameters:
4151
4152      id1 - (string) A <Graph.Node> id.
4153      id2 - (string) A <Graph.Node> id.
4154 */  
4155   removeAdjacence: function(id1, id2) {
4156     delete this.edges[id1][id2];
4157     delete this.edges[id2][id1];
4158   },
4159
4160    /*
4161      Method: hasNode
4162     
4163      Returns a boolean indicating if the node belongs to the <Graph> or not.
4164      
4165      Parameters:
4166     
4167         id - (string) Node id.
4168    */  
4169   hasNode: function(id) {
4170     return id in this.nodes;
4171   },
4172   
4173   /*
4174     Method: empty
4175
4176     Empties the Graph
4177
4178   */
4179   empty: function() { this.nodes = {}; this.edges = {};}
4180
4181 });
4182
4183 var MultiGraph = $jit.MultiGraph;
4184
4185 /*
4186  Object: Accessors
4187  
4188  Defines a set of methods for data, canvas and label styles manipulation implemented by <Graph.Node> and <Graph.Adjacence> instances.
4189  
4190  */
4191 var Accessors;
4192
4193 (function () {
4194   var getDataInternal = function(prefix, prop, type, force, prefixConfig) {
4195     var data;
4196     type = type || 'current';
4197     prefix = "$" + (prefix ? prefix + "-" : "");
4198
4199     if(type == 'current') {
4200       data = this.data;
4201     } else if(type == 'start') {
4202       data = this.startData;
4203     } else if(type == 'end') {
4204       data = this.endData;
4205     }
4206
4207     var dollar = prefix + prop;
4208
4209     if(force) {
4210       return data[dollar];
4211     }
4212
4213     if(!this.Config.overridable)
4214       return prefixConfig[prop] || 0;
4215
4216     return (dollar in data) ?
4217       data[dollar] : ((dollar in this.data) ? this.data[dollar] : (prefixConfig[prop] || 0));
4218   }
4219
4220   var setDataInternal = function(prefix, prop, value, type) {
4221     type = type || 'current';
4222     prefix = '$' + (prefix ? prefix + '-' : '');
4223
4224     var data;
4225
4226     if(type == 'current') {
4227       data = this.data;
4228     } else if(type == 'start') {
4229       data = this.startData;
4230     } else if(type == 'end') {
4231       data = this.endData;
4232     }
4233
4234     data[prefix + prop] = value;
4235   }
4236
4237   var removeDataInternal = function(prefix, properties) {
4238     prefix = '$' + (prefix ? prefix + '-' : '');
4239     var that = this;
4240     $.each(properties, function(prop) {
4241       var pref = prefix + prop;
4242       delete that.data[pref];
4243       delete that.endData[pref];
4244       delete that.startData[pref];
4245     });
4246   }
4247
4248   Accessors = {
4249     /*
4250     Method: getData
4251
4252     Returns the specified data value property.
4253     This is useful for querying special/reserved <Graph.Node> data properties
4254     (i.e dollar prefixed properties).
4255
4256     Parameters:
4257
4258       prop  - (string) The name of the property. The dollar sign is not needed. For
4259               example *getData(width)* will return *data.$width*.
4260       type  - (string) The type of the data property queried. Default's "current". You can access *start* and *end* 
4261               data properties also. These properties are used when making animations.
4262       force - (boolean) Whether to obtain the true value of the property (equivalent to
4263               *data.$prop*) or to check for *node.overridable = true* first.
4264
4265     Returns:
4266
4267       The value of the dollar prefixed property or the global Node/Edge property
4268       value if *overridable=false*
4269
4270     Example:
4271     (start code js)
4272      node.getData('width'); //will return node.data.$width if Node.overridable=true;
4273     (end code)
4274     */
4275     getData: function(prop, type, force) {
4276       return getDataInternal.call(this, "", prop, type, force, this.Config);
4277     },
4278
4279
4280     /*
4281     Method: setData
4282
4283     Sets the current data property with some specific value.
4284     This method is only useful for reserved (dollar prefixed) properties.
4285
4286     Parameters:
4287
4288       prop  - (string) The name of the property. The dollar sign is not necessary. For
4289               example *setData(width)* will set *data.$width*.
4290       value - (mixed) The value to store.
4291       type  - (string) The type of the data property to store. Default's "current" but
4292               can also be "start" or "end".
4293
4294     Example:
4295     
4296     (start code js)
4297      node.setData('width', 30);
4298     (end code)
4299     
4300     If we were to make an animation of a node/edge width then we could do
4301     
4302     (start code js)
4303       var node = viz.getNode('nodeId');
4304       //set start and end values
4305       node.setData('width', 10, 'start');
4306       node.setData('width', 30, 'end');
4307       //will animate nodes width property
4308       viz.fx.animate({
4309         modes: ['node-property:width'],
4310         duration: 1000
4311       });
4312     (end code)
4313     */
4314     setData: function(prop, value, type) {
4315       setDataInternal.call(this, "", prop, value, type);
4316     },
4317
4318     /*
4319     Method: setDataset
4320
4321     Convenience method to set multiple data values at once.
4322     
4323     Parameters:
4324     
4325     types - (array|string) A set of 'current', 'end' or 'start' values.
4326     obj - (object) A hash containing the names and values of the properties to be altered.
4327
4328     Example:
4329     (start code js)
4330       node.setDataset(['current', 'end'], {
4331         'width': [100, 5],
4332         'color': ['#fff', '#ccc']
4333       });
4334       //...or also
4335       node.setDataset('end', {
4336         'width': 5,
4337         'color': '#ccc'
4338       });
4339     (end code)
4340     
4341     See also: 
4342     
4343     <Accessors.setData>
4344     
4345     */
4346     setDataset: function(types, obj) {
4347       types = $.splat(types);
4348       for(var attr in obj) {
4349         for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
4350           this.setData(attr, val[i], types[i]);
4351         }
4352       }
4353     },
4354     
4355     /*
4356     Method: removeData
4357
4358     Remove data properties.
4359
4360     Parameters:
4361
4362     One or more property names as arguments. The dollar sign is not needed.
4363
4364     Example:
4365     (start code js)
4366     node.removeData('width'); //now the default width value is returned
4367     (end code)
4368     */
4369     removeData: function() {
4370       removeDataInternal.call(this, "", Array.prototype.slice.call(arguments));
4371     },
4372
4373     /*
4374     Method: getCanvasStyle
4375
4376     Returns the specified canvas style data value property. This is useful for
4377     querying special/reserved <Graph.Node> canvas style data properties (i.e.
4378     dollar prefixed properties that match with $canvas-<name of canvas style>).
4379
4380     Parameters:
4381
4382       prop  - (string) The name of the property. The dollar sign is not needed. For
4383               example *getCanvasStyle(shadowBlur)* will return *data[$canvas-shadowBlur]*.
4384       type  - (string) The type of the data property queried. Default's *current*. You can access *start* and *end* 
4385               data properties also.
4386               
4387     Example:
4388     (start code js)
4389       node.getCanvasStyle('shadowBlur');
4390     (end code)
4391     
4392     See also:
4393     
4394     <Accessors.getData>
4395     */
4396     getCanvasStyle: function(prop, type, force) {
4397       return getDataInternal.call(
4398           this, 'canvas', prop, type, force, this.Config.CanvasStyles);
4399     },
4400
4401     /*
4402     Method: setCanvasStyle
4403
4404     Sets the canvas style data property with some specific value.
4405     This method is only useful for reserved (dollar prefixed) properties.
4406     
4407     Parameters:
4408     
4409     prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc.
4410     value - (mixed) The value to set to the property.
4411     type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties.
4412     
4413     Example:
4414     
4415     (start code js)
4416      node.setCanvasStyle('shadowBlur', 30);
4417     (end code)
4418     
4419     If we were to make an animation of a node/edge shadowBlur canvas style then we could do
4420     
4421     (start code js)
4422       var node = viz.getNode('nodeId');
4423       //set start and end values
4424       node.setCanvasStyle('shadowBlur', 10, 'start');
4425       node.setCanvasStyle('shadowBlur', 30, 'end');
4426       //will animate nodes canvas style property for nodes
4427       viz.fx.animate({
4428         modes: ['node-style:shadowBlur'],
4429         duration: 1000
4430       });
4431     (end code)
4432     
4433     See also:
4434     
4435     <Accessors.setData>.
4436     */
4437     setCanvasStyle: function(prop, value, type) {
4438       setDataInternal.call(this, 'canvas', prop, value, type);
4439     },
4440
4441     /*
4442     Method: setCanvasStyles
4443
4444     Convenience method to set multiple styles at once.
4445
4446     Parameters:
4447     
4448     types - (array|string) A set of 'current', 'end' or 'start' values.
4449     obj - (object) A hash containing the names and values of the properties to be altered.
4450
4451     See also:
4452     
4453     <Accessors.setDataset>.
4454     */
4455     setCanvasStyles: function(types, obj) {
4456       types = $.splat(types);
4457       for(var attr in obj) {
4458         for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
4459           this.setCanvasStyle(attr, val[i], types[i]);
4460         }
4461       }
4462     },
4463
4464     /*
4465     Method: removeCanvasStyle
4466
4467     Remove canvas style properties from data.
4468
4469     Parameters:
4470     
4471     A variable number of canvas style strings.
4472
4473     See also:
4474     
4475     <Accessors.removeData>.
4476     */
4477     removeCanvasStyle: function() {
4478       removeDataInternal.call(this, 'canvas', Array.prototype.slice.call(arguments));
4479     },
4480
4481     /*
4482     Method: getLabelData
4483
4484     Returns the specified label data value property. This is useful for
4485     querying special/reserved <Graph.Node> label options (i.e.
4486     dollar prefixed properties that match with $label-<name of label style>).
4487
4488     Parameters:
4489
4490       prop  - (string) The name of the property. The dollar sign prefix is not needed. For
4491               example *getLabelData(size)* will return *data[$label-size]*.
4492       type  - (string) The type of the data property queried. Default's *current*. You can access *start* and *end* 
4493               data properties also.
4494               
4495     See also:
4496     
4497     <Accessors.getData>.
4498     */
4499     getLabelData: function(prop, type, force) {
4500       return getDataInternal.call(
4501           this, 'label', prop, type, force, this.Label);
4502     },
4503
4504     /*
4505     Method: setLabelData
4506
4507     Sets the current label data with some specific value.
4508     This method is only useful for reserved (dollar prefixed) properties.
4509
4510     Parameters:
4511     
4512     prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc.
4513     value - (mixed) The value to set to the property.
4514     type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties.
4515     
4516     Example:
4517     
4518     (start code js)
4519      node.setLabelData('size', 30);
4520     (end code)
4521     
4522     If we were to make an animation of a node label size then we could do
4523     
4524     (start code js)
4525       var node = viz.getNode('nodeId');
4526       //set start and end values
4527       node.setLabelData('size', 10, 'start');
4528       node.setLabelData('size', 30, 'end');
4529       //will animate nodes label size
4530       viz.fx.animate({
4531         modes: ['label-property:size'],
4532         duration: 1000
4533       });
4534     (end code)
4535     
4536     See also:
4537     
4538     <Accessors.setData>.
4539     */
4540     setLabelData: function(prop, value, type) {
4541       setDataInternal.call(this, 'label', prop, value, type);
4542     },
4543
4544     /*
4545     Method: setLabelDataset
4546
4547     Convenience function to set multiple label data at once.
4548
4549     Parameters:
4550     
4551     types - (array|string) A set of 'current', 'end' or 'start' values.
4552     obj - (object) A hash containing the names and values of the properties to be altered.
4553
4554     See also:
4555     
4556     <Accessors.setDataset>.
4557     */
4558     setLabelDataset: function(types, obj) {
4559       types = $.splat(types);
4560       for(var attr in obj) {
4561         for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
4562           this.setLabelData(attr, val[i], types[i]);
4563         }
4564       }
4565     },
4566
4567     /*
4568     Method: removeLabelData
4569
4570     Remove label properties from data.
4571     
4572     Parameters:
4573     
4574     A variable number of label property strings.
4575
4576     See also:
4577     
4578     <Accessors.removeData>.
4579     */
4580     removeLabelData: function() {
4581       removeDataInternal.call(this, 'label', Array.prototype.slice.call(arguments));
4582     }
4583   };
4584 })();
4585
4586 /*
4587      Class: Graph.Node
4588
4589      A <Graph> node.
4590      
4591      Implements:
4592      
4593      <Accessors> methods.
4594      
4595      The following <Graph.Util> methods are implemented by <Graph.Node>
4596      
4597     - <Graph.Util.eachAdjacency>
4598     - <Graph.Util.eachLevel>
4599     - <Graph.Util.eachSubgraph>
4600     - <Graph.Util.eachSubnode>
4601     - <Graph.Util.anySubnode>
4602     - <Graph.Util.getSubnodes>
4603     - <Graph.Util.getParents>
4604     - <Graph.Util.isDescendantOf>     
4605 */
4606 MultiGraph.Node = new Class({
4607     
4608   initialize: function(opt, klass, Node, Edge, Label) {
4609     var innerOptions = {
4610       'id': '',
4611       'name': '',
4612       'data': {},
4613       'startData': {},
4614       'endData': {},
4615       'adjacencies': {},
4616
4617       'selected': false,
4618       'drawn': false,
4619       'exist': false,
4620
4621       'angleSpan': {
4622         'begin': 0,
4623         'end' : 0
4624       },
4625
4626       'pos': new klass,
4627       'startPos': new klass,
4628       'endPos': new klass
4629     };
4630     
4631     $.extend(this, $.extend(innerOptions, opt));
4632     this.Config = this.Node = Node;
4633     this.Edge = Edge;
4634     this.Label = Label;
4635   },
4636
4637     /*
4638        Method: adjacentTo
4639     
4640        Indicates if the node is adjacent to the node specified by id
4641
4642        Parameters:
4643     
4644           id - (string) A node id.
4645     
4646        Example:
4647        (start code js)
4648         node.adjacentTo('nodeId') == true;
4649        (end code)
4650     */
4651     adjacentTo: function(node, port) {
4652                 return false;
4653                 /*
4654                 if (this.adjacencies[node.id] != undefined) {
4655                         for(var i = 0, il = this.adjacencies[node.id].length; i < il; i++) {
4656                                 if (this.adjacencies[node.id][i]["portFrom"] == port)
4657                                         return true;
4658                         }
4659                 }
4660                 return false;
4661                 */
4662         //return node.id in this.adjacencies;
4663     },
4664
4665     /*
4666      Method: adjacentWithDirectionTo
4667
4668      Indicates if the node has a directed edge to the node specified by id
4669
4670      Parameters:
4671
4672      id - (string) A node id.
4673
4674      Example:
4675      (start code js)
4676      node.adjacentWithDirectionTo('nodeId') == true;
4677      (end code)
4678      */
4679     adjacentWithDirectionTo: function(node) {
4680         var areNeighbors = node.id in this.adjacencies;
4681         if (!areNeighbors) {
4682             return false;
4683         }
4684
4685         var direction = this.adjacencies[node.id].data.$direction;
4686         return direction[0] === this.id ;
4687     },
4688
4689     /*
4690        Method: getAdjacency
4691     
4692        Returns a <Graph.Adjacence> object connecting the current <Graph.Node> and the node having *id* as id.
4693
4694        Parameters:
4695     
4696           id - (string) A node id.
4697     */  
4698     getAdjacency: function(id) {
4699         return this.adjacencies[id];
4700     },
4701
4702     /*
4703       Method: getPos
4704    
4705       Returns the position of the node.
4706   
4707       Parameters:
4708    
4709          type - (string) Default's *current*. Possible values are "start", "end" or "current".
4710    
4711       Returns:
4712    
4713         A <Complex> or <Polar> instance.
4714   
4715       Example:
4716       (start code js)
4717        var pos = node.getPos('end');
4718       (end code)
4719    */
4720    getPos: function(type) {
4721        type = type || "current";
4722        if(type == "current") {
4723          return this.pos;
4724        } else if(type == "end") {
4725          return this.endPos;
4726        } else if(type == "start") {
4727          return this.startPos;
4728        }
4729    },
4730    /*
4731      Method: setPos
4732   
4733      Sets the node's position.
4734   
4735      Parameters:
4736   
4737         value - (object) A <Complex> or <Polar> instance.
4738         type - (string) Default's *current*. Possible values are "start", "end" or "current".
4739   
4740      Example:
4741      (start code js)
4742       node.setPos(new $jit.Complex(0, 0), 'end');
4743      (end code)
4744   */
4745   setPos: function(value, type) {
4746       type = type || "current";
4747       var pos;
4748       if(type == "current") {
4749         pos = this.pos;
4750       } else if(type == "end") {
4751         pos = this.endPos;
4752       } else if(type == "start") {
4753         pos = this.startPos;
4754       }
4755       pos.set(value);
4756   }
4757 });
4758
4759 MultiGraph.Node.implement(Accessors);
4760
4761 /*
4762      Class: Graph.Adjacence
4763
4764      A <Graph> adjacence (or edge) connecting two <Graph.Nodes>.
4765      
4766      Implements:
4767      
4768      <Accessors> methods.
4769
4770      See also:
4771
4772      <Graph>, <Graph.Node>
4773
4774      Properties:
4775      
4776       nodeFrom - A <Graph.Node> connected by this edge.
4777       nodeTo - Another  <Graph.Node> connected by this edge.
4778       data - Node data property containing a hash (i.e {}) with custom options.
4779 */
4780 MultiGraph.Adjacence = new Class({
4781   
4782   initialize: function(nodeFrom, nodeTo, portFrom, portTo, data, Edge, Label) {
4783     this.nodeFrom = nodeFrom;
4784     this.nodeTo = nodeTo;
4785     this.data = data || {};
4786     this.startData = {};
4787     this.endData = {};
4788     this.Config = this.Edge = Edge;
4789     this.Label = Label;
4790
4791         this.portFrom = portFrom;
4792         this.portTo = portTo;
4793   }
4794 });
4795
4796 MultiGraph.Adjacence.implement(Accessors);
4797
4798 /*
4799    Object: Graph.Util
4800
4801    <Graph> traversal and processing utility object.
4802    
4803    Note:
4804    
4805    For your convenience some of these methods have also been appended to <Graph> and <Graph.Node> classes.
4806 */
4807 MultiGraph.Util = {
4808     /*
4809        filter
4810     
4811        For internal use only. Provides a filtering function based on flags.
4812     */
4813     filter: function(param) {
4814         if(!param || !($.type(param) == 'string')) return function() { return true; };
4815         var props = param.split(" ");
4816         return function(elem) {
4817             for(var i=0; i<props.length; i++) { 
4818               if(elem[props[i]]) { 
4819                 return false; 
4820               }
4821             }
4822             return true;
4823         };
4824     },
4825     /*
4826        Method: getNode
4827     
4828        Returns a <Graph.Node> by *id*.
4829        
4830        Also implemented by:
4831        
4832        <Graph>
4833
4834        Parameters:
4835
4836        graph - (object) A <Graph> instance.
4837        id - (string) A <Graph.Node> id.
4838
4839        Example:
4840
4841        (start code js)
4842          $jit.Graph.Util.getNode(graph, 'nodeid');
4843          //or...
4844          graph.getNode('nodeid');
4845        (end code)
4846     */
4847     getNode: function(graph, id) {
4848         return graph.nodes[id];
4849     },
4850     
4851     /*
4852        Method: eachNode
4853     
4854        Iterates over <Graph> nodes performing an *action*.
4855        
4856        Also implemented by:
4857        
4858        <Graph>.
4859
4860        Parameters:
4861
4862        graph - (object) A <Graph> instance.
4863        action - (function) A callback function having a <Graph.Node> as first formal parameter.
4864
4865        Example:
4866        (start code js)
4867          $jit.Graph.Util.eachNode(graph, function(node) {
4868           alert(node.name);
4869          });
4870          //or...
4871          graph.eachNode(function(node) {
4872            alert(node.name);
4873          });
4874        (end code)
4875     */
4876     eachNode: function(graph, action, flags) {
4877         var filter = this.filter(flags);
4878         for(var i in graph.nodes) {
4879           if(filter(graph.nodes[i])) action(graph.nodes[i]);
4880         } 
4881     },
4882     
4883     /*
4884       Method: each
4885    
4886       Iterates over <Graph> nodes performing an *action*. It's an alias for <Graph.Util.eachNode>.
4887       
4888       Also implemented by:
4889       
4890       <Graph>.
4891   
4892       Parameters:
4893   
4894       graph - (object) A <Graph> instance.
4895       action - (function) A callback function having a <Graph.Node> as first formal parameter.
4896   
4897       Example:
4898       (start code js)
4899         $jit.Graph.Util.each(graph, function(node) {
4900          alert(node.name);
4901         });
4902         //or...
4903         graph.each(function(node) {
4904           alert(node.name);
4905         });
4906       (end code)
4907    */
4908    each: function(graph, action, flags) {
4909       this.eachNode(graph, action, flags); 
4910    },
4911
4912    eachAdjacencyBatch: function(node, action, flags) {
4913                 var adj = node.adjacencies;
4914
4915                 for(var id in adj) {
4916                         var a = adj[id];
4917                         action(a, id);
4918                 }
4919    },
4920
4921  /*
4922        Method: eachAdjacency
4923     
4924        Iterates over <Graph.Node> adjacencies applying the *action* function.
4925        
4926        Also implemented by:
4927        
4928        <Graph.Node>.
4929
4930        Parameters:
4931
4932        node - (object) A <Graph.Node>.
4933        action - (function) A callback function having <Graph.Adjacence> as first formal parameter.
4934
4935        Example:
4936        (start code js)
4937          $jit.Graph.Util.eachAdjacency(node, function(adj) {
4938           alert(adj.nodeTo.name);
4939          });
4940          //or...
4941          node.eachAdjacency(function(adj) {
4942            alert(adj.nodeTo.name);
4943          });
4944        (end code)
4945     */
4946     eachAdjacency: function(node, action, flags) {
4947                 var adj = node.adjacencies, filter = this.filter(flags);
4948
4949                 for(var id in adj) {
4950                         var a = adj[id];
4951                         for(var idj in a) {
4952                                 action(a[idj], id);
4953                         }
4954                 }
4955
4956         /*var adj = node.adjacencies, filter = this.filter(flags);
4957         for(var id in adj) {
4958           var a = adj[id];
4959           if(filter(a)) {
4960             if(a.nodeFrom != node) {
4961               var tmp = a.nodeFrom;
4962               a.nodeFrom = a.nodeTo;
4963               a.nodeTo = tmp;
4964             }
4965             action(a, id);
4966           }
4967         }*/
4968     },
4969
4970      /*
4971        Method: computeLevels
4972     
4973        Performs a BFS traversal setting the correct depth for each node.
4974         
4975        Also implemented by:
4976        
4977        <Graph>.
4978        
4979        Note:
4980        
4981        The depth of each node can then be accessed by 
4982        >node._depth
4983
4984        Parameters:
4985
4986        graph - (object) A <Graph>.
4987        id - (string) A starting node id for the BFS traversal.
4988        startDepth - (optional|number) A minimum depth value. Default's 0.
4989
4990     */
4991     computeLevels: function(graph, id, startDepth, flags) {
4992         startDepth = startDepth || 0;
4993         var filter = this.filter(flags);
4994         this.eachNode(graph, function(elem) {
4995             elem._flag = false;
4996             elem._depth = -1;
4997         }, flags);
4998         var root = graph.getNode(id);
4999         root._depth = startDepth;
5000         var queue = [root];
5001         while(queue.length != 0) {
5002             var node = queue.pop();
5003             node._flag = true;
5004             this.eachAdjacency(node, function(adj) {
5005                 var n = adj.nodeTo;
5006                 if(n._flag == false && filter(n) && !adj._hiding) {
5007                     if(n._depth < 0) n._depth = node._depth + 1 + startDepth;
5008                     queue.unshift(n);
5009                 }
5010             }, flags);
5011         }
5012     },
5013
5014     /*
5015        Method: eachBFS
5016     
5017        Performs a BFS traversal applying *action* to each <Graph.Node>.
5018        
5019        Also implemented by:
5020        
5021        <Graph>.
5022
5023        Parameters:
5024
5025        graph - (object) A <Graph>.
5026        id - (string) A starting node id for the BFS traversal.
5027        action - (function) A callback function having a <Graph.Node> as first formal parameter.
5028
5029        Example:
5030        (start code js)
5031          $jit.Graph.Util.eachBFS(graph, 'mynodeid', function(node) {
5032           alert(node.name);
5033          });
5034          //or...
5035          graph.eachBFS('mynodeid', function(node) {
5036            alert(node.name);
5037          });
5038        (end code)
5039     */
5040     eachBFS: function(graph, id, action, flags) {
5041         var filter = this.filter(flags);
5042         this.clean(graph);
5043         var queue = [graph.getNode(id)];
5044         while(queue.length != 0) {
5045             var node = queue.pop();
5046             if (!node) return;
5047             node._flag = true;
5048             action(node, node._depth);
5049             this.eachAdjacency(node, function(adj) {
5050                 var n = adj.nodeTo;
5051                 if(n._flag == false && filter(n) && !adj._hiding) {
5052                     n._flag = true;
5053                     queue.unshift(n);
5054                 }
5055             }, flags);
5056         }
5057     },
5058     
5059     /*
5060        Method: eachLevel
5061     
5062        Iterates over a node's subgraph applying *action* to the nodes of relative depth between *levelBegin* and *levelEnd*.
5063        In case you need to break the iteration, *action* should return false.
5064        
5065        Also implemented by:
5066        
5067        <Graph.Node>.
5068
5069        Parameters:
5070        
5071        node - (object) A <Graph.Node>.
5072        levelBegin - (number) A relative level value.
5073        levelEnd - (number) A relative level value.
5074        action - (function) A callback function having a <Graph.Node> as first formal parameter.
5075
5076     */
5077     eachLevel: function(node, levelBegin, levelEnd, action, flags) {
5078         var d = node._depth, filter = this.filter(flags), that = this, shouldContinue = true;
5079         levelEnd = levelEnd === false? Number.MAX_VALUE -d : levelEnd;
5080         (function loopLevel(node, levelBegin, levelEnd) {
5081             if(!shouldContinue) return;
5082             var d = node._depth, ret;
5083             if(d >= levelBegin && d <= levelEnd && filter(node)) ret = action(node, d);
5084             if(typeof ret !== "undefined") shouldContinue = ret;
5085             if(shouldContinue && d < levelEnd) {
5086                 that.eachAdjacency(node, function(adj) {
5087                     var n = adj.nodeTo;
5088                     if(n._depth > d) loopLevel(n, levelBegin, levelEnd);
5089                 });
5090             }
5091         })(node, levelBegin + d, levelEnd + d);
5092     },
5093
5094     /*
5095        Method: eachSubgraph
5096     
5097        Iterates over a node's children recursively.
5098        
5099        Also implemented by:
5100        
5101        <Graph.Node>.
5102
5103        Parameters:
5104        node - (object) A <Graph.Node>.
5105        action - (function) A callback function having a <Graph.Node> as first formal parameter.
5106
5107        Example:
5108        (start code js)
5109          $jit.Graph.Util.eachSubgraph(node, function(node) {
5110            alert(node.name);
5111          });
5112          //or...
5113          node.eachSubgraph(function(node) {
5114            alert(node.name);
5115          });
5116        (end code)
5117     */
5118     eachSubgraph: function(node, action, flags) {
5119       this.eachLevel(node, 0, false, action, flags);
5120     },
5121
5122     /*
5123        Method: eachSubnode
5124     
5125        Iterates over a node's children (without deeper recursion).
5126        
5127        Also implemented by:
5128        
5129        <Graph.Node>.
5130        
5131        Parameters:
5132        node - (object) A <Graph.Node>.
5133        action - (function) A callback function having a <Graph.Node> as first formal parameter.
5134
5135        Example:
5136        (start code js)
5137          $jit.Graph.Util.eachSubnode(node, function(node) {
5138           alert(node.name);
5139          });
5140          //or...
5141          node.eachSubnode(function(node) {
5142            alert(node.name);
5143          });
5144        (end code)
5145     */
5146     eachSubnode: function(node, action, flags) {
5147         this.eachLevel(node, 1, 1, action, flags);
5148     },
5149
5150     /*
5151        Method: anySubnode
5152     
5153        Returns *true* if any subnode matches the given condition.
5154        
5155        Also implemented by:
5156        
5157        <Graph.Node>.
5158
5159        Parameters:
5160        node - (object) A <Graph.Node>.
5161        cond - (function) A callback function returning a Boolean instance. This function has as first formal parameter a <Graph.Node>.
5162
5163        Example:
5164        (start code js)
5165          $jit.Graph.Util.anySubnode(node, function(node) { return node.name == "mynodename"; });
5166          //or...
5167          node.anySubnode(function(node) { return node.name == 'mynodename'; });
5168        (end code)
5169     */
5170     anySubnode: function(node, cond, flags) {
5171       var flag = false;
5172       cond = cond || $.lambda(true);
5173       var c = $.type(cond) == 'string'? function(n) { return n[cond]; } : cond;
5174       this.eachSubnode(node, function(elem) {
5175         if(c(elem)) flag = true;
5176       }, flags);
5177       return flag;
5178     },
5179   
5180     /*
5181        Method: getSubnodes
5182     
5183        Collects all subnodes for a specified node. 
5184        The *level* parameter filters nodes having relative depth of *level* from the root node. 
5185        
5186        Also implemented by:
5187        
5188        <Graph.Node>.
5189
5190        Parameters:
5191        node - (object) A <Graph.Node>.
5192        level - (optional|number) Default's *0*. A starting relative depth for collecting nodes.
5193
5194        Returns:
5195        An array of nodes.
5196
5197     */
5198     getSubnodes: function(node, level, flags) {
5199         var ans = [], that = this;
5200         level = level || 0;
5201         var levelStart, levelEnd;
5202         if($.type(level) == 'array') {
5203             levelStart = level[0];
5204             levelEnd = level[1];
5205         } else {
5206             levelStart = level;
5207             levelEnd = Number.MAX_VALUE - node._depth;
5208         }
5209         this.eachLevel(node, levelStart, levelEnd, function(n) {
5210             ans.push(n);
5211         }, flags);
5212         return ans;
5213     },
5214   
5215   
5216     /*
5217        Method: getParents
5218     
5219        Returns an Array of <Graph.Nodes> which are parents of the given node.
5220        
5221        Also implemented by:
5222        
5223        <Graph.Node>.
5224
5225        Parameters:
5226        node - (object) A <Graph.Node>.
5227
5228        Returns:
5229        An Array of <Graph.Nodes>.
5230
5231        Example:
5232        (start code js)
5233          var pars = $jit.Graph.Util.getParents(node);
5234          //or...
5235          var pars = node.getParents();
5236          
5237          if(pars.length > 0) {
5238            //do stuff with parents
5239          }
5240        (end code)
5241     */
5242     getParents: function(node) {
5243         var ans = [];
5244         this.eachAdjacency(node, function(adj) {
5245             var n = adj.nodeTo;
5246             if(n._depth < node._depth) ans.push(n);
5247         });
5248         return ans;
5249     },
5250     
5251     /*
5252     Method: isDescendantOf
5253  
5254     Returns a boolean indicating if some node is descendant of the node with the given id. 
5255
5256     Also implemented by:
5257     
5258     <Graph.Node>.
5259     
5260     
5261     Parameters:
5262     node - (object) A <Graph.Node>.
5263     id - (string) A <Graph.Node> id.
5264
5265     Example:
5266     (start code js)
5267       $jit.Graph.Util.isDescendantOf(node, "nodeid"); //true|false
5268       //or...
5269       node.isDescendantOf('nodeid');//true|false
5270     (end code)
5271  */
5272  isDescendantOf: function(node, id) {
5273     if(node.id == id) return true;
5274     var pars = this.getParents(node), ans = false;
5275     for ( var i = 0; !ans && i < pars.length; i++) {
5276     ans = ans || this.isDescendantOf(pars[i], id);
5277   }
5278     return ans;
5279  },
5280
5281  /*
5282      Method: clean
5283   
5284      Cleans flags from nodes.
5285
5286      Also implemented by:
5287      
5288      <Graph>.
5289      
5290      Parameters:
5291      graph - A <Graph> instance.
5292   */
5293   clean: function(graph) { this.eachNode(graph, function(elem) { elem._flag = false; }); },
5294   
5295   /* 
5296     Method: getClosestNodeToOrigin 
5297   
5298     Returns the closest node to the center of canvas.
5299   
5300     Also implemented by:
5301     
5302     <Graph>.
5303     
5304     Parameters:
5305    
5306      graph - (object) A <Graph> instance.
5307      prop - (optional|string) Default's 'current'. A <Graph.Node> position property. Possible properties are 'start', 'current' or 'end'.
5308   
5309   */
5310   getClosestNodeToOrigin: function(graph, prop, flags) {
5311    return this.getClosestNodeToPos(graph, Polar.KER, prop, flags);
5312   },
5313   
5314   /* 
5315     Method: getClosestNodeToPos
5316   
5317     Returns the closest node to the given position.
5318   
5319     Also implemented by:
5320     
5321     <Graph>.
5322     
5323     Parameters:
5324    
5325      graph - (object) A <Graph> instance.
5326      pos - (object) A <Complex> or <Polar> instance.
5327      prop - (optional|string) Default's *current*. A <Graph.Node> position property. Possible properties are 'start', 'current' or 'end'.
5328   
5329   */
5330   getClosestNodeToPos: function(graph, pos, prop, flags) {
5331    var node = null;
5332    prop = prop || 'current';
5333    pos = pos && pos.getc(true) || Complex.KER;
5334    var distance = function(a, b) {
5335      var d1 = a.x - b.x, d2 = a.y - b.y;
5336      return d1 * d1 + d2 * d2;
5337    };
5338    this.eachNode(graph, function(elem) {
5339      node = (node == null || distance(elem.getPos(prop).getc(true), pos) < distance(
5340          node.getPos(prop).getc(true), pos)) ? elem : node;
5341    }, flags);
5342    return node;
5343   } 
5344 };
5345
5346 //Append graph methods to <Graph>
5347 $.each(['get', 'getNode', 'each', 'eachNode', 'computeLevels', 'eachBFS', 'clean', 'getClosestNodeToPos', 'getClosestNodeToOrigin'], function(m) {
5348   MultiGraph.prototype[m] = function() {
5349     return MultiGraph.Util[m].apply(MultiGraph.Util, [this].concat(Array.prototype.slice.call(arguments)));
5350   };
5351 });
5352
5353 //Append node methods to <Graph.Node>
5354 $.each(['eachAdjacencyBatch', 'eachAdjacency', 'eachLevel', 'eachSubgraph', 'eachSubnode', 'anySubnode', 'getSubnodes', 'getParents', 'isDescendantOf'], function(m) {
5355   MultiGraph.Node.prototype[m] = function() {
5356     return MultiGraph.Util[m].apply(MultiGraph.Util, [this].concat(Array.prototype.slice.call(arguments)));
5357   };
5358 });
5359
5360
5361 /*
5362  * File: Graph.Op.js
5363  *
5364 */
5365
5366 /*
5367    Object: Graph.Op
5368
5369    Perform <Graph> operations like adding/removing <Graph.Nodes> or <Graph.Adjacences>, 
5370    morphing a <Graph> into another <Graph>, contracting or expanding subtrees, etc.
5371
5372 */
5373 MultiGraph.Op = {
5374
5375     options: {
5376       type: 'nothing',
5377       duration: 2000,
5378       hideLabels: true,
5379       fps:30
5380     },
5381     
5382     initialize: function(viz) {
5383       this.viz = viz;
5384     },
5385
5386     /*
5387        Method: removeNode
5388     
5389        Removes one or more <Graph.Nodes> from the visualization. 
5390        It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.
5391
5392        Parameters:
5393     
5394         node - (string|array) The node's id. Can also be an array having many ids.
5395         opt - (object) Animation options. It's an object with optional properties described below
5396         type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq",  "fade:con" or "iter".
5397         duration - Described in <Options.Fx>.
5398         fps - Described in <Options.Fx>.
5399         transition - Described in <Options.Fx>.
5400         hideLabels - (boolean) Default's *true*. Hide labels during the animation.
5401    
5402       Example:
5403       (start code js)
5404         var viz = new $jit.Viz(options);
5405         viz.op.removeNode('nodeId', {
5406           type: 'fade:seq',
5407           duration: 1000,
5408           hideLabels: false,
5409           transition: $jit.Trans.Quart.easeOut
5410         });
5411         //or also
5412         viz.op.removeNode(['someId', 'otherId'], {
5413           type: 'fade:con',
5414           duration: 1500
5415         });
5416       (end code)
5417     */
5418   
5419     removeNode: function(node, opt) {
5420         var viz = this.viz;
5421         var options = $.merge(this.options, viz.controller, opt);
5422         var n = $.splat(node);
5423         var i, that, nodeObj;
5424         switch(options.type) {
5425             case 'nothing':
5426                 for(i=0; i<n.length; i++) {
5427                     options.onBeforeRemoveNode(viz.graph.getNode(n[i]));
5428                     viz.graph.removeNode(n[i]);
5429                 }
5430                 break;
5431             
5432             case 'replot':
5433                 this.removeNode(n, { type: 'nothing' });
5434                 viz.labels.clearLabels();
5435                 viz.refresh(true);
5436                 break;
5437             
5438             case 'fade:seq': case 'fade':
5439                 that = this;
5440                 //set alpha to 0 for nodes to remove.
5441                 for(i=0; i<n.length; i++) {
5442                     nodeObj = viz.graph.getNode(n[i]);
5443                     nodeObj.setData('alpha', 0, 'end');
5444                 }
5445                 viz.fx.animate($.merge(options, {
5446                     modes: ['node-property:alpha'],
5447                     onComplete: function() {
5448                         that.removeNode(n, { type: 'nothing' });
5449                         viz.labels.clearLabels();
5450                         viz.reposition();
5451                         viz.fx.animate($.merge(options, {
5452                             modes: ['linear']
5453                         }));
5454                     }
5455                 }));
5456                 break;
5457             
5458             case 'fade:con':
5459                 that = this;
5460                 //set alpha to 0 for nodes to remove. Tag them for being ignored on computing positions.
5461                 for(i=0; i<n.length; i++) {
5462                     nodeObj = viz.graph.getNode(n[i]);
5463                     nodeObj.setData('alpha', 0, 'end');
5464                     nodeObj.ignore = true;
5465                 }
5466                 viz.reposition();
5467                 viz.fx.animate($.merge(options, {
5468                     modes: ['node-property:alpha', 'linear'],
5469                     onComplete: function() {
5470                         that.removeNode(n, { type: 'nothing' });
5471                         options.onComplete && options.onComplete();
5472                     }
5473                 }));
5474                 break;
5475             
5476             case 'iter':
5477                 that = this;
5478                 viz.fx.sequence({
5479                     condition: function() { return n.length != 0; },
5480                     step: function() { that.removeNode(n.shift(), { type: 'nothing' });  viz.labels.clearLabels(); },
5481                     onComplete: function() { options.onComplete && options.onComplete(); },
5482                     duration: Math.ceil(options.duration / n.length)
5483                 });
5484                 break;
5485                 
5486             default: this.doError();
5487         }
5488     },
5489     
5490     /*
5491        Method: removeEdge
5492     
5493        Removes one or more <Graph.Adjacences> from the visualization. 
5494        It can also perform several animations like fading sequentially, fading concurrently, iterating or replotting.
5495
5496        Parameters:
5497     
5498        vertex - (array) 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'], ...]).
5499        opt - (object) Animation options. It's an object with optional properties described below
5500        type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq",  "fade:con" or "iter".
5501        duration - Described in <Options.Fx>.
5502        fps - Described in <Options.Fx>.
5503        transition - Described in <Options.Fx>.
5504        hideLabels - (boolean) Default's *true*. Hide labels during the animation.
5505    
5506       Example:
5507       (start code js)
5508         var viz = new $jit.Viz(options);
5509         viz.op.removeEdge(['nodeId', 'otherId'], {
5510           type: 'fade:seq',
5511           duration: 1000,
5512           hideLabels: false,
5513           transition: $jit.Trans.Quart.easeOut
5514         });
5515         //or also
5516         viz.op.removeEdge([['someId', 'otherId'], ['id3', 'id4']], {
5517           type: 'fade:con',
5518           duration: 1500
5519         });
5520       (end code)
5521     
5522     */
5523     removeEdge: function(vertex, opt) {
5524         var viz = this.viz;
5525         var options = $.merge(this.options, viz.controller, opt);
5526         var v = ($.type(vertex[0]) == 'string')? [vertex] : vertex;
5527         var i, that, adj;
5528         switch(options.type) {
5529             case 'nothing':
5530                 for(i=0; i<v.length; i++)   viz.graph.removeAdjacence(v[i][0], v[i][1]);
5531                 break;
5532             
5533             case 'replot':
5534                 this.removeEdge(v, { type: 'nothing' });
5535                 viz.refresh(true);
5536                 break;
5537             
5538             case 'fade:seq': case 'fade':
5539                 that = this;
5540                 //set alpha to 0 for edges to remove.
5541                 for(i=0; i<v.length; i++) {
5542                     adj = viz.graph.getAdjacence(v[i][0], v[i][1]);
5543                     if(adj) {
5544                         adj.setData('alpha', 0,'end');
5545                     }
5546                 }
5547                 viz.fx.animate($.merge(options, {
5548                     modes: ['edge-property:alpha'],
5549                     onComplete: function() {
5550                         that.removeEdge(v, { type: 'nothing' });
5551                         viz.reposition();
5552                         viz.fx.animate($.merge(options, {
5553                             modes: ['linear']
5554                         }));
5555                     }
5556                 }));
5557                 break;
5558             
5559             case 'fade:con':
5560                 that = this;
5561                 //set alpha to 0 for nodes to remove. Tag them for being ignored when computing positions.
5562                 for(i=0; i<v.length; i++) {
5563                     adj = viz.graph.getAdjacence(v[i][0], v[i][1]);
5564                     if(adj) {
5565                         adj.setData('alpha',0 ,'end');
5566                         adj.ignore = true;
5567                     }
5568                 }
5569                 viz.reposition();
5570                 viz.fx.animate($.merge(options, {
5571                     modes: ['edge-property:alpha', 'linear'],
5572                     onComplete: function() {
5573                         that.removeEdge(v, { type: 'nothing' });
5574                         options.onComplete && options.onComplete();
5575                     }
5576                 }));
5577                 break;
5578             
5579             case 'iter':
5580                 that = this;
5581                 viz.fx.sequence({
5582                     condition: function() { return v.length != 0; },
5583                     step: function() { that.removeEdge(v.shift(), { type: 'nothing' }); viz.labels.clearLabels(); },
5584                     onComplete: function() { options.onComplete(); },
5585                     duration: Math.ceil(options.duration / v.length)
5586                 });
5587                 break;
5588                 
5589             default: this.doError();
5590         }
5591     },
5592     
5593     /*
5594        Method: sum
5595     
5596        Adds a new graph to the visualization. 
5597        The JSON graph (or tree) must at least have a common node with the current graph plotted by the visualization. 
5598        The resulting graph can be defined as follows <http://mathworld.wolfram.com/GraphSum.html>
5599
5600        Parameters:
5601     
5602        json - (object) A json tree or graph structure. See also <Loader.loadJSON>.
5603        opt - (object) Animation options. It's an object with optional properties described below
5604        type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:seq",  "fade:con".
5605        duration - Described in <Options.Fx>.
5606        fps - Described in <Options.Fx>.
5607        transition - Described in <Options.Fx>.
5608        hideLabels - (boolean) Default's *true*. Hide labels during the animation.
5609    
5610       Example:
5611       (start code js)
5612         //...json contains a tree or graph structure...
5613
5614         var viz = new $jit.Viz(options);
5615         viz.op.sum(json, {
5616           type: 'fade:seq',
5617           duration: 1000,
5618           hideLabels: false,
5619           transition: $jit.Trans.Quart.easeOut
5620         });
5621         //or also
5622         viz.op.sum(json, {
5623           type: 'fade:con',
5624           duration: 1500
5625         });
5626       (end code)
5627     
5628     */
5629     sum: function(json, opt) {
5630         var viz = this.viz;
5631         var options = $.merge(this.options, viz.controller, opt), root = viz.root;
5632         var graph;
5633         viz.root = opt.id || viz.root;
5634         switch(options.type) {
5635             case 'nothing':
5636                 graph = viz.construct(json);
5637                 graph.eachNode(function(elem) {
5638                     elem.eachAdjacency(function(adj) {
5639                         viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
5640                     });
5641                 });
5642                 break;
5643             
5644             case 'replot':
5645                 viz.refresh(true);
5646                 this.sum(json, { type: 'nothing' });
5647                 viz.refresh(true);
5648                 break;
5649             
5650             case 'fade:seq': case 'fade': case 'fade:con':
5651                 that = this;
5652                 graph = viz.construct(json);
5653
5654                 //set alpha to 0 for nodes to add.
5655                 var fadeEdges = this.preprocessSum(graph);
5656                 var modes = !fadeEdges? ['node-property:alpha'] : ['node-property:alpha', 'edge-property:alpha'];
5657                 viz.reposition();
5658                 if(options.type != 'fade:con') {
5659                     viz.fx.animate($.merge(options, {
5660                         modes: ['linear'],
5661                         onComplete: function() {
5662                             viz.fx.animate($.merge(options, {
5663                                 modes: modes,
5664                                 onComplete: function() {
5665                                     options.onComplete();
5666                                 }
5667                             }));
5668                         }
5669                     }));
5670                 } else {
5671                     viz.graph.eachNode(function(elem) {
5672                         if (elem.id != root && elem.pos.isZero()) {
5673                           elem.pos.set(elem.endPos); 
5674                           elem.startPos.set(elem.endPos);
5675                         }
5676                     });
5677                     viz.fx.animate($.merge(options, {
5678                         modes: ['linear'].concat(modes)
5679                     }));
5680                 }
5681                 break;
5682
5683             default: this.doError();
5684         }
5685     },
5686     
5687     /*
5688        Method: morph
5689     
5690        This method will transform the current visualized graph into the new JSON representation passed in the method. 
5691        The JSON object must at least have the root node in common with the current visualized graph.
5692
5693        Parameters:
5694     
5695        json - (object) A json tree or graph structure. See also <Loader.loadJSON>.
5696        opt - (object) Animation options. It's an object with optional properties described below
5697        type - (string) Default's *nothing*. Type of the animation. Can be "nothing", "replot", "fade:con".
5698        duration - Described in <Options.Fx>.
5699        fps - Described in <Options.Fx>.
5700        transition - Described in <Options.Fx>.
5701        hideLabels - (boolean) Default's *true*. Hide labels during the animation.
5702        id - (string) The shared <Graph.Node> id between both graphs.
5703        
5704        extraModes - (optional|object) When morphing with an animation, dollar prefixed data parameters are added to 
5705                     *endData* and not *data* itself. This way you can animate dollar prefixed parameters during your morphing operation. 
5706                     For animating these extra-parameters you have to specify an object that has animation groups as keys and animation 
5707                     properties as values, just like specified in <Graph.Plot.animate>.
5708    
5709       Example:
5710       (start code js)
5711         //...json contains a tree or graph structure...
5712
5713         var viz = new $jit.Viz(options);
5714         viz.op.morph(json, {
5715           type: 'fade',
5716           duration: 1000,
5717           hideLabels: false,
5718           transition: $jit.Trans.Quart.easeOut
5719         });
5720         //or also
5721         viz.op.morph(json, {
5722           type: 'fade',
5723           duration: 1500
5724         });
5725         //if the json data contains dollar prefixed params
5726         //like $width or $height these too can be animated
5727         viz.op.morph(json, {
5728           type: 'fade',
5729           duration: 1500
5730         }, {
5731           'node-property': ['width', 'height']
5732         });
5733       (end code)
5734     
5735     */
5736     morph: function(json, opt, extraModes) {
5737         extraModes = extraModes || {};
5738         var viz = this.viz;
5739         var options = $.merge(this.options, viz.controller, opt), root = viz.root;
5740         var graph;
5741         //TODO(nico) this hack makes morphing work with the Hypertree. 
5742         //Need to check if it has been solved and this can be removed.
5743         viz.root = opt.id || viz.root;
5744         switch(options.type) {
5745             case 'nothing':
5746                 graph = viz.construct(json);
5747                 graph.eachNode(function(elem) {
5748                   var nodeExists = viz.graph.hasNode(elem.id);  
5749                   elem.eachAdjacency(function(adj) {
5750                     var adjExists = !!viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
5751                     viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
5752                     //Update data properties if the node existed
5753                     if(adjExists) {
5754                       var addedAdj = viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
5755                       for(var prop in (adj.data || {})) {
5756                         addedAdj.data[prop] = adj.data[prop];
5757                       }
5758                     }
5759                   });
5760                   //Update data properties if the node existed
5761                   if(nodeExists) {
5762                     var addedNode = viz.graph.getNode(elem.id);
5763                     for(var prop in (elem.data || {})) {
5764                       addedNode.data[prop] = elem.data[prop];
5765                     }
5766                   }
5767                 });
5768                 viz.graph.eachNode(function(elem) {
5769                     elem.eachAdjacency(function(adj) {
5770                         if(!graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id)) {
5771                             viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
5772                         }
5773                     });
5774                     if(!graph.hasNode(elem.id)) viz.graph.removeNode(elem.id);
5775                 });
5776                 
5777                 break;
5778             
5779             case 'replot':
5780                 viz.labels.clearLabels(true);
5781                 this.morph(json, { type: 'nothing' });
5782                 viz.refresh(true);
5783                 viz.refresh(true);
5784                 break;
5785                 
5786             case 'fade:seq': case 'fade': case 'fade:con':
5787                 that = this;
5788                 graph = viz.construct(json);
5789                 //preprocessing for nodes to delete.
5790                 //get node property modes to interpolate
5791                 var nodeModes = ('node-property' in extraModes) 
5792                   && $.map($.splat(extraModes['node-property']), 
5793                       function(n) { return '$' + n; });
5794                 viz.graph.eachNode(function(elem) {
5795                   var graphNode = graph.getNode(elem.id);   
5796                   if(!graphNode) {
5797                       elem.setData('alpha', 1);
5798                       elem.setData('alpha', 1, 'start');
5799                       elem.setData('alpha', 0, 'end');
5800                       elem.ignore = true;
5801                     } else {
5802                       //Update node data information
5803                       var graphNodeData = graphNode.data;
5804                       for(var prop in graphNodeData) {
5805                         if(nodeModes && ($.indexOf(nodeModes, prop) > -1)) {
5806                           elem.endData[prop] = graphNodeData[prop];
5807                         } else {
5808                           elem.data[prop] = graphNodeData[prop];
5809                         }
5810                       }
5811                     }
5812                 }); 
5813                 viz.graph.eachNode(function(elem) {
5814                     if(elem.ignore) return;
5815                     elem.eachAdjacency(function(adj) {
5816                         if(adj.nodeFrom.ignore || adj.nodeTo.ignore) return;
5817                         var nodeFrom = graph.getNode(adj.nodeFrom.id);
5818                         var nodeTo = graph.getNode(adj.nodeTo.id);
5819                         if(!nodeFrom.adjacentTo(nodeTo)) {
5820                             var adj = viz.graph.getAdjacence(nodeFrom.id, nodeTo.id);
5821                             fadeEdges = true;
5822                             adj.setData('alpha', 1);
5823                             adj.setData('alpha', 1, 'start');
5824                             adj.setData('alpha', 0, 'end');
5825                             adj._hiding = true;
5826                         } else if (adj.data.$direction && adj.data.$direction[0] === nodeFrom.id) {
5827                             // only check one direction (from -> to)
5828                             if (!nodeFrom.adjacentWithDirectionTo(nodeTo)) {
5829                                 adj._reversing = true;
5830                             }
5831                         }
5832                     });
5833                 }); 
5834                 //preprocessing for adding nodes.
5835                 var fadeEdges = this.preprocessSum(graph);
5836
5837                 var modes = !fadeEdges? ['node-property:alpha'] : 
5838                                         ['node-property:alpha', 
5839                                          'edge-property:alpha'];
5840                 //Append extra node-property animations (if any)
5841                 modes[0] = modes[0] + (('node-property' in extraModes)? 
5842                     (':' + $.splat(extraModes['node-property']).join(':')) : '');
5843                 //Append extra edge-property animations (if any)
5844                 modes[1] = (modes[1] || 'edge-property:alpha') + (('edge-property' in extraModes)? 
5845                     (':' + $.splat(extraModes['edge-property']).join(':')) : '');
5846                 //Add label-property animations (if any)
5847                 if('label-property' in extraModes) {
5848                   modes.push('label-property:' + $.splat(extraModes['label-property']).join(':'))
5849                 }
5850                 //only use reposition if its implemented.
5851                 if (viz.reposition) {
5852                   viz.reposition();
5853                 } else {
5854                   viz.compute('end');
5855                 }
5856                 this._updateDirectedEdges();
5857
5858                 viz.graph.eachNode(function(elem) {
5859                     if (elem.id != root && elem.pos.getp().equals(Polar.KER)) {
5860                       elem.pos.set(elem.endPos); elem.startPos.set(elem.endPos);
5861                     }
5862                 });
5863                 viz.fx.animate($.merge(options, {
5864                     modes: [extraModes.position || 'polar'].concat(modes),
5865                     onComplete: function() {
5866                         viz.graph.eachNode(function(elem) {
5867                             if(elem.ignore) viz.graph.removeNode(elem.id);
5868                         });
5869                         viz.graph.eachNode(function(elem) {
5870                             elem.eachAdjacency(function(adj) {
5871                                 if(adj.ignore) viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
5872                             });
5873                         });
5874                         options.onComplete();
5875                     }
5876                 }));
5877                 break;
5878
5879             default:;
5880         }
5881     },
5882
5883     _updateDirectedEdges: function () {
5884         var graph = this.viz.graph;
5885         graph.eachNode(function(node) {
5886             node.eachAdjacency(function (adj) {
5887
5888                 var isDirectedEdge = adj.data.$direction;
5889                 if (isDirectedEdge && adj.nodeFrom.id !== adj.data.$direction[0]) {
5890                     return;
5891                 }
5892
5893                 if (adj._hiding) {
5894                     graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
5895                 }
5896
5897                 if (adj._reversing) {
5898                     var from = adj.nodeFrom.id;
5899                     var to = adj.nodeTo.id;
5900 //
5901 //                    // swap instead of adding and removing
5902                     var edge1 = graph.edges[from][to];
5903                     var edge2 = graph.edges[to][from];
5904
5905                     edge1.data.$direction = [to, from];
5906                     edge2.data.$direction = [to, from];
5907
5908                     adj._reversing = undefined;
5909                 }
5910             });
5911         });
5912     },
5913     
5914   /*
5915     Method: contract
5916  
5917     Collapses the subtree of the given node. The node will have a _collapsed=true_ property.
5918     
5919     Parameters:
5920  
5921     node - (object) A <Graph.Node>.
5922     opt - (object) An object containing options described below
5923     type - (string) Whether to 'replot' or 'animate' the contraction.
5924    
5925     There are also a number of Animation options. For more information see <Options.Fx>.
5926
5927     Example:
5928     (start code js)
5929      var viz = new $jit.Viz(options);
5930      viz.op.contract(node, {
5931        type: 'animate',
5932        duration: 1000,
5933        hideLabels: true,
5934        transition: $jit.Trans.Quart.easeOut
5935      });
5936    (end code)
5937  
5938    */
5939     contract: function(node, opt) {
5940       var viz = this.viz;
5941       if(node.collapsed || !node.anySubnode($.lambda(true))) return;
5942       opt = $.merge(this.options, viz.config, opt || {}, {
5943         'modes': ['node-property:alpha:span', 'linear']
5944       });
5945       node.collapsed = true;
5946       (function subn(n) {
5947         n.eachSubnode(function(ch) {
5948           ch.ignore = true;
5949           ch.setData('alpha', 0, opt.type == 'animate'? 'end' : 'current');
5950           subn(ch);
5951         });
5952       })(node);
5953       if(opt.type == 'animate') {
5954         viz.compute('end');
5955         if(viz.rotated) {
5956           viz.rotate(viz.rotated, 'none', {
5957             'property':'end'
5958           });
5959         }
5960         (function subn(n) {
5961           n.eachSubnode(function(ch) {
5962             ch.setPos(node.getPos('end'), 'end');
5963             subn(ch);
5964           });
5965         })(node);
5966         viz.fx.animate(opt);
5967       } else if(opt.type == 'replot'){
5968         viz.refresh();
5969       }
5970     },
5971     
5972     /*
5973     Method: expand
5974  
5975     Expands the previously contracted subtree. The given node must have the _collapsed=true_ property.
5976     
5977     Parameters:
5978  
5979     node - (object) A <Graph.Node>.
5980     opt - (object) An object containing options described below
5981     type - (string) Whether to 'replot' or 'animate'.
5982      
5983     There are also a number of Animation options. For more information see <Options.Fx>.
5984
5985     Example:
5986     (start code js)
5987       var viz = new $jit.Viz(options);
5988       viz.op.expand(node, {
5989         type: 'animate',
5990         duration: 1000,
5991         hideLabels: true,
5992         transition: $jit.Trans.Quart.easeOut
5993       });
5994     (end code)
5995  
5996    */
5997     expand: function(node, opt) {
5998       if(!('collapsed' in node)) return;
5999       var viz = this.viz;
6000       opt = $.merge(this.options, viz.config, opt || {}, {
6001         'modes': ['node-property:alpha:span', 'linear']
6002       });
6003       delete node.collapsed;
6004       (function subn(n) {
6005         n.eachSubnode(function(ch) {
6006           delete ch.ignore;
6007           ch.setData('alpha', 1, opt.type == 'animate'? 'end' : 'current');
6008           subn(ch);
6009         });
6010       })(node);
6011       if(opt.type == 'animate') {
6012         viz.compute('end');
6013         if(viz.rotated) {
6014           viz.rotate(viz.rotated, 'none', {
6015             'property':'end'
6016           });
6017         }
6018         viz.fx.animate(opt);
6019       } else if(opt.type == 'replot'){
6020         viz.refresh();
6021       }
6022     },
6023
6024     preprocessSum: function(graph) {
6025         var viz = this.viz;
6026         graph.eachNode(function(elem) {
6027             if(!viz.graph.hasNode(elem.id)) {
6028                 viz.graph.addNode(elem);
6029                 var n = viz.graph.getNode(elem.id);
6030                 n.setData('alpha', 0);
6031                 n.setData('alpha', 0, 'start');
6032                 n.setData('alpha', 1, 'end');
6033             }
6034         }); 
6035         var fadeEdges = false;
6036         graph.eachNode(function(elem) {
6037             elem.eachAdjacency(function(adj) {
6038                 var nodeFrom = viz.graph.getNode(adj.nodeFrom.id);
6039                 var nodeTo = viz.graph.getNode(adj.nodeTo.id);
6040                 if(!nodeFrom.adjacentTo(nodeTo)) {
6041                     var adj = viz.graph.addAdjacence(nodeFrom, nodeTo, adj.data);
6042                     if(nodeFrom.startAlpha == nodeFrom.endAlpha 
6043                     && nodeTo.startAlpha == nodeTo.endAlpha) {
6044                         fadeEdges = true;
6045                         adj.setData('alpha', 0);
6046                         adj.setData('alpha', 0, 'start');
6047                         adj.setData('alpha', 1, 'end');
6048                     } 
6049                 }
6050             });
6051         }); 
6052         return fadeEdges;
6053     }
6054 };
6055
6056
6057
6058 /*
6059  File: Helpers.js
6060
6061  Helpers are objects that contain rendering primitives (like rectangles, ellipses, etc), for plotting nodes and edges.
6062  Helpers also contain implementations of the *contains* method, a method returning a boolean indicating whether the mouse
6063  position is over the rendered shape.
6064
6065  Helpers are very useful when implementing new NodeTypes, since you can access them through *this.nodeHelper* and
6066  *this.edgeHelper* <Graph.Plot> properties, providing you with simple primitives and mouse-position check functions.
6067
6068  Example:
6069  (start code js)
6070  //implement a new node type
6071  $jit.Viz.Plot.NodeTypes.implement({
6072  'customNodeType': {
6073  'render': function(node, canvas) {
6074  this.nodeHelper.circle.render ...
6075  },
6076  'contains': function(node, pos) {
6077  this.nodeHelper.circle.contains ...
6078  }
6079  }
6080  });
6081  //implement an edge type
6082  $jit.Viz.Plot.EdgeTypes.implement({
6083  'customNodeType': {
6084  'render': function(node, canvas) {
6085  this.edgeHelper.circle.render ...
6086  },
6087  //optional
6088  'contains': function(node, pos) {
6089  this.edgeHelper.circle.contains ...
6090  }
6091  }
6092  });
6093  (end code)
6094
6095  */
6096
6097 /*
6098  Object: NodeHelper
6099
6100  Contains rendering and other type of primitives for simple shapes.
6101  */
6102 var MultiNodeHelper = {
6103     'none': {
6104         'render': $.empty,
6105         'contains': $.lambda(false)
6106     },
6107         'host': {
6108                 'render': function(pos, canvas, animating) {
6109                         var ctx = canvas.getCtx();
6110                         var img = new Image();
6111                         img.src='../img/Device_pc_3045_default_64.png';
6112                         if(animating == false) {
6113                                 img.onload = function() {
6114                                         ctx.drawImage(img,pos.x-32,pos.y-32);
6115                                 };
6116                         } else {
6117                                 ctx.drawImage(img,pos.x-32,pos.y-32);
6118                         }
6119                         /*var width = 64, height = 55;
6120                         ctx.fillStyle = "rgba(0,0,0,0)";
6121                         ctx.fillRect(pos.x - width / 2, pos.y - height / 2, width, height);*/
6122                 },
6123                 'contains': function(npos, pos) {
6124                         var width = 64, height = 55;
6125                         return Math.abs(pos.x - npos.x) <= width / 2
6126                                 && Math.abs(pos.y - npos.y) <= height / 2;
6127                 }
6128         },
6129         'swtch': {
6130                 'render': function(pos, canvas, animating) {
6131                         var ctx = canvas.getCtx();
6132                         var img = new Image();
6133                         img.src='../img/Device_switch_3062_unknown_64.png';
6134                         if(animating == false) {
6135                                 img.onload = function() {
6136                                         ctx.drawImage(img,pos.x-32,pos.y-32);
6137                                 };
6138                         } else {
6139                                 ctx.drawImage(img,pos.x-32,pos.y-32);
6140                         }
6141                         /*var width = 64, height = 45;
6142                         ctx.fillStyle = "rgba(0,0,0,0)";
6143                         ctx.fillRect(pos.x - width / 2, pos.y - height / 2, width, height);*/
6144                 },
6145                 'contains': function(npos, pos) {
6146                         var width = 64, height = 45;
6147                         return Math.abs(pos.x - npos.x) <= width / 2
6148                                 && Math.abs(pos.y - npos.y) <= height / 2;
6149                 }
6150         }
6151 };
6152
6153 /*
6154  Object: EdgeHelper
6155
6156  Contains rendering primitives for simple edge shapes.
6157  */
6158 var MultiEdgeHelper = {
6159     /*
6160      Object: EdgeHelper.line
6161      */
6162     'line': {
6163         /*
6164          Method: render
6165
6166          Renders a line into the canvas.
6167
6168          Parameters:
6169
6170          from - (object) An *x*, *y* object with the starting position of the line.
6171          to - (object) An *x*, *y* object with the ending position of the line.
6172          canvas - (object) A <Canvas> instance.
6173
6174          Example:
6175          (start code js)
6176          EdgeHelper.line.render({ x: 10, y: 30 }, { x: 10, y: 50 }, viz.canvas);
6177          (end code)
6178          */
6179         'render': function(from, to, alpha, canvas){
6180                         alpha *= 8;
6181             var ctx = canvas.getCtx();
6182                         ctx.beginPath();
6183             
6184                         // trig path
6185                         dx = from.x-to.x; dy = from.y-to.y;
6186                         tan = Math.atan(dx/dy);
6187                         cos = (-1)*Math.cos(tan);
6188                         sin = Math.sin(tan);
6189
6190                         // draw the line
6191             ctx.moveTo(from.x+(alpha*cos), from.y+(alpha*sin));
6192             ctx.lineTo(to.x+(alpha*cos), to.y+(alpha*sin));
6193             ctx.stroke();
6194         },
6195         /*
6196          Method: contains
6197
6198          Returns *true* if *pos* is contained in the area of the shape. Returns *false* otherwise.
6199
6200          Parameters:
6201
6202          posFrom - (object) An *x*, *y* object with a <Graph.Node> position.
6203          posTo - (object) An *x*, *y* object with a <Graph.Node> position.
6204          pos - (object) An *x*, *y* object with the position to check.
6205          epsilon - (number) The dimension of the shape.
6206
6207          Example:
6208          (start code js)
6209          EdgeHelper.line.contains({ x: 10, y: 30 }, { x: 15, y: 35 }, { x: 15, y: 35 }, 30);
6210          (end code)
6211          */
6212         'contains': function(posFrom, posTo, alpha, pos, epsilon, canvas) {
6213                         alpha *= 8;
6214                         var ctx = canvas.getCtx();
6215                         ctx.save();
6216                         ctx.beginPath();
6217
6218                         // trig path
6219                         dx = posFrom.x-posTo.x; dy = posFrom.y-posTo.y;
6220                         tan = Math.atan(dx/dy);
6221                         cos = (-1)*Math.cos(tan);
6222                         sin = Math.sin(tan);
6223
6224                         // draw rect
6225                         var width = 2.5;
6226                         ctx.moveTo(posFrom.x+((alpha-width)*cos), posFrom.y+((alpha-width)*sin));
6227                         ctx.lineTo(posTo.x+((alpha-width)*cos), posTo.y+((alpha-width)*sin));
6228                         ctx.lineTo(posTo.x+((alpha+width)*cos), posTo.y+((alpha+width)*sin));
6229                         ctx.lineTo(posFrom.x+((alpha+width)*cos), posFrom.y+((alpha+width)*sin));
6230
6231                         // check if point is in path
6232                         ox = ctx.canvas.offsetWidth/2;
6233                         oy = ctx.canvas.offsetHeight/2;
6234                         sx = canvas.scaleOffsetX;
6235                         sy = canvas.scaleOffsetY;
6236                         tx = canvas.translateOffsetX;
6237                         ty = canvas.translateOffsetY;
6238                         if (ctx.isPointInPath((tx+ox+pos.x*sx), (ty+oy+pos.y*sy))) {
6239                                 ctx.restore();
6240                                 return true;
6241                         }
6242
6243                         ctx.restore();
6244                         return false;
6245         }
6246     }
6247 };
6248
6249
6250         /*
6251  * File: Graph.Plot.js
6252  */
6253
6254 /*
6255    Object: Graph.Plot
6256
6257    <Graph> rendering and animation methods.
6258    
6259    Properties:
6260    
6261    nodeHelper - <NodeHelper> object.
6262    edgeHelper - <EdgeHelper> object.
6263 */
6264 MultiGraph.Plot = {
6265     //Default initializer
6266     initialize: function(viz, klass){
6267       this.viz = viz;
6268       this.config = viz.config;
6269       this.node = viz.config.Node;
6270       this.edge = viz.config.Edge;
6271       this.animation = new Animation;
6272       this.nodeTypes = new klass.Plot.NodeTypes;
6273       this.edgeTypes = new klass.Plot.EdgeTypes;
6274       this.labels = viz.labels;
6275    },
6276
6277     //Add helpers
6278     nodeHelper: MultiNodeHelper,
6279     edgeHelper: MultiEdgeHelper,
6280     
6281     Interpolator: {
6282         //node/edge property parsers
6283         'map': {
6284           'border': 'color',
6285           'color': 'color',
6286           'width': 'number',
6287           'height': 'number',
6288           'dim': 'number',
6289           'alpha': 'number',
6290           'lineWidth': 'number',
6291           'angularWidth':'number',
6292           'span':'number',
6293           'valueArray':'array-number',
6294           'dimArray':'array-number',
6295           'vertices':'polygon'
6296           //'colorArray':'array-color'
6297         },
6298
6299         //canvas specific parsers
6300         'canvas': {
6301           'globalAlpha': 'number',
6302           'fillStyle': 'color',
6303           'strokeStyle': 'color',
6304           'lineWidth': 'number',
6305           'shadowBlur': 'number',
6306           'shadowColor': 'color',
6307           'shadowOffsetX': 'number',
6308           'shadowOffsetY': 'number',
6309           'miterLimit': 'number'
6310         },
6311
6312         //label parsers
6313         'label': {
6314           'size': 'number',
6315           'color': 'color'
6316         },
6317
6318         //Number interpolator
6319         'compute': function(from, to, delta) {
6320           return from + (to - from) * delta;
6321         },
6322
6323         //Position interpolators
6324         'moebius': function(elem, props, delta, vector) {
6325           var v = vector.scale(-delta);
6326           if(v.norm() < 1) {
6327               var x = v.x, y = v.y;
6328               var ans = elem.startPos
6329                 .getc().moebiusTransformation(v);
6330               elem.pos.setc(ans.x, ans.y);
6331               v.x = x; v.y = y;
6332             }
6333         },
6334
6335         'linear': function(elem, props, delta) {
6336             var from = elem.startPos.getc(true);
6337             var to = elem.endPos.getc(true);
6338             elem.pos.setc(this.compute(from.x, to.x, delta),
6339                           this.compute(from.y, to.y, delta));
6340         },
6341
6342         'polar': function(elem, props, delta) {
6343           var from = elem.startPos.getp(true);
6344           var to = elem.endPos.getp();
6345           var ans = to.interpolate(from, delta);
6346           elem.pos.setp(ans.theta, ans.rho);
6347         },
6348
6349         //Graph's Node/Edge interpolators
6350         'number': function(elem, prop, delta, getter, setter) {
6351                         var from, to;
6352                         if(Array.isArray(elem)) { // for multi-links
6353                                 for(var e in elem) {
6354                                         var ee = elem[e];
6355                                         from = ee[getter](prop, 'start');
6356                                         to = ee[getter](prop, 'end');
6357                                         if (from != to) {
6358                                                 elem = ee;
6359                                                 break;
6360                                         }
6361                                 }
6362                                 if(Array.isArray(elem)) return;
6363                         } else { // for nodes
6364                           from = elem[getter](prop, 'start');
6365                           to = elem[getter](prop, 'end');
6366                     }
6367                         elem[setter](prop, this.compute(from, to, delta));
6368         },
6369
6370         'color': function(elem, prop, delta, getter, setter) {
6371                           var from, to;
6372                           if(Array.isArray(elem)) { // for multi-links
6373                                 for(var e in elem) {
6374                                         var ee = elem[e];
6375                                         from = $.hexToRgb(ee[getter](prop, 'start'));
6376                                         to = $.hexToRgb(ee[getter](prop, 'end'));
6377                                         if(from[0] != to[0] || from[1] != to[1] || from[2] != to[2]) {
6378                                                 elem = ee;
6379                                                 break;
6380                                         }
6381                                 }
6382                                 if(Array.isArray(elem)) return;
6383                           } else { // for nodes
6384                                   var from = $.hexToRgb(elem[getter](prop, 'start'));
6385                                   var to = $.hexToRgb(elem[getter](prop, 'end'));
6386                           }
6387                           var comp = this.compute;
6388                           var val = $.rgbToHex([parseInt(comp(from[0], to[0], delta)),
6389                                                                         parseInt(comp(from[1], to[1], delta)),
6390                                                                         parseInt(comp(from[2], to[2], delta))]);
6391                           elem[setter](prop, val);
6392         },
6393
6394         'array-number': function(elem, prop, delta, getter, setter) {
6395           var from = elem[getter](prop, 'start'),
6396               to = elem[getter](prop, 'end'),
6397               cur = [];
6398           for(var i=0, l=from.length; i<l; i++) {
6399             var fromi = from[i], toi = to[i];
6400             if(fromi.length) {
6401               for(var j=0, len=fromi.length, curi=[]; j<len; j++) {
6402                 curi.push(this.compute(fromi[j], toi[j], delta));
6403               }
6404               cur.push(curi);
6405             } else {
6406               cur.push(this.compute(fromi, toi, delta));
6407             }
6408           }
6409           elem[setter](prop, cur);
6410         },
6411
6412         'node': function(elem, props, delta, map, getter, setter) {
6413           map = this[map];
6414           if(props) {
6415             var len = props.length;
6416             for(var i=0; i<len; i++) {
6417               var pi = props[i];
6418               this[map[pi]](elem, pi, delta, getter, setter);
6419             }
6420           } else {
6421             for(var pi in map) {
6422               this[map[pi]](elem, pi, delta, getter, setter);
6423             }
6424           }
6425         },
6426
6427         'edge': function(elem, props, delta, mapKey, getter, setter) {
6428             var adjs = elem.adjacencies;
6429             for(var id in adjs) this['node'](adjs[id], props, delta, mapKey, getter, setter);
6430         },
6431
6432         'node-property': function(elem, props, delta) {
6433           this['node'](elem, props, delta, 'map', 'getData', 'setData');
6434         },
6435
6436         'edge-property': function(elem, props, delta) {
6437           this['edge'](elem, props, delta, 'map', 'getData', 'setData');
6438         },
6439
6440         'label-property': function(elem, props, delta) {
6441           this['node'](elem, props, delta, 'label', 'getLabelData', 'setLabelData');
6442         },
6443
6444         'node-style': function(elem, props, delta) {
6445           this['node'](elem, props, delta, 'canvas', 'getCanvasStyle', 'setCanvasStyle');
6446         },
6447
6448         'edge-style': function(elem, props, delta) {
6449           this['edge'](elem, props, delta, 'canvas', 'getCanvasStyle', 'setCanvasStyle');
6450         },
6451
6452         'polygon': function(elem, prop, delta, getter, setter) {
6453           var from = elem[getter](prop, 'start'),
6454               to = elem[getter](prop, 'end'),
6455               cur = [];
6456           if (typeof from.offset == 'undefined') {
6457             if (from === 0) {
6458               from = $.map(to, function() {
6459                 return new $jit.Complex(0, 0);
6460               });
6461               from.offset = 0;
6462             }
6463             else {
6464               if (from.length == 0) {
6465                 from.push(new $jit.Complex(0, 0));
6466               }
6467               while (from.length < to.length) {
6468                 from.push(from[0]);
6469               }
6470               while (from.length > to.length) {
6471                 to.push(to[0] || new $jit.Complex(0, 0));
6472               }
6473               if (from.length == 0) return;
6474               var l = from.length;
6475               var minDist = 1e300;
6476               for (var offset = 0; offset < l; offset ++) {
6477                 var d = 0;
6478                 for (var i = 0; i < l; i++) {
6479                   d +=Geometry.dist2(from[(offset + i) % l], to[i]);
6480                 }
6481                 if (d < minDist) {
6482                   from.offset = offset;
6483                   minDist = d;
6484                 }
6485               }
6486             }
6487           }
6488
6489           for (var i = 0, l = from.length; i < l; i++) {
6490             var fromi = from[(i + from.offset) % l], toi = to[i];
6491             cur.push(new $jit.Complex(
6492                 this.compute(fromi.x, toi.x, delta),
6493                 this.compute(fromi.y, toi.y, delta)
6494             ));
6495           }
6496           elem[setter](prop, cur);
6497         }
6498     },
6499     
6500   
6501     /*
6502        sequence
6503     
6504        Iteratively performs an action while refreshing the state of the visualization.
6505
6506        Parameters:
6507
6508        options - (object) An object containing some sequence options described below
6509        condition - (function) A function returning a boolean instance in order to stop iterations.
6510        step - (function) A function to execute on each step of the iteration.
6511        onComplete - (function) A function to execute when the sequence finishes.
6512        duration - (number) Duration (in milliseconds) of each step.
6513
6514       Example:
6515        (start code js)
6516         var rg = new $jit.RGraph(options);
6517         var i = 0;
6518         rg.fx.sequence({
6519           condition: function() {
6520            return i == 10;
6521           },
6522           step: function() {
6523             alert(i++);
6524           },
6525           onComplete: function() {
6526            alert('done!');
6527           }
6528         });
6529        (end code)
6530
6531     */
6532     sequence: function(options) {
6533         var that = this;
6534         options = $.merge({
6535           condition: $.lambda(false),
6536           step: $.empty,
6537           onComplete: $.empty,
6538           duration: 200
6539         }, options || {});
6540
6541         var interval = setInterval(function() {
6542           if(options.condition()) {
6543             options.step();
6544           } else {
6545             clearInterval(interval);
6546             options.onComplete();
6547           }
6548           that.viz.refresh(true);
6549         }, options.duration);
6550     },
6551     
6552     /*
6553       prepare
6554  
6555       Prepare graph position and other attribute values before performing an Animation. 
6556       This method is used internally by the Toolkit.
6557       
6558       See also:
6559        
6560        <Animation>, <Graph.Plot.animate>
6561
6562     */
6563     prepare: function(modes) {
6564       var graph = this.viz.graph,
6565           accessors = {
6566             'node-property': {
6567               'getter': 'getData',
6568               'setter': 'setData'
6569             },
6570             'edge-property': {
6571               'getter': 'getData',
6572               'setter': 'setData'
6573             },
6574             'node-style': {
6575               'getter': 'getCanvasStyle',
6576               'setter': 'setCanvasStyle'
6577             },
6578             'edge-style': {
6579               'getter': 'getCanvasStyle',
6580               'setter': 'setCanvasStyle'
6581             }
6582           };
6583
6584       //parse modes
6585       var m = {};
6586       if($.type(modes) == 'array') {
6587         for(var i=0, len=modes.length; i < len; i++) {
6588           var elems = modes[i].split(':');
6589           m[elems.shift()] = elems;
6590         }
6591       } else {
6592         for(var p in modes) {
6593           if(p == 'position') {
6594             m[modes.position] = [];
6595           } else {
6596             m[p] = $.splat(modes[p]);
6597           }
6598         }
6599       }
6600       
6601       graph.eachNode(function(node) { 
6602         node.startPos.set(node.pos);
6603         $.each(['node-property', 'node-style'], function(p) {
6604           if(p in m) {
6605             var prop = m[p];
6606             for(var i=0, l=prop.length; i < l; i++) {
6607               node[accessors[p].setter](prop[i], node[accessors[p].getter](prop[i]), 'start');
6608             }
6609           }
6610         });
6611         $.each(['edge-property', 'edge-style'], function(p) {
6612           if(p in m) {
6613             var prop = m[p];
6614             node.eachAdjacency(function(adj) {
6615               for(var i=0, l=prop.length; i < l; i++) {
6616                 adj[accessors[p].setter](prop[i], adj[accessors[p].getter](prop[i]), 'start');
6617               }
6618             });
6619           }
6620         });
6621       });
6622       return m;
6623     },
6624     
6625     /*
6626        Method: animate
6627     
6628        Animates a <Graph> by interpolating some <Graph.Node>, <Graph.Adjacence> or <Graph.Label> properties.
6629
6630        Parameters:
6631
6632        opt - (object) Animation options. The object properties are described below
6633        duration - (optional) Described in <Options.Fx>.
6634        fps - (optional) Described in <Options.Fx>.
6635        hideLabels - (optional|boolean) Whether to hide labels during the animation.
6636        modes - (required|object) An object with animation modes (described below).
6637
6638        Animation modes:
6639        
6640        Animation modes are strings representing different node/edge and graph properties that you'd like to animate. 
6641        They are represented by an object that has as keys main categories of properties to animate and as values a list 
6642        of these specific properties. The properties are described below
6643        
6644        position - Describes the way nodes' positions must be interpolated. Possible values are 'linear', 'polar' or 'moebius'.
6645        node-property - Describes which Node properties will be interpolated. These properties can be any of the ones defined in <Options.Node>.
6646        edge-property - Describes which Edge properties will be interpolated. These properties can be any the ones defined in <Options.Edge>.
6647        label-property - Describes which Label properties will be interpolated. These properties can be any of the ones defined in <Options.Label> like color or size.
6648        node-style - Describes which Node Canvas Styles will be interpolated. These are specific canvas properties like fillStyle, strokeStyle, lineWidth, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, etc.
6649        edge-style - Describes which Edge Canvas Styles will be interpolated. These are specific canvas properties like fillStyle, strokeStyle, lineWidth, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, etc.
6650
6651        Example:
6652        (start code js)
6653        var viz = new $jit.Viz(options);
6654        //...tweak some Data, CanvasStyles or LabelData properties...
6655        viz.fx.animate({
6656          modes: {
6657            'position': 'linear',
6658            'node-property': ['width', 'height'],
6659            'node-style': 'shadowColor',
6660            'label-property': 'size'
6661          },
6662          hideLabels: false
6663        });
6664        //...can also be written like this...
6665        viz.fx.animate({
6666          modes: ['linear',
6667                  'node-property:width:height',
6668                  'node-style:shadowColor',
6669                  'label-property:size'],
6670          hideLabels: false
6671        });
6672        (end code)
6673     */
6674     animate: function(opt, versor) {
6675       opt = $.merge(this.viz.config, opt || {});
6676       var that = this,
6677           viz = this.viz,
6678           graph  = viz.graph,
6679           interp = this.Interpolator,
6680           animation =  opt.type === 'nodefx'? this.nodeFxAnimation : this.animation;
6681       //prepare graph values
6682       var m = this.prepare(opt.modes);
6683       
6684       //animate
6685       if(opt.hideLabels) this.labels.hideLabels(true);
6686       animation.setOptions($.extend(opt, {
6687         $animating: false,
6688         compute: function(delta) {
6689           graph.eachNode(function(node) { 
6690             for(var p in m) {
6691               interp[p](node, m[p], delta, versor);
6692             }
6693           });
6694           that.plot(opt, this.$animating, delta);
6695           this.$animating = true;
6696         },
6697         complete: function() {
6698           if(opt.hideLabels) that.labels.hideLabels(false);
6699           that.plot(opt);
6700           opt.onComplete();
6701           //TODO(nico): This shouldn't be here!
6702           //opt.onAfterCompute();
6703         }       
6704       })).start();
6705     },
6706     
6707     /*
6708       nodeFx
6709    
6710       Apply animation to node properties like color, width, height, dim, etc.
6711   
6712       Parameters:
6713   
6714       options - Animation options. This object properties is described below
6715       elements - The Elements to be transformed. This is an object that has a properties
6716       
6717       (start code js)
6718       'elements': {
6719         //can also be an array of ids
6720         'id': 'id-of-node-to-transform',
6721         //properties to be modified. All properties are optional.
6722         'properties': {
6723           'color': '#ccc', //some color
6724           'width': 10, //some width
6725           'height': 10, //some height
6726           'dim': 20, //some dim
6727           'lineWidth': 10 //some line width
6728         } 
6729       }
6730       (end code)
6731       
6732       - _reposition_ Whether to recalculate positions and add a motion animation. 
6733       This might be used when changing _width_ or _height_ properties in a <Layouts.Tree> like layout. Default's *false*.
6734       
6735       - _onComplete_ A method that is called when the animation completes.
6736       
6737       ...and all other <Graph.Plot.animate> options like _duration_, _fps_, _transition_, etc.
6738   
6739       Example:
6740       (start code js)
6741        var rg = new RGraph(canvas, config); //can be also Hypertree or ST
6742        rg.fx.nodeFx({
6743          'elements': {
6744            'id':'mynodeid',
6745            'properties': {
6746              'color':'#ccf'
6747            },
6748            'transition': Trans.Quart.easeOut
6749          }
6750        });
6751       (end code)    
6752    */
6753    nodeFx: function(opt) {
6754      if (this.nodeFxAnimation == undefined) {
6755        this.nodeFxAnimation = new Animation();
6756      }
6757
6758      var viz = this.viz,
6759          graph  = viz.graph,
6760          animation = this.nodeFxAnimation,
6761          options = $.merge(this.viz.config, {
6762            'elements': {
6763              'id': false,
6764              'properties': {}
6765            },
6766            'reposition': false
6767          });
6768      opt = $.merge(options, opt || {}, {
6769        onBeforeCompute: $.empty,
6770        onAfterCompute: $.empty
6771      });
6772      //check if an animation is running
6773      animation.stopTimer();
6774      var props = opt.elements.properties;
6775      //set end values for nodes
6776      if(!opt.elements.id) {
6777        graph.eachNode(function(n) {
6778          for(var prop in props) {
6779            n.setData(prop, props[prop], 'end');
6780          }
6781        });
6782      } else {
6783        var ids = $.splat(opt.elements.id);
6784        $.each(ids, function(id) {
6785          var n = graph.getNode(id);
6786          if(n) {
6787            for(var prop in props) {
6788              n.setData(prop, props[prop], 'end');
6789            }
6790          }
6791        });
6792      }
6793      //get keys
6794      var propnames = [];
6795      for(var prop in props) propnames.push(prop);
6796      //add node properties modes
6797      var modes = ['node-property:' + propnames.join(':')];
6798      //set new node positions
6799      if(opt.reposition) {
6800        modes.push('linear');
6801        viz.compute('end');
6802      }
6803      //animate
6804      this.animate($.merge(opt, {
6805        modes: modes,
6806        type: 'nodefx'
6807      }));
6808    },
6809
6810     
6811     /*
6812        Method: plot
6813     
6814        Plots a <Graph>.
6815
6816        Parameters:
6817
6818        opt - (optional) Plotting options. Most of them are described in <Options.Fx>.
6819
6820        Example:
6821
6822        (start code js)
6823        var viz = new $jit.Viz(options);
6824        viz.fx.plot(); 
6825        (end code)
6826
6827     */
6828    plot: function(opt, animating) {
6829      var viz = this.viz, 
6830          aGraph = viz.graph, 
6831          canvas = viz.canvas, 
6832          id = viz.root, 
6833          that = this, 
6834          ctx = canvas.getCtx(), 
6835          min = Math.min,
6836          opt = opt || this.viz.controller;
6837      
6838      opt.clearCanvas && canvas.clear();
6839        
6840      var root = aGraph.getNode(id);
6841      if(!root) return;
6842      
6843      var T = !!root.visited;
6844
6845          // helper method
6846                 var checkDupEdge = function(e) {                                          
6847                         var skip = false;                                                       
6848                         for(var d in viz.graph.dup) {                                               
6849                                 var ee = viz.graph.dup[d];                                              
6850                                 if(e.nodeTo.id == ee.nodeTo.id && e.nodeFrom.id == ee.nodeFrom.id) {
6851                                         if(e.portTo == ee.portTo && e.portFrom == ee.portFrom) {        
6852                                                 skip = true;                                                
6853                                                 break; // NOTE: does this break the outer for loop?         
6854                                         }                                                               
6855                                 }                                                                   
6856                         }                                                                       
6857                         return skip;                                                            
6858                 };                                                                        
6859                                                                                                                                                            
6860
6861          // plot each line
6862          var that = this;
6863      aGraph.eachNode(function(node) {
6864                 node.eachAdjacencyBatch(function(adj) {
6865                         // plot this line if it hasn't been plotted
6866                         var total = adj.length;
6867                         if (total == 1) {
6868                                 if(!checkDupEdge(adj[0])) // plot this edge if it isn't a dup
6869                                         that.plotLine(adj[0], canvas, animating);
6870                         } else {
6871                                 for(var pos in adj) {
6872                                         var a = adj[pos];
6873
6874                                         // check if this edge is in duplicates
6875                                         if(checkDupEdge(a)) continue; // skip plot this edge if it's a dup
6876
6877                                         that.plotBezierLine(a, pos, total, canvas, animating);
6878                                 }
6879                         }
6880                 });
6881
6882            /*
6883        var nodeAlpha = node.getData('alpha');
6884        node.eachAdjacency(function(adj) {
6885          var nodeTo = adj.nodeTo;
6886          if(!!nodeTo.visited === T && node.drawn && nodeTo.drawn) {
6887            !animating && opt.onBeforePlotLine(adj);
6888            that.plotLine(adj, canvas, animating);
6889            !animating && opt.onAfterPlotLine(adj);
6890          }
6891        });
6892        if(node.drawn) {
6893          !animating && opt.onBeforePlotNode(node);
6894          that.plotNode(node, canvas, animating);
6895          !animating && opt.onAfterPlotNode(node);
6896        }
6897        if(!that.labelsHidden && opt.withLabels) {
6898          if(node.drawn && nodeAlpha >= 0.95) {
6899            that.labels.plotLabel(canvas, node, opt);
6900          } else {
6901            that.labels.hideLabel(node, false);
6902          }
6903        }
6904        node.visited = !T;
6905            */
6906      });
6907
6908          // plot all of the nodes
6909          if (opt.modes != undefined && opt.modes.length > 0 && opt.modes[0] == "edge-property:color") {
6910                 animating = true; // HACK
6911          }
6912          aGraph.eachNode(function(node) {
6913                 !animating && opt.onBeforePlotNode(node);
6914                 that.plotNode(node, canvas, animating);
6915                 !animating && opt.onAfterPlotNode(node);
6916                         that.labels.plotLabel(canvas, node, opt);
6917          });
6918     },
6919
6920   /*
6921       Plots a Subtree.
6922    */
6923    plotTree: function(node, opt, animating) {
6924        var that = this, 
6925            viz = this.viz, 
6926            canvas = viz.canvas,
6927            config = this.config,
6928            ctx = canvas.getCtx();
6929        var nodeAlpha = node.getData('alpha');
6930        node.eachSubnode(function(elem) {
6931          if(opt.plotSubtree(node, elem) && elem.exist && elem.drawn) {
6932              var adj = node.getAdjacency(elem.id);
6933              !animating && opt.onBeforePlotLine(adj);
6934              that.plotLine(adj, canvas, animating);
6935              !animating && opt.onAfterPlotLine(adj);
6936              that.plotTree(elem, opt, animating);
6937          }
6938        });
6939        if(node.drawn) {
6940            !animating && opt.onBeforePlotNode(node);
6941            this.plotNode(node, canvas, animating);
6942            !animating && opt.onAfterPlotNode(node);
6943            if(!opt.hideLabels && opt.withLabels && nodeAlpha >= 0.95) 
6944                this.labels.plotLabel(canvas, node, opt);
6945            else 
6946                this.labels.hideLabel(node, false);
6947        } else {
6948            this.labels.hideLabel(node, true);
6949        }
6950    },
6951
6952   /*
6953        Method: plotNode
6954     
6955        Plots a <Graph.Node>.
6956
6957        Parameters:
6958        
6959        node - (object) A <Graph.Node>.
6960        canvas - (object) A <Canvas> element.
6961
6962     */
6963     plotNode: function(node, canvas, animating) {
6964         var f = node.getData('type'), 
6965             ctxObj = this.node.CanvasStyles;
6966         if(f != 'none') {
6967           var width = node.getData('lineWidth'),
6968               color = node.getData('color'),
6969               alpha = node.getData('alpha'),
6970               ctx = canvas.getCtx();
6971           ctx.save();
6972           ctx.lineWidth = width;
6973           ctx.fillStyle = ctx.strokeStyle = color;
6974           ctx.globalAlpha = alpha;
6975           
6976           for(var s in ctxObj) {
6977             ctx[s] = node.getCanvasStyle(s);
6978           }
6979
6980           this.nodeTypes[f].render.call(this, node, canvas, animating);
6981           ctx.restore();
6982         }
6983     },
6984     
6985     /*
6986        Method: plotLine
6987     
6988        Plots a <Graph.Adjacence>.
6989
6990        Parameters:
6991
6992        adj - (object) A <Graph.Adjacence>.
6993        canvas - (object) A <Canvas> instance.
6994
6995     */
6996     plotLine: function(adj, canvas, animating) {
6997       var f = adj.getData('type'),
6998           ctxObj = this.edge.CanvasStyles;
6999       if(f != 'none') {
7000         var width = adj.getData('lineWidth'),
7001             color = adj.getData('color'),
7002             ctx = canvas.getCtx(),
7003             nodeFrom = adj.nodeFrom,
7004             nodeTo = adj.nodeTo;
7005         
7006         ctx.save();
7007         ctx.lineWidth = width;
7008         ctx.fillStyle = ctx.strokeStyle = color;
7009         ctx.globalAlpha = Math.min(nodeFrom.getData('alpha'), 
7010             nodeTo.getData('alpha'), 
7011             adj.getData('alpha'));
7012         
7013         for(var s in ctxObj) {
7014           ctx[s] = adj.getCanvasStyle(s);
7015         }
7016
7017         this.edgeTypes[f].render.call(this, adj, 0, canvas, animating);
7018         ctx.restore();
7019       }
7020     },
7021
7022         /*
7023                 Method: plotBezierLine
7024
7025                 Plots a <MultiGraph.Adjacence>.
7026
7027                 Parameters:
7028                 adj - (object) A <MultiGraph.Adjacence>.
7029                 pos - (int) Position of this line
7030                 total - (int) Total number of lines contained within this batch
7031         */
7032         plotBezierLine: function(adj, pos, total, canvas, animating) {
7033                   var f = adj.getData('type'),
7034           ctxObj = this.edge.CanvasStyles;
7035                   if(f != 'none') {
7036                         var width = adj.getData('lineWidth'),
7037                                 color = adj.getData('color'),
7038                                 ctx = canvas.getCtx(),
7039                                 nodeFrom = adj.nodeFrom,
7040                                 nodeTo = adj.nodeTo;
7041                         
7042                         ctx.save();
7043                         ctx.lineWidth = width;
7044                         ctx.fillStyle = ctx.strokeStyle = color;
7045                         ctx.globalAlpha = Math.min(nodeFrom.getData('alpha'), 
7046                                 nodeTo.getData('alpha'), 
7047                                 adj.getData('alpha'));
7048                         
7049                         for(var s in ctxObj) {
7050                           ctx[s] = adj.getCanvasStyle(s);
7051                         }
7052
7053                         var alpha = parseInt(pos,10);
7054                         var start = (0.5-(total/2));
7055                         alpha += start;
7056
7057                         this.edgeTypes[f].render.call(this, adj, alpha, canvas, animating);
7058                         ctx.restore();
7059                 }
7060         }
7061   
7062 };
7063
7064
7065 /*
7066  * File: Graph.Label.js
7067  *
7068 */
7069
7070 /*
7071    Object: Graph.Label
7072
7073    An interface for plotting/hiding/showing labels.
7074
7075    Description:
7076
7077    This is a generic interface for plotting/hiding/showing labels.
7078    The <Graph.Label> interface is implemented in multiple ways to provide
7079    different label types.
7080
7081    For example, the Graph.Label interface is implemented as <Graph.Label.HTML> to provide
7082    HTML label elements. Also we provide the <Graph.Label.SVG> interface for SVG type labels. 
7083    The <Graph.Label.Native> interface implements these methods with the native Canvas text rendering functions.
7084    
7085    All subclasses (<Graph.Label.HTML>, <Graph.Label.SVG> and <Graph.Label.Native>) implement the method plotLabel.
7086 */
7087
7088 MultiGraph.Label = {};
7089
7090 /*
7091    Class: Graph.Label.Native
7092
7093    Implements labels natively, using the Canvas text API.
7094 */
7095 MultiGraph.Label.Native = new Class({
7096     initialize: function(viz) {
7097       this.viz = viz;
7098     },
7099
7100     /*
7101        Method: plotLabel
7102
7103        Plots a label for a given node.
7104
7105        Parameters:
7106
7107        canvas - (object) A <Canvas> instance.
7108        node - (object) A <Graph.Node>.
7109        controller - (object) A configuration object.
7110        
7111        Example:
7112        
7113        (start code js)
7114        var viz = new $jit.Viz(options);
7115        var node = viz.graph.getNode('nodeId');
7116        viz.labels.plotLabel(viz.canvas, node, viz.config);
7117        (end code)
7118     */
7119     plotLabel: function(canvas, node, controller) {
7120       var ctx = canvas.getCtx();
7121       var pos = node.pos.getc(true);
7122
7123       ctx.font = node.getLabelData('style') + ' ' + node.getLabelData('size') + 'px ' + node.getLabelData('family');
7124       ctx.textAlign = node.getLabelData('textAlign');
7125       ctx.fillStyle = ctx.strokeStyle = node.getLabelData('color');
7126       ctx.textBaseline = node.getLabelData('textBaseline');
7127
7128       this.renderLabel(canvas, node, controller);
7129     },
7130
7131     /*
7132        renderLabel
7133
7134        Does the actual rendering of the label in the canvas. The default
7135        implementation renders the label close to the position of the node, this
7136        method should be overriden to position the labels differently.
7137
7138        Parameters:
7139
7140        canvas - A <Canvas> instance.
7141        node - A <Graph.Node>.
7142        controller - A configuration object. See also <Hypertree>, <RGraph>, <ST>.
7143     */
7144     renderLabel: function(canvas, node, controller) {
7145       var ctx = canvas.getCtx();
7146       var pos = node.pos.getc(true);
7147       ctx.fillText(node.name, pos.x, pos.y + node.getData("height") / 2);
7148     },
7149
7150     /*
7151        Method: hideLabel
7152    
7153        Hides the corresponding <Graph.Node> label.
7154     
7155        Parameters:
7156    
7157        node - (object) A <Graph.Node>. Can also be an array of <Graph.Nodes>.
7158        show - (boolean) If *true*, nodes will be shown. Otherwise nodes will be hidden.
7159    
7160        Example:
7161        (start code js)
7162         var rg = new $jit.Viz(options);
7163         viz.labels.hideLabel(viz.graph.getNode('someid'), false);
7164        (end code)
7165     */
7166     hideLabel: function(node, show) {
7167       node = $.splat(node);
7168       var al = show ? false : true;
7169       $.each(node, function(n) {
7170         n._hideLabel = al;
7171       });
7172     },
7173     hideLabels: $.empty
7174 });
7175
7176 /*
7177    Class: Graph.Label.DOM
7178
7179    Abstract Class implementing some DOM label methods.
7180
7181    Implemented by:
7182
7183    <Graph.Label.HTML> and <Graph.Label.SVG>.
7184
7185 */
7186 MultiGraph.Label.DOM = new Class({
7187     //A flag value indicating if node labels are being displayed or not.
7188     labelsHidden: false,
7189     //Label container
7190     labelContainer: false,
7191     //Label elements hash.
7192     labels: {},
7193
7194     /*
7195        Method: getLabelContainer
7196
7197        Lazy fetcher for the label container.
7198
7199        Returns:
7200
7201        The label container DOM element.
7202
7203        Example:
7204
7205       (start code js)
7206         var viz = new $jit.Viz(options);
7207         var labelContainer = viz.labels.getLabelContainer();
7208         alert(labelContainer.innerHTML);
7209       (end code)
7210     */
7211     getLabelContainer: function() {
7212       return this.labelContainer ?
7213         this.labelContainer :
7214         this.labelContainer = document.getElementById(this.viz.config.labelContainer);
7215     },
7216
7217     /*
7218        Method: getLabel
7219
7220        Lazy fetcher for the label element.
7221
7222        Parameters:
7223
7224        id - (string) The label id (which is also a <Graph.Node> id).
7225
7226        Returns:
7227
7228        The label element.
7229
7230        Example:
7231
7232       (start code js)
7233         var viz = new $jit.Viz(options);
7234         var label = viz.labels.getLabel('someid');
7235         alert(label.innerHTML);
7236       (end code)
7237
7238     */
7239     getLabel: function(id) {
7240       return (id in this.labels && this.labels[id] != null) ?
7241         this.labels[id] :
7242         this.labels[id] = document.getElementById(id);
7243     },
7244
7245     /*
7246        Method: hideLabels
7247
7248        Hides all labels (by hiding the label container).
7249
7250        Parameters:
7251
7252        hide - (boolean) A boolean value indicating if the label container must be hidden or not.
7253
7254        Example:
7255        (start code js)
7256         var viz = new $jit.Viz(options);
7257         rg.labels.hideLabels(true);
7258        (end code)
7259
7260     */
7261     hideLabels: function (hide) {
7262       var container = this.getLabelContainer();
7263       if(hide)
7264         container.style.display = 'none';
7265       else
7266         container.style.display = '';
7267       this.labelsHidden = hide;
7268     },
7269
7270     /*
7271        Method: clearLabels
7272
7273        Clears the label container.
7274
7275        Useful when using a new visualization with the same canvas element/widget.
7276
7277        Parameters:
7278
7279        force - (boolean) Forces deletion of all labels.
7280
7281        Example:
7282        (start code js)
7283         var viz = new $jit.Viz(options);
7284         viz.labels.clearLabels();
7285         (end code)
7286     */
7287     clearLabels: function(force) {
7288       for(var id in this.labels) {
7289         if (force || !this.viz.graph.hasNode(id)) {
7290           this.disposeLabel(id);
7291           delete this.labels[id];
7292         }
7293       }
7294     },
7295
7296     /*
7297        Method: disposeLabel
7298
7299        Removes a label.
7300
7301        Parameters:
7302
7303        id - (string) A label id (which generally is also a <Graph.Node> id).
7304
7305        Example:
7306        (start code js)
7307         var viz = new $jit.Viz(options);
7308         viz.labels.disposeLabel('labelid');
7309        (end code)
7310     */
7311     disposeLabel: function(id) {
7312       var elem = this.getLabel(id);
7313       if(elem && elem.parentNode) {
7314         elem.parentNode.removeChild(elem);
7315       }
7316     },
7317
7318     /*
7319        Method: hideLabel
7320
7321        Hides the corresponding <Graph.Node> label.
7322
7323        Parameters:
7324
7325        node - (object) A <Graph.Node>. Can also be an array of <Graph.Nodes>.
7326        show - (boolean) If *true*, nodes will be shown. Otherwise nodes will be hidden.
7327
7328        Example:
7329        (start code js)
7330         var rg = new $jit.Viz(options);
7331         viz.labels.hideLabel(viz.graph.getNode('someid'), false);
7332        (end code)
7333     */
7334     hideLabel: function(node, show) {
7335       node = $.splat(node);
7336       var st = show ? "" : "none", lab, that = this;
7337       $.each(node, function(n) {
7338         lab = that.getLabel(n.id);
7339         if (lab) {
7340           lab.style.display = st;
7341         }
7342       });
7343     },
7344
7345     /*
7346        fitsInCanvas
7347
7348        Returns _true_ or _false_ if the label for the node is contained in the canvas dom element or not.
7349
7350        Parameters:
7351
7352        pos - A <Complex> instance (I'm doing duck typing here so any object with _x_ and _y_ parameters will do).
7353        canvas - A <Canvas> instance.
7354
7355        Returns:
7356
7357        A boolean value specifying if the label is contained in the <Canvas> DOM element or not.
7358
7359     */
7360     fitsInCanvas: function(pos, canvas) {
7361       var size = canvas.getSize();
7362       if (pos.w && pos.h) {
7363         if (pos.x >= size.width || pos.x < -pos.w
7364          || pos.y >= size.height || pos.y < -pos.h) return false;       
7365       }
7366       else {
7367         if (pos.x >= size.width || pos.x < 0
7368          || pos.y >= size.height || pos.y < 0) return false;
7369       }
7370        return true;
7371     }
7372 });
7373
7374 /*
7375    Class: Graph.Label.HTML
7376
7377    Implements HTML labels.
7378
7379    Extends:
7380
7381    All <Graph.Label.DOM> methods.
7382
7383 */
7384 MultiGraph.Label.HTML = new Class({
7385     Implements: MultiGraph.Label.DOM,
7386
7387     /*
7388        Method: plotLabel
7389
7390        Plots a label for a given node.
7391
7392        Parameters:
7393
7394        canvas - (object) A <Canvas> instance.
7395        node - (object) A <Graph.Node>.
7396        controller - (object) A configuration object.
7397        
7398       Example:
7399        
7400        (start code js)
7401        var viz = new $jit.Viz(options);
7402        var node = viz.graph.getNode('nodeId');
7403        viz.labels.plotLabel(viz.canvas, node, viz.config);
7404        (end code)
7405
7406
7407     */
7408     plotLabel: function(canvas, node, controller) {
7409       var id = node.id, tag = this.getLabel(id);
7410
7411       if(!tag && !(tag = document.getElementById(id))) {
7412         tag = document.createElement('div');
7413         var container = this.getLabelContainer();
7414         tag.id = id;
7415         tag.className = 'node';
7416         tag.style.position = 'absolute';
7417         controller.onCreateLabel(tag, node);
7418         container.appendChild(tag);
7419         this.labels[node.id] = tag;
7420       }
7421
7422       this.placeLabel(tag, node, controller);
7423     }
7424 });
7425
7426 /*
7427    Class: Graph.Label.SVG
7428
7429    Implements SVG labels.
7430
7431    Extends:
7432
7433    All <Graph.Label.DOM> methods.
7434 */
7435 MultiGraph.Label.SVG = new Class({
7436     Implements: MultiGraph.Label.DOM,
7437
7438     /*
7439        Method: plotLabel
7440
7441        Plots a label for a given node.
7442
7443        Parameters:
7444
7445        canvas - (object) A <Canvas> instance.
7446        node - (object) A <Graph.Node>.
7447        controller - (object) A configuration object.
7448        
7449        Example:
7450        
7451        (start code js)
7452        var viz = new $jit.Viz(options);
7453        var node = viz.graph.getNode('nodeId');
7454        viz.labels.plotLabel(viz.canvas, node, viz.config);
7455        (end code)
7456
7457
7458     */
7459     plotLabel: function(canvas, node, controller) {
7460       var id = node.id, tag = this.getLabel(id);
7461       if(!tag && !(tag = document.getElementById(id))) {
7462         var ns = 'http://www.w3.org/2000/svg';
7463           tag = document.createElementNS(ns, 'svg:text');
7464         var tspan = document.createElementNS(ns, 'svg:tspan');
7465         tag.appendChild(tspan);
7466         var container = this.getLabelContainer();
7467         tag.setAttribute('id', id);
7468         tag.setAttribute('class', 'node');
7469         container.appendChild(tag);
7470         controller.onCreateLabel(tag, node);
7471         this.labels[node.id] = tag;
7472       }
7473       this.placeLabel(tag, node, controller);
7474     }
7475 });
7476
7477
7478
7479 /*
7480  * File: MultiLoader.js
7481  * 
7482  */
7483
7484 /*
7485    Object: MultiLoader
7486
7487    Provides methods for loading and serving JSON data.
7488 */
7489 var MultiLoader = {
7490      construct: function(json) {
7491         var ans = new MultiGraph(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);
7492                 //make graph
7493                 (function (ans, json) {
7494                         var getNode = function(id) {
7495                           for(var i=0, l=json.length; i<l; i++) {
7496                                 if(json[i].id == id) {
7497                                   return json[i];
7498                                 }
7499                           }
7500                           // The node was not defined in the JSON
7501                           // Let's create it
7502                           var newNode = {
7503                                         "id" : id,
7504                                         "name" : id
7505                                 };
7506                           return ans.addNode(newNode);
7507                         };
7508
7509                         for(var i=0, l=json.length; i<l; i++) {
7510                           ans.addNode(json[i]);
7511                           var adj = json[i].adjacencies;
7512                           if (adj) {
7513                                 for(var j=0, lj=adj.length; j<lj; j++) {
7514                                   var node = adj[j], data = {};
7515                                   data = $.merge(node.data, {});
7516                                   node = node.nodeTo;
7517                                   ans.addAdjacence(json[i], getNode(node), data);
7518                                 }
7519                           }
7520                         }
7521                 })(ans, json);
7522
7523         return ans;
7524     },
7525
7526     /*
7527      Method: loadJSON
7528     
7529      Loads a JSON structure to the visualization. The JSON structure can be a JSON *tree* or *graph* structure.
7530      
7531       A JSON tree or graph structure consists of nodes, each having as properties
7532        
7533        id - (string) A unique identifier for the node
7534        name - (string) A node's name
7535        data - (object) The data optional property contains a hash (i.e {}) 
7536        where you can store all the information you want about this node.
7537         
7538       For JSON *Tree* structures, there's an extra optional property *children* of type Array which contains the node's children.
7539       
7540       Example:
7541
7542       (start code js)
7543         var json = {  
7544           "id": "aUniqueIdentifier",  
7545           "name": "usually a nodes name",  
7546           "data": {
7547             "some key": "some value",
7548             "some other key": "some other value"
7549            },  
7550           "children": [ *other nodes or empty* ]  
7551         };  
7552       (end code)
7553         
7554         JSON *Graph* structures consist of an array of nodes, each specifying the nodes to which the current node is connected. 
7555         For JSON *Graph* structures, the *children* property is replaced by the *adjacencies* property.
7556         
7557         There are two types of *Graph* structures, *simple* and *extended* graph structures.
7558         
7559         For *simple* Graph structures, the adjacencies property contains an array of strings, each specifying the 
7560         id of the node connected to the main node.
7561         
7562         Example:
7563         
7564         (start code js)
7565         var json = [  
7566           {  
7567             "id": "aUniqueIdentifier",  
7568             "name": "usually a nodes name",  
7569             "data": {
7570               "some key": "some value",
7571               "some other key": "some other value"
7572              },  
7573             "adjacencies": ["anotherUniqueIdentifier", "yetAnotherUniqueIdentifier", 'etc']  
7574           },
7575
7576           'other nodes go here...' 
7577         ];          
7578         (end code)
7579         
7580         For *extended Graph structures*, the adjacencies property contains an array of Adjacency objects that have as properties
7581         
7582         nodeTo - (string) The other node connected by this adjacency.
7583         data - (object) A data property, where we can store custom key/value information.
7584         
7585         Example:
7586         
7587         (start code js)
7588         var json = [  
7589           {  
7590             "id": "aUniqueIdentifier",  
7591             "name": "usually a nodes name",  
7592             "data": {
7593               "some key": "some value",
7594               "some other key": "some other value"
7595              },  
7596             "adjacencies": [  
7597             {  
7598               nodeTo:"aNodeId",  
7599               data: {} //put whatever you want here  
7600             },
7601             'other adjacencies go here...'  
7602           },
7603
7604           'other nodes go here...' 
7605         ];          
7606         (end code)
7607        
7608        About the data property:
7609        
7610        As described before, you can store custom data in the *data* property of JSON *nodes* and *adjacencies*. 
7611        You can use almost any string as key for the data object. Some keys though are reserved by the toolkit, and 
7612        have special meanings. This is the case for keys starting with a dollar sign, for example, *$width*.
7613        
7614        For JSON *node* objects, adding dollar prefixed properties that match the names of the options defined in 
7615        <Options.Node> will override the general value for that option with that particular value. For this to work 
7616        however, you do have to set *overridable = true* in <Options.Node>.
7617        
7618        The same thing is true for JSON adjacencies. Dollar prefixed data properties will alter values set in <Options.Edge> 
7619        if <Options.Edge> has *overridable = true*.
7620        
7621        When loading JSON data into TreeMaps, the *data* property must contain a value for the *$area* key, 
7622        since this is the value which will be taken into account when creating the layout. 
7623        The same thing goes for the *$color* parameter.
7624        
7625        In JSON Nodes you can use also *$label-* prefixed properties to refer to <Options.Label> properties. For example, 
7626        *$label-size* will refer to <Options.Label> size property. Also, in JSON nodes and adjacencies you can set 
7627        canvas specific properties individually by using the *$canvas-* prefix. For example, *$canvas-shadowBlur* will refer 
7628        to the *shadowBlur* property.
7629        
7630        These properties can also be accessed after loading the JSON data from <Graph.Nodes> and <Graph.Adjacences> 
7631        by using <Accessors>. For more information take a look at the <Graph> and <Accessors> documentation.
7632        
7633        Finally, these properties can also be used to create advanced animations like with <Options.NodeStyles>. For more 
7634        information about creating animations please take a look at the <Graph.Plot> and <Graph.Plot.animate> documentation.
7635        
7636        loadJSON Parameters:
7637     
7638         json - A JSON Tree or Graph structure.
7639         i - For Graph structures only. Sets the indexed node as root for the visualization.
7640
7641     */
7642     loadJSON: function(json, i) {
7643       this.json = json;
7644       //if they're canvas labels erase them.
7645       if(this.labels && this.labels.clearLabels) {
7646         this.labels.clearLabels(true);
7647       }
7648       this.graph = this.construct(json);
7649       if($.type(json) != 'array'){
7650         this.root = json.id;
7651       } else {
7652         this.root = json[i? i : 0].id;
7653       }
7654     },
7655     
7656     /*
7657       Method: toJSON
7658    
7659       Returns a JSON tree/graph structure from the visualization's <Graph>. 
7660       See <MultiLoader.loadJSON> for the graph formats available.
7661       
7662       See also:
7663       
7664       <MultiLoader.loadJSON>
7665       
7666       Parameters:
7667       
7668       type - (string) Default's "tree". The type of the JSON structure to be returned. 
7669       Possible options are "tree" or "graph".
7670     */    
7671     toJSON: function(type) {
7672       type = type || "tree";
7673       if(type == 'tree') {
7674         var ans = {};
7675         var rootNode = this.graph.getNode(this.root);
7676         var ans = (function recTree(node) {
7677           var ans = {};
7678           ans.id = node.id;
7679           ans.name = node.name;
7680           ans.data = node.data;
7681           var ch =[];
7682           node.eachSubnode(function(n) {
7683             ch.push(recTree(n));
7684           });
7685           ans.children = ch;
7686           return ans;
7687         })(rootNode);
7688         return ans;
7689       } else {
7690         var ans = [];
7691         var T = !!this.graph.getNode(this.root).visited;
7692         this.graph.eachNode(function(node) {
7693           var ansNode = {};
7694           ansNode.id = node.id;
7695           ansNode.name = node.name;
7696           ansNode.data = node.data;
7697           var adjs = [];
7698           node.eachAdjacency(function(adj) {
7699             var nodeTo = adj.nodeTo;
7700             if(!!nodeTo.visited === T) {
7701               var ansAdj = {};
7702               ansAdj.nodeTo = nodeTo.id;
7703               ansAdj.data = adj.data;
7704               adjs.push(ansAdj);
7705             }
7706           });
7707           ansNode.adjacencies = adjs;
7708           ans.push(ansNode);
7709           node.visited = !T;
7710         });
7711         return ans;
7712       }
7713     }
7714 };
7715
7716
7717
7718 /*
7719  * File: Graph.js
7720  *
7721 */
7722
7723 /*
7724  Class: Graph
7725
7726  A Graph Class that provides useful manipulation functions. You can find more manipulation methods in the <Graph.Util> object.
7727
7728  An instance of this class can be accessed by using the *graph* parameter of any tree or graph visualization.
7729  
7730  Example:
7731
7732  (start code js)
7733    //create new visualization
7734    var viz = new $jit.Viz(options);
7735    //load JSON data
7736    viz.loadJSON(json);
7737    //access model
7738    viz.graph; //<Graph> instance
7739  (end code)
7740  
7741  Implements:
7742  
7743  The following <Graph.Util> methods are implemented in <Graph>
7744  
7745   - <Graph.Util.getNode>
7746   - <Graph.Util.eachNode>
7747   - <Graph.Util.computeLevels>
7748   - <Graph.Util.eachBFS>
7749   - <Graph.Util.clean>
7750   - <Graph.Util.getClosestNodeToPos>
7751   - <Graph.Util.getClosestNodeToOrigin>
7752  
7753 */  
7754
7755 $jit.Graph = new Class({
7756
7757   initialize: function(opt, Node, Edge, Label) {
7758     var innerOptions = {
7759     'klass': Complex,
7760     'Node': {}
7761     };
7762     this.Node = Node;
7763     this.Edge = Edge;
7764     this.Label = Label;
7765     this.opt = $.merge(innerOptions, opt || {});
7766     this.nodes = {};
7767     this.edges = {};
7768     
7769     //add nodeList methods
7770     var that = this;
7771     this.nodeList = {};
7772     for(var p in Accessors) {
7773       that.nodeList[p] = (function(p) {
7774         return function() {
7775           var args = Array.prototype.slice.call(arguments);
7776           that.eachNode(function(n) {
7777             n[p].apply(n, args);
7778           });
7779         };
7780       })(p);
7781     }
7782
7783  },
7784
7785 /*
7786      Method: getNode
7787     
7788      Returns a <Graph.Node> by *id*.
7789
7790      Parameters:
7791
7792      id - (string) A <Graph.Node> id.
7793
7794      Example:
7795
7796      (start code js)
7797        var node = graph.getNode('nodeId');
7798      (end code)
7799 */  
7800  getNode: function(id) {
7801     if(this.hasNode(id)) return this.nodes[id];
7802     return false;
7803  },
7804
7805  /*
7806      Method: get
7807     
7808      An alias for <Graph.Util.getNode>. Returns a node by *id*.
7809     
7810      Parameters:
7811     
7812      id - (string) A <Graph.Node> id.
7813     
7814      Example:
7815     
7816      (start code js)
7817        var node = graph.get('nodeId');
7818      (end code)
7819 */  
7820   get: function(id) {
7821     return this.getNode(id);
7822   },
7823
7824  /*
7825    Method: getByName
7826   
7827    Returns a <Graph.Node> by *name*.
7828   
7829    Parameters:
7830   
7831    name - (string) A <Graph.Node> name.
7832   
7833    Example:
7834   
7835    (start code js)
7836      var node = graph.getByName('someName');
7837    (end code)
7838   */  
7839   getByName: function(name) {
7840     for(var id in this.nodes) {
7841       var n = this.nodes[id];
7842       if(n.name == name) return n;
7843     }
7844     return false;
7845   },
7846
7847 /*
7848    Method: getAdjacence
7849   
7850    Returns a <Graph.Adjacence> object connecting nodes with ids *id* and *id2*.
7851
7852    Parameters:
7853
7854    id - (string) A <Graph.Node> id.
7855    id2 - (string) A <Graph.Node> id.
7856 */  
7857   getAdjacence: function (id, id2) {
7858     if(id in this.edges) {
7859       return this.edges[id][id2];
7860     }
7861     return false;
7862  },
7863
7864     /*
7865      Method: addNode
7866     
7867      Adds a node.
7868      
7869      Parameters:
7870     
7871       obj - An object with the properties described below
7872
7873       id - (string) A node id
7874       name - (string) A node's name
7875       data - (object) A node's data hash
7876
7877     See also:
7878     <Graph.Node>
7879
7880   */  
7881   addNode: function(obj) { 
7882    if(!this.nodes[obj.id]) {  
7883      var edges = this.edges[obj.id] = {};
7884      this.nodes[obj.id] = new Graph.Node($.extend({
7885         'id': obj.id,
7886         'name': obj.name,
7887         'data': $.merge(obj.data || {}, {}),
7888         'adjacencies': edges 
7889       }, this.opt.Node), 
7890       this.opt.klass, 
7891       this.Node, 
7892       this.Edge,
7893       this.Label);
7894     }
7895     return this.nodes[obj.id];
7896   },
7897   
7898     /*
7899      Method: addAdjacence
7900     
7901      Connects nodes specified by *obj* and *obj2*. If not found, nodes are created.
7902      
7903      Parameters:
7904     
7905       obj - (object) A <Graph.Node> object.
7906       obj2 - (object) Another <Graph.Node> object.
7907       data - (object) A data object. Used to store some extra information in the <Graph.Adjacence> object created.
7908
7909     See also:
7910
7911     <Graph.Node>, <Graph.Adjacence>
7912     */  
7913   addAdjacence: function (obj, obj2, data) {
7914     if(!this.hasNode(obj.id)) { this.addNode(obj); }
7915     if(!this.hasNode(obj2.id)) { this.addNode(obj2); }
7916     obj = this.nodes[obj.id]; obj2 = this.nodes[obj2.id];
7917     if(!obj.adjacentTo(obj2)) {
7918       var adjsObj = this.edges[obj.id] = this.edges[obj.id] || {};
7919       var adjsObj2 = this.edges[obj2.id] = this.edges[obj2.id] || {};
7920       adjsObj[obj2.id] = adjsObj2[obj.id] = new Graph.Adjacence(obj, obj2, data, this.Edge, this.Label);
7921       return adjsObj[obj2.id];
7922     }
7923     return this.edges[obj.id][obj2.id];
7924  },
7925
7926     /*
7927      Method: removeNode
7928     
7929      Removes a <Graph.Node> matching the specified *id*.
7930
7931      Parameters:
7932
7933      id - (string) A node's id.
7934
7935     */  
7936   removeNode: function(id) {
7937     if(this.hasNode(id)) {
7938       delete this.nodes[id];
7939       var adjs = this.edges[id];
7940       for(var to in adjs) {
7941         delete this.edges[to][id];
7942       }
7943       delete this.edges[id];
7944     }
7945   },
7946   
7947 /*
7948      Method: removeAdjacence
7949     
7950      Removes a <Graph.Adjacence> matching *id1* and *id2*.
7951
7952      Parameters:
7953
7954      id1 - (string) A <Graph.Node> id.
7955      id2 - (string) A <Graph.Node> id.
7956 */  
7957   removeAdjacence: function(id1, id2) {
7958     delete this.edges[id1][id2];
7959     delete this.edges[id2][id1];
7960   },
7961
7962    /*
7963      Method: hasNode
7964     
7965      Returns a boolean indicating if the node belongs to the <Graph> or not.
7966      
7967      Parameters:
7968     
7969         id - (string) Node id.
7970    */  
7971   hasNode: function(id) {
7972     return id in this.nodes;
7973   },
7974   
7975   /*
7976     Method: empty
7977
7978     Empties the Graph
7979
7980   */
7981   empty: function() { this.nodes = {}; this.edges = {};}
7982
7983 });
7984
7985 var Graph = $jit.Graph;
7986
7987 /*
7988  Object: Accessors
7989  
7990  Defines a set of methods for data, canvas and label styles manipulation implemented by <Graph.Node> and <Graph.Adjacence> instances.
7991  
7992  */
7993 var Accessors;
7994
7995 (function () {
7996   var getDataInternal = function(prefix, prop, type, force, prefixConfig) {
7997     var data;
7998     type = type || 'current';
7999     prefix = "$" + (prefix ? prefix + "-" : "");
8000
8001     if(type == 'current') {
8002       data = this.data;
8003     } else if(type == 'start') {
8004       data = this.startData;
8005     } else if(type == 'end') {
8006       data = this.endData;
8007     }
8008
8009     var dollar = prefix + prop;
8010
8011     if(force) {
8012       return data[dollar];
8013     }
8014
8015     if(!this.Config.overridable)
8016       return prefixConfig[prop] || 0;
8017
8018     return (dollar in data) ?
8019       data[dollar] : ((dollar in this.data) ? this.data[dollar] : (prefixConfig[prop] || 0));
8020   }
8021
8022   var setDataInternal = function(prefix, prop, value, type) {
8023     type = type || 'current';
8024     prefix = '$' + (prefix ? prefix + '-' : '');
8025
8026     var data;
8027
8028     if(type == 'current') {
8029       data = this.data;
8030     } else if(type == 'start') {
8031       data = this.startData;
8032     } else if(type == 'end') {
8033       data = this.endData;
8034     }
8035
8036     data[prefix + prop] = value;
8037   }
8038
8039   var removeDataInternal = function(prefix, properties) {
8040     prefix = '$' + (prefix ? prefix + '-' : '');
8041     var that = this;
8042     $.each(properties, function(prop) {
8043       var pref = prefix + prop;
8044       delete that.data[pref];
8045       delete that.endData[pref];
8046       delete that.startData[pref];
8047     });
8048   }
8049
8050   Accessors = {
8051     /*
8052     Method: getData
8053
8054     Returns the specified data value property.
8055     This is useful for querying special/reserved <Graph.Node> data properties
8056     (i.e dollar prefixed properties).
8057
8058     Parameters:
8059
8060       prop  - (string) The name of the property. The dollar sign is not needed. For
8061               example *getData(width)* will return *data.$width*.
8062       type  - (string) The type of the data property queried. Default's "current". You can access *start* and *end* 
8063               data properties also. These properties are used when making animations.
8064       force - (boolean) Whether to obtain the true value of the property (equivalent to
8065               *data.$prop*) or to check for *node.overridable = true* first.
8066
8067     Returns:
8068
8069       The value of the dollar prefixed property or the global Node/Edge property
8070       value if *overridable=false*
8071
8072     Example:
8073     (start code js)
8074      node.getData('width'); //will return node.data.$width if Node.overridable=true;
8075     (end code)
8076     */
8077     getData: function(prop, type, force) {
8078       return getDataInternal.call(this, "", prop, type, force, this.Config);
8079     },
8080
8081
8082     /*
8083     Method: setData
8084
8085     Sets the current data property with some specific value.
8086     This method is only useful for reserved (dollar prefixed) properties.
8087
8088     Parameters:
8089
8090       prop  - (string) The name of the property. The dollar sign is not necessary. For
8091               example *setData(width)* will set *data.$width*.
8092       value - (mixed) The value to store.
8093       type  - (string) The type of the data property to store. Default's "current" but
8094               can also be "start" or "end".
8095
8096     Example:
8097     
8098     (start code js)
8099      node.setData('width', 30);
8100     (end code)
8101     
8102     If we were to make an animation of a node/edge width then we could do
8103     
8104     (start code js)
8105       var node = viz.getNode('nodeId');
8106       //set start and end values
8107       node.setData('width', 10, 'start');
8108       node.setData('width', 30, 'end');
8109       //will animate nodes width property
8110       viz.fx.animate({
8111         modes: ['node-property:width'],
8112         duration: 1000
8113       });
8114     (end code)
8115     */
8116     setData: function(prop, value, type) {
8117       setDataInternal.call(this, "", prop, value, type);
8118     },
8119
8120     /*
8121     Method: setDataset
8122
8123     Convenience method to set multiple data values at once.
8124     
8125     Parameters:
8126     
8127     types - (array|string) A set of 'current', 'end' or 'start' values.
8128     obj - (object) A hash containing the names and values of the properties to be altered.
8129
8130     Example:
8131     (start code js)
8132       node.setDataset(['current', 'end'], {
8133         'width': [100, 5],
8134         'color': ['#fff', '#ccc']
8135       });
8136       //...or also
8137       node.setDataset('end', {
8138         'width': 5,
8139         'color': '#ccc'
8140       });
8141     (end code)
8142     
8143     See also: 
8144     
8145     <Accessors.setData>
8146     
8147     */
8148     setDataset: function(types, obj) {
8149       types = $.splat(types);
8150       for(var attr in obj) {
8151         for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
8152           this.setData(attr, val[i], types[i]);
8153         }
8154       }
8155     },
8156     
8157     /*
8158     Method: removeData
8159
8160     Remove data properties.
8161
8162     Parameters:
8163
8164     One or more property names as arguments. The dollar sign is not needed.
8165
8166     Example:
8167     (start code js)
8168     node.removeData('width'); //now the default width value is returned
8169     (end code)
8170     */
8171     removeData: function() {
8172       removeDataInternal.call(this, "", Array.prototype.slice.call(arguments));
8173     },
8174
8175     /*
8176     Method: getCanvasStyle
8177
8178     Returns the specified canvas style data value property. This is useful for
8179     querying special/reserved <Graph.Node> canvas style data properties (i.e.
8180     dollar prefixed properties that match with $canvas-<name of canvas style>).
8181
8182     Parameters:
8183
8184       prop  - (string) The name of the property. The dollar sign is not needed. For
8185               example *getCanvasStyle(shadowBlur)* will return *data[$canvas-shadowBlur]*.
8186       type  - (string) The type of the data property queried. Default's *current*. You can access *start* and *end* 
8187               data properties also.
8188               
8189     Example:
8190     (start code js)
8191       node.getCanvasStyle('shadowBlur');
8192     (end code)
8193     
8194     See also:
8195     
8196     <Accessors.getData>
8197     */
8198     getCanvasStyle: function(prop, type, force) {
8199       return getDataInternal.call(
8200           this, 'canvas', prop, type, force, this.Config.CanvasStyles);
8201     },
8202
8203     /*
8204     Method: setCanvasStyle
8205
8206     Sets the canvas style data property with some specific value.
8207     This method is only useful for reserved (dollar prefixed) properties.
8208     
8209     Parameters:
8210     
8211     prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc.
8212     value - (mixed) The value to set to the property.
8213     type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties.
8214     
8215     Example:
8216     
8217     (start code js)
8218      node.setCanvasStyle('shadowBlur', 30);
8219     (end code)
8220     
8221     If we were to make an animation of a node/edge shadowBlur canvas style then we could do
8222     
8223     (start code js)
8224       var node = viz.getNode('nodeId');
8225       //set start and end values
8226       node.setCanvasStyle('shadowBlur', 10, 'start');
8227       node.setCanvasStyle('shadowBlur', 30, 'end');
8228       //will animate nodes canvas style property for nodes
8229       viz.fx.animate({
8230         modes: ['node-style:shadowBlur'],
8231         duration: 1000
8232       });
8233     (end code)
8234     
8235     See also:
8236     
8237     <Accessors.setData>.
8238     */
8239     setCanvasStyle: function(prop, value, type) {
8240       setDataInternal.call(this, 'canvas', prop, value, type);
8241     },
8242
8243     /*
8244     Method: setCanvasStyles
8245
8246     Convenience method to set multiple styles at once.
8247
8248     Parameters:
8249     
8250     types - (array|string) A set of 'current', 'end' or 'start' values.
8251     obj - (object) A hash containing the names and values of the properties to be altered.
8252
8253     See also:
8254     
8255     <Accessors.setDataset>.
8256     */
8257     setCanvasStyles: function(types, obj) {
8258       types = $.splat(types);
8259       for(var attr in obj) {
8260         for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
8261           this.setCanvasStyle(attr, val[i], types[i]);
8262         }
8263       }
8264     },
8265
8266     /*
8267     Method: removeCanvasStyle
8268
8269     Remove canvas style properties from data.
8270
8271     Parameters:
8272     
8273     A variable number of canvas style strings.
8274
8275     See also:
8276     
8277     <Accessors.removeData>.
8278     */
8279     removeCanvasStyle: function() {
8280       removeDataInternal.call(this, 'canvas', Array.prototype.slice.call(arguments));
8281     },
8282
8283     /*
8284     Method: getLabelData
8285
8286     Returns the specified label data value property. This is useful for
8287     querying special/reserved <Graph.Node> label options (i.e.
8288     dollar prefixed properties that match with $label-<name of label style>).
8289
8290     Parameters:
8291
8292       prop  - (string) The name of the property. The dollar sign prefix is not needed. For
8293               example *getLabelData(size)* will return *data[$label-size]*.
8294       type  - (string) The type of the data property queried. Default's *current*. You can access *start* and *end* 
8295               data properties also.
8296               
8297     See also:
8298     
8299     <Accessors.getData>.
8300     */
8301     getLabelData: function(prop, type, force) {
8302       return getDataInternal.call(
8303           this, 'label', prop, type, force, this.Label);
8304     },
8305
8306     /*
8307     Method: setLabelData
8308
8309     Sets the current label data with some specific value.
8310     This method is only useful for reserved (dollar prefixed) properties.
8311
8312     Parameters:
8313     
8314     prop - (string) Name of the property. Can be any canvas property like 'shadowBlur', 'shadowColor', 'strokeStyle', etc.
8315     value - (mixed) The value to set to the property.
8316     type - (string) Default's *current*. Whether to set *start*, *current* or *end* type properties.
8317     
8318     Example:
8319     
8320     (start code js)
8321      node.setLabelData('size', 30);
8322     (end code)
8323     
8324     If we were to make an animation of a node label size then we could do
8325     
8326     (start code js)
8327       var node = viz.getNode('nodeId');
8328       //set start and end values
8329       node.setLabelData('size', 10, 'start');
8330       node.setLabelData('size', 30, 'end');
8331       //will animate nodes label size
8332       viz.fx.animate({
8333         modes: ['label-property:size'],
8334         duration: 1000
8335       });
8336     (end code)
8337     
8338     See also:
8339     
8340     <Accessors.setData>.
8341     */
8342     setLabelData: function(prop, value, type) {
8343       setDataInternal.call(this, 'label', prop, value, type);
8344     },
8345
8346     /*
8347     Method: setLabelDataset
8348
8349     Convenience function to set multiple label data at once.
8350
8351     Parameters:
8352     
8353     types - (array|string) A set of 'current', 'end' or 'start' values.
8354     obj - (object) A hash containing the names and values of the properties to be altered.
8355
8356     See also:
8357     
8358     <Accessors.setDataset>.
8359     */
8360     setLabelDataset: function(types, obj) {
8361       types = $.splat(types);
8362       for(var attr in obj) {
8363         for(var i=0, val = $.splat(obj[attr]), l=types.length; i<l; i++) {
8364           this.setLabelData(attr, val[i], types[i]);
8365         }
8366       }
8367     },
8368
8369     /*
8370     Method: removeLabelData
8371
8372     Remove label properties from data.
8373     
8374     Parameters:
8375     
8376     A variable number of label property strings.
8377
8378     See also:
8379     
8380     <Accessors.removeData>.
8381     */
8382     removeLabelData: function() {
8383       removeDataInternal.call(this, 'label', Array.prototype.slice.call(arguments));
8384     }
8385   };
8386 })();
8387
8388 /*
8389      Class: Graph.Node
8390
8391      A <Graph> node.
8392      
8393      Implements:
8394      
8395      <Accessors> methods.
8396      
8397      The following <Graph.Util> methods are implemented by <Graph.Node>
8398      
8399     - <Graph.Util.eachAdjacency>
8400     - <Graph.Util.eachLevel>
8401     - <Graph.Util.eachSubgraph>
8402     - <Graph.Util.eachSubnode>
8403     - <Graph.Util.anySubnode>
8404     - <Graph.Util.getSubnodes>
8405     - <Graph.Util.getParents>
8406     - <Graph.Util.isDescendantOf>     
8407 */
8408 Graph.Node = new Class({
8409     
8410   initialize: function(opt, klass, Node, Edge, Label) {
8411     var innerOptions = {
8412       'id': '',
8413       'name': '',
8414       'data': {},
8415       'startData': {},
8416       'endData': {},
8417       'adjacencies': {},
8418
8419       'selected': false,
8420       'drawn': false,
8421       'exist': false,
8422
8423       'angleSpan': {
8424         'begin': 0,
8425         'end' : 0
8426       },
8427
8428       'pos': new klass,
8429       'startPos': new klass,
8430       'endPos': new klass
8431     };
8432     
8433     $.extend(this, $.extend(innerOptions, opt));
8434     this.Config = this.Node = Node;
8435     this.Edge = Edge;
8436     this.Label = Label;
8437   },
8438
8439     /*
8440        Method: adjacentTo
8441     
8442        Indicates if the node is adjacent to the node specified by id
8443
8444        Parameters:
8445     
8446           id - (string) A node id.
8447     
8448        Example:
8449        (start code js)
8450         node.adjacentTo('nodeId') == true;
8451        (end code)
8452     */
8453     adjacentTo: function(node) {
8454         return node.id in this.adjacencies;
8455     },
8456
8457     /*
8458      Method: adjacentWithDirectionTo
8459
8460      Indicates if the node has a directed edge to the node specified by id
8461
8462      Parameters:
8463
8464      id - (string) A node id.
8465
8466      Example:
8467      (start code js)
8468      node.adjacentWithDirectionTo('nodeId') == true;
8469      (end code)
8470      */
8471     adjacentWithDirectionTo: function(node) {
8472         var areNeighbors = node.id in this.adjacencies;
8473         if (!areNeighbors) {
8474             return false;
8475         }
8476
8477         var direction = this.adjacencies[node.id].data.$direction;
8478         return direction[0] === this.id ;
8479     },
8480
8481     /*
8482        Method: getAdjacency
8483     
8484        Returns a <Graph.Adjacence> object connecting the current <Graph.Node> and the node having *id* as id.
8485
8486        Parameters:
8487     
8488           id - (string) A node id.
8489     */  
8490     getAdjacency: function(id) {
8491         return this.adjacencies[id];
8492     },
8493
8494     /*
8495       Method: getPos
8496    
8497       Returns the position of the node.
8498   
8499       Parameters:
8500    
8501          type - (string) Default's *current*. Possible values are "start", "end" or "current".
8502    
8503       Returns:
8504    
8505         A <Complex> or <Polar> instance.
8506   
8507       Example:
8508       (start code js)
8509        var pos = node.getPos('end');
8510       (end code)
8511    */
8512    getPos: function(type) {
8513        type = type || "current";
8514        if(type == "current") {
8515          return this.pos;
8516        } else if(type == "end") {
8517          return this.endPos;
8518        } else if(type == "start") {
8519          return this.startPos;
8520        }
8521    },
8522    /*
8523      Method: setPos
8524   
8525      Sets the node's position.
8526   
8527      Parameters:
8528   
8529         value - (object) A <Complex> or <Polar> instance.
8530         type - (string) Default's *current*. Possible values are "start", "end" or "current".
8531   
8532      Example:
8533      (start code js)
8534       node.setPos(new $jit.Complex(0, 0), 'end');
8535      (end code)
8536   */
8537   setPos: function(value, type) {
8538       type = type || "current";
8539       var pos;
8540       if(type == "current") {
8541         pos = this.pos;
8542       } else if(type == "end") {
8543         pos = this.endPos;
8544       } else if(type == "start") {
8545         pos = this.startPos;
8546       }
8547       pos.set(value);
8548   }
8549 });
8550
8551 Graph.Node.implement(Accessors);
8552
8553 /*
8554      Class: Graph.Adjacence
8555
8556      A <Graph> adjacence (or edge) connecting two <Graph.Nodes>.
8557      
8558      Implements:
8559      
8560      <Accessors> methods.
8561
8562      See also:
8563
8564      <Graph>, <Graph.Node>
8565
8566      Properties:
8567      
8568       nodeFrom - A <Graph.Node> connected by this edge.
8569       nodeTo - Another  <Graph.Node> connected by this edge.
8570       data - Node data property containing a hash (i.e {}) with custom options.
8571 */
8572 Graph.Adjacence = new Class({
8573   
8574   initialize: function(nodeFrom, nodeTo, data, Edge, Label) {
8575     this.nodeFrom = nodeFrom;
8576     this.nodeTo = nodeTo;
8577     this.data = data || {};
8578     this.startData = {};
8579     this.endData = {};
8580     this.Config = this.Edge = Edge;
8581     this.Label = Label;
8582   }
8583 });
8584
8585 Graph.Adjacence.implement(Accessors);
8586
8587 /*
8588    Object: Graph.Util
8589
8590    <Graph> traversal and processing utility object.
8591    
8592    Note:
8593    
8594    For your convenience some of these methods have also been appended to <Graph> and <Graph.Node> classes.
8595 */
8596 Graph.Util = {
8597     /*
8598        filter
8599     
8600        For internal use only. Provides a filtering function based on flags.
8601     */
8602     filter: function(param) {
8603         if(!param || !($.type(param) == 'string')) return function() { return true; };
8604         var props = param.split(" ");
8605         return function(elem) {
8606             for(var i=0; i<props.length; i++) { 
8607               if(elem[props[i]]) { 
8608                 return false; 
8609               }
8610             }
8611             return true;
8612         };
8613     },
8614     /*
8615        Method: getNode
8616     
8617        Returns a <Graph.Node> by *id*.
8618        
8619        Also implemented by:
8620        
8621        <Graph>
8622
8623        Parameters:
8624
8625        graph - (object) A <Graph> instance.
8626        id - (string) A <Graph.Node> id.
8627
8628        Example:
8629
8630        (start code js)
8631          $jit.Graph.Util.getNode(graph, 'nodeid');
8632          //or...
8633          graph.getNode('nodeid');
8634        (end code)
8635     */
8636     getNode: function(graph, id) {
8637         return graph.nodes[id];
8638     },
8639     
8640     /*
8641        Method: eachNode
8642     
8643        Iterates over <Graph> nodes performing an *action*.
8644        
8645        Also implemented by:
8646        
8647        <Graph>.
8648
8649        Parameters:
8650
8651        graph - (object) A <Graph> instance.
8652        action - (function) A callback function having a <Graph.Node> as first formal parameter.
8653
8654        Example:
8655        (start code js)
8656          $jit.Graph.Util.eachNode(graph, function(node) {
8657           alert(node.name);
8658          });
8659          //or...
8660          graph.eachNode(function(node) {
8661            alert(node.name);
8662          });
8663        (end code)
8664     */
8665     eachNode: function(graph, action, flags) {
8666         var filter = this.filter(flags);
8667         for(var i in graph.nodes) {
8668           if(filter(graph.nodes[i])) action(graph.nodes[i]);
8669         } 
8670     },
8671     
8672     /*
8673       Method: each
8674    
8675       Iterates over <Graph> nodes performing an *action*. It's an alias for <Graph.Util.eachNode>.
8676       
8677       Also implemented by:
8678       
8679       <Graph>.
8680   
8681       Parameters:
8682   
8683       graph - (object) A <Graph> instance.
8684       action - (function) A callback function having a <Graph.Node> as first formal parameter.
8685   
8686       Example:
8687       (start code js)
8688         $jit.Graph.Util.each(graph, function(node) {
8689          alert(node.name);
8690         });
8691         //or...
8692         graph.each(function(node) {
8693           alert(node.name);
8694         });
8695       (end code)
8696    */
8697    each: function(graph, action, flags) {
8698       this.eachNode(graph, action, flags); 
8699    },
8700
8701  /*
8702        Method: eachAdjacency
8703     
8704        Iterates over <Graph.Node> adjacencies applying the *action* function.
8705        
8706        Also implemented by:
8707        
8708        <Graph.Node>.
8709
8710        Parameters:
8711
8712        node - (object) A <Graph.Node>.
8713        action - (function) A callback function having <Graph.Adjacence> as first formal parameter.
8714
8715        Example:
8716        (start code js)
8717          $jit.Graph.Util.eachAdjacency(node, function(adj) {
8718           alert(adj.nodeTo.name);
8719          });
8720          //or...
8721          node.eachAdjacency(function(adj) {
8722            alert(adj.nodeTo.name);
8723          });
8724        (end code)
8725     */
8726     eachAdjacency: function(node, action, flags) {
8727         var adj = node.adjacencies, filter = this.filter(flags);
8728         for(var id in adj) {
8729           var a = adj[id];
8730           if(filter(a)) {
8731             if(a.nodeFrom != node) {
8732               var tmp = a.nodeFrom;
8733               a.nodeFrom = a.nodeTo;
8734               a.nodeTo = tmp;
8735             }
8736             action(a, id);
8737           }
8738         }
8739     },
8740
8741      /*
8742        Method: computeLevels
8743     
8744        Performs a BFS traversal setting the correct depth for each node.
8745         
8746        Also implemented by:
8747        
8748        <Graph>.
8749        
8750        Note:
8751        
8752        The depth of each node can then be accessed by 
8753        >node._depth
8754
8755        Parameters:
8756
8757        graph - (object) A <Graph>.
8758        id - (string) A starting node id for the BFS traversal.
8759        startDepth - (optional|number) A minimum depth value. Default's 0.
8760
8761     */
8762     computeLevels: function(graph, id, startDepth, flags) {
8763         startDepth = startDepth || 0;
8764         var filter = this.filter(flags);
8765         this.eachNode(graph, function(elem) {
8766             elem._flag = false;
8767             elem._depth = -1;
8768         }, flags);
8769         var root = graph.getNode(id);
8770         root._depth = startDepth;
8771         var queue = [root];
8772         while(queue.length != 0) {
8773             var node = queue.pop();
8774             node._flag = true;
8775             this.eachAdjacency(node, function(adj) {
8776                 var n = adj.nodeTo;
8777                 if(n._flag == false && filter(n) && !adj._hiding) {
8778                     if(n._depth < 0) n._depth = node._depth + 1 + startDepth;
8779                     queue.unshift(n);
8780                 }
8781             }, flags);
8782         }
8783     },
8784
8785     /*
8786        Method: eachBFS
8787     
8788        Performs a BFS traversal applying *action* to each <Graph.Node>.
8789        
8790        Also implemented by:
8791        
8792        <Graph>.
8793
8794        Parameters:
8795
8796        graph - (object) A <Graph>.
8797        id - (string) A starting node id for the BFS traversal.
8798        action - (function) A callback function having a <Graph.Node> as first formal parameter.
8799
8800        Example:
8801        (start code js)
8802          $jit.Graph.Util.eachBFS(graph, 'mynodeid', function(node) {
8803           alert(node.name);
8804          });
8805          //or...
8806          graph.eachBFS('mynodeid', function(node) {
8807            alert(node.name);
8808          });
8809        (end code)
8810     */
8811     eachBFS: function(graph, id, action, flags) {
8812         var filter = this.filter(flags);
8813         this.clean(graph);
8814         var queue = [graph.getNode(id)];
8815         while(queue.length != 0) {
8816             var node = queue.pop();
8817             if (!node) return;
8818             node._flag = true;
8819             action(node, node._depth);
8820             this.eachAdjacency(node, function(adj) {
8821                 var n = adj.nodeTo;
8822                 if(n._flag == false && filter(n) && !adj._hiding) {
8823                     n._flag = true;
8824                     queue.unshift(n);
8825                 }
8826             }, flags);
8827         }
8828     },
8829     
8830     /*
8831        Method: eachLevel
8832     
8833        Iterates over a node's subgraph applying *action* to the nodes of relative depth between *levelBegin* and *levelEnd*.
8834        In case you need to break the iteration, *action* should return false.
8835        
8836        Also implemented by:
8837        
8838        <Graph.Node>.
8839
8840        Parameters:
8841        
8842        node - (object) A <Graph.Node>.
8843        levelBegin - (number) A relative level value.
8844        levelEnd - (number) A relative level value.
8845        action - (function) A callback function having a <Graph.Node> as first formal parameter.
8846
8847     */
8848     eachLevel: function(node, levelBegin, levelEnd, action, flags) {
8849         var d = node._depth, filter = this.filter(flags), that = this, shouldContinue = true;
8850         levelEnd = levelEnd === false? Number.MAX_VALUE -d : levelEnd;
8851         (function loopLevel(node, levelBegin, levelEnd) {
8852             if(!shouldContinue) return;
8853             var d = node._depth, ret;
8854             if(d >= levelBegin && d <= levelEnd && filter(node)) ret = action(node, d);
8855             if(typeof ret !== "undefined") shouldContinue = ret;
8856             if(shouldContinue && d < levelEnd) {
8857                 that.eachAdjacency(node, function(adj) {
8858                     var n = adj.nodeTo;
8859                     if(n._depth > d) loopLevel(n, levelBegin, levelEnd);
8860                 });
8861             }
8862         })(node, levelBegin + d, levelEnd + d);
8863     },
8864
8865     /*
8866        Method: eachSubgraph
8867     
8868        Iterates over a node's children recursively.
8869        
8870        Also implemented by:
8871        
8872        <Graph.Node>.
8873
8874        Parameters:
8875        node - (object) A <Graph.Node>.
8876        action - (function) A callback function having a <Graph.Node> as first formal parameter.
8877
8878        Example:
8879        (start code js)
8880          $jit.Graph.Util.eachSubgraph(node, function(node) {
8881            alert(node.name);
8882          });
8883          //or...
8884          node.eachSubgraph(function(node) {
8885            alert(node.name);
8886          });
8887        (end code)
8888     */
8889     eachSubgraph: function(node, action, flags) {
8890       this.eachLevel(node, 0, false, action, flags);
8891     },
8892
8893     /*
8894        Method: eachSubnode
8895     
8896        Iterates over a node's children (without deeper recursion).
8897        
8898        Also implemented by:
8899        
8900        <Graph.Node>.
8901        
8902        Parameters:
8903        node - (object) A <Graph.Node>.
8904        action - (function) A callback function having a <Graph.Node> as first formal parameter.
8905
8906        Example:
8907        (start code js)
8908          $jit.Graph.Util.eachSubnode(node, function(node) {
8909           alert(node.name);
8910          });
8911          //or...
8912          node.eachSubnode(function(node) {
8913            alert(node.name);
8914          });
8915        (end code)
8916     */
8917     eachSubnode: function(node, action, flags) {
8918         this.eachLevel(node, 1, 1, action, flags);
8919     },
8920
8921     /*
8922        Method: anySubnode
8923     
8924        Returns *true* if any subnode matches the given condition.
8925        
8926        Also implemented by:
8927        
8928        <Graph.Node>.
8929
8930        Parameters:
8931        node - (object) A <Graph.Node>.
8932        cond - (function) A callback function returning a Boolean instance. This function has as first formal parameter a <Graph.Node>.
8933
8934        Example:
8935        (start code js)
8936          $jit.Graph.Util.anySubnode(node, function(node) { return node.name == "mynodename"; });
8937          //or...
8938          node.anySubnode(function(node) { return node.name == 'mynodename'; });
8939        (end code)
8940     */
8941     anySubnode: function(node, cond, flags) {
8942       var flag = false;
8943       cond = cond || $.lambda(true);
8944       var c = $.type(cond) == 'string'? function(n) { return n[cond]; } : cond;
8945       this.eachSubnode(node, function(elem) {
8946         if(c(elem)) flag = true;
8947       }, flags);
8948       return flag;
8949     },
8950   
8951     /*
8952        Method: getSubnodes
8953     
8954        Collects all subnodes for a specified node. 
8955        The *level* parameter filters nodes having relative depth of *level* from the root node. 
8956        
8957        Also implemented by:
8958        
8959        <Graph.Node>.
8960
8961        Parameters:
8962        node - (object) A <Graph.Node>.
8963        level - (optional|number) Default's *0*. A starting relative depth for collecting nodes.
8964
8965        Returns:
8966        An array of nodes.
8967
8968     */
8969     getSubnodes: function(node, level, flags) {
8970         var ans = [], that = this;
8971         level = level || 0;
8972         var levelStart, levelEnd;
8973         if($.type(level) == 'array') {
8974             levelStart = level[0];
8975             levelEnd = level[1];
8976         } else {
8977             levelStart = level;
8978             levelEnd = Number.MAX_VALUE - node._depth;
8979         }
8980         this.eachLevel(node, levelStart, levelEnd, function(n) {
8981             ans.push(n);
8982         }, flags);
8983         return ans;
8984     },
8985   
8986   
8987     /*
8988        Method: getParents
8989     
8990        Returns an Array of <Graph.Nodes> which are parents of the given node.
8991        
8992        Also implemented by:
8993        
8994        <Graph.Node>.
8995
8996        Parameters:
8997        node - (object) A <Graph.Node>.
8998
8999        Returns:
9000        An Array of <Graph.Nodes>.
9001
9002        Example:
9003        (start code js)
9004          var pars = $jit.Graph.Util.getParents(node);
9005          //or...
9006          var pars = node.getParents();
9007          
9008          if(pars.length > 0) {
9009            //do stuff with parents
9010          }
9011        (end code)
9012     */
9013     getParents: function(node) {
9014         var ans = [];
9015         this.eachAdjacency(node, function(adj) {
9016             var n = adj.nodeTo;
9017             if(n._depth < node._depth) ans.push(n);
9018         });
9019         return ans;
9020     },
9021     
9022     /*
9023     Method: isDescendantOf
9024  
9025     Returns a boolean indicating if some node is descendant of the node with the given id. 
9026
9027     Also implemented by:
9028     
9029     <Graph.Node>.
9030     
9031     
9032     Parameters:
9033     node - (object) A <Graph.Node>.
9034     id - (string) A <Graph.Node> id.
9035
9036     Example:
9037     (start code js)
9038       $jit.Graph.Util.isDescendantOf(node, "nodeid"); //true|false
9039       //or...
9040       node.isDescendantOf('nodeid');//true|false
9041     (end code)
9042  */
9043  isDescendantOf: function(node, id) {
9044     if(node.id == id) return true;
9045     var pars = this.getParents(node), ans = false;
9046     for ( var i = 0; !ans && i < pars.length; i++) {
9047     ans = ans || this.isDescendantOf(pars[i], id);
9048   }
9049     return ans;
9050  },
9051
9052  /*
9053      Method: clean
9054   
9055      Cleans flags from nodes.
9056
9057      Also implemented by:
9058      
9059      <Graph>.
9060      
9061      Parameters:
9062      graph - A <Graph> instance.
9063   */
9064   clean: function(graph) { this.eachNode(graph, function(elem) { elem._flag = false; }); },
9065   
9066   /* 
9067     Method: getClosestNodeToOrigin 
9068   
9069     Returns the closest node to the center of canvas.
9070   
9071     Also implemented by:
9072     
9073     <Graph>.
9074     
9075     Parameters:
9076    
9077      graph - (object) A <Graph> instance.
9078      prop - (optional|string) Default's 'current'. A <Graph.Node> position property. Possible properties are 'start', 'current' or 'end'.
9079   
9080   */
9081   getClosestNodeToOrigin: function(graph, prop, flags) {
9082    return this.getClosestNodeToPos(graph, Polar.KER, prop, flags);
9083   },
9084   
9085   /* 
9086     Method: getClosestNodeToPos
9087   
9088     Returns the closest node to the given position.
9089   
9090     Also implemented by:
9091     
9092     <Graph>.
9093     
9094     Parameters:
9095    
9096      graph - (object) A <Graph> instance.
9097      pos - (object) A <Complex> or <Polar> instance.
9098      prop - (optional|string) Default's *current*. A <Graph.Node> position property. Possible properties are 'start', 'current' or 'end'.
9099   
9100   */
9101   getClosestNodeToPos: function(graph, pos, prop, flags) {
9102    var node = null;
9103    prop = prop || 'current';
9104    pos = pos && pos.getc(true) || Complex.KER;
9105    var distance = function(a, b) {
9106      var d1 = a.x - b.x, d2 = a.y - b.y;
9107      return d1 * d1 + d2 * d2;
9108    };
9109    this.eachNode(graph, function(elem) {
9110      node = (node == null || distance(elem.getPos(prop).getc(true), pos) < distance(
9111          node.getPos(prop).getc(true), pos)) ? elem : node;
9112    }, flags);
9113    return node;
9114   } 
9115 };
9116
9117 //Append graph methods to <Graph>
9118 $.each(['get', 'getNode', 'each', 'eachNode', 'computeLevels', 'eachBFS', 'clean', 'getClosestNodeToPos', 'getClosestNodeToOrigin'], function(m) {
9119   Graph.prototype[m] = function() {
9120     return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments)));
9121   };
9122 });
9123
9124 //Append node methods to <Graph.Node>
9125 $.each(['eachAdjacency', 'eachLevel', 'eachSubgraph', 'eachSubnode', 'anySubnode', 'getSubnodes', 'getParents', 'isDescendantOf'], function(m) {
9126   Graph.Node.prototype[m] = function() {
9127     return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments)));
9128   };
9129 });
9130
9131
9132 /*
9133  * File: Layouts.js
9134  * 
9135  * Implements base Tree and Graph layouts.
9136  *
9137  * Description:
9138  *
9139  * Implements base Tree and Graph layouts like Radial, Tree, etc.
9140  * 
9141  */
9142
9143 /*
9144  * Object: Layouts
9145  * 
9146  * Parent object for common layouts.
9147  *
9148  */
9149 var Layouts = $jit.Layouts = {};
9150
9151
9152 //Some util shared layout functions are defined here.
9153 var NodeDim = {
9154   label: null,
9155   
9156   compute: function(graph, prop, opt) {
9157     this.initializeLabel(opt);
9158     var label = this.label, style = label.style;
9159     graph.eachNode(function(n) {
9160       var autoWidth  = n.getData('autoWidth'),
9161           autoHeight = n.getData('autoHeight');
9162       if(autoWidth || autoHeight) {
9163         //delete dimensions since these are
9164         //going to be overridden now.
9165         delete n.data.$width;
9166         delete n.data.$height;
9167         delete n.data.$dim;
9168         
9169         var width  = n.getData('width'),
9170             height = n.getData('height');
9171         //reset label dimensions
9172         style.width  = autoWidth? 'auto' : width + 'px';
9173         style.height = autoHeight? 'auto' : height + 'px';
9174         
9175         //TODO(nico) should let the user choose what to insert here.
9176         label.innerHTML = n.name;
9177         
9178         var offsetWidth  = label.offsetWidth,
9179             offsetHeight = label.offsetHeight;
9180         var type = n.getData('type');
9181         if($.indexOf(['circle', 'square', 'triangle', 'star'], type) === -1) {
9182           n.setData('width', offsetWidth);
9183           n.setData('height', offsetHeight);
9184         } else {
9185           var dim = offsetWidth > offsetHeight? offsetWidth : offsetHeight;
9186           n.setData('width', dim);
9187           n.setData('height', dim);
9188           n.setData('dim', dim); 
9189         }
9190       }
9191     });
9192   },
9193   
9194   initializeLabel: function(opt) {
9195     if(!this.label) {
9196       this.label = document.createElement('div');
9197       document.body.appendChild(this.label);
9198     }
9199     this.setLabelStyles(opt);
9200   },
9201   
9202   setLabelStyles: function(opt) {
9203     $.extend(this.label.style, {
9204       'visibility': 'hidden',
9205       'position': 'absolute',
9206       'width': 'auto',
9207       'height': 'auto'
9208     });
9209     this.label.className = 'jit-autoadjust-label';
9210   }
9211 };
9212
9213
9214 /*
9215  * File: Layouts.MultiTopology.js
9216  *
9217 */
9218
9219 /*
9220  * Class: Layouts.MultiTopology
9221  * 
9222  * Implements a Multi Topology Layout.
9223  * Adapted from Layouts.ForceDirected
9224  * 
9225  * Implemented By:
9226  * 
9227  * <MultiTopology>
9228  * 
9229  * Credits:
9230  * 
9231  * Marcus Cobden <http://marcuscobden.co.uk>
9232  * 
9233  */
9234 Layouts.MultiTopology = new Class({
9235
9236   getOptions: function(random) {
9237     var s = this.canvas.getSize();
9238     var w = s.width, h = s.height;
9239     //count nodes
9240     var count = 0;
9241     this.graph.eachNode(function(n) { 
9242       count++;
9243     });
9244     var k2 = w * h / count, k = Math.sqrt(k2);
9245     var l = this.config.levelDistance;
9246     
9247     return {
9248       width: w - l,
9249       height: h - l,
9250       tstart: w * 0.1,
9251       nodef: function(x) { return k2 / (x || 1); },
9252       edgef: function(x) { return /* x * x / k; */ k * (x - l); }
9253     };
9254   },
9255   
9256   compute: function(property, incremental) {
9257     var prop = $.splat(property || ['current', 'start', 'end']);
9258     var opt = this.getOptions();
9259     NodeDim.compute(this.graph, prop, this.config);
9260     this.graph.computeLevels(this.root, 0, "ignore");
9261     this.graph.eachNode(function(n) {
9262       $.each(prop, function(p) {
9263         var pos = n.getPos(p);
9264         if(pos.equals(Complex.KER)) {
9265           pos.x = opt.width/5 * (Math.random() - 0.5);
9266           pos.y = opt.height/5 * (Math.random() - 0.5);
9267         }
9268         //initialize disp vector
9269         n.disp = {};
9270         $.each(prop, function(p) {
9271           n.disp[p] = $C(0, 0);
9272         });
9273       });
9274     });
9275     this.computePositions(prop, opt, incremental);
9276   },
9277   
9278   computePositions: function(property, opt, incremental) {
9279     var times = this.config.iterations, i = 0, that = this;
9280     if(incremental) {
9281       (function iter() {
9282         for(var total=incremental.iter, j=0; j<total; j++) {
9283           opt.t = opt.tstart;
9284           if(times) opt.t *= (1 - i++/(times -1));
9285           that.computePositionStep(property, opt);
9286           if(times && i >= times) {
9287             incremental.onComplete();
9288             return;
9289           }
9290         }
9291         incremental.onStep(Math.round(i / (times -1) * 100));
9292         setTimeout(iter, 1);
9293       })();
9294     } else {
9295       for(; i < times; i++) {
9296         opt.t = opt.tstart * (1 - i/(times -1));
9297         this.computePositionStep(property, opt);
9298       }
9299     }
9300   },
9301   
9302   computePositionStep: function(property, opt) {
9303     var graph = this.graph;
9304     var min = Math.min, max = Math.max;
9305     var dpos = $C(0, 0);
9306     //calculate repulsive forces
9307     graph.eachNode(function(v) {
9308       //initialize disp
9309       $.each(property, function(p) {
9310         v.disp[p].x = 0; v.disp[p].y = 0;
9311       });
9312       graph.eachNode(function(u) {
9313         if(u.id != v.id) {
9314           $.each(property, function(p) {
9315             var vp = v.getPos(p), up = u.getPos(p);
9316             dpos.x = vp.x - up.x;
9317             dpos.y = vp.y - up.y;
9318             var norm = dpos.norm() || 1;
9319             v.disp[p].$add(dpos
9320                 .$scale(opt.nodef(norm) / norm));
9321           });
9322         }
9323       });
9324     });
9325     //calculate attractive forces
9326     var T = !!graph.getNode(this.root).visited;
9327     graph.eachNode(function(node) {
9328       node.eachAdjacency(function(adj) {
9329         var nodeTo = adj.nodeTo;
9330         if(!!nodeTo.visited === T) {
9331           $.each(property, function(p) {
9332             var vp = node.getPos(p), up = nodeTo.getPos(p);
9333             dpos.x = vp.x - up.x;
9334             dpos.y = vp.y - up.y;
9335             var norm = dpos.norm() || 1;
9336             node.disp[p].$add(dpos.$scale(-opt.edgef(norm) / norm));
9337             nodeTo.disp[p].$add(dpos.$scale(-1));
9338           });
9339         }
9340       });
9341       node.visited = !T;
9342     });
9343     //arrange positions to fit the canvas
9344     var t = opt.t, w2 = opt.width / 2, h2 = opt.height / 2;
9345     graph.eachNode(function(u) {
9346       $.each(property, function(p) {
9347         var disp = u.disp[p];
9348         var norm = disp.norm() || 1;
9349         var p = u.getPos(p);
9350         p.$add($C(disp.x * min(Math.abs(disp.x), t) / norm, 
9351             disp.y * min(Math.abs(disp.y), t) / norm));
9352         p.x = min(w2, max(-w2, p.x));
9353         p.y = min(h2, max(-h2, p.y));
9354       });
9355     });
9356   }
9357 });
9358
9359
9360 /*
9361  * File: MultiTopology.js
9362  */
9363
9364 /*
9365    Class: MultiTopology
9366       
9367    A network graph visualization adapted from the Force-Directed graph
9368    
9369   Implements:
9370   
9371   All <MultiLoader> methods
9372   
9373    Constructor Options:
9374    
9375    Inherits options from
9376    
9377    - <Options.Canvas>
9378    - <Options.Controller>
9379    - <Options.Node>
9380    - <Options.Edge>
9381    - <Options.Label>
9382    - <Options.Events>
9383    - <Options.Tips>
9384    - <Options.NodeStyles>
9385    - <Options.Navigation>
9386    
9387    Additionally, there are two parameters
9388    
9389    levelDistance - (number) Default's *50*. The natural length desired for the edges.
9390    iterations - (number) Default's *50*. The number of iterations for the spring layout simulation. Depending on the browser's speed you could set this to a more 'interesting' number, like *200*. 
9391      
9392    Instance Properties:
9393
9394    canvas - Access a <Canvas> instance.
9395    graph - Access a <Graph> instance.
9396    op - Access a <ForceDirected.Op> instance.
9397    fx - Access a <ForceDirected.Plot> instance.
9398    labels - Access a <ForceDirected.Label> interface implementation.
9399
9400 */
9401
9402 $jit.MultiTopology = new Class( {
9403
9404   Implements: [ MultiLoader, MultiExtras, Layouts.MultiTopology ],
9405
9406   initialize: function(controller) {
9407     var $MultiTopology = $jit.MultiTopology;
9408
9409     var config = {
9410       iterations: 50,
9411       levelDistance: 50
9412     };
9413
9414     this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge",
9415         "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller);
9416
9417     var canvasConfig = this.config;
9418     if(canvasConfig.useCanvas) {
9419       this.canvas = canvasConfig.useCanvas;
9420       this.config.labelContainer = this.canvas.id + '-label';
9421     } else {
9422       if(canvasConfig.background) {
9423         canvasConfig.background = $.merge({
9424           type: 'Circles'
9425         }, canvasConfig.background);
9426       }
9427       this.canvas = new Canvas(this, canvasConfig);
9428       this.config.labelContainer = (typeof canvasConfig.injectInto == 'string'? canvasConfig.injectInto : canvasConfig.injectInto.id) + '-label';
9429     }
9430
9431     this.graphOptions = {
9432       'klass': Complex,
9433       'Node': {
9434         'selected': false,
9435         'exist': true,
9436         'drawn': true
9437       }
9438     };
9439     this.graph = new MultiGraph(this.graphOptions, this.config.Node,
9440         this.config.Edge);
9441     this.labels = new $MultiTopology.Label[canvasConfig.Label.type](this);
9442     this.fx = new $MultiTopology.Plot(this, $MultiTopology);
9443     this.op = new $MultiTopology.Op(this);
9444     this.json = null;
9445     this.busy = false;
9446     // initialize extras
9447     this.initializeExtras();
9448   },
9449
9450   /* 
9451     Method: refresh 
9452     
9453     Computes positions and plots the tree.
9454   */
9455   refresh: function() {
9456     this.compute();
9457     this.plot();
9458   },
9459
9460   reposition: function() {
9461     this.compute('end');
9462   },
9463
9464 /*
9465   Method: computeIncremental
9466   
9467   Performs the Force Directed algorithm incrementally.
9468   
9469   Description:
9470   
9471   ForceDirected algorithms can perform many computations and lead to JavaScript taking too much time to complete. 
9472   This method splits the algorithm into smaller parts allowing the user to track the evolution of the algorithm and 
9473   avoiding browser messages such as "This script is taking too long to complete".
9474   
9475   Parameters:
9476   
9477   opt - (object) The object properties are described below
9478   
9479   iter - (number) Default's *20*. Split the algorithm into pieces of _iter_ iterations. For example, if the _iterations_ configuration property 
9480   of your <ForceDirected> class is 100, then you could set _iter_ to 20 to split the main algorithm into 5 smaller pieces.
9481   
9482   property - (string) Default's *end*. Whether to update starting, current or ending node positions. Possible values are 'end', 'start', 'current'. 
9483   You can also set an array of these properties. If you'd like to keep the current node positions but to perform these 
9484   computations for final animation positions then you can just choose 'end'.
9485   
9486   onStep - (function) A callback function called when each "small part" of the algorithm completed. This function gets as first formal 
9487   parameter a percentage value.
9488   
9489   onComplete - A callback function called when the algorithm completed.
9490   
9491   Example:
9492   
9493   In this example I calculate the end positions and then animate the graph to those positions
9494   
9495   (start code js)
9496   var fd = new $jit.ForceDirected(...);
9497   fd.computeIncremental({
9498     iter: 20,
9499     property: 'end',
9500     onStep: function(perc) {
9501       Log.write("loading " + perc + "%");
9502     },
9503     onComplete: function() {
9504       Log.write("done");
9505       fd.animate();
9506     }
9507   });
9508   (end code)
9509   
9510   In this example I calculate all positions and (re)plot the graph
9511   
9512   (start code js)
9513   var fd = new ForceDirected(...);
9514   fd.computeIncremental({
9515     iter: 20,
9516     property: ['end', 'start', 'current'],
9517     onStep: function(perc) {
9518       Log.write("loading " + perc + "%");
9519     },
9520     onComplete: function() {
9521       Log.write("done");
9522       fd.plot();
9523     }
9524   });
9525   (end code)
9526   
9527   */
9528   computeIncremental: function(opt) {
9529     opt = $.merge( {
9530       iter: 20,
9531       property: 'end',
9532       onStep: $.empty,
9533       onComplete: $.empty
9534     }, opt || {});
9535
9536     this.config.onBeforeCompute(this.graph.getNode(this.root));
9537     this.compute(opt.property, opt);
9538   },
9539
9540   /*
9541     Method: plot
9542    
9543     Plots the ForceDirected graph. This is a shortcut to *fx.plot*.
9544    */
9545   plot: function() {
9546     this.fx.plot();
9547   },
9548
9549   /*
9550      Method: animate
9551     
9552      Animates the graph from the current positions to the 'end' node positions.
9553   */
9554   animate: function(opt) {
9555     this.fx.animate($.merge( {
9556       modes: [ 'linear' ]
9557     }, opt || {}));
9558   }
9559 });
9560
9561 $jit.MultiTopology.$extend = true;
9562
9563 (function(MultiTopology) {
9564
9565   /*
9566      Class: ForceDirected.Op
9567      
9568      Custom extension of <Graph.Op>.
9569
9570      Extends:
9571
9572      All <Graph.Op> methods
9573      
9574      See also:
9575      
9576      <Graph.Op>
9577
9578   */
9579   MultiTopology.Op = new Class( {
9580
9581     Implements: MultiGraph.Op
9582
9583   });
9584
9585   /*
9586     Class: ForceDirected.Plot
9587     
9588     Custom extension of <Graph.Plot>.
9589   
9590     Extends:
9591   
9592     All <Graph.Plot> methods
9593     
9594     See also:
9595     
9596     <Graph.Plot>
9597   
9598   */
9599   MultiTopology.Plot = new Class( {
9600
9601     Implements: MultiGraph.Plot
9602
9603   });
9604
9605   /*
9606     Class: ForceDirected.Label
9607     
9608     Custom extension of <Graph.Label>. 
9609     Contains custom <Graph.Label.SVG>, <Graph.Label.HTML> and <Graph.Label.Native> extensions.
9610   
9611     Extends:
9612   
9613     All <Graph.Label> methods and subclasses.
9614   
9615     See also:
9616   
9617     <Graph.Label>, <Graph.Label.Native>, <Graph.Label.HTML>, <Graph.Label.SVG>.
9618   
9619   */
9620   MultiTopology.Label = {};
9621
9622   /*
9623      ForceDirected.Label.Native
9624      
9625      Custom extension of <Graph.Label.Native>.
9626
9627      Extends:
9628
9629      All <Graph.Label.Native> methods
9630
9631      See also:
9632
9633      <Graph.Label.Native>
9634
9635   */
9636   MultiTopology.Label.Native = new Class( {
9637     Implements: MultiGraph.Label.Native
9638   });
9639
9640   /*
9641     ForceDirected.Label.SVG
9642     
9643     Custom extension of <Graph.Label.SVG>.
9644   
9645     Extends:
9646   
9647     All <Graph.Label.SVG> methods
9648   
9649     See also:
9650   
9651     <Graph.Label.SVG>
9652   
9653   */
9654   MultiTopology.Label.SVG = new Class( {
9655     Implements: MultiGraph.Label.SVG,
9656
9657     initialize: function(viz) {
9658       this.viz = viz;
9659     },
9660
9661     /* 
9662        placeLabel
9663
9664        Overrides abstract method placeLabel in <Graph.Label>.
9665
9666        Parameters:
9667
9668        tag - A DOM label element.
9669        node - A <Graph.Node>.
9670        controller - A configuration/controller object passed to the visualization.
9671       
9672      */
9673     placeLabel: function(tag, node, controller) {
9674       var pos = node.pos.getc(true), 
9675           canvas = this.viz.canvas,
9676           ox = canvas.translateOffsetX,
9677           oy = canvas.translateOffsetY,
9678           sx = canvas.scaleOffsetX,
9679           sy = canvas.scaleOffsetY,
9680           radius = canvas.getSize();
9681       var labelPos = {
9682         x: Math.round(pos.x * sx + ox + radius.width / 2),
9683         y: Math.round(pos.y * sy + oy + radius.height / 2)
9684       };
9685       tag.setAttribute('x', labelPos.x);
9686       tag.setAttribute('y', labelPos.y);
9687
9688       controller.onPlaceLabel(tag, node);
9689     }
9690   });
9691
9692   /*
9693      ForceDirected.Label.HTML
9694      
9695      Custom extension of <Graph.Label.HTML>.
9696
9697      Extends:
9698
9699      All <Graph.Label.HTML> methods.
9700
9701      See also:
9702
9703      <Graph.Label.HTML>
9704
9705   */
9706   MultiTopology.Label.HTML = new Class( {
9707     Implements: MultiGraph.Label.HTML,
9708
9709     initialize: function(viz) {
9710       this.viz = viz;
9711     },
9712     /* 
9713        placeLabel
9714
9715        Overrides abstract method placeLabel in <Graph.Plot>.
9716
9717        Parameters:
9718
9719        tag - A DOM label element.
9720        node - A <Graph.Node>.
9721        controller - A configuration/controller object passed to the visualization.
9722       
9723      */
9724     placeLabel: function(tag, node, controller) {
9725       var pos = node.pos.getc(true), 
9726           canvas = this.viz.canvas,
9727           ox = canvas.translateOffsetX,
9728           oy = canvas.translateOffsetY,
9729           sx = canvas.scaleOffsetX,
9730           sy = canvas.scaleOffsetY,
9731           radius = canvas.getSize();
9732       var labelPos = {
9733         x: Math.round(pos.x * sx + ox + radius.width / 2),
9734         y: Math.round(pos.y * sy + oy + radius.height / 2)
9735       };
9736       var style = tag.style;
9737       style.left = labelPos.x + 'px';
9738       style.top = labelPos.y + 'px';
9739       style.display = this.fitsInCanvas(labelPos, canvas) ? '' : 'none';
9740
9741       controller.onPlaceLabel(tag, node);
9742     }
9743   });
9744
9745   /*
9746     Class: ForceDirected.Plot.NodeTypes
9747
9748     This class contains a list of <Graph.Node> built-in types. 
9749     Node types implemented are 'none', 'circle', 'triangle', 'rectangle', 'star', 'ellipse' and 'square'.
9750
9751     You can add your custom node types, customizing your visualization to the extreme.
9752
9753     Example:
9754
9755     (start code js)
9756       ForceDirected.Plot.NodeTypes.implement({
9757         'mySpecialType': {
9758           'render': function(node, canvas) {
9759             //print your custom node to canvas
9760           },
9761           //optional
9762           'contains': function(node, pos) {
9763             //return true if pos is inside the node or false otherwise
9764           }
9765         }
9766       });
9767     (end code)
9768
9769   */
9770   MultiTopology.Plot.NodeTypes = new Class({
9771     'none': {
9772       'render': $.empty,
9773       'contains': $.lambda(false)
9774     },
9775         'host': {
9776                 'render': function(node, canvas, animating) {
9777                         var pos = node.pos.getc(true);
9778                         this.nodeHelper.host.render(pos, canvas, animating);
9779                 },
9780                 'contains': function(node, pos) {
9781                         var npos = node.pos.getc(true);
9782                         return this.nodeHelper.host.contains(npos, pos);
9783                 }
9784         },
9785         'swtch': {
9786                 'render': function(node, canvas, animating) {
9787                         var pos = node.pos.getc(true);
9788                         this.nodeHelper.swtch.render(pos, canvas, animating);
9789                 },
9790                 'contains': function(node, pos) {
9791                         var npos = node.pos.getc(true);
9792                         return this.nodeHelper.swtch.contains(npos, pos);
9793                 }
9794         }
9795   });
9796
9797   /*
9798     Class: ForceDirected.Plot.EdgeTypes
9799   
9800     This class contains a list of <Graph.Adjacence> built-in types. 
9801     Edge types implemented are 'none', 'line' and 'arrow'.
9802   
9803     You can add your custom edge types, customizing your visualization to the extreme.
9804   
9805     Example:
9806   
9807     (start code js)
9808       ForceDirected.Plot.EdgeTypes.implement({
9809         'mySpecialType': {
9810           'render': function(adj, canvas) {
9811             //print your custom edge to canvas
9812           },
9813           //optional
9814           'contains': function(adj, pos) {
9815             //return true if pos is inside the arc or false otherwise
9816           }
9817         }
9818       });
9819     (end code)
9820   
9821   */
9822   MultiTopology.Plot.EdgeTypes = new Class({
9823     'none': $.empty,
9824     'line': {
9825       'render': function(adj, alpha, canvas) {
9826         var from = adj.nodeFrom.pos.getc(true),
9827             to = adj.nodeTo.pos.getc(true);
9828         this.edgeHelper.line.render(from, to, alpha, canvas);
9829       },
9830       'contains': function(adj, alpha, pos, canvas) {
9831         var from = adj.nodeFrom.pos.getc(true),
9832             to = adj.nodeTo.pos.getc(true);
9833         return this.edgeHelper.line.contains(from, to, alpha, pos, this.edge.epsilon, canvas);
9834       }
9835     }
9836   });
9837
9838 })($jit.MultiTopology);
9839
9840
9841
9842
9843  })();