Fix disappearing nodes
[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.