Nettacker/lib/graph/jit_circle_v1/engine.py

14811 lines
427 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import string
import random
import json
from core.alert import messages
from core.compatible import version
def start(graph_flag, language, data, _HOST, _USERNAME, _PASSWORD, _PORT, _TYPE, _DESCRIPTION):
"""
generate the jit_circle_v1_graph with events
Args:
graph_flag: graph name
language: language
data: events in JSON
_HOST: host key
_USERNAME: username key
_PASSWORD: password key
_PORT: port key
_TYPE: module name key
_DESCRIPTION: description key
Returns:
a graph in HTML
"""
# define a normalised_json
normalisedjson = {
"name": "Started attack",
"children": {}
}
# get data for normalised_json
for each_scan in data:
if each_scan['HOST'] not in normalisedjson['children']:
normalisedjson['children'].update({each_scan['HOST']: {}})
normalisedjson['children'][each_scan['HOST']].update(
{each_scan['TYPE']: []})
if each_scan['TYPE'] not in normalisedjson['children'][each_scan['HOST']]:
normalisedjson['children'][each_scan['HOST']].update(
{each_scan['TYPE']: []})
normalisedjson['children'][each_scan['HOST']][each_scan['TYPE']].append("HOST: \"%s\", PORT:\"%s\", DESCRIPTION:\"%s\", USERNAME:\"%s\", PASSWORD:\"%s\"" % (
each_scan['HOST'], each_scan['PORT'], each_scan['DESCRIPTION'], each_scan['USERNAME'], each_scan['PASSWORD']))
# define a dgraph_json
dgraph = {
"id": "0",
"data": [],
"relation": "",
"name": "Start Attacking",
"children": []
}
# get data for dgraph_json
n = 1
for host in normalisedjson['children']:
dgraph['children'].append({"id": str(n), "name": host, "data": {"relation": "Start Attacking"}, "children": [{"id": ''.join(random.choice(
string.ascii_letters + string.digits) for _ in range(20)), "name": otype, "data": {"band": [description.split(', ')[2].lstrip("DESCRIPTION: ").strip("\"") for description in normalisedjson['children'][host][otype]][0], "relation": [description.split(', ')[1:] for description in normalisedjson['children'][host][otype]]}, "children": [{"children": [], "data":{"band": description.split(', ')[2], "relation": description.split(', ')[1:]}, "id": ''.join(random.choice(
string.ascii_letters + string.digits) for _ in range(20)), "name": description.split(', ')[1].lstrip("PORT: ").strip("\"")} for description in normalisedjson['children'][host][otype]]} for otype in normalisedjson['children'][host]]})
n += 1
data = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- THIS SAMPLE COPIED AND MODIFIED FROM http://philogb.github.io/jit/static/v20/Jit/Examples/Hypertree/example1.html -->
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>__html_title_to_replace__</title>
<!-- CSS Files -->
<!-- MODIFIED FROM http://philogb.github.io/jit/static/v20/Jit/Examples/css/base.css
\t\t\t\t http://philogb.github.io/jit/static/v20/Jit/Examples/css/Hypertree.css -->
<style>
html, body {
margina:0;
padding:0;
font-family: "Lucida Grande", Verdana;
font-size: 0.9em;
text-align: center;
background-color:#F2F2F2;
}
input, select {
font-size:0.9em;
}
table {
margin-top:-10px;
margin-left:7px;
}
h4 {
font-size:1.1em;
text-decoration:none;
font-weight:normal;
color:#23A4FF;
}
a {
color:#23A4FF;
}
#container {
width: 1000px;
height: 600px;
margin:0 auto;
position:relative;
}
#left-container,
#right-container,
#center-container {
height:600px;
position:absolute;
top:0;
}
#left-container, #right-container {
width:200px;
color:#686c70;
text-align: left;
overflow: auto;
background-color:#fff;
background-repeat:no-repeat;
border-bottom:1px solid #ddd;
}
#left-container {
left:0;
background-image:url(\'col2.png\');
background-position:center right;
border-left:1px solid #ddd;
}
#right-container {
right:0;
background-image:url(\'col1.png\');
background-position:center left;
border-right:1px solid #ddd;
}
#right-container h4{
text-indent:8px;
}
#center-container {
width:600px;
left:200px;
background-color:#1a1a1a;
color:#ccc;
}
.text {
margin: 7px;
}
#inner-details {
font-size:0.8em;
list-style:none;
margin:7px;
}
#log {
position:absolute;
top:10px;
font-size:1.0em;
font-weight:bold;
color:#23A4FF;
}
#infovis {
position:relative;
width:600px;
height:600px;
margin:auto;
overflow:hidden;
}
/*TOOLTIPS*/
.tip {
color: #111;
width: 139px;
background-color: white;
border:1px solid #ccc;
-moz-box-shadow:#555 2px 2px 8px;
-webkit-box-shadow:#555 2px 2px 8px;
-o-box-shadow:#555 2px 2px 8px;
box-shadow:#555 2px 2px 8px;
opacity:0.9;
filter:alpha(opacity=90);
font-size:10px;
font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
padding:7px;
}
#infovis-canvaswidget {
margin:25px 0 0 25px;
}
</style>
<a target="_blank" href="https://github.com/OWASP/Nettacker"><h2>OWASP Nettacker</h2></a>
<!--[if IE]><script language="javascript" type="text/javascript" src="../../Extras/excanvas.js"></script><![endif]-->
<!-- JIT Library File -->
<script>
__js_jit_lib_will_locate_here__
</script>
<!-- jit library -->
<script>
/*
Copyright (c) 2011 Sencha Inc. - Author: Nicolas Garcia Belmonte (http://philogb.github.com/)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
(function() {
/**
* @param {Object} w
* @return {undefined}
*/
window.$jit = function(w) {
w = w || window;
var k;
for (k in $jit) {
if ($jit[k].$extend) {
w[k] = $jit[k];
}
}
};
/** @type {string} */
$jit.version = "2.0.1";
/**
* @param {?} obj
* @return {?}
*/
var $ = function(obj) {
return document.getElementById(obj);
};
/**
* @return {undefined}
*/
$.empty = function() {
};
/**
* @param {?} obj
* @param {?} opt_attributes
* @return {?}
*/
$.extend = function(obj, opt_attributes) {
var val;
for (val in opt_attributes || {}) {
obj[val] = opt_attributes[val];
}
return obj;
};
/**
* @param {boolean} recurring
* @return {?}
*/
$.lambda = function(recurring) {
return typeof recurring == "function" ? recurring : function() {
return recurring;
};
};
/** @type {function (): number} */
$.time = Date.now || function() {
return+new Date;
};
/**
* @param {string} obj
* @return {?}
*/
$.splat = function(obj) {
var type = $.type(obj);
return type ? type != "array" ? [obj] : obj : [];
};
/**
* @param {Object} obj
* @return {?}
*/
$.type = function(obj) {
/** @type {string} */
var t = $.type.s.call(obj).match(/^\\[object\\s(.*)\\]$/)[1].toLowerCase();
if (t != "object") {
return t;
}
if (obj && obj.$$family) {
return obj.$$family;
}
return obj && (obj.nodeName && obj.nodeType == 1) ? "element" : t;
};
/** @type {function (this:*): string} */
$.type.s = Object.prototype.toString;
/**
* @param {?} opt_attributes
* @param {Function} f
* @return {undefined}
*/
$.each = function(opt_attributes, f) {
var value = $.type(opt_attributes);
if (value == "object") {
var i;
for (i in opt_attributes) {
f(opt_attributes[i], i);
}
} else {
/** @type {number} */
var m = 0;
var n = opt_attributes.length;
for (;m < n;m++) {
f(opt_attributes[m], m);
}
}
};
/**
* @param {Array} arr
* @param {?} obj
* @return {?}
*/
$.indexOf = function(arr, obj) {
if (Array.indexOf) {
return arr.indexOf(obj);
}
/** @type {number} */
var i = 0;
var e = arr.length;
for (;i < e;i++) {
if (arr[i] === obj) {
return i;
}
}
return-1;
};
/**
* @param {?} attributes
* @param {Function} fun
* @return {?}
*/
$.map = function(attributes, fun) {
/** @type {Array} */
var fin = [];
$.each(attributes, function(k, v) {
fin.push(fun(k, v));
});
return fin;
};
/**
* @param {?} arr
* @param {Function} callback
* @param {number} mayParseLabeledStatementInstead
* @return {?}
*/
$.reduce = function(arr, callback, mayParseLabeledStatementInstead) {
var j = arr.length;
if (j == 0) {
return mayParseLabeledStatementInstead;
}
var basis = arguments.length == 3 ? mayParseLabeledStatementInstead : arr[--j];
for (;j--;) {
basis = callback(basis, arr[j]);
}
return basis;
};
/**
* @return {?}
*/
$.merge = function() {
var mix = {};
/** @type {number} */
var argsIndex = 0;
/** @type {number} */
var argsLength = arguments.length;
for (;argsIndex < argsLength;argsIndex++) {
var iterable = arguments[argsIndex];
if ($.type(iterable) != "object") {
continue;
}
var key;
for (key in iterable) {
var op = iterable[key];
var mp = mix[key];
mix[key] = mp && ($.type(op) == "object" && $.type(mp) == "object") ? $.merge(mp, op) : $.unlink(op);
}
}
return mix;
};
/**
* @param {Object} object
* @return {?}
*/
$.unlink = function(object) {
var safe;
switch($.type(object)) {
case "object":
safe = {};
var key;
for (key in object) {
safe[key] = $.unlink(object[key]);
}
break;
case "array":
/** @type {Array} */
safe = [];
/** @type {number} */
var i = 0;
var length = object.length;
for (;i < length;i++) {
safe[i] = $.unlink(object[i]);
}
break;
default:
return object;
}
return safe;
};
/**
* @return {?}
*/
$.zip = function() {
if (arguments.length === 0) {
return[];
}
/** @type {number} */
var j = 0;
/** @type {Array} */
var out = [];
/** @type {number} */
var argLength = arguments.length;
var jl = arguments[0].length;
for (;j < jl;j++) {
/** @type {number} */
var i = 0;
/** @type {Array} */
var copies = [];
for (;i < argLength;i++) {
copies.push(arguments[i][j]);
}
out.push(copies);
}
return out;
};
/**
* @param {Array} ans
* @param {boolean} array
* @return {?}
*/
$.rgbToHex = function(ans, array) {
if (ans.length < 3) {
return null;
}
if (ans.length == 4 && (ans[3] == 0 && !array)) {
return "transparent";
}
/** @type {Array} */
var hex = [];
/** @type {number} */
var i = 0;
for (;i < 3;i++) {
/** @type {string} */
var bit = (ans[i] - 0).toString(16);
hex.push(bit.length == 1 ? "0" + bit : bit);
}
return array ? hex : "#" + hex.join("");
};
/**
* @param {string} hex
* @return {?}
*/
$.hexToRgb = function(hex) {
if (hex.length != 7) {
hex = hex.match(/^#?(\\w{1,2})(\\w{1,2})(\\w{1,2})$/);
hex.shift();
if (hex.length != 3) {
return null;
}
/** @type {Array} */
var rgb = [];
/** @type {number} */
var index = 0;
for (;index < 3;index++) {
var value = hex[index];
if (value.length == 1) {
value += value;
}
rgb.push(parseInt(value, 16));
}
return rgb;
} else {
/** @type {number} */
hex = parseInt(hex.slice(1), 16);
return[hex >> 16, hex >> 8 & 255, hex & 255];
}
};
/**
* @param {Element} elem
* @return {undefined}
*/
$.destroy = function(elem) {
$.clean(elem);
if (elem.parentNode) {
elem.parentNode.removeChild(elem);
}
if (elem.clearAttributes) {
elem.clearAttributes();
}
};
/**
* @param {Element} el
* @return {undefined}
*/
$.clean = function(el) {
var nodes = el.childNodes;
/** @type {number} */
var i = 0;
var len = nodes.length;
for (;i < len;i++) {
$.destroy(nodes[i]);
}
};
/**
* @param {Object} elem
* @param {string} type
* @param {Function} cb
* @return {undefined}
*/
$.addEvent = function(elem, type, cb) {
if (elem.addEventListener) {
elem.addEventListener(type, cb, false);
} else {
elem.attachEvent("on" + type, cb);
}
};
/**
* @param {Object} element
* @param {Object} events
* @return {undefined}
*/
$.addEvents = function(element, events) {
var type;
for (type in events) {
$.addEvent(element, type, events[type]);
}
};
/**
* @param {Element} domElement
* @param {string} selector
* @return {?}
*/
$.hasClass = function(domElement, selector) {
return(" " + domElement.className + " ").indexOf(" " + selector + " ") > -1;
};
/**
* @param {Element} domElement
* @param {string} className
* @return {undefined}
*/
$.addClass = function(domElement, className) {
if (!$.hasClass(domElement, className)) {
/** @type {string} */
domElement.className = domElement.className + " " + className;
}
};
/**
* @param {Element} element
* @param {string} classNames
* @return {undefined}
*/
$.removeClass = function(element, classNames) {
element.className = element.className.replace(new RegExp("(^|\\\\s)" + classNames + "(?:\\\\s|$)"), "$1");
};
/**
* @param {Object} c
* @return {?}
*/
$.getPos = function(c) {
/**
* @param {Object} elem
* @return {?}
*/
function getOffsets(elem) {
var offset = {
x : 0,
y : 0
};
for (;elem && !isBody(elem);) {
offset.x += elem.offsetLeft;
offset.y += elem.offsetTop;
elem = elem.offsetParent;
}
return offset;
}
/**
* @param {HTMLElement} element
* @return {?}
*/
function getScrolls(element) {
var position = {
x : 0,
y : 0
};
for (;element && !isBody(element);) {
position.x += element.scrollLeft;
position.y += element.scrollTop;
element = element.parentNode;
}
return position;
}
/**
* @param {Object} element
* @return {?}
*/
function isBody(element) {
return/^(?:body|html)$/i.test(element.tagName);
}
var pos = getOffsets(c);
var e = getScrolls(c);
return{
x : pos.x - e.x,
y : pos.y - e.y
};
};
$.event = {
/**
* @param {Object} adj
* @param {Object} lab
* @return {?}
*/
get : function(adj, lab) {
lab = lab || window;
return adj || lab.event;
},
/**
* @param {Event} e
* @return {?}
*/
getWheel : function(e) {
return e.wheelDelta ? e.wheelDelta / 120 : -(e.detail || 0) / 3;
},
/**
* @param {Event} event
* @return {?}
*/
isRightClick : function(event) {
return event.which == 3 || event.button == 2;
},
/**
* @param {Object} value
* @param {Object} win
* @return {?}
*/
getPos : function(value, win) {
win = win || window;
value = value || win.event;
var doc = win.document;
doc = doc.documentElement || doc.body;
if (value.touches && value.touches.length) {
value = value.touches[0];
}
var pos = {
x : value.pageX || value.clientX + doc.scrollLeft,
y : value.pageY || value.clientY + doc.scrollTop
};
return pos;
},
/**
* @param {Event} event
* @return {undefined}
*/
stop : function(event) {
if (event.stopPropagation) {
event.stopPropagation();
}
/** @type {boolean} */
event.cancelBubble = true;
if (event.preventDefault) {
event.preventDefault();
} else {
/** @type {boolean} */
event.returnValue = false;
}
}
};
/** @type {function (?): ?} */
$jit.util = $jit.id = $;
/**
* @param {Object} properties
* @return {?}
*/
var Class = function(properties) {
properties = properties || {};
/**
* @return {?}
*/
var klass = function() {
var p;
for (p in this) {
if (typeof this[p] != "function") {
this[p] = $.unlink(this[p]);
}
}
/** @type {function (): ?} */
this.constructor = klass;
if (Class.prototyping) {
return this;
}
var instance = this.initialize ? this.initialize.apply(this, arguments) : this;
/** @type {string} */
this.$$family = "class";
return instance;
};
var mutator;
for (mutator in Class.Mutators) {
if (!properties[mutator]) {
continue;
}
properties = Class.Mutators[mutator](properties, properties[mutator]);
delete properties[mutator];
}
$.extend(klass, this);
/** @type {function (Object): ?} */
klass.constructor = Class;
/** @type {Object} */
klass.prototype = properties;
return klass;
};
Class.Mutators = {
/**
* @param {Object} self
* @param {string} klasses
* @return {?}
*/
Implements : function(self, klasses) {
$.each($.splat(klasses), function(klass) {
/** @type {string} */
Class.prototyping = klass;
var iterable = typeof klass == "function" ? new klass : klass;
var key;
for (key in iterable) {
if (!(key in self)) {
self[key] = iterable[key];
}
}
delete Class.prototyping;
});
return self;
}
};
$.extend(Class, {
/**
* @param {Object} object
* @param {Object} properties
* @return {?}
*/
inherit : function(object, properties) {
var key;
for (key in properties) {
var override = properties[key];
var previous = object[key];
var type = $.type(override);
if (previous && type == "function") {
if (override != previous) {
Class.override(object, key, override);
}
} else {
if (type == "object") {
object[key] = $.merge(previous, override);
} else {
object[key] = override;
}
}
}
return object;
},
/**
* @param {Object} object
* @param {string} name
* @param {Function} matcherFunction
* @return {undefined}
*/
override : function(object, name, matcherFunction) {
var parent = Class.prototyping;
if (parent && object[name] != parent[name]) {
/** @type {null} */
parent = null;
}
/**
* @return {?}
*/
var next = function() {
var tmp = this.parent;
this.parent = parent ? parent[name] : object[name];
var rv = matcherFunction.apply(this, arguments);
this.parent = tmp;
return rv;
};
/** @type {function (): ?} */
object[name] = next;
}
});
/**
* @return {?}
*/
Class.prototype.implement = function() {
var proto = this.prototype;
$.each(Array.prototype.slice.call(arguments || []), function(properties) {
Class.inherit(proto, properties);
});
return this;
};
/** @type {function (Object): ?} */
$jit.Class = Class;
$jit.json = {
/**
* @param {?} attributes
* @param {?} maxLevel
* @return {undefined}
*/
prune : function(attributes, maxLevel) {
this.each(attributes, function(elem, i) {
if (i == maxLevel && elem.children) {
delete elem.children;
/** @type {Array} */
elem.children = [];
}
});
},
/**
* @param {Object} tree
* @param {?} id
* @return {?}
*/
getParent : function(tree, id) {
if (tree.id == id) {
return false;
}
var ch = tree.children;
if (ch && ch.length > 0) {
/** @type {number} */
var i = 0;
for (;i < ch.length;i++) {
if (ch[i].id == id) {
return tree;
} else {
var ans = this.getParent(ch[i], id);
if (ans) {
return ans;
}
}
}
}
return false;
},
/**
* @param {Object} tree
* @param {?} id
* @return {?}
*/
getSubtree : function(tree, id) {
if (tree.id == id) {
return tree;
}
/** @type {number} */
var i = 0;
var ch = tree.children;
for (;ch && i < ch.length;i++) {
var t = this.getSubtree(ch[i], id);
if (t != null) {
return t;
}
}
return null;
},
/**
* @param {number} value
* @param {number} opt_isDefault
* @param {Function} recurring
* @param {Function} action
* @return {undefined}
*/
eachLevel : function(value, opt_isDefault, recurring, action) {
if (opt_isDefault <= recurring) {
action(value, opt_isDefault);
if (!value.children) {
return;
}
/** @type {number} */
var i = 0;
var codeSegments = value.children;
for (;i < codeSegments.length;i++) {
this.eachLevel(codeSegments[i], opt_isDefault + 1, recurring, action);
}
}
},
/**
* @param {?} opt_attributes
* @param {Function} action
* @return {undefined}
*/
each : function(opt_attributes, action) {
this.eachLevel(opt_attributes, 0, Number.MAX_VALUE, action);
}
};
$jit.Trans = {
$extend : true,
/**
* @param {?} t
* @return {?}
*/
linear : function(t) {
return t;
}
};
var $cookies = $jit.Trans;
(function() {
/**
* @param {Function} transition
* @param {Text} params
* @return {?}
*/
var makeTrans = function(transition, params) {
params = $.splat(params);
return $.extend(transition, {
/**
* @param {?} pos
* @return {?}
*/
easeIn : function(pos) {
return transition(pos, params);
},
/**
* @param {number} pos
* @return {?}
*/
easeOut : function(pos) {
return 1 - transition(1 - pos, params);
},
/**
* @param {number} pos
* @return {?}
*/
easeInOut : function(pos) {
return pos <= 0.5 ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
}
});
};
var transitions = {
/**
* @param {?} p
* @param {Array} x
* @return {?}
*/
Pow : function(p, x) {
return Math.pow(p, x[0] || 6);
},
/**
* @param {number} p
* @return {?}
*/
Expo : function(p) {
return Math.pow(2, 8 * (p - 1));
},
/**
* @param {?} p
* @return {?}
*/
Circ : function(p) {
return 1 - Math.sin(Math.acos(p));
},
/**
* @param {number} p
* @return {?}
*/
Sine : function(p) {
return 1 - Math.sin((1 - p) * Math.PI / 2);
},
/**
* @param {?} p
* @param {number} x
* @return {?}
*/
Back : function(p, x) {
x = x[0] || 1.618;
return Math.pow(p, 2) * ((x + 1) * p - x);
},
/**
* @param {number} p
* @return {?}
*/
Bounce : function(p) {
var value;
/** @type {number} */
var a = 0;
/** @type {number} */
var b = 1;
for (;1;a += b, b /= 2) {
if (p >= (7 - 4 * a) / 11) {
/** @type {number} */
value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
break;
}
}
return value;
},
/**
* @param {number} p
* @param {Array} x
* @return {?}
*/
Elastic : function(p, x) {
return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
}
};
$.each(transitions, function(value, key) {
$cookies[key] = makeTrans(value);
});
$.each(["Quad", "Cubic", "Quart", "Quint"], function(key, dataAndEvents) {
$cookies[key] = makeTrans(function(pos) {
return Math.pow(pos, [dataAndEvents + 2]);
});
});
})();
var Animation = new Class({
/**
* @param {Object} options
* @return {undefined}
*/
initialize : function(options) {
this.setOptions(options);
},
/**
* @param {Object} options
* @return {?}
*/
setOptions : function(options) {
var opt = {
duration : 2500,
fps : 40,
transition : $cookies.Quart.easeInOut,
/** @type {function (): undefined} */
compute : $.empty,
/** @type {function (): undefined} */
complete : $.empty,
link : "ignore"
};
this.opt = $.merge(opt, options || {});
return this;
},
/**
* @return {undefined}
*/
step : function() {
/** @type {number} */
var time = $.time();
var opt = this.opt;
if (time < this.time + opt.duration) {
var from = opt.transition((time - this.time) / opt.duration);
opt.compute(from);
} else {
this.timer = clearInterval(this.timer);
opt.compute(1);
opt.complete();
}
},
/**
* @return {?}
*/
start : function() {
if (!this.check()) {
return this;
}
/** @type {number} */
this.time = 0;
this.startTimer();
return this;
},
/**
* @return {?}
*/
startTimer : function() {
var self = this;
var fps = this.opt.fps;
if (this.timer) {
return false;
}
/** @type {number} */
this.time = $.time() - this.time;
/** @type {number} */
this.timer = setInterval(function() {
self.step();
}, Math.round(1E3 / fps));
return true;
},
/**
* @return {?}
*/
pause : function() {
this.stopTimer();
return this;
},
/**
* @return {?}
*/
resume : function() {
this.startTimer();
return this;
},
/**
* @return {?}
*/
stopTimer : function() {
if (!this.timer) {
return false;
}
/** @type {number} */
this.time = $.time() - this.time;
this.timer = clearInterval(this.timer);
return true;
},
/**
* @return {?}
*/
check : function() {
if (!this.timer) {
return true;
}
if (this.opt.link == "cancel") {
this.stopTimer();
return true;
}
return false;
}
});
/**
* @return {?}
*/
var Options = function() {
/** @type {Arguments} */
var args = arguments;
/** @type {number} */
var i = 0;
/** @type {number} */
var argLength = args.length;
var methods = {};
for (;i < argLength;i++) {
var attributes = Options[args[i]];
if (attributes.$extend) {
$.extend(methods, attributes);
} else {
methods[args[i]] = attributes;
}
}
return methods;
};
Options.AreaChart = {
$extend : true,
animate : true,
labelOffset : 3,
type : "stacked",
Tips : {
enable : false,
/** @type {function (): undefined} */
onShow : $.empty,
/** @type {function (): undefined} */
onHide : $.empty
},
Events : {
enable : false,
/** @type {function (): undefined} */
onClick : $.empty
},
selectOnHover : true,
showAggregates : true,
showLabels : true,
filterOnClick : false,
restoreOnRightClick : false
};
Options.Margin = {
$extend : false,
top : 0,
left : 0,
right : 0,
bottom : 0
};
Options.Canvas = {
$extend : true,
injectInto : "id",
type : "2D",
width : false,
height : false,
useCanvas : false,
withLabels : true,
background : false,
Scene : {
Lighting : {
enable : false,
ambient : [1, 1, 1],
directional : {
direction : {
x : -100,
y : -100,
z : -100
},
color : [0.5, 0.3, 0.1]
}
}
}
};
Options.Tree = {
$extend : true,
orientation : "left",
subtreeOffset : 8,
siblingOffset : 5,
indent : 10,
multitree : false,
align : "center"
};
Options.Node = {
$extend : false,
overridable : false,
type : "circle",
color : "#ccb",
alpha : 1,
dim : 3,
height : 20,
width : 90,
autoHeight : false,
autoWidth : false,
lineWidth : 1,
transform : true,
align : "center",
angularWidth : 1,
span : 1,
CanvasStyles : {}
};
Options.Edge = {
$extend : false,
overridable : false,
type : "line",
color : "#ccb",
lineWidth : 1,
dim : 15,
alpha : 1,
epsilon : 7,
CanvasStyles : {}
};
Options.Fx = {
$extend : true,
fps : 40,
duration : 2500,
transition : $jit.Trans.Quart.easeInOut,
clearCanvas : true
};
Options.Label = {
$extend : false,
overridable : false,
type : "HTML",
style : " ",
size : 10,
family : "sans-serif",
textAlign : "center",
textBaseline : "alphabetic",
color : "#fff"
};
Options.Tips = {
$extend : false,
enable : false,
type : "auto",
offsetX : 20,
offsetY : 20,
force : false,
/** @type {function (): undefined} */
onShow : $.empty,
/** @type {function (): undefined} */
onHide : $.empty
};
Options.NodeStyles = {
$extend : false,
enable : false,
type : "auto",
stylesHover : false,
stylesClick : false
};
Options.Events = {
$extend : false,
enable : false,
enableForEdges : false,
type : "auto",
/** @type {function (): undefined} */
onClick : $.empty,
/** @type {function (): undefined} */
onRightClick : $.empty,
/** @type {function (): undefined} */
onMouseMove : $.empty,
/** @type {function (): undefined} */
onMouseEnter : $.empty,
/** @type {function (): undefined} */
onMouseLeave : $.empty,
/** @type {function (): undefined} */
onDragStart : $.empty,
/** @type {function (): undefined} */
onDragMove : $.empty,
/** @type {function (): undefined} */
onDragCancel : $.empty,
/** @type {function (): undefined} */
onDragEnd : $.empty,
/** @type {function (): undefined} */
onTouchStart : $.empty,
/** @type {function (): undefined} */
onTouchMove : $.empty,
/** @type {function (): undefined} */
onTouchEnd : $.empty,
/** @type {function (): undefined} */
onMouseWheel : $.empty
};
Options.Navigation = {
$extend : false,
enable : false,
type : "auto",
panning : false,
zooming : false
};
Options.Controller = {
$extend : true,
/** @type {function (): undefined} */
onBeforeCompute : $.empty,
/** @type {function (): undefined} */
onAfterCompute : $.empty,
/** @type {function (): undefined} */
onCreateLabel : $.empty,
/** @type {function (): undefined} */
onPlaceLabel : $.empty,
/** @type {function (): undefined} */
onComplete : $.empty,
/** @type {function (): undefined} */
onBeforePlotLine : $.empty,
/** @type {function (): undefined} */
onAfterPlotLine : $.empty,
/** @type {function (): undefined} */
onBeforePlotNode : $.empty,
/** @type {function (): undefined} */
onAfterPlotNode : $.empty,
request : false
};
var Events = {
/**
* @param {?} className
* @param {Object} viz
* @return {undefined}
*/
initialize : function(className, viz) {
/** @type {Object} */
this.viz = viz;
this.canvas = viz.canvas;
this.config = viz.config[className];
this.nodeTypes = viz.fx.nodeTypes;
var type = this.config.type;
/** @type {boolean} */
this.dom = type == "auto" ? viz.config.Label.type != "Native" : type != "Native";
this.labelContainer = this.dom && viz.labels.getLabelContainer();
if (this.isEnabled()) {
this.initializePost();
}
},
/** @type {function (): undefined} */
initializePost : $.empty,
setAsProperty : $.lambda(false),
/**
* @return {?}
*/
isEnabled : function() {
return this.config.enable;
},
/**
* @param {?} adj
* @param {?} lab
* @param {boolean} recurring
* @return {?}
*/
isLabel : function(adj, lab, recurring) {
adj = $.event.get(adj, lab);
var labelContainer = this.labelContainer;
var target = adj.target || adj.srcElement;
var related = adj.relatedTarget;
if (recurring) {
return related && (related == this.viz.canvas.getCtx().canvas && (!!target && this.isDescendantOf(target, labelContainer)));
} else {
return this.isDescendantOf(target, labelContainer);
}
},
/**
* @param {HTMLElement} elem
* @param {?} par
* @return {?}
*/
isDescendantOf : function(elem, par) {
for (;elem && elem.parentNode;) {
if (elem.parentNode == par) {
return elem;
}
elem = elem.parentNode;
}
return false;
}
};
var Aspect = {
/** @type {function (): undefined} */
onMouseUp : $.empty,
/** @type {function (): undefined} */
onMouseDown : $.empty,
/** @type {function (): undefined} */
onMouseMove : $.empty,
/** @type {function (): undefined} */
onMouseOver : $.empty,
/** @type {function (): undefined} */
onMouseOut : $.empty,
/** @type {function (): undefined} */
onMouseWheel : $.empty,
/** @type {function (): undefined} */
onTouchStart : $.empty,
/** @type {function (): undefined} */
onTouchMove : $.empty,
/** @type {function (): undefined} */
onTouchEnd : $.empty,
/** @type {function (): undefined} */
onTouchCancel : $.empty
};
var Tips = new Class({
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
this.canvas = viz.canvas;
/** @type {boolean} */
this.node = false;
/** @type {boolean} */
this.edge = false;
/** @type {Array} */
this.registeredObjects = [];
this.attachEvents();
},
/**
* @return {undefined}
*/
attachEvents : function() {
var element = this.canvas.getElement();
var that = this;
element.oncontextmenu = $.lambda(false);
$.addEvents(element, {
/**
* @param {Object} e
* @param {Object} win
* @return {undefined}
*/
mouseup : function(e, win) {
var event = $.event.get(e, win);
that.handleEvent("MouseUp", e, win, that.makeEventObject(e, win), $.event.isRightClick(event));
},
/**
* @param {Object} e
* @param {Object} win
* @return {undefined}
*/
mousedown : function(e, win) {
var event = $.event.get(e, win);
that.handleEvent("MouseDown", e, win, that.makeEventObject(e, win), $.event.isRightClick(event));
},
/**
* @param {Object} e
* @param {?} win
* @return {undefined}
*/
mousemove : function(e, win) {
that.handleEvent("MouseMove", e, win, that.makeEventObject(e, win));
},
/**
* @param {Object} e
* @param {?} win
* @return {undefined}
*/
mouseover : function(e, win) {
that.handleEvent("MouseOver", e, win, that.makeEventObject(e, win));
},
/**
* @param {Object} e
* @param {?} win
* @return {undefined}
*/
mouseout : function(e, win) {
that.handleEvent("MouseOut", e, win, that.makeEventObject(e, win));
},
/**
* @param {Object} e
* @param {?} win
* @return {undefined}
*/
touchstart : function(e, win) {
that.handleEvent("TouchStart", e, win, that.makeEventObject(e, win));
},
/**
* @param {Object} e
* @param {?} win
* @return {undefined}
*/
touchmove : function(e, win) {
that.handleEvent("TouchMove", e, win, that.makeEventObject(e, win));
},
/**
* @param {Object} e
* @param {?} win
* @return {undefined}
*/
touchend : function(e, win) {
that.handleEvent("TouchEnd", e, win, that.makeEventObject(e, win));
}
});
/**
* @param {Object} from
* @param {Object} win
* @return {undefined}
*/
var handleMouseWheel = function(from, win) {
var event = $.event.get(from, win);
var wheel = $.event.getWheel(event);
that.handleEvent("MouseWheel", from, win, wheel);
};
if (!document.getBoxObjectFor && window.mozInnerScreenX == null) {
$.addEvent(element, "mousewheel", handleMouseWheel);
} else {
element.addEventListener("DOMMouseScroll", handleMouseWheel, false);
}
},
/**
* @param {?} obj
* @return {undefined}
*/
register : function(obj) {
this.registeredObjects.push(obj);
},
/**
* @return {undefined}
*/
handleEvent : function() {
/** @type {Array.<?>} */
var args = Array.prototype.slice.call(arguments);
var type = args.shift();
/** @type {number} */
var i = 0;
var regs = this.registeredObjects;
var l = regs.length;
for (;i < l;i++) {
regs[i]["on" + type].apply(regs[i], args);
}
},
/**
* @param {Object} prop
* @param {?} win
* @return {?}
*/
makeEventObject : function(prop, win) {
var that = this;
var graph = this.viz.graph;
var fx = this.viz.fx;
var ntypes = fx.nodeTypes;
var etypes = fx.edgeTypes;
return{
pos : false,
node : false,
edge : false,
contains : false,
getNodeCalled : false,
getEdgeCalled : false,
/**
* @return {?}
*/
getPos : function() {
var canvas = that.viz.canvas;
var $cont = canvas.getSize();
var cameraPos = canvas.getPos();
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var pos = $.event.getPos(prop, win);
this.pos = {
x : (pos.x - cameraPos.x - $cont.width / 2 - ox) * 1 / sx,
y : (pos.y - cameraPos.y - $cont.height / 2 - oy) * 1 / sy
};
return this.pos;
},
/**
* @return {?}
*/
getNode : function() {
if (this.getNodeCalled) {
return this.node;
}
/** @type {boolean} */
this.getNodeCalled = true;
var id;
for (id in graph.nodes) {
var n = graph.nodes[id];
var geom = n && ntypes[n.getData("type")];
var contains = geom && (geom.contains && geom.contains.call(fx, n, this.getPos()));
if (contains) {
this.contains = contains;
return that.node = this.node = n;
}
}
return that.node = this.node = false;
},
/**
* @return {?}
*/
getEdge : function() {
if (this.getEdgeCalled) {
return this.edge;
}
/** @type {boolean} */
this.getEdgeCalled = true;
var hashset = {};
var id;
for (id in graph.edges) {
var edgeFrom = graph.edges[id];
/** @type {boolean} */
hashset[id] = true;
var edgeId;
for (edgeId in edgeFrom) {
if (edgeId in hashset) {
continue;
}
var e = edgeFrom[edgeId];
var geom = e && etypes[e.getData("type")];
var contains = geom && (geom.contains && geom.contains.call(fx, e, this.getPos()));
if (contains) {
this.contains = contains;
return that.edge = this.edge = e;
}
}
}
return that.edge = this.edge = false;
},
/**
* @return {?}
*/
getContains : function() {
if (this.getNodeCalled) {
return this.contains;
}
this.getNode();
return this.contains;
}
};
}
});
var Extras = {
/**
* @return {undefined}
*/
initializeExtras : function() {
var doh = new Tips(this);
var that = this;
$.each(["NodeStyles", "Tips", "Navigation", "Events"], function(k) {
var obj = new Extras.Classes[k](k, that);
if (obj.isEnabled()) {
doh.register(obj);
}
if (obj.setAsProperty()) {
that[k.toLowerCase()] = obj;
}
});
}
};
Extras.Classes = {};
Extras.Classes.Events = new Class({
Implements : [Events, Aspect],
/**
* @return {undefined}
*/
initializePost : function() {
this.fx = this.viz.fx;
this.ntypes = this.viz.fx.nodeTypes;
this.etypes = this.viz.fx.edgeTypes;
/** @type {boolean} */
this.hovered = false;
/** @type {boolean} */
this.pressed = false;
/** @type {boolean} */
this.touched = false;
/** @type {boolean} */
this.touchMoved = false;
/** @type {boolean} */
this.moved = false;
},
setAsProperty : $.lambda(true),
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
onMouseUp : function(adj, lab, event, type) {
var qualifier = $.event.get(adj, lab);
if (!this.moved) {
if (type) {
this.config.onRightClick(this.hovered, event, qualifier);
} else {
this.config.onClick(this.pressed, event, qualifier);
}
}
if (this.pressed) {
if (this.moved) {
this.config.onDragEnd(this.pressed, event, qualifier);
} else {
this.config.onDragCancel(this.pressed, event, qualifier);
}
/** @type {boolean} */
this.pressed = this.moved = false;
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseOut : function(adj, lab, event) {
var qualifier = $.event.get(adj, lab);
var label;
if (this.dom && (label = this.isLabel(adj, lab, true))) {
this.config.onMouseLeave(this.viz.graph.getNode(label.id), event, qualifier);
/** @type {boolean} */
this.hovered = false;
return;
}
var rt = qualifier.relatedTarget;
var canvasWidget = this.canvas.getElement();
for (;rt && rt.parentNode;) {
if (canvasWidget == rt.parentNode) {
return;
}
rt = rt.parentNode;
}
if (this.hovered) {
this.config.onMouseLeave(this.hovered, event, qualifier);
/** @type {boolean} */
this.hovered = false;
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseOver : function(adj, lab, event) {
var qualifier = $.event.get(adj, lab);
var label;
if (this.dom && (label = this.isLabel(adj, lab, true))) {
this.hovered = this.viz.graph.getNode(label.id);
this.config.onMouseEnter(this.hovered, event, qualifier);
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseMove : function(adj, lab, event) {
var x;
var qualifier = $.event.get(adj, lab);
if (this.pressed) {
/** @type {boolean} */
this.moved = true;
this.config.onDragMove(this.pressed, event, qualifier);
return;
}
if (this.dom) {
this.config.onMouseMove(this.hovered, event, qualifier);
} else {
if (this.hovered) {
var from = this.hovered;
var geom = from.nodeFrom ? this.etypes[from.getData("type")] : this.ntypes[from.getData("type")];
var contains = geom && (geom.contains && geom.contains.call(this.fx, from, event.getPos()));
if (contains) {
this.config.onMouseMove(from, event, qualifier);
return;
} else {
this.config.onMouseLeave(from, event, qualifier);
/** @type {boolean} */
this.hovered = false;
}
}
if (this.hovered = event.getNode() || this.config.enableForEdges && event.getEdge()) {
this.config.onMouseEnter(this.hovered, event, qualifier);
} else {
this.config.onMouseMove(false, event, qualifier);
}
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} from
* @return {undefined}
*/
onMouseWheel : function(adj, lab, from) {
this.config.onMouseWheel(from, $.event.get(adj, lab));
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseDown : function(adj, lab, event) {
var qualifier = $.event.get(adj, lab);
var label;
if (this.dom) {
if (label = this.isLabel(adj, lab)) {
this.pressed = this.viz.graph.getNode(label.id);
}
} else {
this.pressed = event.getNode() || this.config.enableForEdges && event.getEdge();
}
if (this.pressed) {
this.config.onDragStart(this.pressed, event, qualifier);
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onTouchStart : function(adj, lab, event) {
var qualifier = $.event.get(adj, lab);
var label;
if (this.dom && (label = this.isLabel(adj, lab))) {
this.touched = this.viz.graph.getNode(label.id);
} else {
this.touched = event.getNode() || this.config.enableForEdges && event.getEdge();
}
if (this.touched) {
this.config.onTouchStart(this.touched, event, qualifier);
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onTouchMove : function(adj, lab, event) {
var qualifier = $.event.get(adj, lab);
if (this.touched) {
/** @type {boolean} */
this.touchMoved = true;
this.config.onTouchMove(this.touched, event, qualifier);
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onTouchEnd : function(adj, lab, event) {
var qualifier = $.event.get(adj, lab);
if (this.touched) {
if (this.touchMoved) {
this.config.onTouchEnd(this.touched, event, qualifier);
} else {
this.config.onTouchCancel(this.touched, event, qualifier);
}
/** @type {boolean} */
this.touched = this.touchMoved = false;
}
}
});
Extras.Classes.Tips = new Class({
Implements : [Events, Aspect],
/**
* @return {undefined}
*/
initializePost : function() {
if (document.body) {
var tip = $("_tooltip") || document.createElement("div");
/** @type {string} */
tip.id = "_tooltip";
/** @type {string} */
tip.className = "tip";
$.extend(tip.style, {
position : "absolute",
display : "none",
zIndex : 13E3
});
document.body.appendChild(tip);
this.tip = tip;
/** @type {boolean} */
this.node = false;
}
},
setAsProperty : $.lambda(true),
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onMouseOut : function(adj, lab) {
var orn = $.event.get(adj, lab);
if (this.dom && this.isLabel(adj, lab, true)) {
this.hide(true);
return;
}
var rt = adj.relatedTarget;
var canvasWidget = this.canvas.getElement();
for (;rt && rt.parentNode;) {
if (canvasWidget == rt.parentNode) {
return;
}
rt = rt.parentNode;
}
this.hide(false);
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onMouseOver : function(adj, lab) {
var qualifier;
if (this.dom && (qualifier = this.isLabel(adj, lab, false))) {
this.node = this.viz.graph.getNode(qualifier.id);
this.config.onShow(this.tip, this.node, qualifier);
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseMove : function(adj, lab, event) {
if (this.dom && this.isLabel(adj, lab)) {
this.setTooltipPosition($.event.getPos(adj, lab));
}
if (!this.dom) {
var cycle = event.getNode();
if (!cycle) {
this.hide(true);
return;
}
if (this.config.force || (!this.node || this.node.id != cycle.id)) {
this.node = cycle;
this.config.onShow(this.tip, cycle, event.getContains());
}
this.setTooltipPosition($.event.getPos(adj, lab));
}
},
/**
* @param {?} pos
* @return {undefined}
*/
setTooltipPosition : function(pos) {
var tip = this.tip;
var style = tip.style;
var cont = this.config;
/** @type {string} */
style.display = "";
var win = {
height : document.body.clientHeight,
width : document.body.clientWidth
};
var obj = {
width : tip.offsetWidth,
height : tip.offsetHeight
};
var x = cont.offsetX;
var y = cont.offsetY;
/** @type {string} */
style.top = (pos.y + y + obj.height > win.height ? pos.y - obj.height - y : pos.y + y) + "px";
/** @type {string} */
style.left = (pos.x + obj.width + x > win.width ? pos.x - obj.width - x : pos.x + x) + "px";
},
/**
* @param {boolean} recurring
* @return {undefined}
*/
hide : function(recurring) {
/** @type {string} */
this.tip.style.display = "none";
if (recurring) {
this.config.onHide();
}
}
});
Extras.Classes.NodeStyles = new Class({
Implements : [Events, Aspect],
/**
* @return {undefined}
*/
initializePost : function() {
this.fx = this.viz.fx;
this.types = this.viz.fx.nodeTypes;
this.nStyles = this.config;
this.nodeStylesOnHover = this.nStyles.stylesHover;
this.nodeStylesOnClick = this.nStyles.stylesClick;
/** @type {boolean} */
this.hoveredNode = false;
this.fx.nodeFxAnimation = new Animation;
/** @type {boolean} */
this.down = false;
/** @type {boolean} */
this.move = false;
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onMouseOut : function(adj, lab) {
/** @type {boolean} */
this.down = this.move = false;
if (!this.hoveredNode) {
return;
}
if (this.dom && this.isLabel(adj, lab, true)) {
this.toggleStylesOnHover(this.hoveredNode, false);
}
var rt = adj.relatedTarget;
var canvasWidget = this.canvas.getElement();
for (;rt && rt.parentNode;) {
if (canvasWidget == rt.parentNode) {
return;
}
rt = rt.parentNode;
}
this.toggleStylesOnHover(this.hoveredNode, false);
/** @type {boolean} */
this.hoveredNode = false;
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onMouseOver : function(adj, lab) {
var label;
if (this.dom && (label = this.isLabel(adj, lab, true))) {
var node = this.viz.graph.getNode(label.id);
if (node.selected) {
return;
}
this.hoveredNode = node;
this.toggleStylesOnHover(this.hoveredNode, true);
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
onMouseDown : function(adj, lab, event, type) {
if (type) {
return;
}
var label;
if (this.dom && (label = this.isLabel(adj, lab))) {
this.down = this.viz.graph.getNode(label.id);
} else {
if (!this.dom) {
this.down = event.getNode();
}
}
/** @type {boolean} */
this.move = false;
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
onMouseUp : function(adj, lab, event, type) {
if (type) {
return;
}
if (!this.move) {
this.onClick(event.getNode());
}
/** @type {boolean} */
this.down = this.move = false;
},
/**
* @param {Object} node
* @param {string} type
* @return {?}
*/
getRestoredStyles : function(node, type) {
var restoredStyles = {};
var source = this["nodeStylesOn" + type];
var prop;
for (prop in source) {
restoredStyles[prop] = node.styles["$" + prop];
}
return restoredStyles;
},
/**
* @param {?} node
* @param {boolean} recurring
* @return {undefined}
*/
toggleStylesOnHover : function(node, recurring) {
if (this.nodeStylesOnHover) {
this.toggleStylesOn("Hover", node, recurring);
}
},
/**
* @param {Object} node
* @param {boolean} recurring
* @return {undefined}
*/
toggleStylesOnClick : function(node, recurring) {
if (this.nodeStylesOnClick) {
this.toggleStylesOn("Click", node, recurring);
}
},
/**
* @param {string} type
* @param {Object} node
* @param {boolean} recurring
* @return {undefined}
*/
toggleStylesOn : function(type, node, recurring) {
var viz = this.viz;
var nStyles = this.nStyles;
if (recurring) {
var that = this;
if (!node.styles) {
node.styles = $.merge(node.data, {});
}
var s;
for (s in this["nodeStylesOn" + type]) {
/** @type {string} */
var $s = "$" + s;
if (!($s in node.styles)) {
node.styles[$s] = node.getData(s);
}
}
viz.fx.nodeFx($.extend({
elements : {
id : node.id,
properties : that["nodeStylesOn" + type]
},
transition : $cookies.Quart.easeOut,
duration : 300,
fps : 40
}, this.config));
} else {
var queue = this.getRestoredStyles(node, type);
viz.fx.nodeFx($.extend({
elements : {
id : node.id,
properties : queue
},
transition : $cookies.Quart.easeOut,
duration : 300,
fps : 40
}, this.config));
}
},
/**
* @param {?} adj
* @return {undefined}
*/
onClick : function(adj) {
if (!adj) {
return;
}
var nStyles = this.nodeStylesOnClick;
if (!nStyles) {
return;
}
if (adj.selected) {
this.toggleStylesOnClick(adj, false);
delete adj.selected;
} else {
this.viz.graph.eachNode(function(n) {
if (n.selected) {
var s;
for (s in nStyles) {
n.setData(s, n.styles["$" + s], "end");
}
delete n.selected;
}
});
this.toggleStylesOnClick(adj, true);
/** @type {boolean} */
adj.selected = true;
delete adj.hovered;
/** @type {boolean} */
this.hoveredNode = false;
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseMove : function(adj, lab, event) {
if (this.down) {
/** @type {boolean} */
this.move = true;
}
if (this.dom && this.isLabel(adj, lab)) {
return;
}
var nStyles = this.nodeStylesOnHover;
if (!nStyles) {
return;
}
if (!this.dom) {
if (this.hoveredNode) {
var geom = this.types[this.hoveredNode.getData("type")];
var contains = geom && (geom.contains && geom.contains.call(this.fx, this.hoveredNode, event.getPos()));
if (contains) {
return;
}
}
var node = event.getNode();
if (!this.hoveredNode && !node) {
return;
}
if (node.hovered) {
return;
}
if (node && !node.selected) {
this.fx.nodeFxAnimation.stopTimer();
this.viz.graph.eachNode(function(n) {
if (n.hovered && !n.selected) {
var s;
for (s in nStyles) {
n.setData(s, n.styles["$" + s], "end");
}
delete n.hovered;
}
});
/** @type {boolean} */
node.hovered = true;
this.hoveredNode = node;
this.toggleStylesOnHover(node, true);
} else {
if (this.hoveredNode && !this.hoveredNode.selected) {
this.fx.nodeFxAnimation.stopTimer();
this.toggleStylesOnHover(this.hoveredNode, false);
delete this.hoveredNode.hovered;
/** @type {boolean} */
this.hoveredNode = false;
}
}
}
}
});
Extras.Classes.Navigation = new Class({
Implements : [Events, Aspect],
/**
* @return {undefined}
*/
initializePost : function() {
/** @type {boolean} */
this.pos = false;
/** @type {boolean} */
this.pressed = false;
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseWheel : function(adj, lab, event) {
if (!this.config.zooming) {
return;
}
$.event.stop($.event.get(adj, lab));
/** @type {number} */
var A = this.config.zooming / 1E3;
/** @type {number} */
var scaling = 1 + event * A;
this.canvas.scale(scaling, scaling);
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseDown : function(adj, lab, event) {
if (!this.config.panning) {
return;
}
if (this.config.panning == "avoid nodes" && (this.dom ? this.isLabel(adj, lab) : event.getNode())) {
return;
}
/** @type {boolean} */
this.pressed = true;
this.pos = event.getPos();
var canvas = this.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
this.pos.x *= sx;
this.pos.x += ox;
this.pos.y *= sy;
this.pos.y += oy;
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseMove : function(adj, lab, event) {
if (!this.config.panning) {
return;
}
if (!this.pressed) {
return;
}
if (this.config.panning == "avoid nodes" && (this.dom ? this.isLabel(adj, lab) : event.getNode())) {
return;
}
var thispos = this.pos;
var currentPos = event.getPos();
var canvas = this.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
currentPos.x *= sx;
currentPos.y *= sy;
currentPos.x += ox;
currentPos.y += oy;
/** @type {number} */
var x = currentPos.x - thispos.x;
/** @type {number} */
var y = currentPos.y - thispos.y;
this.pos = currentPos;
this.canvas.translate(x * 1 / sx, y * 1 / sy);
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
onMouseUp : function(adj, lab, event, type) {
if (!this.config.panning) {
return;
}
/** @type {boolean} */
this.pressed = false;
}
});
var Canvas;
(function() {
/**
* @param {string} tag
* @param {?} props
* @return {?}
*/
function $E(tag, props) {
/** @type {Element} */
var elem = document.createElement(tag);
var name;
for (name in props) {
if (typeof props[name] == "object") {
$.extend(elem[name], props[name]);
} else {
elem[name] = props[name];
}
}
if (tag == "canvas" && (!supportsCanvas && G_vmlCanvasManager)) {
elem = G_vmlCanvasManager.initElement(document.body.appendChild(elem));
}
return elem;
}
/** @type {string} */
var typeOfCanvas = typeof HTMLCanvasElement;
/** @type {boolean} */
var supportsCanvas = typeOfCanvas == "object" || typeOfCanvas == "function";
$jit.Canvas = Canvas = new Class({
canvases : [],
pos : false,
element : false,
labelContainer : false,
translateOffsetX : 0,
translateOffsetY : 0,
scaleOffsetX : 1,
scaleOffsetY : 1,
/**
* @param {Object} viz
* @param {Object} opt
* @return {undefined}
*/
initialize : function(viz, opt) {
/** @type {Object} */
this.viz = viz;
this.opt = this.config = opt;
var id = $.type(opt.injectInto) == "string" ? opt.injectInto : opt.injectInto.id;
var type = opt.type;
/** @type {string} */
var idLabel = id + "-label";
var wrapper = $(id);
var originalWidth = opt.width || wrapper.offsetWidth;
var _height = opt.height || wrapper.offsetHeight;
this.id = id;
var canvasOptions = {
injectInto : id,
width : originalWidth,
height : _height
};
this.element = $E("div", {
id : id + "-canvaswidget",
style : {
position : "relative",
width : originalWidth + "px",
height : _height + "px"
}
});
this.labelContainer = this.createLabelContainer(opt.Label.type, idLabel, canvasOptions);
this.canvases.push(new Canvas.Base[type]({
config : $.extend({
idSuffix : "-canvas"
}, canvasOptions),
/**
* @param {?} opt
* @return {undefined}
*/
plot : function(opt) {
viz.fx.plot();
},
/**
* @return {undefined}
*/
resize : function() {
viz.refresh();
}
}));
var back = opt.background;
if (back) {
var backCanvas = new Canvas.Background[back.type](viz, $.extend(back, canvasOptions));
this.canvases.push(new Canvas.Base[type](backCanvas));
}
var len = this.canvases.length;
for (;len--;) {
this.element.appendChild(this.canvases[len].canvas);
if (len > 0) {
this.canvases[len].plot();
}
}
this.element.appendChild(this.labelContainer);
wrapper.appendChild(this.element);
/** @type {null} */
var tref = null;
var f = this;
$.addEvent(window, "scroll", function() {
clearTimeout(tref);
/** @type {number} */
tref = setTimeout(function() {
f.getPos(true);
}, 500);
});
},
/**
* @param {number} i
* @return {?}
*/
getCtx : function(i) {
return this.canvases[i || 0].getCtx();
},
/**
* @return {?}
*/
getConfig : function() {
return this.opt;
},
/**
* @return {?}
*/
getElement : function() {
return this.element;
},
/**
* @param {number} dataAndEvents
* @return {?}
*/
getSize : function(dataAndEvents) {
return this.canvases[dataAndEvents || 0].getSize();
},
/**
* @param {number} w
* @param {number} height
* @return {undefined}
*/
resize : function(w, height) {
this.getPos(true);
/** @type {number} */
this.translateOffsetX = this.translateOffsetY = 0;
/** @type {number} */
this.scaleOffsetX = this.scaleOffsetY = 1;
/** @type {number} */
var i = 0;
var l = this.canvases.length;
for (;i < l;i++) {
this.canvases[i].resize(w, height);
}
var style = this.element.style;
/** @type {string} */
style.width = w + "px";
/** @type {string} */
style.height = height + "px";
if (this.labelContainer) {
/** @type {string} */
this.labelContainer.style.width = w + "px";
}
},
/**
* @param {number} x
* @param {number} y
* @param {boolean} z
* @return {undefined}
*/
translate : function(x, y, z) {
this.translateOffsetX += x * this.scaleOffsetX;
this.translateOffsetY += y * this.scaleOffsetY;
/** @type {number} */
var i = 0;
var l = this.canvases.length;
for (;i < l;i++) {
this.canvases[i].translate(x, y, z);
}
},
/**
* @param {number} x
* @param {number} y
* @param {boolean} dataAndEvents
* @return {undefined}
*/
scale : function(x, y, dataAndEvents) {
/** @type {number} */
var px = this.scaleOffsetX * x;
/** @type {number} */
var py = this.scaleOffsetY * y;
/** @type {number} */
var ll = this.translateOffsetX * (x - 1) / px;
/** @type {number} */
var dy = this.translateOffsetY * (y - 1) / py;
/** @type {number} */
this.scaleOffsetX = px;
/** @type {number} */
this.scaleOffsetY = py;
/** @type {number} */
var i = 0;
var l = this.canvases.length;
for (;i < l;i++) {
this.canvases[i].scale(x, y, true);
}
this.translate(ll, dy, false);
},
/**
* @param {boolean} expectation
* @return {?}
*/
getPos : function(expectation) {
if (expectation || !this.pos) {
return this.pos = $.getPos(this.getElement());
}
return this.pos;
},
/**
* @param {number} arr
* @return {undefined}
*/
clear : function(arr) {
this.canvases[arr || 0].clear();
},
/**
* @param {?} id
* @param {?} callback
* @return {undefined}
*/
path : function(id, callback) {
var me = this.canvases[0].getCtx();
me.beginPath();
callback(me);
me[id]();
me.closePath();
},
/**
* @param {string} type
* @param {string} idLabel
* @param {?} dim
* @return {?}
*/
createLabelContainer : function(type, idLabel, dim) {
/** @type {string} */
var NS = "http://www.w3.org/2000/svg";
if (type == "HTML" || type == "Native") {
return $E("div", {
id : idLabel,
style : {
overflow : "visible",
position : "absolute",
top : 0,
left : 0,
width : dim.width + "px",
height : 0
}
});
} else {
if (type == "SVG") {
/** @type {Element} */
var svgContainer = document.createElementNS(NS, "svg:svg");
svgContainer.setAttribute("width", dim.width);
svgContainer.setAttribute("height", dim.height);
/** @type {(CSSStyleDeclaration|null)} */
var style = svgContainer.style;
/** @type {string} */
style.position = "absolute";
/** @type {string} */
style.left = style.top = "0px";
/** @type {Element} */
var labelContainer = document.createElementNS(NS, "svg:g");
labelContainer.setAttribute("width", dim.width);
labelContainer.setAttribute("height", dim.height);
labelContainer.setAttribute("x", 0);
labelContainer.setAttribute("y", 0);
labelContainer.setAttribute("id", idLabel);
svgContainer.appendChild(labelContainer);
return svgContainer;
}
}
}
});
Canvas.Base = {};
Canvas.Base["2D"] = new Class({
translateOffsetX : 0,
translateOffsetY : 0,
scaleOffsetX : 1,
scaleOffsetY : 1,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
this.opt = viz.config;
/** @type {boolean} */
this.size = false;
this.createCanvas();
this.translateToCenter();
},
/**
* @return {undefined}
*/
createCanvas : function() {
var opt = this.opt;
var width = opt.width;
var h = opt.height;
this.canvas = $E("canvas", {
id : opt.injectInto + opt.idSuffix,
width : width,
height : h,
style : {
position : "absolute",
top : 0,
left : 0,
width : width + "px",
height : h + "px"
}
});
},
/**
* @return {?}
*/
getCtx : function() {
if (!this.ctx) {
return this.ctx = this.canvas.getContext("2d");
}
return this.ctx;
},
/**
* @return {?}
*/
getSize : function() {
if (this.size) {
return this.size;
}
var canvas = this.canvas;
return this.size = {
width : canvas.width,
height : canvas.height
};
},
/**
* @param {boolean} ps
* @return {undefined}
*/
translateToCenter : function(ps) {
var size = this.getSize();
var width = ps ? size.width - ps.width - this.translateOffsetX * 2 : size.width;
height = ps ? size.height - ps.height - this.translateOffsetY * 2 : size.height;
var ctx = this.getCtx();
if (ps) {
ctx.scale(1 / this.scaleOffsetX, 1 / this.scaleOffsetY);
}
ctx.translate(width / 2, height / 2);
},
/**
* @param {number} width
* @param {number} height
* @return {undefined}
*/
resize : function(width, height) {
var size = this.getSize();
var canvas = this.canvas;
var style = canvas.style;
/** @type {boolean} */
this.size = false;
/** @type {number} */
canvas.width = width;
/** @type {number} */
canvas.height = height;
/** @type {string} */
style.width = width + "px";
/** @type {string} */
style.height = height + "px";
if (!supportsCanvas) {
this.translateToCenter(size);
} else {
this.translateToCenter();
}
/** @type {number} */
this.translateOffsetX = this.translateOffsetY = 0;
/** @type {number} */
this.scaleOffsetX = this.scaleOffsetY = 1;
this.clear();
this.viz.resize(width, height, this);
},
/**
* @param {number} x
* @param {number} y
* @param {boolean} z
* @return {undefined}
*/
translate : function(x, y, z) {
var sx = this.scaleOffsetX;
var sy = this.scaleOffsetY;
this.translateOffsetX += x * sx;
this.translateOffsetY += y * sy;
this.getCtx().translate(x, y);
if (!z) {
this.plot();
}
},
/**
* @param {number} x
* @param {number} y
* @param {boolean} dataAndEvents
* @return {undefined}
*/
scale : function(x, y, dataAndEvents) {
this.scaleOffsetX *= x;
this.scaleOffsetY *= y;
this.getCtx().scale(x, y);
if (!dataAndEvents) {
this.plot();
}
},
/**
* @return {undefined}
*/
clear : function() {
var size = this.getSize();
var ox = this.translateOffsetX;
var oy = this.translateOffsetY;
var sx = this.scaleOffsetX;
var sy = this.scaleOffsetY;
this.getCtx().clearRect((-size.width / 2 - ox) * 1 / sx, (-size.height / 2 - oy) * 1 / sy, size.width * 1 / sx, size.height * 1 / sy);
},
/**
* @return {undefined}
*/
plot : function() {
this.clear();
this.viz.plot(this);
}
});
Canvas.Background = {};
Canvas.Background.Circles = new Class({
/**
* @param {?} viz
* @param {?} options
* @return {undefined}
*/
initialize : function(viz, options) {
this.viz = viz;
this.config = $.merge({
idSuffix : "-bkcanvas",
levelDistance : 100,
numberOfCircles : 6,
CanvasStyles : {},
offset : 0
}, options);
},
/**
* @param {number} w
* @param {number} height
* @param {?} opt
* @return {undefined}
*/
resize : function(w, height, opt) {
this.plot(opt);
},
/**
* @param {?} base
* @return {undefined}
*/
plot : function(base) {
var canvas = base.canvas;
var ctx = base.getCtx();
var conf = this.config;
var styles = conf.CanvasStyles;
var s;
for (s in styles) {
ctx[s] = styles[s];
}
var n = conf.numberOfCircles;
var rho = conf.levelDistance;
/** @type {number} */
var i = 1;
for (;i <= n;i++) {
ctx.beginPath();
ctx.arc(0, 0, rho * i, 0, 2 * Math.PI, false);
ctx.stroke();
ctx.closePath();
}
}
});
})();
/**
* @param {number} v
* @param {number} str
* @return {undefined}
*/
var Transform = function(v, str) {
this.theta = v || 0;
this.rho = str || 0;
};
/** @type {function (number, number): undefined} */
$jit.Polar = Transform;
Transform.prototype = {
/**
* @param {boolean} dataAndEvents
* @return {?}
*/
getc : function(dataAndEvents) {
return this.toComplex(dataAndEvents);
},
/**
* @return {?}
*/
getp : function() {
return this;
},
/**
* @param {?} item
* @return {undefined}
*/
set : function(item) {
item = item.getp();
this.theta = item.theta;
this.rho = item.rho;
},
/**
* @param {number} x
* @param {number} y
* @return {undefined}
*/
setc : function(x, y) {
/** @type {number} */
this.rho = Math.sqrt(x * x + y * y);
/** @type {number} */
this.theta = Math.atan2(y, x);
if (this.theta < 0) {
this.theta += Math.PI * 2;
}
},
/**
* @param {number} theta
* @param {?} dataAndEvents
* @return {undefined}
*/
setp : function(theta, dataAndEvents) {
/** @type {number} */
this.theta = theta;
this.rho = dataAndEvents;
},
/**
* @return {?}
*/
clone : function() {
return new Transform(this.theta, this.rho);
},
/**
* @param {boolean} dataAndEvents
* @return {?}
*/
toComplex : function(dataAndEvents) {
/** @type {number} */
var ex = Math.cos(this.theta) * this.rho;
/** @type {number} */
var py = Math.sin(this.theta) * this.rho;
if (dataAndEvents) {
return{
x : ex,
y : py
};
}
return new Vector(ex, py);
},
/**
* @param {?} v2
* @return {?}
*/
add : function(v2) {
return new Transform(this.theta + v2.theta, this.rho + v2.rho);
},
/**
* @param {number} x
* @return {?}
*/
scale : function(x) {
return new Transform(this.theta, this.rho * x);
},
/**
* @param {?} item
* @return {?}
*/
equals : function(item) {
return this.theta == item.theta && this.rho == item.rho;
},
/**
* @param {number} item
* @return {?}
*/
$add : function(item) {
this.theta = this.theta + item.theta;
this.rho += item.rho;
return this;
},
/**
* @param {?} item
* @return {?}
*/
$madd : function(item) {
/** @type {number} */
this.theta = (this.theta + item.theta) % (Math.PI * 2);
this.rho += item.rho;
return this;
},
/**
* @param {number} opt_attributes
* @return {?}
*/
$scale : function(opt_attributes) {
this.rho *= opt_attributes;
return this;
},
/**
* @return {?}
*/
isZero : function() {
/** @type {number} */
var distance = 1E-4;
/** @type {function (*): number} */
var abs = Math.abs;
return abs(this.theta) < distance && abs(this.rho) < distance;
},
/**
* @param {?} item
* @param {number} x
* @return {?}
*/
interpolate : function(item, x) {
/** @type {number} */
var end = Math.PI;
/** @type {number} */
var base = end * 2;
/**
* @param {number} n
* @return {?}
*/
var toString = function(n) {
/** @type {number} */
var callStr = n < 0 ? n % base + base : n % base;
return callStr;
};
var a = this.theta;
var b = item.theta;
var str;
/** @type {number} */
var start = Math.abs(a - b);
if (start == end) {
if (a > b) {
str = toString(b + (a - base - b) * x);
} else {
str = toString(b - base + (a - b) * x);
}
} else {
if (start >= end) {
if (a > b) {
str = toString(b + (a - base - b) * x);
} else {
str = toString(b - base + (a - (b - base)) * x);
}
} else {
str = toString(b + (a - b) * x);
}
}
var rho = (this.rho - item.rho) * x + item.rho;
return{
theta : str,
rho : rho
};
}
};
/**
* @param {number} x
* @param {number} recurring
* @return {?}
*/
var $P = function(x, recurring) {
return new Transform(x, recurring);
};
Transform.KER = $P(0, 0);
/**
* @param {number} x
* @param {(number|string)} y
* @return {undefined}
*/
var Vector = function(x, y) {
this.x = x || 0;
this.y = y || 0;
};
/** @type {function (number, (number|string)): undefined} */
$jit.Complex = Vector;
Vector.prototype = {
/**
* @return {?}
*/
getc : function() {
return this;
},
/**
* @param {boolean} deepDataAndEvents
* @return {?}
*/
getp : function(deepDataAndEvents) {
return this.toPolar(deepDataAndEvents);
},
/**
* @param {?} pos
* @return {undefined}
*/
set : function(pos) {
pos = pos.getc(true);
this.x = pos.x;
this.y = pos.y;
},
/**
* @param {number} x1
* @param {?} y
* @return {undefined}
*/
setc : function(x1, y) {
/** @type {number} */
this.x = x1;
this.y = y;
},
/**
* @param {?} theta2
* @param {number} fact
* @return {undefined}
*/
setp : function(theta2, fact) {
/** @type {number} */
this.x = Math.cos(theta2) * fact;
/** @type {number} */
this.y = Math.sin(theta2) * fact;
},
/**
* @return {?}
*/
clone : function() {
return new Vector(this.x, this.y);
},
/**
* @param {boolean} deepDataAndEvents
* @return {?}
*/
toPolar : function(deepDataAndEvents) {
var rho = this.norm();
/** @type {number} */
var x = Math.atan2(this.y, this.x);
if (x < 0) {
x += Math.PI * 2;
}
if (deepDataAndEvents) {
return{
theta : x,
rho : rho
};
}
return new Transform(x, rho);
},
/**
* @return {?}
*/
norm : function() {
return Math.sqrt(this.squaredNorm());
},
/**
* @return {?}
*/
squaredNorm : function() {
return this.x * this.x + this.y * this.y;
},
/**
* @param {?} v2
* @return {?}
*/
add : function(v2) {
return new Vector(this.x + v2.x, this.y + v2.y);
},
/**
* @param {?} v
* @return {?}
*/
prod : function(v) {
return new Vector(this.x * v.x - this.y * v.y, this.y * v.x + this.x * v.y);
},
/**
* @return {?}
*/
conjugate : function() {
return new Vector(this.x, -this.y);
},
/**
* @param {number} n
* @return {?}
*/
scale : function(n) {
return new Vector(this.x * n, this.y * n);
},
/**
* @param {?} other
* @return {?}
*/
equals : function(other) {
return this.x == other.x && this.y == other.y;
},
/**
* @param {number} vec
* @return {?}
*/
$add : function(vec) {
this.x += vec.x;
this.y += vec.y;
return this;
},
/**
* @param {?} c
* @return {?}
*/
$prod : function(c) {
var x = this.x;
var y = this.y;
/** @type {number} */
this.x = x * c.x - y * c.y;
/** @type {number} */
this.y = y * c.x + x * c.y;
return this;
},
/**
* @return {?}
*/
$conjugate : function() {
/** @type {number} */
this.y = -this.y;
return this;
},
/**
* @param {number} opt_attributes
* @return {?}
*/
$scale : function(opt_attributes) {
this.x *= opt_attributes;
this.y *= opt_attributes;
return this;
},
/**
* @param {?} p
* @return {?}
*/
$div : function(p) {
var x = this.x;
var y = this.y;
var z = p.squaredNorm();
/** @type {number} */
this.x = x * p.x + y * p.y;
/** @type {number} */
this.y = y * p.x - x * p.y;
return this.$scale(1 / z);
},
/**
* @return {?}
*/
isZero : function() {
/** @type {number} */
var distance = 1E-4;
/** @type {function (*): number} */
var abs = Math.abs;
return abs(this.x) < distance && abs(this.y) < distance;
}
};
/**
* @param {number} recurring
* @param {number} mayParseLabeledStatementInstead
* @return {?}
*/
var getIndex = function(recurring, mayParseLabeledStatementInstead) {
return new Vector(recurring, mayParseLabeledStatementInstead);
};
Vector.KER = getIndex(0, 0);
$jit.Graph = new Class({
/**
* @param {Object} options
* @param {?} Node
* @param {?} Edge
* @param {?} Label
* @return {undefined}
*/
initialize : function(options, Node, Edge, Label) {
var innerOptions = {
/** @type {function (number, (number|string)): undefined} */
klass : Vector,
Node : {}
};
this.Node = Node;
this.Edge = Edge;
this.Label = Label;
this.opt = $.merge(innerOptions, options || {});
this.nodes = {};
this.edges = {};
var that = this;
this.nodeList = {};
var i;
for (i in methods) {
that.nodeList[i] = function(method) {
return function() {
/** @type {Array.<?>} */
var args = Array.prototype.slice.call(arguments);
that.eachNode(function(reporter) {
reporter[method].apply(reporter, args);
});
};
}(i);
}
},
/**
* @param {?} id
* @return {?}
*/
getNode : function(id) {
if (this.hasNode(id)) {
return this.nodes[id];
}
return false;
},
/**
* @param {?} adj
* @return {?}
*/
get : function(adj) {
return this.getNode(adj);
},
/**
* @param {?} name
* @return {?}
*/
getByName : function(name) {
var i2;
for (i2 in this.nodes) {
var n = this.nodes[i2];
if (n.name == name) {
return n;
}
}
return false;
},
/**
* @param {?} id
* @param {?} id2
* @return {?}
*/
getAdjacence : function(id, id2) {
if (id in this.edges) {
return this.edges[id][id2];
}
return false;
},
/**
* @param {Object} obj
* @return {?}
*/
addNode : function(obj) {
if (!this.nodes[obj.id]) {
var edges = this.edges[obj.id] = {};
this.nodes[obj.id] = new Graph.Node($.extend({
id : obj.id,
name : obj.name,
data : $.merge(obj.data || {}, {}),
adjacencies : edges
}, this.opt.Node), this.opt.klass, this.Node, this.Edge, this.Label);
}
return this.nodes[obj.id];
},
/**
* @param {Object} obj
* @param {number} obj2
* @param {number} data
* @return {?}
*/
addAdjacence : function(obj, obj2, data) {
if (!this.hasNode(obj.id)) {
this.addNode(obj);
}
if (!this.hasNode(obj2.id)) {
this.addNode(obj2);
}
obj = this.nodes[obj.id];
obj2 = this.nodes[obj2.id];
if (!obj.adjacentTo(obj2)) {
var adjsObj = this.edges[obj.id] = this.edges[obj.id] || {};
var adjsObj2 = this.edges[obj2.id] = this.edges[obj2.id] || {};
adjsObj[obj2.id] = adjsObj2[obj.id] = new Graph.Adjacence(obj, obj2, data, this.Edge, this.Label);
return adjsObj[obj2.id];
}
return this.edges[obj.id][obj2.id];
},
/**
* @param {Array} id
* @return {undefined}
*/
removeNode : function(id) {
if (this.hasNode(id)) {
delete this.nodes[id];
var adjs = this.edges[id];
var to;
for (to in adjs) {
delete this.edges[to][id];
}
delete this.edges[id];
}
},
/**
* @param {?} id2
* @param {?} id1
* @return {undefined}
*/
removeAdjacence : function(id2, id1) {
delete this.edges[id2][id1];
delete this.edges[id1][id2];
},
/**
* @param {?} id
* @return {?}
*/
hasNode : function(id) {
return id in this.nodes;
},
/**
* @return {undefined}
*/
empty : function() {
this.nodes = {};
this.edges = {};
}
});
var Graph = $jit.Graph;
var methods;
(function() {
/**
* @param {string} prefix
* @param {number} prop
* @param {string} type
* @param {?} force
* @param {Array} prefixConfig
* @return {?}
*/
var getDataInternal = function(prefix, prop, type, force, prefixConfig) {
var data;
type = type || "current";
/** @type {string} */
prefix = "$" + (prefix ? prefix + "-" : "");
if (type == "current") {
data = this.data;
} else {
if (type == "start") {
data = this.startData;
} else {
if (type == "end") {
data = this.endData;
}
}
}
/** @type {string} */
var dollar = prefix + prop;
if (force) {
return data[dollar];
}
if (!this.Config.overridable) {
return prefixConfig[prop] || 0;
}
return dollar in data ? data[dollar] : dollar in this.data ? this.data[dollar] : prefixConfig[prop] || 0;
};
/**
* @param {string} prefix
* @param {string} prop
* @param {?} value
* @param {string} type
* @return {undefined}
*/
var setDataInternal = function(prefix, prop, value, type) {
type = type || "current";
/** @type {string} */
prefix = "$" + (prefix ? prefix + "-" : "");
var data;
if (type == "current") {
data = this.data;
} else {
if (type == "start") {
data = this.startData;
} else {
if (type == "end") {
data = this.endData;
}
}
}
data[prefix + prop] = value;
};
/**
* @param {string} prefix
* @param {?} attributes
* @return {undefined}
*/
var removeDataInternal = function(prefix, attributes) {
/** @type {string} */
prefix = "$" + (prefix ? prefix + "-" : "");
var that = this;
$.each(attributes, function(t) {
var pref = prefix + t;
delete that.data[pref];
delete that.endData[pref];
delete that.startData[pref];
});
};
methods = {
/**
* @param {string} x
* @param {Object} callback
* @param {?} force
* @return {?}
*/
getData : function(x, callback, force) {
return getDataInternal.call(this, "", x, callback, force, this.Config);
},
/**
* @param {string} prop
* @param {number} recurring
* @param {string} callback
* @return {undefined}
*/
setData : function(prop, recurring, callback) {
setDataInternal.call(this, "", prop, recurring, callback);
},
/**
* @param {(Array|string)} types
* @param {?} obj
* @return {undefined}
*/
setDataset : function(types, obj) {
types = $.splat(types);
var attr;
for (attr in obj) {
/** @type {number} */
var i = 0;
var prevSources = $.splat(obj[attr]);
var valuesLen = types.length;
for (;i < valuesLen;i++) {
this.setData(attr, prevSources[i], types[i]);
}
}
},
/**
* @return {undefined}
*/
removeData : function() {
removeDataInternal.call(this, "", Array.prototype.slice.call(arguments));
},
/**
* @param {string} prop
* @param {?} type
* @param {?} force
* @return {?}
*/
getCanvasStyle : function(prop, type, force) {
return getDataInternal.call(this, "canvas", prop, type, force, this.Config.CanvasStyles);
},
/**
* @param {string} prop
* @param {?} value
* @param {?} type
* @return {undefined}
*/
setCanvasStyle : function(prop, value, type) {
setDataInternal.call(this, "canvas", prop, value, type);
},
/**
* @param {(Array|string)} types
* @param {Object} obj
* @return {undefined}
*/
setCanvasStyles : function(types, obj) {
types = $.splat(types);
var attr;
for (attr in obj) {
/** @type {number} */
var i = 0;
var prevSources = $.splat(obj[attr]);
var valuesLen = types.length;
for (;i < valuesLen;i++) {
this.setCanvasStyle(attr, prevSources[i], types[i]);
}
}
},
/**
* @return {undefined}
*/
removeCanvasStyle : function() {
removeDataInternal.call(this, "canvas", Array.prototype.slice.call(arguments));
},
/**
* @param {string} property
* @param {?} type
* @param {?} force
* @return {?}
*/
getLabelData : function(property, type, force) {
return getDataInternal.call(this, "label", property, type, force, this.Label);
},
/**
* @param {string} prop
* @param {?} value
* @param {?} type
* @return {undefined}
*/
setLabelData : function(prop, value, type) {
setDataInternal.call(this, "label", prop, value, type);
},
/**
* @param {(Array|string)} types
* @param {Object} obj
* @return {undefined}
*/
setLabelDataset : function(types, obj) {
types = $.splat(types);
var attr;
for (attr in obj) {
/** @type {number} */
var i = 0;
var prevSources = $.splat(obj[attr]);
var valuesLen = types.length;
for (;i < valuesLen;i++) {
this.setLabelData(attr, prevSources[i], types[i]);
}
}
},
/**
* @return {undefined}
*/
removeLabelData : function() {
removeDataInternal.call(this, "label", Array.prototype.slice.call(arguments));
}
};
})();
Graph.Node = new Class({
/**
* @param {?} attributes
* @param {?} klass
* @param {?} Node
* @param {?} Edge
* @param {?} Label
* @return {undefined}
*/
initialize : function(attributes, klass, Node, Edge, Label) {
var innerOptions = {
id : "",
name : "",
data : {},
startData : {},
endData : {},
adjacencies : {},
selected : false,
drawn : false,
exist : false,
angleSpan : {
begin : 0,
end : 0
},
pos : new klass,
startPos : new klass,
endPos : new klass
};
$.extend(this, $.extend(innerOptions, attributes));
this.Config = this.Node = Node;
this.Edge = Edge;
this.Label = Label;
},
/**
* @param {Object} node
* @return {?}
*/
adjacentTo : function(node) {
return node.id in this.adjacencies;
},
/**
* @param {?} id
* @return {?}
*/
getAdjacency : function(id) {
return this.adjacencies[id];
},
/**
* @param {string} expectation
* @return {?}
*/
getPos : function(expectation) {
expectation = expectation || "current";
if (expectation == "current") {
return this.pos;
} else {
if (expectation == "end") {
return this.endPos;
} else {
if (expectation == "start") {
return this.startPos;
}
}
}
},
/**
* @param {?} x
* @param {string} type
* @return {undefined}
*/
setPos : function(x, type) {
type = type || "current";
var pos;
if (type == "current") {
pos = this.pos;
} else {
if (type == "end") {
pos = this.endPos;
} else {
if (type == "start") {
pos = this.startPos;
}
}
}
pos.set(x);
}
});
Graph.Node.implement(methods);
Graph.Adjacence = new Class({
/**
* @param {number} nodeFrom
* @param {?} nodeTo
* @param {Object} data
* @param {?} Edge
* @param {number} Label
* @return {undefined}
*/
initialize : function(nodeFrom, nodeTo, data, Edge, Label) {
/** @type {number} */
this.nodeFrom = nodeFrom;
this.nodeTo = nodeTo;
this.data = data || {};
this.startData = {};
this.endData = {};
this.Config = this.Edge = Edge;
/** @type {number} */
this.Label = Label;
}
});
Graph.Adjacence.implement(methods);
Graph.Util = {
/**
* @param {string} param
* @return {?}
*/
filter : function(param) {
if (!param || !($.type(param) == "string")) {
return function() {
return true;
};
}
var codeSegments = param.split(" ");
return function(searchParams) {
/** @type {number} */
var i = 0;
for (;i < codeSegments.length;i++) {
if (searchParams[codeSegments[i]]) {
return false;
}
}
return true;
};
},
/**
* @param {?} id
* @param {?} i
* @return {?}
*/
getNode : function(id, i) {
return id.nodes[i];
},
/**
* @param {Function} graph
* @param {Function} action
* @param {string} flags
* @return {undefined}
*/
eachNode : function(graph, action, flags) {
var filter = this.filter(flags);
var i;
for (i in graph.nodes) {
if (filter(graph.nodes[i])) {
action(graph.nodes[i]);
}
}
},
/**
* @param {?} opt_attributes
* @param {Function} action
* @param {string} flags
* @return {undefined}
*/
each : function(opt_attributes, action, flags) {
this.eachNode(opt_attributes, action, flags);
},
/**
* @param {Function} node
* @param {Function} action
* @param {string} flags
* @return {undefined}
*/
eachAdjacency : function(node, action, flags) {
var adj = node.adjacencies;
var filter = this.filter(flags);
var id;
for (id in adj) {
var a = adj[id];
if (filter(a)) {
if (a.nodeFrom != node) {
var tmp = a.nodeFrom;
a.nodeFrom = a.nodeTo;
a.nodeTo = tmp;
}
action(a, id);
}
}
},
/**
* @param {?} graph
* @param {number} recurring
* @param {number} startDepth
* @param {string} flags
* @return {undefined}
*/
computeLevels : function(graph, recurring, startDepth, flags) {
startDepth = startDepth || 0;
var filter = this.filter(flags);
this.eachNode(graph, function(node) {
/** @type {boolean} */
node._flag = false;
/** @type {number} */
node._depth = -1;
}, flags);
var root = graph.getNode(recurring);
/** @type {number} */
root._depth = startDepth;
/** @type {Array} */
var queue = [root];
for (;queue.length != 0;) {
var node = queue.pop();
/** @type {boolean} */
node._flag = true;
this.eachAdjacency(node, function(adj) {
var n = adj.nodeTo;
if (n._flag == false && filter(n)) {
if (n._depth < 0) {
n._depth = node._depth + 1 + startDepth;
}
queue.unshift(n);
}
}, flags);
}
},
/**
* @param {Element} graph
* @param {Function} id
* @param {string} action
* @param {string} flags
* @return {undefined}
*/
eachBFS : function(graph, id, action, flags) {
var filter = this.filter(flags);
this.clean(graph);
/** @type {Array} */
var lines = [graph.getNode(id)];
for (;lines.length != 0;) {
var node = lines.pop();
/** @type {boolean} */
node._flag = true;
action(node, node._depth);
this.eachAdjacency(node, function(adj) {
var n = adj.nodeTo;
if (n._flag == false && filter(n)) {
/** @type {boolean} */
n._flag = true;
lines.unshift(n);
}
}, flags);
}
},
/**
* @param {number} b
* @param {number} opt_isDefault
* @param {Object} recurring
* @param {Function} action
* @param {string} flags
* @return {undefined}
*/
eachLevel : function(b, opt_isDefault, recurring, action, flags) {
var d = b._depth;
var filter = this.filter(flags);
var root = this;
recurring = recurring === false ? Number.MAX_VALUE - d : recurring;
(function loopLevel(node, levelBegin, levelEnd) {
var d = node._depth;
if (d >= levelBegin && (d <= levelEnd && filter(node))) {
action(node, d);
}
if (d < levelEnd) {
root.eachAdjacency(node, function(adj) {
var n = adj.nodeTo;
if (n._depth > d) {
loopLevel(n, levelBegin, levelEnd);
}
});
}
})(b, opt_isDefault + d, recurring + d);
},
/**
* @param {Object} node
* @param {Function} action
* @param {string} flags
* @return {undefined}
*/
eachSubgraph : function(node, action, flags) {
this.eachLevel(node, 0, false, action, flags);
},
/**
* @param {Function} node
* @param {Function} action
* @param {string} flags
* @return {undefined}
*/
eachSubnode : function(node, action, flags) {
this.eachLevel(node, 1, 1, action, flags);
},
/**
* @param {?} node
* @param {Object} options
* @param {string} flags
* @return {?}
*/
anySubnode : function(node, options, flags) {
/** @type {boolean} */
var flag = false;
options = options || $.lambda(true);
var opts = $.type(options) == "string" ? function(deepDataAndEvents) {
return deepDataAndEvents[options];
} : options;
this.eachSubnode(node, function(deepDataAndEvents) {
if (opts(deepDataAndEvents)) {
/** @type {boolean} */
flag = true;
}
}, flags);
return flag;
},
/**
* @param {?} node
* @param {number} options
* @param {string} flags
* @return {?}
*/
getSubnodes : function(node, options, flags) {
/** @type {Array} */
var assigns = [];
var A = this;
options = options || 0;
var isDefault;
var recurring;
if ($.type(options) == "array") {
isDefault = options[0];
recurring = options[1];
} else {
/** @type {number} */
isDefault = options;
/** @type {number} */
recurring = Number.MAX_VALUE - node._depth;
}
this.eachLevel(node, isDefault, recurring, function(vvar) {
assigns.push(vvar);
}, flags);
return assigns;
},
/**
* @param {Function} node
* @return {?}
*/
getParents : function(node) {
/** @type {Array} */
var matched = [];
this.eachAdjacency(node, function(adj) {
var n = adj.nodeTo;
if (n._depth < node._depth) {
matched.push(n);
}
});
return matched;
},
/**
* @param {?} node
* @param {?} id
* @return {?}
*/
isDescendantOf : function(node, id) {
if (node.id == id) {
return true;
}
var codeSegments = this.getParents(node);
/** @type {boolean} */
var ans = false;
/** @type {number} */
var i = 0;
for (;!ans && i < codeSegments.length;i++) {
ans = ans || this.isDescendantOf(codeSegments[i], id);
}
return ans;
},
/**
* @param {?} graph
* @return {undefined}
*/
clean : function(graph) {
this.eachNode(graph, function(v) {
/** @type {boolean} */
v._flag = false;
});
},
/**
* @param {?} graph
* @param {string} prop
* @param {string} flags
* @return {?}
*/
getClosestNodeToOrigin : function(graph, prop, flags) {
return this.getClosestNodeToPos(graph, Transform.KER, prop, flags);
},
/**
* @param {?} graph
* @param {?} pos
* @param {string} prop
* @param {string} flags
* @return {?}
*/
getClosestNodeToPos : function(graph, pos, prop, flags) {
/** @type {null} */
var node = null;
prop = prop || "current";
pos = pos && pos.getc(true) || Vector.KER;
/**
* @param {?} a
* @param {?} b
* @return {?}
*/
var distance = function(a, b) {
/** @type {number} */
var z0 = a.x - b.x;
/** @type {number} */
var z1 = a.y - b.y;
return z0 * z0 + z1 * z1;
};
this.eachNode(graph, function(elem) {
node = node == null || distance(elem.getPos(prop).getc(true), pos) < distance(node.getPos(prop).getc(true), pos) ? elem : node;
}, flags);
return node;
}
};
$.each(["get", "getNode", "each", "eachNode", "computeLevels", "eachBFS", "clean", "getClosestNodeToPos", "getClosestNodeToOrigin"], function(m) {
/**
* @return {?}
*/
Graph.prototype[m] = function() {
return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments)));
};
});
$.each(["eachAdjacency", "eachLevel", "eachSubgraph", "eachSubnode", "anySubnode", "getSubnodes", "getParents", "isDescendantOf"], function(m) {
/**
* @return {?}
*/
Graph.Node.prototype[m] = function() {
return Graph.Util[m].apply(Graph.Util, [this].concat(Array.prototype.slice.call(arguments)));
};
});
Graph.Op = {
options : {
type : "nothing",
duration : 2E3,
hideLabels : true,
fps : 30
},
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {(Array|string)} node
* @param {?} opt_attributes
* @return {undefined}
*/
removeNode : function(node, opt_attributes) {
var viz = this.viz;
var options = $.merge(this.options, viz.controller, opt_attributes);
var n = $.splat(node);
var i;
var element;
var nodeObj;
switch(options.type) {
case "nothing":
/** @type {number} */
i = 0;
for (;i < n.length;i++) {
viz.graph.removeNode(n[i]);
}
break;
case "replot":
this.removeNode(n, {
type : "nothing"
});
viz.labels.clearLabels();
viz.refresh(true);
break;
case "fade:seq":
;
case "fade":
element = this;
/** @type {number} */
i = 0;
for (;i < n.length;i++) {
nodeObj = viz.graph.getNode(n[i]);
nodeObj.setData("alpha", 0, "end");
}
viz.fx.animate($.merge(options, {
modes : ["node-property:alpha"],
/**
* @return {undefined}
*/
onComplete : function() {
element.removeNode(n, {
type : "nothing"
});
viz.labels.clearLabels();
viz.reposition();
viz.fx.animate($.merge(options, {
modes : ["linear"]
}));
}
}));
break;
case "fade:con":
element = this;
/** @type {number} */
i = 0;
for (;i < n.length;i++) {
nodeObj = viz.graph.getNode(n[i]);
nodeObj.setData("alpha", 0, "end");
/** @type {boolean} */
nodeObj.ignore = true;
}
viz.reposition();
viz.fx.animate($.merge(options, {
modes : ["node-property:alpha", "linear"],
/**
* @return {undefined}
*/
onComplete : function() {
element.removeNode(n, {
type : "nothing"
});
if (options.onComplete) {
options.onComplete();
}
}
}));
break;
case "iter":
element = this;
viz.fx.sequence({
/**
* @return {?}
*/
condition : function() {
return n.length != 0;
},
/**
* @return {undefined}
*/
step : function() {
element.removeNode(n.shift(), {
type : "nothing"
});
viz.labels.clearLabels();
},
/**
* @return {undefined}
*/
onComplete : function() {
if (options.onComplete) {
options.onComplete();
}
},
duration : Math.ceil(options.duration / n.length)
});
break;
default:
this.doError();
}
},
/**
* @param {?} vertex
* @param {?} opt_attributes
* @return {undefined}
*/
removeEdge : function(vertex, opt_attributes) {
var viz = this.viz;
var options = $.merge(this.options, viz.controller, opt_attributes);
var v = $.type(vertex[0]) == "string" ? [vertex] : vertex;
var ii;
var that;
var nodeObj;
switch(options.type) {
case "nothing":
/** @type {number} */
ii = 0;
for (;ii < v.length;ii++) {
viz.graph.removeAdjacence(v[ii][0], v[ii][1]);
}
break;
case "replot":
this.removeEdge(v, {
type : "nothing"
});
viz.refresh(true);
break;
case "fade:seq":
;
case "fade":
that = this;
/** @type {number} */
ii = 0;
for (;ii < v.length;ii++) {
nodeObj = viz.graph.getAdjacence(v[ii][0], v[ii][1]);
if (nodeObj) {
nodeObj.setData("alpha", 0, "end");
}
}
viz.fx.animate($.merge(options, {
modes : ["edge-property:alpha"],
/**
* @return {undefined}
*/
onComplete : function() {
that.removeEdge(v, {
type : "nothing"
});
viz.reposition();
viz.fx.animate($.merge(options, {
modes : ["linear"]
}));
}
}));
break;
case "fade:con":
that = this;
/** @type {number} */
ii = 0;
for (;ii < v.length;ii++) {
nodeObj = viz.graph.getAdjacence(v[ii][0], v[ii][1]);
if (nodeObj) {
nodeObj.setData("alpha", 0, "end");
/** @type {boolean} */
nodeObj.ignore = true;
}
}
viz.reposition();
viz.fx.animate($.merge(options, {
modes : ["edge-property:alpha", "linear"],
/**
* @return {undefined}
*/
onComplete : function() {
that.removeEdge(v, {
type : "nothing"
});
if (options.onComplete) {
options.onComplete();
}
}
}));
break;
case "iter":
that = this;
viz.fx.sequence({
/**
* @return {?}
*/
condition : function() {
return v.length != 0;
},
/**
* @return {undefined}
*/
step : function() {
that.removeEdge(v.shift(), {
type : "nothing"
});
viz.labels.clearLabels();
},
/**
* @return {undefined}
*/
onComplete : function() {
options.onComplete();
},
duration : Math.ceil(options.duration / v.length)
});
break;
default:
this.doError();
}
},
/**
* @param {?} json
* @param {?} opt
* @return {undefined}
*/
sum : function(json, opt) {
var viz = this.viz;
var options = $.merge(this.options, viz.controller, opt);
var root = viz.root;
var graph;
viz.root = opt.id || viz.root;
switch(options.type) {
case "nothing":
graph = viz.construct(json);
graph.eachNode(function(rt) {
rt.eachAdjacency(function(adj) {
viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
});
});
break;
case "replot":
viz.refresh(true);
this.sum(json, {
type : "nothing"
});
viz.refresh(true);
break;
case "fade:seq":
;
case "fade":
;
case "fade:con":
that = this;
graph = viz.construct(json);
var fadeEdges = this.preprocessSum(graph);
/** @type {Array} */
var modes = !fadeEdges ? ["node-property:alpha"] : ["node-property:alpha", "edge-property:alpha"];
viz.reposition();
if (options.type != "fade:con") {
viz.fx.animate($.merge(options, {
modes : ["linear"],
/**
* @return {undefined}
*/
onComplete : function() {
viz.fx.animate($.merge(options, {
modes : modes,
/**
* @return {undefined}
*/
onComplete : function() {
options.onComplete();
}
}));
}
}));
} else {
viz.graph.eachNode(function(elem) {
if (elem.id != root && elem.pos.isZero()) {
elem.pos.set(elem.endPos);
elem.startPos.set(elem.endPos);
}
});
viz.fx.animate($.merge(options, {
modes : ["linear"].concat(modes)
}));
}
break;
default:
this.doError();
}
},
/**
* @param {(Error|string)} json
* @param {Element} opt
* @param {Object} extraModes
* @return {undefined}
*/
morph : function(json, opt, extraModes) {
extraModes = extraModes || {};
var viz = this.viz;
var options = $.merge(this.options, viz.controller, opt);
var root = viz.root;
var graph;
viz.root = opt.id || viz.root;
switch(options.type) {
case "nothing":
graph = viz.construct(json);
graph.eachNode(function(elem) {
var H = viz.graph.hasNode(elem.id);
elem.eachAdjacency(function(adj) {
/** @type {boolean} */
var L = !!viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
viz.graph.addAdjacence(adj.nodeFrom, adj.nodeTo, adj.data);
if (L) {
var event = viz.graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
var prop;
for (prop in adj.data || {}) {
event.data[prop] = adj.data[prop];
}
}
});
if (H) {
var jQuery = viz.graph.getNode(elem.id);
var name;
for (name in elem.data || {}) {
jQuery.data[name] = elem.data[name];
}
}
});
viz.graph.eachNode(function(elem) {
elem.eachAdjacency(function(adj) {
if (!graph.getAdjacence(adj.nodeFrom.id, adj.nodeTo.id)) {
viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
}
});
if (!graph.hasNode(elem.id)) {
viz.graph.removeNode(elem.id);
}
});
break;
case "replot":
viz.labels.clearLabels(true);
this.morph(json, {
type : "nothing"
});
viz.refresh(true);
viz.refresh(true);
break;
case "fade:seq":
;
case "fade":
;
case "fade:con":
that = this;
graph = viz.construct(json);
var selection = "node-property" in extraModes && $.map($.splat(extraModes["node-property"]), function(type) {
return "$" + type;
});
viz.graph.eachNode(function(elem) {
var response = graph.getNode(elem.id);
if (!response) {
elem.setData("alpha", 1);
elem.setData("alpha", 1, "start");
elem.setData("alpha", 0, "end");
/** @type {boolean} */
elem.ignore = true;
} else {
var template = response.data;
var prop;
for (prop in template) {
if (selection && $.indexOf(selection, prop) > -1) {
elem.endData[prop] = template[prop];
} else {
elem.data[prop] = template[prop];
}
}
}
});
viz.graph.eachNode(function(node) {
if (node.ignore) {
return;
}
node.eachAdjacency(function(adj) {
if (adj.nodeFrom.ignore || adj.nodeTo.ignore) {
return;
}
var nodeFrom = graph.getNode(adj.nodeFrom.id);
var nodeTo = graph.getNode(adj.nodeTo.id);
if (!nodeFrom.adjacentTo(nodeTo)) {
adj = viz.graph.getAdjacence(nodeFrom.id, nodeTo.id);
/** @type {boolean} */
fadeEdges = true;
adj.setData("alpha", 1);
adj.setData("alpha", 1, "start");
adj.setData("alpha", 0, "end");
}
});
});
var fadeEdges = this.preprocessSum(graph);
/** @type {Array} */
var modes = !fadeEdges ? ["node-property:alpha"] : ["node-property:alpha", "edge-property:alpha"];
modes[0] = modes[0] + ("node-property" in extraModes ? ":" + $.splat(extraModes["node-property"]).join(":") : "");
modes[1] = (modes[1] || "edge-property:alpha") + ("edge-property" in extraModes ? ":" + $.splat(extraModes["edge-property"]).join(":") : "");
if ("label-property" in extraModes) {
modes.push("label-property:" + $.splat(extraModes["label-property"]).join(":"));
}
if (viz.reposition) {
viz.reposition();
} else {
viz.compute("end");
}
viz.graph.eachNode(function(elem) {
if (elem.id != root && elem.pos.getp().equals(Transform.KER)) {
elem.pos.set(elem.endPos);
elem.startPos.set(elem.endPos);
}
});
viz.fx.animate($.merge(options, {
modes : [extraModes.position || "polar"].concat(modes),
/**
* @return {undefined}
*/
onComplete : function() {
viz.graph.eachNode(function(elem) {
if (elem.ignore) {
viz.graph.removeNode(elem.id);
}
});
viz.graph.eachNode(function(rt) {
rt.eachAdjacency(function(adj) {
if (adj.ignore) {
viz.graph.removeAdjacence(adj.nodeFrom.id, adj.nodeTo.id);
}
});
});
options.onComplete();
}
}));
break;
default:
;
}
},
/**
* @param {?} node
* @param {Object} opt
* @return {undefined}
*/
contract : function(node, opt) {
var viz = this.viz;
if (node.collapsed || !node.anySubnode($.lambda(true))) {
return;
}
opt = $.merge(this.options, viz.config, opt || {}, {
modes : ["node-property:alpha:span", "linear"]
});
/** @type {boolean} */
node.collapsed = true;
(function subn(n) {
n.eachSubnode(function(ch) {
/** @type {boolean} */
ch.ignore = true;
ch.setData("alpha", 0, opt.type == "animate" ? "end" : "current");
subn(ch);
});
})(node);
if (opt.type == "animate") {
viz.compute("end");
if (viz.rotated) {
viz.rotate(viz.rotated, "none", {
property : "end"
});
}
(function subn(n) {
n.eachSubnode(function(ch) {
ch.setPos(node.getPos("end"), "end");
subn(ch);
});
})(node);
viz.fx.animate(opt);
} else {
if (opt.type == "replot") {
viz.refresh();
}
}
},
/**
* @param {Object} node
* @param {Object} opt
* @return {undefined}
*/
expand : function(node, opt) {
if (!("collapsed" in node)) {
return;
}
var viz = this.viz;
opt = $.merge(this.options, viz.config, opt || {}, {
modes : ["node-property:alpha:span", "linear"]
});
delete node.collapsed;
(function subn(n) {
n.eachSubnode(function(ch) {
delete ch.ignore;
ch.setData("alpha", 1, opt.type == "animate" ? "end" : "current");
subn(ch);
});
})(node);
if (opt.type == "animate") {
viz.compute("end");
if (viz.rotated) {
viz.rotate(viz.rotated, "none", {
property : "end"
});
}
viz.fx.animate(opt);
} else {
if (opt.type == "replot") {
viz.refresh();
}
}
},
/**
* @param {?} graph
* @return {?}
*/
preprocessSum : function(graph) {
var viz = this.viz;
graph.eachNode(function(elem) {
if (!viz.graph.hasNode(elem.id)) {
viz.graph.addNode(elem);
var n = viz.graph.getNode(elem.id);
n.setData("alpha", 0);
n.setData("alpha", 0, "start");
n.setData("alpha", 1, "end");
}
});
/** @type {boolean} */
var fadeEdges = false;
graph.eachNode(function(rt) {
rt.eachAdjacency(function(adj) {
var nodeFrom = viz.graph.getNode(adj.nodeFrom.id);
var nodeTo = viz.graph.getNode(adj.nodeTo.id);
if (!nodeFrom.adjacentTo(nodeTo)) {
adj = viz.graph.addAdjacence(nodeFrom, nodeTo, adj.data);
if (nodeFrom.startAlpha == nodeFrom.endAlpha && nodeTo.startAlpha == nodeTo.endAlpha) {
/** @type {boolean} */
fadeEdges = true;
adj.setData("alpha", 0);
adj.setData("alpha", 0, "start");
adj.setData("alpha", 1, "end");
}
}
});
});
return fadeEdges;
}
};
var self = {
none : {
/** @type {function (): undefined} */
render : $.empty,
contains : $.lambda(false)
},
circle : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
render : function(adj, lab, event, type) {
var that = type.getCtx();
that.beginPath();
that.arc(lab.x, lab.y, event, 0, Math.PI * 2, true);
that.closePath();
that[adj]();
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @return {?}
*/
contains : function(opt_attributes, value, testName) {
/** @type {number} */
var z0 = opt_attributes.x - value.x;
/** @type {number} */
var z1 = opt_attributes.y - value.y;
/** @type {number} */
var z = z0 * z0 + z1 * z1;
return z <= testName * testName;
}
},
ellipse : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @param {?} keepData
* @return {undefined}
*/
render : function(adj, lab, event, type, keepData) {
var ctx = keepData.getCtx();
/** @type {number} */
var c = 1;
/** @type {number} */
var scaleY = 1;
/** @type {number} */
var scaleposx = 1;
/** @type {number} */
var scaleposy = 1;
/** @type {number} */
var diameter = 0;
if (event > type) {
/** @type {number} */
diameter = event / 2;
/** @type {number} */
scaleY = type / event;
/** @type {number} */
scaleposy = event / type;
} else {
/** @type {number} */
diameter = type / 2;
/** @type {number} */
c = event / type;
/** @type {number} */
scaleposx = type / event;
}
ctx.save();
ctx.scale(c, scaleY);
ctx.beginPath();
ctx.arc(lab.x * scaleposx, lab.y * scaleposy, diameter, 0, Math.PI * 2, true);
ctx.closePath();
ctx[adj]();
ctx.restore();
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @param {?} epsilon
* @return {?}
*/
contains : function(opt_attributes, value, testName, epsilon) {
/** @type {number} */
var radii = 0;
/** @type {number} */
var B = 1;
/** @type {number} */
var t = 1;
/** @type {number} */
var z0 = 0;
/** @type {number} */
var z1 = 0;
/** @type {number} */
var distSq = 0;
if (testName > epsilon) {
/** @type {number} */
radii = testName / 2;
/** @type {number} */
t = epsilon / testName;
} else {
/** @type {number} */
radii = epsilon / 2;
/** @type {number} */
B = testName / epsilon;
}
/** @type {number} */
z0 = (opt_attributes.x - value.x) * (1 / B);
/** @type {number} */
z1 = (opt_attributes.y - value.y) * (1 / t);
/** @type {number} */
distSq = z0 * z0 + z1 * z1;
return distSq <= radii * radii;
}
},
square : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
render : function(adj, lab, event, type) {
type.getCtx()[adj + "Rect"](lab.x - event, lab.y - event, 2 * event, 2 * event);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @return {?}
*/
contains : function(opt_attributes, value, testName) {
return Math.abs(value.x - opt_attributes.x) <= testName && Math.abs(value.y - opt_attributes.y) <= testName;
}
},
rectangle : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @param {?} keepData
* @return {undefined}
*/
render : function(adj, lab, event, type, keepData) {
keepData.getCtx()[adj + "Rect"](lab.x - event / 2, lab.y - type / 2, event, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @param {?} epsilon
* @return {?}
*/
contains : function(opt_attributes, value, testName, epsilon) {
return Math.abs(value.x - opt_attributes.x) <= testName / 2 && Math.abs(value.y - opt_attributes.y) <= epsilon / 2;
}
},
triangle : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
render : function(adj, lab, event, type) {
var context = type.getCtx();
var left = lab.x;
/** @type {number} */
var fromY = lab.y - event;
/** @type {number} */
var vLine2 = left - event;
var hly = lab.y + event;
var centerX = left + event;
var gy = hly;
context.beginPath();
context.moveTo(left, fromY);
context.lineTo(vLine2, hly);
context.lineTo(centerX, gy);
context.closePath();
context[adj]();
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @return {?}
*/
contains : function(opt_attributes, value, testName) {
return self.circle.contains(opt_attributes, value, testName);
}
},
star : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
render : function(adj, lab, event, type) {
var ctx = type.getCtx();
/** @type {number} */
var thetap = Math.PI / 5;
ctx.save();
ctx.translate(lab.x, lab.y);
ctx.beginPath();
ctx.moveTo(event, 0);
/** @type {number} */
var y = 0;
for (;y < 9;y++) {
ctx.rotate(thetap);
if (y % 2 == 0) {
ctx.lineTo(event / 0.525731 * 0.200811, 0);
} else {
ctx.lineTo(event, 0);
}
}
ctx.closePath();
ctx[adj]();
ctx.restore();
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @return {?}
*/
contains : function(opt_attributes, value, testName) {
return self.circle.contains(opt_attributes, value, testName);
}
}
};
var element = {
line : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
render : function(adj, lab, event) {
var ctx = event.getCtx();
ctx.beginPath();
ctx.moveTo(adj.x, adj.y);
ctx.lineTo(lab.x, lab.y);
ctx.stroke();
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @param {?} epsilon
* @return {?}
*/
contains : function(opt_attributes, value, testName, epsilon) {
/** @type {function (...[*]): number} */
var min = Math.min;
/** @type {function (...[*]): number} */
var max = Math.max;
/** @type {number} */
var minX = min(opt_attributes.x, value.x);
/** @type {number} */
var x = max(opt_attributes.x, value.x);
/** @type {number} */
var minY = min(opt_attributes.y, value.y);
/** @type {number} */
var maxY = max(opt_attributes.y, value.y);
if (testName.x >= minX && (testName.x <= x && (testName.y >= minY && testName.y <= maxY))) {
if (Math.abs(value.x - opt_attributes.x) <= epsilon) {
return true;
}
var newTop = (value.y - opt_attributes.y) / (value.x - opt_attributes.x) * (testName.x - opt_attributes.x) + opt_attributes.y;
return Math.abs(newTop - testName.y) <= epsilon;
}
return false;
}
},
arrow : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @param {?} keepData
* @return {undefined}
*/
render : function(adj, lab, event, type, keepData) {
var ctx = keepData.getCtx();
if (type) {
var fx = adj;
adj = lab;
lab = fx;
}
var p = new Vector(lab.x - adj.x, lab.y - adj.y);
p.$scale(event / p.norm());
var collection = new Vector(lab.x - p.x, lab.y - p.y);
var to = new Vector(-p.y / 2, p.x / 2);
var d = collection.add(to);
var p4coord = collection.$add(to.$scale(-1));
ctx.beginPath();
ctx.moveTo(adj.x, adj.y);
ctx.lineTo(lab.x, lab.y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(d.x, d.y);
ctx.lineTo(p4coord.x, p4coord.y);
ctx.lineTo(lab.x, lab.y);
ctx.closePath();
ctx.fill();
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @param {?} epsilon
* @return {?}
*/
contains : function(opt_attributes, value, testName, epsilon) {
return element.line.contains(opt_attributes, value, testName, epsilon);
}
},
hyperline : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @param {?} type
* @return {undefined}
*/
render : function(adj, lab, event, type) {
/**
* @param {?} p1
* @param {?} p2
* @return {?}
*/
function computeArcThroughTwoPoints(p1, p2) {
/** @type {number} */
var YY_START = p1.x * p2.y - p1.y * p2.x;
/** @type {number} */
var YYSTATE = YY_START;
var b3 = p1.squaredNorm();
var b1 = p2.squaredNorm();
if (YY_START == 0) {
return{
x : 0,
y : 0,
ratio : -1
};
}
/** @type {number} */
var z0 = (p1.y * b1 - p2.y * b3 + p1.y - p2.y) / YY_START;
/** @type {number} */
var z1 = (p2.x * b3 - p1.x * b1 + p2.x - p1.x) / YYSTATE;
/** @type {number} */
var moveX = -z0 / 2;
/** @type {number} */
var moveY = -z1 / 2;
/** @type {number} */
var squaredRatio = (z0 * z0 + z1 * z1) / 4 - 1;
if (squaredRatio < 0) {
return{
x : 0,
y : 0,
ratio : -1
};
}
/** @type {number} */
var ratio = Math.sqrt(squaredRatio);
var out = {
x : moveX,
y : moveY,
ratio : ratio > 1E3 ? -1 : ratio,
a : z0,
b : z1
};
return out;
}
/**
* @param {number} angleBegin
* @param {number} angleEnd
* @return {?}
*/
function sense(angleBegin, angleEnd) {
return angleBegin < angleEnd ? angleBegin + Math.PI > angleEnd ? false : true : angleEnd + Math.PI > angleBegin ? true : false;
}
var ctx = type.getCtx();
var centerOfCircle = computeArcThroughTwoPoints(adj, lab);
if (centerOfCircle.a > 1E3 || (centerOfCircle.b > 1E3 || centerOfCircle.ratio < 0)) {
ctx.beginPath();
ctx.moveTo(adj.x * event, adj.y * event);
ctx.lineTo(lab.x * event, lab.y * event);
ctx.stroke();
} else {
/** @type {number} */
var angleBegin = Math.atan2(lab.y - centerOfCircle.y, lab.x - centerOfCircle.x);
/** @type {number} */
var angleEnd = Math.atan2(adj.y - centerOfCircle.y, adj.x - centerOfCircle.x);
sense = sense(angleBegin, angleEnd);
ctx.beginPath();
ctx.arc(centerOfCircle.x * event, centerOfCircle.y * event, centerOfCircle.ratio * event, angleBegin, angleEnd, sense);
ctx.stroke();
}
},
contains : $.lambda(false)
}
};
Graph.Plot = {
/**
* @param {Object} viz
* @param {?} klass
* @return {undefined}
*/
initialize : function(viz, klass) {
/** @type {Object} */
this.viz = viz;
this.config = viz.config;
this.node = viz.config.Node;
this.edge = viz.config.Edge;
this.animation = new Animation;
this.nodeTypes = new klass.Plot.NodeTypes;
this.edgeTypes = new klass.Plot.EdgeTypes;
this.labels = viz.labels;
},
nodeHelper : self,
edgeHelper : element,
Interpolator : {
map : {
border : "color",
color : "color",
width : "number",
height : "number",
dim : "number",
alpha : "number",
lineWidth : "number",
angularWidth : "number",
span : "number",
valueArray : "array-number",
dimArray : "array-number"
},
canvas : {
globalAlpha : "number",
fillStyle : "color",
strokeStyle : "color",
lineWidth : "number",
shadowBlur : "number",
shadowColor : "color",
shadowOffsetX : "number",
shadowOffsetY : "number",
miterLimit : "number"
},
label : {
size : "number",
color : "color"
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {?}
*/
compute : function(adj, lab, event) {
return adj + (lab - adj) * event;
},
/**
* @param {Object} elem
* @param {?} dataAndEvents
* @param {?} delta
* @param {Object} vector
* @return {undefined}
*/
moebius : function(elem, dataAndEvents, delta, vector) {
var v = vector.scale(-delta);
if (v.norm() < 1) {
var x = v.x;
var y = v.y;
var pos = elem.startPos.getc().moebiusTransformation(v);
elem.pos.setc(pos.x, pos.y);
v.x = x;
v.y = y;
}
},
/**
* @param {Object} n
* @param {?} diff
* @param {?} qualifier
* @return {undefined}
*/
linear : function(n, diff, qualifier) {
var from = n.startPos.getc(true);
var to = n.endPos.getc(true);
n.pos.setc(this.compute(from.x, to.x, qualifier), this.compute(from.y, to.y, qualifier));
},
/**
* @param {Object} elem
* @param {?} r
* @param {number} delta
* @return {undefined}
*/
polar : function(elem, r, delta) {
var from = elem.startPos.getp(true);
var to = elem.endPos.getp();
var ans = to.interpolate(from, delta);
elem.pos.setp(ans.theta, ans.rho);
},
/**
* @param {Array} elem
* @param {?} prop
* @param {?} qualifier
* @param {number} getter
* @param {number} setter
* @return {undefined}
*/
number : function(elem, prop, qualifier, getter, setter) {
var from = elem[getter](prop, "start");
var lab = elem[getter](prop, "end");
elem[setter](prop, this.compute(from, lab, qualifier));
},
/**
* @param {Array} elem
* @param {?} prop
* @param {?} qualifier
* @param {number} getter
* @param {number} setter
* @return {undefined}
*/
color : function(elem, prop, qualifier, getter, setter) {
var arr = $.hexToRgb(elem[getter](prop, "start"));
var to = $.hexToRgb(elem[getter](prop, "end"));
var comp = this.compute;
var val = $.rgbToHex([parseInt(comp(arr[0], to[0], qualifier)), parseInt(comp(arr[1], to[1], qualifier)), parseInt(comp(arr[2], to[2], qualifier))]);
elem[setter](prop, val);
},
/**
* @param {Array} elem
* @param {?} prop
* @param {?} qualifier
* @param {number} getter
* @param {number} setter
* @return {undefined}
*/
"array-number" : function(elem, prop, qualifier, getter, setter) {
var v = elem[getter](prop, "start");
var parts = elem[getter](prop, "end");
/** @type {Array} */
var cur = [];
/** @type {number} */
var id = 0;
var pad = v.length;
for (;id < pad;id++) {
var from = v[id];
var lab = parts[id];
if (from.length) {
/** @type {number} */
var i = 0;
var len = from.length;
/** @type {Array} */
var curi = [];
for (;i < len;i++) {
curi.push(this.compute(from[i], lab[i], qualifier));
}
cur.push(curi);
} else {
cur.push(this.compute(from, lab, qualifier));
}
}
elem[setter](prop, cur);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @param {?} epsilon
* @param {?} node
* @param {?} namespaces
* @return {undefined}
*/
node : function(opt_attributes, value, testName, epsilon, node, namespaces) {
epsilon = this[epsilon];
if (value) {
var len = value.length;
/** @type {number} */
var status = 0;
for (;status < len;status++) {
var msg = value[status];
this[epsilon[msg]](opt_attributes, msg, testName, node, namespaces);
}
} else {
for (msg in epsilon) {
this[epsilon[msg]](opt_attributes, msg, testName, node, namespaces);
}
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @param {?} testName
* @param {?} epsilon
* @param {?} getter
* @param {?} setter
* @return {undefined}
*/
edge : function(opt_attributes, value, testName, epsilon, getter, setter) {
var adjs = opt_attributes.adjacencies;
var id;
for (id in adjs) {
this["node"](adjs[id], value, testName, epsilon, getter, setter);
}
},
/**
* @param {?} elem
* @param {?} props
* @param {?} delta
* @return {undefined}
*/
"node-property" : function(elem, props, delta) {
this["node"](elem, props, delta, "map", "getData", "setData");
},
/**
* @param {?} elem
* @param {?} props
* @param {?} delta
* @return {undefined}
*/
"edge-property" : function(elem, props, delta) {
this["edge"](elem, props, delta, "map", "getData", "setData");
},
/**
* @param {?} elem
* @param {?} props
* @param {?} delta
* @return {undefined}
*/
"label-property" : function(elem, props, delta) {
this["node"](elem, props, delta, "label", "getLabelData", "setLabelData");
},
/**
* @param {?} elem
* @param {?} props
* @param {?} delta
* @return {undefined}
*/
"node-style" : function(elem, props, delta) {
this["node"](elem, props, delta, "canvas", "getCanvasStyle", "setCanvasStyle");
},
/**
* @param {?} elem
* @param {?} props
* @param {?} delta
* @return {undefined}
*/
"edge-style" : function(elem, props, delta) {
this["edge"](elem, props, delta, "canvas", "getCanvasStyle", "setCanvasStyle");
}
},
/**
* @param {Object} options
* @return {undefined}
*/
sequence : function(options) {
var that = this;
options = $.merge({
condition : $.lambda(false),
/** @type {function (): undefined} */
step : $.empty,
/** @type {function (): undefined} */
onComplete : $.empty,
duration : 200
}, options || {});
/** @type {number} */
var poll = setInterval(function() {
if (options.condition()) {
options.step();
} else {
clearInterval(poll);
options.onComplete();
}
that.viz.refresh(true);
}, options.duration);
},
/**
* @param {Object} obj
* @return {?}
*/
prepare : function(obj) {
var graph = this.viz.graph;
var accessors = {
"node-property" : {
getter : "getData",
setter : "setData"
},
"edge-property" : {
getter : "getData",
setter : "setData"
},
"node-style" : {
getter : "getCanvasStyle",
setter : "setCanvasStyle"
},
"edge-style" : {
getter : "getCanvasStyle",
setter : "setCanvasStyle"
}
};
var self = {};
if ($.type(obj) == "array") {
/** @type {number} */
var i = 0;
var l = obj.length;
for (;i < l;i++) {
var e = obj[i].split(":");
self[e.shift()] = e;
}
} else {
var p;
for (p in obj) {
if (p == "position") {
/** @type {Array} */
self[obj.position] = [];
} else {
self[p] = $.splat(obj[p]);
}
}
}
graph.eachNode(function(node) {
node.startPos.set(node.pos);
$.each(["node-property", "node-style"], function(name) {
if (name in self) {
var events = self[name];
/** @type {number} */
var i = 0;
var l = events.length;
for (;i < l;i++) {
node[accessors[name].setter](events[i], node[accessors[name].getter](events[i]), "start");
}
}
});
$.each(["edge-property", "edge-style"], function(name) {
if (name in self) {
var events = self[name];
node.eachAdjacency(function(adj) {
/** @type {number} */
var i = 0;
var l = events.length;
for (;i < l;i++) {
adj[accessors[name].setter](events[i], adj[accessors[name].getter](events[i]), "start");
}
});
}
});
});
return self;
},
/**
* @param {?} opt
* @param {?} versor
* @return {undefined}
*/
animate : function(opt, versor) {
opt = $.merge(this.viz.config, opt || {});
var that = this;
var viz = this.viz;
var graph = viz.graph;
var interp = this.Interpolator;
var animation = opt.type === "nodefx" ? this.nodeFxAnimation : this.animation;
var m = this.prepare(opt.modes);
if (opt.hideLabels) {
this.labels.hideLabels(true);
}
animation.setOptions($.extend(opt, {
$animating : false,
/**
* @param {?} adj
* @return {undefined}
*/
compute : function(adj) {
graph.eachNode(function(node) {
var p;
for (p in m) {
interp[p](node, m[p], adj, versor);
}
});
that.plot(opt, this.$animating, adj);
/** @type {boolean} */
this.$animating = true;
},
/**
* @return {undefined}
*/
complete : function() {
if (opt.hideLabels) {
that.labels.hideLabels(false);
}
that.plot(opt);
opt.onComplete();
}
})).start();
},
/**
* @param {Object} opt
* @return {undefined}
*/
nodeFx : function(opt) {
var viz = this.viz;
var graph = viz.graph;
var animation = this.nodeFxAnimation;
var nodes = $.merge(this.viz.config, {
elements : {
id : false,
properties : {}
},
reposition : false
});
opt = $.merge(nodes, opt || {}, {
/** @type {function (): undefined} */
onBeforeCompute : $.empty,
/** @type {function (): undefined} */
onAfterCompute : $.empty
});
animation.stopTimer();
var props = opt.elements.properties;
if (!opt.elements.id) {
graph.eachNode(function(n) {
var prop;
for (prop in props) {
n.setData(prop, props[prop], "end");
}
});
} else {
var attributes = $.splat(opt.elements.id);
$.each(attributes, function(node) {
var n = graph.getNode(node);
if (n) {
var prop;
for (prop in props) {
n.setData(prop, props[prop], "end");
}
}
});
}
/** @type {Array} */
var assigns = [];
var vvar;
for (vvar in props) {
assigns.push(vvar);
}
/** @type {Array} */
var modes = ["node-property:" + assigns.join(":")];
if (opt.reposition) {
modes.push("linear");
viz.compute("end");
}
this.animate($.merge(opt, {
modes : modes,
type : "nodefx"
}));
},
/**
* @param {?} opt
* @param {boolean} animating
* @return {undefined}
*/
plot : function(opt, animating) {
var viz = this.viz;
var graph = viz.graph;
var canvas = viz.canvas;
var id = viz.root;
var that = this;
var F = canvas.getCtx();
/** @type {function (...[*]): number} */
var min = Math.min;
opt = opt || this.viz.controller;
if (opt.clearCanvas) {
canvas.clear();
}
var n = graph.getNode(id);
if (!n) {
return;
}
/** @type {boolean} */
var T = !!n.visited;
graph.eachNode(function(from) {
var nodeAlpha = from.getData("alpha");
from.eachAdjacency(function(adj) {
var nodeTo = adj.nodeTo;
if (!!nodeTo.visited === T && (from.drawn && nodeTo.drawn)) {
if (!animating) {
opt.onBeforePlotLine(adj);
}
that.plotLine(adj, canvas, animating);
if (!animating) {
opt.onAfterPlotLine(adj);
}
}
});
if (from.drawn) {
if (!animating) {
opt.onBeforePlotNode(from);
}
that.plotNode(from, canvas, animating);
if (!animating) {
opt.onAfterPlotNode(from);
}
}
if (!that.labelsHidden && opt.withLabels) {
if (from.drawn && nodeAlpha >= 0.95) {
that.labels.plotLabel(canvas, from, opt);
} else {
that.labels.hideLabel(from, false);
}
}
/** @type {boolean} */
from.visited = !T;
});
},
/**
* @param {?} npos
* @param {?} opt
* @param {boolean} animating
* @return {undefined}
*/
plotTree : function(npos, opt, animating) {
var that = this;
var viz = this.viz;
var canvas = viz.canvas;
var config = this.config;
var D = canvas.getCtx();
var nodeAlpha = npos.getData("alpha");
npos.eachSubnode(function(elem) {
if (opt.plotSubtree(npos, elem) && (elem.exist && elem.drawn)) {
var from = npos.getAdjacency(elem.id);
if (!animating) {
opt.onBeforePlotLine(from);
}
that.plotLine(from, canvas, animating);
if (!animating) {
opt.onAfterPlotLine(from);
}
that.plotTree(elem, opt, animating);
}
});
if (npos.drawn) {
if (!animating) {
opt.onBeforePlotNode(npos);
}
this.plotNode(npos, canvas, animating);
if (!animating) {
opt.onAfterPlotNode(npos);
}
if (!opt.hideLabels && (opt.withLabels && nodeAlpha >= 0.95)) {
this.labels.plotLabel(canvas, npos, opt);
} else {
this.labels.hideLabel(npos, false);
}
} else {
this.labels.hideLabel(npos, true);
}
},
/**
* @param {?} node
* @param {?} canvas
* @param {boolean} animating
* @return {undefined}
*/
plotNode : function(node, canvas, animating) {
var f = node.getData("type");
var ctxObj = this.node.CanvasStyles;
if (f != "none") {
var width = node.getData("lineWidth");
var color = node.getData("color");
var alpha = node.getData("alpha");
var ctx = canvas.getCtx();
ctx.save();
ctx.lineWidth = width;
ctx.fillStyle = ctx.strokeStyle = color;
ctx.globalAlpha = alpha;
var s;
for (s in ctxObj) {
ctx[s] = node.getCanvasStyle(s);
}
this.nodeTypes[f].render.call(this, node, canvas, animating);
ctx.restore();
}
},
/**
* @param {?} adj
* @param {?} canvas
* @param {boolean} animating
* @return {undefined}
*/
plotLine : function(adj, canvas, animating) {
var f = adj.getData("type");
var ctxObj = this.edge.CanvasStyles;
if (f != "none") {
var width = adj.getData("lineWidth");
var color = adj.getData("color");
var ctx = canvas.getCtx();
var nodeFrom = adj.nodeFrom;
var nodeTo = adj.nodeTo;
ctx.save();
ctx.lineWidth = width;
ctx.fillStyle = ctx.strokeStyle = color;
/** @type {number} */
ctx.globalAlpha = Math.min(nodeFrom.getData("alpha"), nodeTo.getData("alpha"), adj.getData("alpha"));
var s;
for (s in ctxObj) {
ctx[s] = adj.getCanvasStyle(s);
}
this.edgeTypes[f].render.call(this, adj, canvas, animating);
ctx.restore();
}
}
};
Graph.Plot3D = $.merge(Graph.Plot, {
Interpolator : {
/**
* @param {Object} n
* @param {?} diff
* @param {?} qualifier
* @return {undefined}
*/
linear : function(n, diff, qualifier) {
var from = n.startPos.getc(true);
var to = n.endPos.getc(true);
n.pos.setc(this.compute(from.x, to.x, qualifier), this.compute(from.y, to.y, qualifier), this.compute(from.z, to.z, qualifier));
}
},
/**
* @param {Object} node
* @param {Object} canvas
* @return {undefined}
*/
plotNode : function(node, canvas) {
if (node.getData("type") == "none") {
return;
}
this.plotElement(node, canvas, {
/**
* @return {?}
*/
getAlpha : function() {
return node.getData("alpha");
}
});
},
/**
* @param {Object} adj
* @param {Object} canvas
* @return {undefined}
*/
plotLine : function(adj, canvas) {
if (adj.getData("type") == "none") {
return;
}
this.plotElement(adj, canvas, {
/**
* @return {?}
*/
getAlpha : function() {
return Math.min(adj.nodeFrom.getData("alpha"), adj.nodeTo.getData("alpha"), adj.getData("alpha"));
}
});
},
/**
* @param {Object} elem
* @param {Object} canvas
* @param {?} opt_attributes
* @return {undefined}
*/
plotElement : function(elem, canvas, opt_attributes) {
var gl = canvas.getCtx();
var viewMatrix = new Matrix4;
var lighting = canvas.config.Scene.Lighting;
var wcanvas = canvas.canvases[0];
var program = wcanvas.program;
var camera = wcanvas.camera;
if (!elem.geometry) {
elem.geometry = new (O3D[elem.getData("type")]);
}
elem.geometry.update(elem);
if (!elem.webGLVertexBuffer) {
/** @type {Array} */
var normals = [];
/** @type {Array} */
var faces = [];
/** @type {Array} */
var positions = [];
/** @type {number} */
var vertexIndex = 0;
var geom = elem.geometry;
/** @type {number} */
var i = 0;
var vs = geom.vertices;
var fs = geom.faces;
var len = fs.length;
for (;i < len;i++) {
var face = fs[i];
var normal = vs[face.a];
var n = vs[face.b];
var v1 = vs[face.c];
var p0 = face.d ? vs[face.d] : false;
var position = face.normal;
normals.push(normal.x, normal.y, normal.z);
normals.push(n.x, n.y, n.z);
normals.push(v1.x, v1.y, v1.z);
if (p0) {
normals.push(p0.x, p0.y, p0.z);
}
positions.push(position.x, position.y, position.z);
positions.push(position.x, position.y, position.z);
positions.push(position.x, position.y, position.z);
if (p0) {
positions.push(position.x, position.y, position.z);
}
faces.push(vertexIndex, vertexIndex + 1, vertexIndex + 2);
if (p0) {
faces.push(vertexIndex, vertexIndex + 2, vertexIndex + 3);
vertexIndex += 4;
} else {
vertexIndex += 3;
}
}
elem.webGLVertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, elem.webGLVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normals), gl.STATIC_DRAW);
elem.webGLFaceBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elem.webGLFaceBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(faces), gl.STATIC_DRAW);
/** @type {number} */
elem.webGLFaceCount = faces.length;
elem.webGLNormalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, elem.webGLNormalBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
}
viewMatrix.multiply(camera.matrix, elem.geometry.matrix);
gl.uniformMatrix4fv(program.viewMatrix, false, viewMatrix.flatten());
gl.uniformMatrix4fv(program.projectionMatrix, false, camera.projectionMatrix.flatten());
var normalMatrix = Matrix4.makeInvert(viewMatrix);
normalMatrix.$transpose();
gl.uniformMatrix4fv(program.normalMatrix, false, normalMatrix.flatten());
var color = $.hexToRgb(elem.getData("color"));
color.push(opt_attributes.getAlpha());
gl.uniform4f(program.color, color[0] / 255, color[1] / 255, color[2] / 255, color[3]);
gl.uniform1i(program.enableLighting, lighting.enable);
if (lighting.enable) {
if (lighting.ambient) {
var acolor = lighting.ambient;
gl.uniform3f(program.ambientColor, acolor[0], acolor[1], acolor[2]);
}
if (lighting.directional) {
var dir = lighting.directional;
color = dir.color;
var pos = dir.direction;
var vd = (new Vector3(pos.x, pos.y, pos.z)).normalize().$scale(-1);
gl.uniform3f(program.lightingDirection, vd.x, vd.y, vd.z);
gl.uniform3f(program.directionalColor, color[0], color[1], color[2]);
}
}
gl.bindBuffer(gl.ARRAY_BUFFER, elem.webGLVertexBuffer);
gl.vertexAttribPointer(program.position, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, elem.webGLNormalBuffer);
gl.vertexAttribPointer(program.normal, 3, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elem.webGLFaceBuffer);
gl.drawElements(gl.TRIANGLES, elem.webGLFaceCount, gl.UNSIGNED_SHORT, 0);
}
});
Graph.Label = {};
Graph.Label.Native = new Class({
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} canvas
* @param {Object} node
* @param {?} opt
* @return {undefined}
*/
plotLabel : function(canvas, node, opt) {
var ctx = canvas.getCtx();
var A = node.pos.getc(true);
ctx.font = node.getLabelData("style") + " " + node.getLabelData("size") + "px " + node.getLabelData("family");
ctx.textAlign = node.getLabelData("textAlign");
ctx.fillStyle = ctx.strokeStyle = node.getLabelData("color");
ctx.textBaseline = node.getLabelData("textBaseline");
this.renderLabel(canvas, node, opt);
},
/**
* @param {?} canvas
* @param {Object} node
* @param {?} opt
* @return {undefined}
*/
renderLabel : function(canvas, node, opt) {
var ctx = canvas.getCtx();
var pt = node.pos.getc(true);
ctx.fillText(node.name, pt.x, pt.y + node.getData("height") / 2);
},
/** @type {function (): undefined} */
hideLabel : $.empty,
/** @type {function (): undefined} */
hideLabels : $.empty
});
Graph.Label.DOM = new Class({
labelsHidden : false,
labelContainer : false,
labels : {},
/**
* @return {?}
*/
getLabelContainer : function() {
return this.labelContainer ? this.labelContainer : this.labelContainer = document.getElementById(this.viz.config.labelContainer);
},
/**
* @param {?} id
* @return {?}
*/
getLabel : function(id) {
return id in this.labels && this.labels[id] != null ? this.labels[id] : this.labels[id] = document.getElementById(id);
},
/**
* @param {?} adj
* @return {undefined}
*/
hideLabels : function(adj) {
var container = this.getLabelContainer();
if (adj) {
/** @type {string} */
container.style.display = "none";
} else {
/** @type {string} */
container.style.display = "";
}
this.labelsHidden = adj;
},
/**
* @param {boolean} dataAndEvents
* @return {undefined}
*/
clearLabels : function(dataAndEvents) {
var id;
for (id in this.labels) {
if (dataAndEvents || !this.viz.graph.hasNode(id)) {
this.disposeLabel(id);
delete this.labels[id];
}
}
},
/**
* @param {string} id
* @return {undefined}
*/
disposeLabel : function(id) {
var elem = this.getLabel(id);
if (elem && elem.parentNode) {
elem.parentNode.removeChild(elem);
}
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
hideLabel : function(adj, lab) {
adj = $.splat(adj);
/** @type {string} */
var disp = lab ? "" : "none";
var y;
var that = this;
$.each(adj, function(n) {
var testElement = that.getLabel(n.id);
if (testElement) {
/** @type {string} */
testElement.style.display = disp;
}
});
},
/**
* @param {Object} pos
* @param {?} canvas
* @return {?}
*/
fitsInCanvas : function(pos, canvas) {
var size = canvas.getSize();
if (pos.x >= size.width || (pos.x < 0 || (pos.y >= size.height || pos.y < 0))) {
return false;
}
return true;
}
});
Graph.Label.HTML = new Class({
Implements : Graph.Label.DOM,
/**
* @param {?} canvas
* @param {?} lab
* @param {?} pending
* @return {undefined}
*/
plotLabel : function(canvas, lab, pending) {
var id = lab.id;
var from = this.getLabel(id);
if (!from && !(from = document.getElementById(id))) {
/** @type {Element} */
from = document.createElement("div");
var container = this.getLabelContainer();
from.id = id;
/** @type {string} */
from.className = "node";
/** @type {string} */
from.style.position = "absolute";
pending.onCreateLabel(from, lab);
container.appendChild(from);
/** @type {Element} */
this.labels[lab.id] = from;
}
this.placeLabel(from, lab, pending);
}
});
Graph.Label.SVG = new Class({
Implements : Graph.Label.DOM,
/**
* @param {?} canvas
* @param {?} lab
* @param {?} pending
* @return {undefined}
*/
plotLabel : function(canvas, lab, pending) {
var id = lab.id;
var from = this.getLabel(id);
if (!from && !(from = document.getElementById(id))) {
/** @type {string} */
var ns = "http://www.w3.org/2000/svg";
/** @type {Element} */
from = document.createElementNS(ns, "svg:text");
/** @type {Element} */
var p = document.createElementNS(ns, "svg:tspan");
from.appendChild(p);
var container = this.getLabelContainer();
from.setAttribute("id", id);
from.setAttribute("class", "node");
container.appendChild(from);
pending.onCreateLabel(from, lab);
/** @type {Element} */
this.labels[lab.id] = from;
}
this.placeLabel(from, lab, pending);
}
});
Graph.Geom = new Class({
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
this.config = viz.config;
this.node = viz.config.Node;
this.edge = viz.config.Edge;
},
/**
* @param {number} x
* @param {?} attributes
* @return {undefined}
*/
translate : function(x, attributes) {
attributes = $.splat(attributes);
this.viz.graph.eachNode(function(obj) {
$.each(attributes, function(prop) {
obj.getPos(prop).$add(x);
});
});
},
/**
* @param {?} node
* @param {?} canvas
* @param {Object} callback
* @return {undefined}
*/
setRightLevelToShow : function(node, canvas, callback) {
var level = this.getRightLevelToShow(node, canvas);
var fx = this.viz.labels;
var opt = $.merge({
execShow : true,
execHide : true,
/** @type {function (): undefined} */
onHide : $.empty,
/** @type {function (): undefined} */
onShow : $.empty
}, callback || {});
node.eachLevel(0, this.config.levelsToShow, function(from) {
/** @type {number} */
var flowLevel = from._depth - node._depth;
if (flowLevel > level) {
opt.onHide(from);
if (opt.execHide) {
/** @type {boolean} */
from.drawn = false;
/** @type {boolean} */
from.exist = false;
fx.hideLabel(from, false);
}
} else {
opt.onShow(from);
if (opt.execShow) {
/** @type {boolean} */
from.exist = true;
}
}
});
/** @type {boolean} */
node.drawn = true;
},
/**
* @param {Object} node
* @param {?} canvas
* @return {?}
*/
getRightLevelToShow : function(node, canvas) {
var config = this.config;
var level = config.levelsToShow;
var constrained = config.constrained;
if (!constrained) {
return level;
}
for (;!this.treeFitsInCanvas(node, canvas, level) && level > 1;) {
level--;
}
return level;
}
});
var valid = {
/**
* @param {?} json
* @return {?}
*/
construct : function(json) {
/** @type {boolean} */
var isArray = $.type(json) == "array";
var ans = new Graph(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);
if (!isArray) {
(function(ans, json) {
ans.addNode(json);
if (json.children) {
/** @type {number} */
var i = 0;
var ch = json.children;
for (;i < ch.length;i++) {
ans.addAdjacence(json, ch[i]);
arguments.callee(ans, ch[i]);
}
}
})(ans, json);
} else {
(function(ans, json) {
/**
* @param {string} key
* @return {?}
*/
var getNode = function(key) {
/** @type {number} */
var i = 0;
var len = json.length;
for (;i < len;i++) {
if (json[i].id == key) {
return json[i];
}
}
var newNode = {
id : key,
name : key
};
return ans.addNode(newNode);
};
/** @type {number} */
var i = 0;
var len = json.length;
for (;i < len;i++) {
ans.addNode(json[i]);
var a = json[i].adjacencies;
if (a) {
/** @type {number} */
var j = 0;
var al = a.length;
for (;j < al;j++) {
var node = a[j];
var pdataCur = {};
if (typeof a[j] != "string") {
pdataCur = $.merge(node.data, {});
node = node.nodeTo;
}
ans.addAdjacence(json[i], getNode(node), pdataCur);
}
}
}
})(ans, json);
}
return ans;
},
/**
* @param {Object} json
* @param {number} i
* @return {undefined}
*/
loadJSON : function(json, i) {
/** @type {Object} */
this.json = json;
if (this.labels && this.labels.clearLabels) {
this.labels.clearLabels(true);
}
this.graph = this.construct(json);
if ($.type(json) != "array") {
this.root = json.id;
} else {
this.root = json[i ? i : 0].id;
}
},
/**
* @param {string} type
* @return {?}
*/
toJSON : function(type) {
type = type || "tree";
if (type == "tree") {
var ans = {};
var rootNode = this.graph.getNode(this.root);
ans = function recTree(node) {
var ans = {};
ans.id = node.id;
ans.name = node.name;
ans.data = node.data;
/** @type {Array} */
var ch = [];
node.eachSubnode(function(n) {
ch.push(recTree(n));
});
/** @type {Array} */
ans.children = ch;
return ans;
}(rootNode);
return ans;
} else {
/** @type {Array} */
ans = [];
/** @type {boolean} */
var T = !!this.graph.getNode(this.root).visited;
this.graph.eachNode(function(node) {
var ansNode = {};
ansNode.id = node.id;
ansNode.name = node.name;
ansNode.data = node.data;
/** @type {Array} */
var adjs = [];
node.eachAdjacency(function(adj) {
var nodeTo = adj.nodeTo;
if (!!nodeTo.visited === T) {
var ansAdj = {};
ansAdj.nodeTo = nodeTo.id;
ansAdj.data = adj.data;
adjs.push(ansAdj);
}
});
/** @type {Array} */
ansNode.adjacencies = adjs;
ans.push(ansNode);
/** @type {boolean} */
node.visited = !T;
});
return ans;
}
}
};
var Layout = $jit.Layouts = {};
var column = {
label : null,
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
compute : function(adj, lab, event) {
this.initializeLabel(event);
var label = this.label;
var style = label.style;
adj.eachNode(function(n) {
var autoWidth = n.getData("autoWidth");
var autoHeight = n.getData("autoHeight");
if (autoWidth || autoHeight) {
delete n.data.$width;
delete n.data.$height;
delete n.data.$dim;
var width = n.getData("width");
var height = n.getData("height");
/** @type {string} */
style.width = autoWidth ? "auto" : width + "px";
/** @type {string} */
style.height = autoHeight ? "auto" : height + "px";
label.innerHTML = n.name;
var offsetWidth = label.offsetWidth;
var offsetHeight = label.offsetHeight;
var nodes = n.getData("type");
if ($.indexOf(["circle", "square", "triangle", "star"], nodes) === -1) {
n.setData("width", offsetWidth);
n.setData("height", offsetHeight);
} else {
var dim = offsetWidth > offsetHeight ? offsetWidth : offsetHeight;
n.setData("width", dim);
n.setData("height", dim);
n.setData("dim", dim);
}
}
});
},
/**
* @param {?} opt
* @return {undefined}
*/
initializeLabel : function(opt) {
if (!this.label) {
/** @type {Element} */
this.label = document.createElement("div");
document.body.appendChild(this.label);
}
this.setLabelStyles(opt);
},
/**
* @param {?} opt
* @return {undefined}
*/
setLabelStyles : function(opt) {
$.extend(this.label.style, {
visibility : "hidden",
position : "absolute",
width : "auto",
height : "auto"
});
/** @type {string} */
this.label.className = "jit-autoadjust-label";
}
};
Layout.Tree = function() {
/**
* @param {?} graph
* @param {Node} config
* @param {?} level
* @param {string} orn
* @param {Object} prop
* @return {?}
*/
function getBoundaries(graph, config, level, orn, prop) {
var dim = config.Node;
var multitree = config.multitree;
if (dim.overridable) {
/** @type {number} */
var w = -1;
/** @type {number} */
var h = -1;
graph.eachNode(function(n) {
if (n._depth == level && (!multitree || "$orn" in n.data && n.data.$orn == orn)) {
var dw = n.getData("width", prop);
var dh = n.getData("height", prop);
w = w < dw ? dw : w;
h = h < dh ? dh : h;
}
});
return{
width : w < 0 ? dim.width : w,
height : h < 0 ? dim.height : h
};
} else {
return dim;
}
}
/**
* @param {?} node
* @param {Object} prop
* @param {?} val
* @param {string} orn
* @return {undefined}
*/
function movetree(node, prop, val, orn) {
/** @type {string} */
var p = orn == "left" || orn == "right" ? "y" : "x";
node.getPos(prop)[p] += val;
}
/**
* @param {?} attributes
* @param {?} ans
* @return {?}
*/
function moveextent(attributes, ans) {
/** @type {Array} */
var a = [];
$.each(attributes, function(next_scope) {
/** @type {Array.<?>} */
next_scope = next_callback.call(next_scope);
next_scope[0] += ans;
next_scope[1] += ans;
a.push(next_scope);
});
return a;
}
/**
* @param {Array} ps
* @param {Array} qs
* @return {?}
*/
function merge(ps, qs) {
if (ps.length == 0) {
return qs;
}
if (qs.length == 0) {
return ps;
}
var J = ps.shift();
var I = qs.shift();
return[[J[0], I[1]]].concat(merge(ps, qs));
}
/**
* @param {Array} ls
* @param {Array} def
* @return {?}
*/
function mergelist(ls, def) {
def = def || [];
if (ls.length == 0) {
return def;
}
var ps = ls.pop();
return mergelist(ls, merge(ps, def));
}
/**
* @param {Array} ext1
* @param {Array} ext2
* @param {?} subtreeOffset
* @param {number} siblingOffset
* @param {number} i
* @return {?}
*/
function fit(ext1, ext2, subtreeOffset, siblingOffset, i) {
if (ext1.length <= i || ext2.length <= i) {
return 0;
}
var p = ext1[i][1];
var q = ext2[i][0];
return Math.max(fit(ext1, ext2, subtreeOffset, siblingOffset, ++i) + subtreeOffset, p - q + siblingOffset);
}
/**
* @param {?} es
* @param {?} subtreeOffset
* @param {number} siblingOffset
* @return {?}
*/
function fitlistl(es, subtreeOffset, siblingOffset) {
/**
* @param {Array} acc
* @param {Array} es
* @param {number} i
* @return {?}
*/
function $fitlistl(acc, es, i) {
if (es.length <= i) {
return[];
}
var e = es[i];
var ans = fit(acc, e, subtreeOffset, siblingOffset, 0);
return[ans].concat($fitlistl(merge(acc, moveextent(e, ans)), es, ++i));
}
return $fitlistl([], es, 0);
}
/**
* @param {Array} es
* @param {?} subtreeOffset
* @param {number} siblingOffset
* @return {?}
*/
function fitlistr(es, subtreeOffset, siblingOffset) {
/**
* @param {?} acc
* @param {Array} es
* @param {number} i
* @return {?}
*/
function $fitlistr(acc, es, i) {
if (es.length <= i) {
return[];
}
var e = es[i];
/** @type {number} */
var ans = -fit(e, acc, subtreeOffset, siblingOffset, 0);
return[ans].concat($fitlistr(merge(moveextent(e, ans), acc), es, ++i));
}
/** @type {Array.<?>} */
es = next_callback.call(es);
var ans = $fitlistr([], es.reverse(), 0);
return ans.reverse();
}
/**
* @param {?} es
* @param {?} subtreeOffset
* @param {number} siblingOffset
* @param {string} align
* @return {?}
*/
function fitlist(es, subtreeOffset, siblingOffset, align) {
var esl = fitlistl(es, subtreeOffset, siblingOffset);
var esr = fitlistr(es, subtreeOffset, siblingOffset);
if (align == "left") {
esr = esl;
} else {
if (align == "right") {
esl = esr;
}
}
/** @type {number} */
var i = 0;
/** @type {Array} */
var prevSources = [];
for (;i < esl.length;i++) {
/** @type {number} */
prevSources[i] = (esl[i] + esr[i]) / 2;
}
return prevSources;
}
/**
* @param {?} graph
* @param {?} node
* @param {Object} prop
* @param {Element} config
* @param {string} orn
* @return {undefined}
*/
function design(graph, node, prop, config, orn) {
/**
* @param {Object} node
* @param {boolean} maxsize
* @param {number} acum
* @return {?}
*/
function $design(node, maxsize, acum) {
var r = node.getData(s, prop);
var notsval = maxsize || node.getData(nots, prop);
/** @type {Array} */
var trees = [];
/** @type {Array} */
var extents = [];
/** @type {boolean} */
var chmaxsize = false;
var chacum = notsval + config.levelDistance;
node.eachSubnode(function(n) {
if (n.exist && (!multitree || "$orn" in n.data && n.data.$orn == orn)) {
if (!chmaxsize) {
chmaxsize = getBoundaries(graph, config, n._depth, orn, prop);
}
var s = $design(n, chmaxsize[nots], acum + chacum);
trees.push(s.tree);
extents.push(s.extent);
}
});
var positions = fitlist(extents, subtreeOffset, siblingOffset, align);
/** @type {number} */
var i = 0;
/** @type {Array} */
var ac = [];
/** @type {Array} */
var pextents = [];
for (;i < trees.length;i++) {
movetree(trees[i], prop, positions[i], orn);
pextents.push(moveextent(extents[i], positions[i]));
}
/** @type {Array} */
var extent = [[-r / 2, r / 2]].concat(mergelist(pextents));
/** @type {number} */
node.getPos(prop)[p] = 0;
if (orn == "top" || orn == "left") {
/** @type {number} */
node.getPos(prop)[notp] = acum;
} else {
/** @type {number} */
node.getPos(prop)[notp] = -acum;
}
return{
tree : node,
extent : extent
};
}
var multitree = config.multitree;
/** @type {Array} */
var auxp = ["x", "y"];
/** @type {Array} */
var auxs = ["width", "height"];
/** @type {number} */
var ind = +(orn == "left" || orn == "right");
var p = auxp[ind];
var notp = auxp[1 - ind];
var cnode = config.Node;
var s = auxs[ind];
var nots = auxs[1 - ind];
var siblingOffset = config.siblingOffset;
var subtreeOffset = config.subtreeOffset;
var align = config.align;
$design(node, false, 0);
}
/** @type {function (this:(Array.<T>|string|{length: number}), *=, *=): Array.<T>} */
var next_callback = Array.prototype.slice;
return new Class({
/**
* @param {number} adj
* @param {?} type
* @return {undefined}
*/
compute : function(adj, type) {
var lab = adj || "start";
var node = this.graph.getNode(this.root);
$.extend(node, {
drawn : true,
exist : true,
selected : true
});
column.compute(this.graph, lab, this.config);
if (!!type || !("_depth" in node)) {
this.graph.computeLevels(this.root, 0, "ignore");
}
this.computePositions(node, lab);
},
/**
* @param {?} node
* @param {Object} prop
* @return {undefined}
*/
computePositions : function(node, prop) {
var config = this.config;
var multitree = config.multitree;
var align = config.align;
var indent = align !== "center" && config.indent;
var orn = config.orientation;
/** @type {Array} */
var attributes = multitree ? ["top", "right", "bottom", "left"] : [orn];
var that = this;
$.each(attributes, function(orn) {
design(that.graph, node, prop, that.config, orn, prop);
var i = ["x", "y"][+(orn == "left" || orn == "right")];
(function red(node) {
node.eachSubnode(function(n) {
if (n.exist && (!multitree || "$orn" in n.data && n.data.$orn == orn)) {
n.getPos(prop)[i] += node.getPos(prop)[i];
if (indent) {
n.getPos(prop)[i] += align == "left" ? indent : -indent;
}
red(n);
}
});
})(node);
});
}
});
}();
$jit.ST = function() {
/**
* @param {Object} node
* @return {?}
*/
function getNodesToHide(node) {
node = node || this.clickedNode;
if (!this.config.constrained) {
return[];
}
var Geom = this.geom;
var graph = this.graph;
var canvas = this.canvas;
var level = node._depth;
/** @type {Array} */
var matched = [];
graph.eachNode(function(n) {
if (n.exist && !n.selected) {
if (n.isDescendantOf(node.id)) {
if (n._depth <= level) {
matched.push(n);
}
} else {
matched.push(n);
}
}
});
var leafLevel = Geom.getRightLevelToShow(node, canvas);
node.eachLevel(leafLevel, leafLevel, function(n) {
if (n.exist && !n.selected) {
matched.push(n);
}
});
/** @type {number} */
var i = 0;
for (;i < nodesInPath.length;i++) {
var n = this.graph.getNode(nodesInPath[i]);
if (!n.isDescendantOf(node.id)) {
matched.push(n);
}
}
return matched;
}
/**
* @param {(number|string)} node
* @return {?}
*/
function getNodesToShow(node) {
/** @type {Array} */
var matched = [];
var config = this.config;
node = node || this.clickedNode;
this.clickedNode.eachLevel(0, config.levelsToShow, function(n) {
if (config.multitree && (!("$orn" in n.data) && n.anySubnode(function(n) {
return n.exist && !n.drawn;
}))) {
matched.push(n);
} else {
if (n.drawn && !n.anySubnode("drawn")) {
matched.push(n);
}
}
});
return matched;
}
/** @type {Array} */
var nodesInPath = [];
return new Class({
Implements : [valid, Extras, Layout.Tree],
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
var $ST = $jit.ST;
var config = {
levelsToShow : 2,
levelDistance : 30,
constrained : true,
Node : {
type : "rectangle"
},
duration : 700,
offsetX : 0,
offsetY : 0
};
this.controller = this.config = $.merge(Options("Canvas", "Fx", "Tree", "Node", "Edge", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller);
var canvasConfig = this.config;
if (canvasConfig.useCanvas) {
this.canvas = canvasConfig.useCanvas;
/** @type {string} */
this.config.labelContainer = this.canvas.id + "-label";
} else {
if (canvasConfig.background) {
canvasConfig.background = $.merge({
type : "Circles"
}, canvasConfig.background);
}
this.canvas = new Canvas(this, canvasConfig);
/** @type {string} */
this.config.labelContainer = (typeof canvasConfig.injectInto == "string" ? canvasConfig.injectInto : canvasConfig.injectInto.id) + "-label";
}
this.graphOptions = {
/** @type {function (number, (number|string)): undefined} */
klass : Vector
};
this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge);
this.labels = new $ST.Label[canvasConfig.Label.type](this);
this.fx = new $ST.Plot(this, $ST);
this.op = new $ST.Op(this);
this.group = new $ST.Group(this);
this.geom = new $ST.Geom(this);
/** @type {null} */
this.clickedNode = null;
this.initializeExtras();
},
/**
* @return {undefined}
*/
plot : function() {
this.fx.plot(this.controller);
},
/**
* @param {number} pos
* @param {string} method
* @param {?} lab
* @return {undefined}
*/
switchPosition : function(pos, method, lab) {
var Geom = this.geom;
var Plot = this.fx;
var that = this;
if (!Plot.busy) {
/** @type {boolean} */
Plot.busy = true;
this.contract({
/**
* @return {undefined}
*/
onComplete : function() {
Geom.switchOrientation(pos);
that.compute("end", false);
/** @type {boolean} */
Plot.busy = false;
if (method == "animate") {
that.onClick(that.clickedNode.id, lab);
} else {
if (method == "replot") {
that.select(that.clickedNode.id, lab);
}
}
}
}, pos);
}
},
/**
* @param {number} align
* @param {string} method
* @param {?} lab
* @return {undefined}
*/
switchAlignment : function(align, method, lab) {
/** @type {number} */
this.config.align = align;
if (method == "animate") {
this.select(this.clickedNode.id, lab);
} else {
if (method == "replot") {
this.onClick(this.clickedNode.id, lab);
}
}
},
/**
* @param {?} id
* @return {undefined}
*/
addNodeInPath : function(id) {
nodesInPath.push(id);
this.select(this.clickedNode && this.clickedNode.id || this.root);
},
/**
* @param {?} dataAndEvents
* @return {undefined}
*/
clearNodesInPath : function(dataAndEvents) {
/** @type {number} */
nodesInPath.length = 0;
this.select(this.clickedNode && this.clickedNode.id || this.root);
},
/**
* @return {undefined}
*/
refresh : function() {
this.reposition();
this.select(this.clickedNode && this.clickedNode.id || this.root);
},
/**
* @return {undefined}
*/
reposition : function() {
this.graph.computeLevels(this.root, 0, "ignore");
this.geom.setRightLevelToShow(this.clickedNode, this.canvas);
this.graph.eachNode(function(n) {
if (n.exist) {
/** @type {boolean} */
n.drawn = true;
}
});
this.compute("end");
},
/**
* @param {Array} node
* @param {?} onComplete
* @return {undefined}
*/
requestNodes : function(node, onComplete) {
var handler = $.merge(this.controller, onComplete);
var lev = this.config.levelsToShow;
if (handler.request) {
/** @type {Array} */
var leaves = [];
var d = node._depth;
node.eachLevel(0, lev, function(n) {
if (n.drawn && !n.anySubnode()) {
leaves.push(n);
/** @type {number} */
n._level = lev - (n._depth - d);
}
});
this.group.requestNodes(leaves, handler);
} else {
handler.onComplete();
}
},
/**
* @param {?} onComplete
* @param {number} switched
* @return {undefined}
*/
contract : function(onComplete, switched) {
var orn = this.config.orientation;
var Geom = this.geom;
var Group = this.group;
if (switched) {
Geom.switchOrientation(switched);
}
var nodes = getNodesToHide.call(this);
if (switched) {
Geom.switchOrientation(orn);
}
Group.contract(nodes, $.merge(this.controller, onComplete));
},
/**
* @param {?} node
* @param {?} onComplete
* @return {undefined}
*/
move : function(node, onComplete) {
this.compute("end", false);
var move = onComplete.Move;
var offset = {
x : move.offsetX,
y : move.offsetY
};
if (move.enable) {
this.geom.translate(node.endPos.add(offset).$scale(-1), "end");
}
this.fx.animate($.merge(this.controller, {
modes : ["linear"]
}, onComplete));
},
/**
* @param {?} node
* @param {?} onComplete
* @return {undefined}
*/
expand : function(node, onComplete) {
var vvar = getNodesToShow.call(this, node);
this.group.expand(vvar, $.merge(this.controller, onComplete));
},
/**
* @param {?} node
* @return {undefined}
*/
selectPath : function(node) {
/**
* @param {Object} node
* @return {undefined}
*/
function path(node) {
if (node == null || node.selected) {
return;
}
/** @type {boolean} */
node.selected = true;
$.each(that.group.getSiblings([node])[node.id], function(n) {
/** @type {boolean} */
n.exist = true;
/** @type {boolean} */
n.drawn = true;
});
var indents = node.getParents();
indents = indents.length > 0 ? indents[0] : null;
path(indents);
}
var that = this;
this.graph.eachNode(function(pane) {
/** @type {boolean} */
pane.selected = false;
});
/** @type {number} */
var i = 0;
/** @type {Array} */
var codeSegments = [node.id].concat(nodesInPath);
for (;i < codeSegments.length;i++) {
path(this.graph.getNode(codeSegments[i]));
}
},
/**
* @param {?} from
* @param {string} method
* @param {Object} onComplete
* @return {undefined}
*/
setRoot : function(from, method, onComplete) {
/**
* @return {undefined}
*/
function $setRoot() {
if (this.config.multitree && clickedNode.data.$orn) {
var orn = clickedNode.data.$orn;
var opp = {
left : "right",
right : "left",
top : "bottom",
bottom : "top"
}[orn];
rootNode.data.$orn = opp;
(function tag(node) {
node.eachSubnode(function(n) {
if (n.id != from) {
n.data.$orn = opp;
tag(n);
}
});
})(rootNode);
delete clickedNode.data.$orn;
}
this.root = from;
this.clickedNode = clickedNode;
this.graph.computeLevels(this.root, 0, "ignore");
this.geom.setRightLevelToShow(clickedNode, canvas, {
execHide : false,
/**
* @param {?} adj
* @return {undefined}
*/
onShow : function(adj) {
if (!adj.drawn) {
/** @type {boolean} */
adj.drawn = true;
adj.setData("alpha", 1, "end");
adj.setData("alpha", 0);
adj.pos.setc(clickedNode.pos.x, clickedNode.pos.y);
}
}
});
this.compute("end");
/** @type {boolean} */
this.busy = true;
this.fx.animate({
modes : ["linear", "node-property:alpha"],
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
that.onClick(from, {
/**
* @return {undefined}
*/
onComplete : function() {
if (onComplete) {
onComplete.onComplete();
}
}
});
}
});
}
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
var that = this;
var canvas = this.canvas;
var rootNode = this.graph.getNode(this.root);
var clickedNode = this.graph.getNode(from);
delete rootNode.data.$orns;
if (method == "animate") {
$setRoot.call(this);
that.selectPath(clickedNode);
} else {
if (method == "replot") {
$setRoot.call(this);
this.select(this.root);
}
}
},
/**
* @param {?} subtree
* @param {string} method
* @param {Object} onComplete
* @return {undefined}
*/
addSubtree : function(subtree, method, onComplete) {
if (method == "replot") {
this.op.sum(subtree, $.extend({
type : "replot"
}, onComplete || {}));
} else {
if (method == "animate") {
this.op.sum(subtree, $.extend({
type : "fade:seq"
}, onComplete || {}));
}
}
},
/**
* @param {?} id
* @param {?} removeRoot
* @param {string} method
* @param {Object} onComplete
* @return {undefined}
*/
removeSubtree : function(id, removeRoot, method, onComplete) {
var n = this.graph.getNode(id);
/** @type {Array} */
var selected = [];
n.eachLevel(+!removeRoot, false, function(row) {
selected.push(row.id);
});
if (method == "replot") {
this.op.removeNode(selected, $.extend({
type : "replot"
}, onComplete || {}));
} else {
if (method == "animate") {
this.op.removeNode(selected, $.extend({
type : "fade:seq"
}, onComplete || {}));
}
}
},
/**
* @param {boolean} id
* @param {boolean} lab
* @return {undefined}
*/
select : function(id, lab) {
var group = this.group;
var geom = this.geom;
var from = this.graph.getNode(id);
var canvas = this.canvas;
var root = this.graph.getNode(this.root);
var complete = $.merge(this.controller, lab);
var that = this;
complete.onBeforeCompute(from);
this.selectPath(from);
this.clickedNode = from;
this.requestNodes(from, {
/**
* @return {undefined}
*/
onComplete : function() {
group.hide(group.prepare(getNodesToHide.call(that)), complete);
geom.setRightLevelToShow(from, canvas);
that.compute("current");
that.graph.eachNode(function(node) {
var pos = node.pos.getc(true);
node.startPos.setc(pos.x, pos.y);
node.endPos.setc(pos.x, pos.y);
/** @type {boolean} */
node.visited = false;
});
var offset = {
x : complete.offsetX,
y : complete.offsetY
};
that.geom.translate(from.endPos.add(offset).$scale(-1), ["start", "current", "end"]);
group.show(getNodesToShow.call(that));
that.plot();
complete.onAfterCompute(that.clickedNode);
complete.onComplete();
}
});
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onClick : function(adj, lab) {
var canvas = this.canvas;
var that = this;
var Geom = this.geom;
var config = this.config;
var innerController = {
Move : {
enable : true,
offsetX : config.offsetX || 0,
offsetY : config.offsetY || 0
},
setRightLevelToShowConfig : false,
/** @type {function (): undefined} */
onBeforeRequest : $.empty,
/** @type {function (): undefined} */
onBeforeContract : $.empty,
/** @type {function (): undefined} */
onBeforeMove : $.empty,
/** @type {function (): undefined} */
onBeforeExpand : $.empty
};
var complete = $.merge(this.controller, innerController, lab);
if (!this.busy) {
/** @type {boolean} */
this.busy = true;
var from = this.graph.getNode(adj);
this.selectPath(from, this.clickedNode);
this.clickedNode = from;
complete.onBeforeCompute(from);
complete.onBeforeRequest(from);
this.requestNodes(from, {
/**
* @return {undefined}
*/
onComplete : function() {
complete.onBeforeContract(from);
that.contract({
/**
* @return {undefined}
*/
onComplete : function() {
Geom.setRightLevelToShow(from, canvas, complete.setRightLevelToShowConfig);
complete.onBeforeMove(from);
that.move(from, {
Move : complete.Move,
/**
* @return {undefined}
*/
onComplete : function() {
complete.onBeforeExpand(from);
that.expand(from, {
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
complete.onAfterCompute(adj);
complete.onComplete();
}
});
}
});
}
});
}
});
}
}
});
}();
/** @type {boolean} */
$jit.ST.$extend = true;
$jit.ST.Op = new Class({
Implements : Graph.Op
});
$jit.ST.Group = new Class({
/**
* @param {Object} viz
* @return {undefined}
*/
initialize : function(viz) {
/** @type {Object} */
this.viz = viz;
this.canvas = viz.canvas;
this.config = viz.config;
this.animation = new Animation;
/** @type {null} */
this.nodes = null;
},
/**
* @param {Array} nodes
* @param {?} controller
* @return {undefined}
*/
requestNodes : function(nodes, controller) {
/** @type {number} */
var counter = 0;
var len = nodes.length;
var nodeSelected = {};
/**
* @return {undefined}
*/
var complete = function() {
controller.onComplete();
};
var viz = this.viz;
if (len == 0) {
complete();
}
/** @type {number} */
var i = 0;
for (;i < len;i++) {
nodeSelected[nodes[i].id] = nodes[i];
controller.request(nodes[i].id, nodes[i]._level, {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onComplete : function(adj, lab) {
if (lab && lab.children) {
lab.id = adj;
viz.op.sum(lab, {
type : "nothing"
});
}
if (++counter == len) {
viz.graph.computeLevels(viz.root, 0);
complete();
}
}
});
}
},
/**
* @param {Object} nodes
* @param {Object} controller
* @return {undefined}
*/
contract : function(nodes, controller) {
var viz = this.viz;
var that = this;
nodes = this.prepare(nodes);
this.animation.setOptions($.merge(controller, {
$animating : false,
/**
* @param {?} adj
* @return {undefined}
*/
compute : function(adj) {
if (adj == 1) {
/** @type {number} */
adj = 0.99;
}
that.plotStep(1 - adj, controller, this.$animating);
/** @type {string} */
this.$animating = "contract";
},
/**
* @return {undefined}
*/
complete : function() {
that.hide(nodes, controller);
}
})).start();
},
/**
* @param {Object} nodes
* @param {Object} controller
* @return {undefined}
*/
hide : function(nodes, controller) {
var viz = this.viz;
/** @type {number} */
var i = 0;
for (;i < nodes.length;i++) {
if (true || (!controller || !controller.request)) {
nodes[i].eachLevel(1, false, function(owner) {
if (owner.exist) {
$.extend(owner, {
drawn : false,
exist : false
});
}
});
} else {
/** @type {Array} */
var selected = [];
nodes[i].eachLevel(1, false, function(row) {
selected.push(row.id);
});
viz.op.removeNode(selected, {
type : "nothing"
});
viz.labels.clearLabels();
}
}
controller.onComplete();
},
/**
* @param {?} name
* @param {Object} controller
* @return {undefined}
*/
expand : function(name, controller) {
var that = this;
this.show(name);
this.animation.setOptions($.merge(controller, {
$animating : false,
/**
* @param {?} adj
* @return {undefined}
*/
compute : function(adj) {
that.plotStep(adj, controller, this.$animating);
/** @type {string} */
this.$animating = "expand";
},
/**
* @return {undefined}
*/
complete : function() {
that.plotStep(undefined, controller, false);
controller.onComplete();
}
})).start();
},
/**
* @param {?} attributes
* @return {undefined}
*/
show : function(attributes) {
var config = this.config;
this.prepare(attributes);
$.each(attributes, function(n) {
if (config.multitree && !("$orn" in n.data)) {
delete n.data.$orns;
/** @type {string} */
var orns = " ";
n.eachSubnode(function(n) {
if ("$orn" in n.data && (orns.indexOf(n.data.$orn) < 0 && (n.exist && !n.drawn))) {
orns += n.data.$orn + " ";
}
});
n.data.$orns = orns;
}
n.eachLevel(0, config.levelsToShow, function(n) {
if (n.exist) {
/** @type {boolean} */
n.drawn = true;
}
});
});
},
/**
* @param {?} nodes
* @return {?}
*/
prepare : function(nodes) {
this.nodes = this.getNodesWithChildren(nodes);
return this.nodes;
},
/**
* @param {Array} nodes
* @return {?}
*/
getNodesWithChildren : function(nodes) {
/** @type {Array} */
var ans = [];
var config = this.config;
var root = this.viz.root;
nodes.sort(function(a, b) {
return(a._depth <= b._depth) - (a._depth >= b._depth);
});
/** @type {number} */
var i = 0;
for (;i < nodes.length;i++) {
if (nodes[i].anySubnode("exist")) {
/** @type {number} */
var j = i + 1;
/** @type {boolean} */
var found = false;
for (;!found && j < nodes.length;j++) {
if (!config.multitree || "$orn" in nodes[j].data) {
found = found || nodes[i].isDescendantOf(nodes[j].id);
}
}
if (!found) {
ans.push(nodes[i]);
}
}
}
return ans;
},
/**
* @param {number} delta
* @param {Object} controller
* @param {boolean} animating
* @return {undefined}
*/
plotStep : function(delta, controller, animating) {
var viz = this.viz;
var config = this.config;
var canvas = viz.canvas;
var cctx = canvas.getCtx();
var nodes = this.nodes;
var i;
var node;
var nds = {};
/** @type {number} */
i = 0;
for (;i < nodes.length;i++) {
node = nodes[i];
/** @type {Array} */
nds[node.id] = [];
var root = config.multitree && !("$orn" in node.data);
var orns = root && node.data.$orns;
node.eachSubgraph(function(n) {
if (root && (orns && (orns.indexOf(n.data.$orn) > 0 && n.drawn))) {
/** @type {boolean} */
n.drawn = false;
nds[node.id].push(n);
} else {
if ((!root || !orns) && n.drawn) {
/** @type {boolean} */
n.drawn = false;
nds[node.id].push(n);
}
}
});
/** @type {boolean} */
node.drawn = true;
}
if (nodes.length > 0) {
viz.fx.plot();
}
for (i in nds) {
$.each(nds[i], function(n) {
/** @type {boolean} */
n.drawn = true;
});
}
/** @type {number} */
i = 0;
for (;i < nodes.length;i++) {
node = nodes[i];
cctx.save();
viz.fx.plotSubtree(node, controller, delta, animating);
cctx.restore();
}
},
/**
* @param {?} attributes
* @return {?}
*/
getSiblings : function(attributes) {
var siblings = {};
$.each(attributes, function(n) {
var par = n.getParents();
if (par.length == 0) {
/** @type {Array} */
siblings[n.id] = [n];
} else {
/** @type {Array} */
var assigns = [];
par[0].eachSubnode(function(vvar) {
assigns.push(vvar);
});
/** @type {Array} */
siblings[n.id] = assigns;
}
});
return siblings;
}
});
$jit.ST.Geom = new Class({
Implements : Graph.Geom,
/**
* @param {number} orn
* @return {undefined}
*/
switchOrientation : function(orn) {
/** @type {number} */
this.config.orientation = orn;
},
/**
* @return {?}
*/
dispatch : function() {
/** @type {Array.<?>} */
var args = Array.prototype.slice.call(arguments);
var s = args.shift();
/** @type {number} */
var args_length = args.length;
/**
* @param {?} a
* @return {?}
*/
var val = function(a) {
return typeof a == "function" ? a() : a;
};
if (args_length == 2) {
return s == "top" || s == "bottom" ? val(args[0]) : val(args[1]);
} else {
if (args_length == 4) {
switch(s) {
case "top":
return val(args[0]);
case "right":
return val(args[1]);
case "bottom":
return val(args[2]);
case "left":
return val(args[3]);
}
}
}
return undefined;
},
/**
* @param {Object} node
* @param {boolean} dataAndEvents
* @return {?}
*/
getSize : function(node, dataAndEvents) {
var data = node.data;
var config = this.config;
var siblingOffset = config.siblingOffset;
var route = config.multitree && ("$orn" in data && data.$orn) || config.orientation;
var h = node.getData("width") + siblingOffset;
var w = node.getData("height") + siblingOffset;
if (!dataAndEvents) {
return this.dispatch(route, w, h);
} else {
return this.dispatch(route, h, w);
}
},
/**
* @param {?} node
* @param {number} level
* @param {Function} leaf
* @return {?}
*/
getTreeBaseSize : function(node, level, leaf) {
var size = this.getSize(node, true);
/** @type {number} */
var baseHeight = 0;
var that = this;
if (leaf(level, node)) {
return size;
}
if (level === 0) {
return 0;
}
node.eachSubnode(function(elem) {
baseHeight += that.getTreeBaseSize(elem, level - 1, leaf);
});
return(size > baseHeight ? size : baseHeight) + this.config.subtreeOffset;
},
/**
* @param {?} node
* @param {string} type
* @param {?} s
* @return {?}
*/
getEdge : function(node, type, s) {
/**
* @param {number} mayParseLabeledStatementInstead
* @param {number} recurring
* @return {?}
*/
var $C = function(mayParseLabeledStatementInstead, recurring) {
return function() {
return node.pos.add(new Vector(mayParseLabeledStatementInstead, recurring));
};
};
var dim = this.node;
var w = node.getData("width");
var h = node.getData("height");
if (type == "begin") {
if (dim.align == "center") {
return this.dispatch(s, $C(0, h / 2), $C(-w / 2, 0), $C(0, -h / 2), $C(w / 2, 0));
} else {
if (dim.align == "left") {
return this.dispatch(s, $C(0, h), $C(0, 0), $C(0, 0), $C(w, 0));
} else {
if (dim.align == "right") {
return this.dispatch(s, $C(0, 0), $C(-w, 0), $C(0, -h), $C(0, 0));
} else {
throw "align: not implemented";
}
}
}
} else {
if (type == "end") {
if (dim.align == "center") {
return this.dispatch(s, $C(0, -h / 2), $C(w / 2, 0), $C(0, h / 2), $C(-w / 2, 0));
} else {
if (dim.align == "left") {
return this.dispatch(s, $C(0, 0), $C(w, 0), $C(0, h), $C(0, 0));
} else {
if (dim.align == "right") {
return this.dispatch(s, $C(0, -h), $C(0, 0), $C(0, 0), $C(-w, 0));
} else {
throw "align: not implemented";
}
}
}
}
}
},
/**
* @param {Object} node
* @param {number} scale
* @return {?}
*/
getScaledTreePosition : function(node, scale) {
var dim = this.node;
var w = node.getData("width");
var h = node.getData("height");
var route = this.config.multitree && ("$orn" in node.data && node.data.$orn) || this.config.orientation;
/**
* @param {number} mayParseLabeledStatementInstead
* @param {number} recurring
* @return {?}
*/
var $C = function(mayParseLabeledStatementInstead, recurring) {
return function() {
return node.pos.add(new Vector(mayParseLabeledStatementInstead, recurring)).$scale(1 - scale);
};
};
if (dim.align == "left") {
return this.dispatch(route, $C(0, h), $C(0, 0), $C(0, 0), $C(w, 0));
} else {
if (dim.align == "center") {
return this.dispatch(route, $C(0, h / 2), $C(-w / 2, 0), $C(0, -h / 2), $C(w / 2, 0));
} else {
if (dim.align == "right") {
return this.dispatch(route, $C(0, 0), $C(-w, 0), $C(0, -h), $C(0, 0));
} else {
throw "align: not implemented";
}
}
}
},
/**
* @param {Object} node
* @param {?} canvas
* @param {number} level
* @return {?}
*/
treeFitsInCanvas : function(node, canvas, level) {
var csize = canvas.getSize();
var s = this.config.multitree && ("$orn" in node.data && node.data.$orn) || this.config.orientation;
var size = this.dispatch(s, csize.width, csize.height);
var baseSize = this.getTreeBaseSize(node, level, function(deepDataAndEvents, dataAndEvents) {
return deepDataAndEvents === 0 || !dataAndEvents.anySubnode();
});
return baseSize < size;
}
});
$jit.ST.Plot = new Class({
Implements : Graph.Plot,
/**
* @param {Object} node
* @param {Object} opt
* @param {number} scale
* @param {boolean} animating
* @return {undefined}
*/
plotSubtree : function(node, opt, scale, animating) {
var viz = this.viz;
var canvas = viz.canvas;
var config = viz.config;
/** @type {number} */
scale = Math.min(Math.max(0.001, scale), 1);
if (scale >= 0) {
/** @type {boolean} */
node.drawn = false;
var ctx = canvas.getCtx();
var diff = viz.geom.getScaledTreePosition(node, scale);
ctx.translate(diff.x, diff.y);
ctx.scale(scale, scale);
}
this.plotTree(node, $.merge(opt, {
withLabels : true,
hideLabels : !!scale,
/**
* @param {?} dataAndEvents
* @param {Object} x
* @return {?}
*/
plotSubtree : function(dataAndEvents, x) {
var root = config.multitree && !("$orn" in node.data);
var orns = root && node.getData("orns");
return!root || orns.indexOf(node.getData("orn")) > -1;
}
}), animating);
if (scale >= 0) {
/** @type {boolean} */
node.drawn = true;
}
},
/**
* @param {?} pos
* @param {number} width
* @param {number} height
* @return {?}
*/
getAlignedPos : function(pos, width, height) {
var dim = this.node;
var square;
var orn;
if (dim.align == "center") {
square = {
x : pos.x - width / 2,
y : pos.y - height / 2
};
} else {
if (dim.align == "left") {
orn = this.config.orientation;
if (orn == "bottom" || orn == "top") {
square = {
x : pos.x - width / 2,
y : pos.y
};
} else {
square = {
x : pos.x,
y : pos.y - height / 2
};
}
} else {
if (dim.align == "right") {
orn = this.config.orientation;
if (orn == "bottom" || orn == "top") {
square = {
x : pos.x - width / 2,
y : pos.y - height
};
} else {
square = {
x : pos.x - width,
y : pos.y - height / 2
};
}
} else {
throw "align: not implemented";
}
}
}
return square;
},
/**
* @param {?} adj
* @return {?}
*/
getOrientation : function(adj) {
var config = this.config;
var orn = config.orientation;
if (config.multitree) {
var nodeFrom = adj.nodeFrom;
var nodeTo = adj.nodeTo;
orn = "$orn" in nodeFrom.data && nodeFrom.data.$orn || "$orn" in nodeTo.data && nodeTo.data.$orn;
}
return orn;
}
});
$jit.ST.Label = {};
$jit.ST.Label.Native = new Class({
Implements : Graph.Label.Native,
/**
* @param {?} canvas
* @param {Object} node
* @param {?} opt
* @return {undefined}
*/
renderLabel : function(canvas, node, opt) {
var ctx = canvas.getCtx();
var coord = node.pos.getc(true);
var width = node.getData("width");
var height = node.getData("height");
var pos = this.viz.fx.getAlignedPos(coord, width, height);
ctx.fillText(node.name, pos.x + width / 2, pos.y + height / 2);
}
});
$jit.ST.Label.DOM = new Class({
Implements : Graph.Label.DOM,
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.getc(true);
var config = this.viz.config;
var dim = config.Node;
var canvas = this.viz.canvas;
var w = lab.getData("width");
var h = lab.getData("height");
var $cont = canvas.getSize();
var labelPos;
var orn;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var posx = pos.x * sx + ox;
var posy = pos.y * sy + oy;
if (dim.align == "center") {
labelPos = {
x : Math.round(posx - w / 2 + $cont.width / 2),
y : Math.round(posy - h / 2 + $cont.height / 2)
};
} else {
if (dim.align == "left") {
orn = config.orientation;
if (orn == "bottom" || orn == "top") {
labelPos = {
x : Math.round(posx - w / 2 + $cont.width / 2),
y : Math.round(posy + $cont.height / 2)
};
} else {
labelPos = {
x : Math.round(posx + $cont.width / 2),
y : Math.round(posy - h / 2 + $cont.height / 2)
};
}
} else {
if (dim.align == "right") {
orn = config.orientation;
if (orn == "bottom" || orn == "top") {
labelPos = {
x : Math.round(posx - w / 2 + $cont.width / 2),
y : Math.round(posy - h + $cont.height / 2)
};
} else {
labelPos = {
x : Math.round(posx - w + $cont.width / 2),
y : Math.round(posy - h / 2 + $cont.height / 2)
};
}
} else {
throw "align: not implemented";
}
}
}
var style = from.style;
/** @type {string} */
style.left = labelPos.x + "px";
/** @type {string} */
style.top = labelPos.y + "px";
/** @type {string} */
style.display = this.fitsInCanvas(labelPos, canvas) ? "" : "none";
options.onPlaceLabel(from, lab);
}
});
$jit.ST.Label.SVG = new Class({
Implements : [$jit.ST.Label.DOM, Graph.Label.SVG],
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
}
});
$jit.ST.Label.HTML = new Class({
Implements : [$jit.ST.Label.DOM, Graph.Label.HTML],
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
}
});
$jit.ST.Plot.NodeTypes = new Class({
none : {
/** @type {function (): undefined} */
render : $.empty,
contains : $.lambda(false)
},
circle : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var dim = adj.getData("dim");
var pos = this.getAlignedPos(adj.pos.getc(true), dim, dim);
/** @type {number} */
var qualifier = dim / 2;
this.nodeHelper.circle.render("fill", {
x : pos.x + qualifier,
y : pos.y + qualifier
}, qualifier, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {undefined}
*/
contains : function(opt_attributes, value) {
var dim = opt_attributes.getData("dim");
var pos = this.getAlignedPos(opt_attributes.pos.getc(true), dim, dim);
/** @type {number} */
var actual = dim / 2;
this.nodeHelper.circle.contains({
x : pos.x + actual,
y : pos.y + actual
}, value, actual);
}
},
square : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var dim = adj.getData("dim");
/** @type {number} */
var qualifier = dim / 2;
var pos = this.getAlignedPos(adj.pos.getc(true), dim, dim);
this.nodeHelper.square.render("fill", {
x : pos.x + qualifier,
y : pos.y + qualifier
}, qualifier, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {undefined}
*/
contains : function(opt_attributes, value) {
var dim = opt_attributes.getData("dim");
var pos = this.getAlignedPos(opt_attributes.pos.getc(true), dim, dim);
/** @type {number} */
var actual = dim / 2;
this.nodeHelper.square.contains({
x : pos.x + actual,
y : pos.y + actual
}, value, actual);
}
},
ellipse : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var qualifier = adj.getData("width");
var cycle = adj.getData("height");
var pos = this.getAlignedPos(adj.pos.getc(true), qualifier, cycle);
this.nodeHelper.ellipse.render("fill", {
x : pos.x + qualifier / 2,
y : pos.y + cycle / 2
}, qualifier, cycle, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {undefined}
*/
contains : function(opt_attributes, value) {
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
var pos = this.getAlignedPos(opt_attributes.pos.getc(true), actual, epsilon);
this.nodeHelper.ellipse.contains({
x : pos.x + actual / 2,
y : pos.y + epsilon / 2
}, value, actual, epsilon);
}
},
rectangle : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var qualifier = adj.getData("width");
var cycle = adj.getData("height");
var pos = this.getAlignedPos(adj.pos.getc(true), qualifier, cycle);
this.nodeHelper.rectangle.render("fill", {
x : pos.x + qualifier / 2,
y : pos.y + cycle / 2
}, qualifier, cycle, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {undefined}
*/
contains : function(opt_attributes, value) {
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
var pos = this.getAlignedPos(opt_attributes.pos.getc(true), actual, epsilon);
this.nodeHelper.rectangle.contains({
x : pos.x + actual / 2,
y : pos.y + epsilon / 2
}, value, actual, epsilon);
}
}
});
$jit.ST.Plot.EdgeTypes = new Class({
/** @type {function (): undefined} */
none : $.empty,
line : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var orn = this.getOrientation(adj);
var nodeFrom = adj.nodeFrom;
var nodeTo = adj.nodeTo;
/** @type {boolean} */
var rel = nodeFrom._depth < nodeTo._depth;
var from = this.viz.geom.getEdge(rel ? nodeFrom : nodeTo, "begin", orn);
var lab = this.viz.geom.getEdge(rel ? nodeTo : nodeFrom, "end", orn);
this.edgeHelper.line.render(from, lab, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var orn = this.getOrientation(opt_attributes);
var nodeFrom = opt_attributes.nodeFrom;
var nodeTo = opt_attributes.nodeTo;
/** @type {boolean} */
var rel = nodeFrom._depth < nodeTo._depth;
var attributes = this.viz.geom.getEdge(rel ? nodeFrom : nodeTo, "begin", orn);
var pdataOld = this.viz.geom.getEdge(rel ? nodeTo : nodeFrom, "end", orn);
return this.edgeHelper.line.contains(attributes, pdataOld, value, this.edge.epsilon);
}
},
arrow : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var orn = this.getOrientation(adj);
var node = adj.nodeFrom;
var child = adj.nodeTo;
var qualifier = adj.getData("dim");
var from = this.viz.geom.getEdge(node, "begin", orn);
var lab = this.viz.geom.getEdge(child, "end", orn);
var direction = adj.data.$direction;
var cycle = direction && (direction.length > 1 && direction[0] != node.id);
this.edgeHelper.arrow.render(from, lab, qualifier, cycle, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var orn = this.getOrientation(opt_attributes);
var nodeFrom = opt_attributes.nodeFrom;
var nodeTo = opt_attributes.nodeTo;
/** @type {boolean} */
var rel = nodeFrom._depth < nodeTo._depth;
var attributes = this.viz.geom.getEdge(rel ? nodeFrom : nodeTo, "begin", orn);
var pdataOld = this.viz.geom.getEdge(rel ? nodeTo : nodeFrom, "end", orn);
return this.edgeHelper.arrow.contains(attributes, pdataOld, value, this.edge.epsilon);
}
},
"quadratic:begin" : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var orn = this.getOrientation(adj);
var nodeFrom = adj.nodeFrom;
var nodeTo = adj.nodeTo;
/** @type {boolean} */
var rel = nodeFrom._depth < nodeTo._depth;
var begin = this.viz.geom.getEdge(rel ? nodeFrom : nodeTo, "begin", orn);
var end = this.viz.geom.getEdge(rel ? nodeTo : nodeFrom, "end", orn);
var dim = adj.getData("dim");
var ctx = lab.getCtx();
ctx.beginPath();
ctx.moveTo(begin.x, begin.y);
switch(orn) {
case "left":
ctx.quadraticCurveTo(begin.x + dim, begin.y, end.x, end.y);
break;
case "right":
ctx.quadraticCurveTo(begin.x - dim, begin.y, end.x, end.y);
break;
case "top":
ctx.quadraticCurveTo(begin.x, begin.y + dim, end.x, end.y);
break;
case "bottom":
ctx.quadraticCurveTo(begin.x, begin.y - dim, end.x, end.y);
break;
}
ctx.stroke();
}
},
"quadratic:end" : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var orn = this.getOrientation(adj);
var nodeFrom = adj.nodeFrom;
var nodeTo = adj.nodeTo;
/** @type {boolean} */
var rel = nodeFrom._depth < nodeTo._depth;
var begin = this.viz.geom.getEdge(rel ? nodeFrom : nodeTo, "begin", orn);
var end = this.viz.geom.getEdge(rel ? nodeTo : nodeFrom, "end", orn);
var dim = adj.getData("dim");
var ctx = lab.getCtx();
ctx.beginPath();
ctx.moveTo(begin.x, begin.y);
switch(orn) {
case "left":
ctx.quadraticCurveTo(end.x - dim, end.y, end.x, end.y);
break;
case "right":
ctx.quadraticCurveTo(end.x + dim, end.y, end.x, end.y);
break;
case "top":
ctx.quadraticCurveTo(end.x, end.y - dim, end.x, end.y);
break;
case "bottom":
ctx.quadraticCurveTo(end.x, end.y + dim, end.x, end.y);
break;
}
ctx.stroke();
}
},
bezier : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var orn = this.getOrientation(adj);
var nodeFrom = adj.nodeFrom;
var nodeTo = adj.nodeTo;
/** @type {boolean} */
var rel = nodeFrom._depth < nodeTo._depth;
var begin = this.viz.geom.getEdge(rel ? nodeFrom : nodeTo, "begin", orn);
var end = this.viz.geom.getEdge(rel ? nodeTo : nodeFrom, "end", orn);
var dim = adj.getData("dim");
var ctx = lab.getCtx();
ctx.beginPath();
ctx.moveTo(begin.x, begin.y);
switch(orn) {
case "left":
ctx.bezierCurveTo(begin.x + dim, begin.y, end.x - dim, end.y, end.x, end.y);
break;
case "right":
ctx.bezierCurveTo(begin.x - dim, begin.y, end.x + dim, end.y, end.x, end.y);
break;
case "top":
ctx.bezierCurveTo(begin.x, begin.y + dim, end.x, end.y - dim, end.x, end.y);
break;
case "bottom":
ctx.bezierCurveTo(begin.x, begin.y - dim, end.x, end.y + dim, end.x, end.y);
break;
}
ctx.stroke();
}
}
});
$jit.ST.Plot.NodeTypes.implement({
"areachart-stacked" : {
/**
* @param {?} node
* @param {?} lab
* @return {undefined}
*/
render : function(node, lab) {
var pos = node.pos.getc(true);
var width = node.getData("width");
var height = node.getData("height");
var algnPos = this.getAlignedPos(pos, width, height);
var x = algnPos.x;
var y = algnPos.y;
var stringArray = node.getData("stringArray");
var dimArray = node.getData("dimArray");
var valArray = node.getData("valueArray");
var valLeft = $.reduce(valArray, function(dataAndEvents, deepDataAndEvents) {
return dataAndEvents + deepDataAndEvents[0];
}, 0);
var valRight = $.reduce(valArray, function(dataAndEvents, deepDataAndEvents) {
return dataAndEvents + deepDataAndEvents[1];
}, 0);
var colorArray = node.getData("colorArray");
var colorLength = colorArray.length;
var config = node.getData("config");
var gradient = node.getData("gradient");
var showLabels = config.showLabels;
var aggregates = config.showAggregates;
var label = config.Label;
var prev = node.getData("prev");
var ctx = lab.getCtx();
var border = node.getData("border");
if (colorArray && (dimArray && stringArray)) {
/** @type {number} */
var i = 0;
var l = dimArray.length;
/** @type {number} */
var acumLeft = 0;
/** @type {number} */
var acumRight = 0;
/** @type {number} */
var valAcum = 0;
for (;i < l;i++) {
ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];
ctx.save();
if (gradient && (dimArray[i][0] > 0 || dimArray[i][1] > 0)) {
var h1 = acumLeft + dimArray[i][0];
var h2 = acumRight + dimArray[i][1];
/** @type {number} */
var theta2 = Math.atan((h2 - h1) / width);
/** @type {number} */
var delta = 55;
var linear = ctx.createLinearGradient(x + width / 2, y - (h1 + h2) / 2, x + width / 2 + delta * Math.sin(theta2), y - (h1 + h2) / 2 + delta * Math.cos(theta2));
var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)), function(dataAndEvents) {
return dataAndEvents * 0.85 >> 0;
}));
linear.addColorStop(0, colorArray[i % colorLength]);
linear.addColorStop(1, color);
ctx.fillStyle = linear;
}
ctx.beginPath();
ctx.moveTo(x, y - acumLeft);
ctx.lineTo(x + width, y - acumRight);
ctx.lineTo(x + width, y - acumRight - dimArray[i][1]);
ctx.lineTo(x, y - acumLeft - dimArray[i][0]);
ctx.lineTo(x, y - acumLeft);
ctx.fill();
ctx.restore();
if (border) {
/** @type {boolean} */
var strong = border.name == stringArray[i];
/** @type {number} */
var b1 = strong ? 0.7 : 0.8;
color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)), function(a4) {
return a4 * b1 >> 0;
}));
ctx.strokeStyle = color;
/** @type {number} */
ctx.lineWidth = strong ? 4 : 1;
ctx.save();
ctx.beginPath();
if (border.index === 0) {
ctx.moveTo(x, y - acumLeft);
ctx.lineTo(x, y - acumLeft - dimArray[i][0]);
} else {
ctx.moveTo(x + width, y - acumRight);
ctx.lineTo(x + width, y - acumRight - dimArray[i][1]);
}
ctx.stroke();
ctx.restore();
}
acumLeft += dimArray[i][0] || 0;
acumRight += dimArray[i][1] || 0;
if (dimArray[i][0] > 0) {
valAcum += valArray[i][0] || 0;
}
}
if (prev && label.type == "Native") {
ctx.save();
ctx.beginPath();
ctx.fillStyle = ctx.strokeStyle = label.color;
/** @type {string} */
ctx.font = label.style + " " + label.size + "px " + label.family;
/** @type {string} */
ctx.textAlign = "center";
/** @type {string} */
ctx.textBaseline = "middle";
var aggValue = aggregates(node.name, valLeft, valRight, node, valAcum);
if (aggValue !== false) {
ctx.fillText(aggValue !== true ? aggValue : valAcum, x, y - acumLeft - config.labelOffset - label.size / 2, width);
}
if (showLabels(node.name, valLeft, valRight, node)) {
ctx.fillText(node.name, x, y + label.size / 2 + config.labelOffset);
}
ctx.restore();
}
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var pos = opt_attributes.pos.getc(true);
var width = opt_attributes.getData("width");
var height = opt_attributes.getData("height");
var algnPos = this.getAlignedPos(pos, width, height);
var x = algnPos.x;
var y = algnPos.y;
var dimArray = opt_attributes.getData("dimArray");
/** @type {number} */
var rx = value.x - x;
if (value.x < x || (value.x > x + width || (value.y > y || value.y < y - height))) {
return false;
}
/** @type {number} */
var i = 0;
var l = dimArray.length;
var lAcum = y;
var rAcum = y;
for (;i < l;i++) {
var dimi = dimArray[i];
lAcum -= dimi[0];
rAcum -= dimi[1];
var intersec = lAcum + (rAcum - lAcum) * rx / width;
if (value.y >= intersec) {
/** @type {number} */
var j = +(rx > width / 2);
return{
name : opt_attributes.getData("stringArray")[i],
color : opt_attributes.getData("colorArray")[i],
value : opt_attributes.getData("valueArray")[i][j],
index : j
};
}
}
return false;
}
}
});
$jit.AreaChart = new Class({
st : null,
colors : ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
selected : {},
busy : false,
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
this.controller = this.config = $.merge(Options("Canvas", "Margin", "Label", "AreaChart"), {
Label : {
type : "Native"
}
}, controller);
var showLabels = this.config.showLabels;
var typeLabels = $.type(showLabels);
var showAggregates = this.config.showAggregates;
var typeAggregates = $.type(showAggregates);
this.config.showLabels = typeLabels == "function" ? showLabels : $.lambda(showLabels);
this.config.showAggregates = typeAggregates == "function" ? showAggregates : $.lambda(showAggregates);
this.initializeViz();
},
/**
* @return {undefined}
*/
initializeViz : function() {
var config = this.config;
var that = this;
var nodeType = config.type.split(":")[0];
var nodeLabels = {};
var delegate = new $jit.ST({
injectInto : config.injectInto,
width : config.width,
height : config.height,
orientation : "bottom",
levelDistance : 0,
siblingOffset : 0,
subtreeOffset : 0,
withLabels : config.Label.type != "Native",
useCanvas : config.useCanvas,
Label : {
type : config.Label.type
},
Node : {
overridable : true,
type : "areachart-" + nodeType,
align : "left",
width : 1,
height : 1
},
Edge : {
type : "none"
},
Tips : {
enable : config.Tips.enable,
type : "Native",
force : true,
/**
* @param {?} from
* @param {?} type
* @param {?} event
* @return {undefined}
*/
onShow : function(from, type, event) {
var lab = event;
config.Tips.onShow(from, lab, type);
}
},
Events : {
enable : true,
type : "Native",
/**
* @param {?} adj
* @param {?} lab
* @param {?} selector
* @return {undefined}
*/
onClick : function(adj, lab, selector) {
if (!config.filterOnClick && !config.Events.enable) {
return;
}
var from = lab.getContains();
if (from) {
if (config.filterOnClick) {
that.filter(from.name);
}
}
if (config.Events.enable) {
config.Events.onClick(from, lab, selector);
}
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onRightClick : function(adj, lab, event) {
if (!config.restoreOnRightClick) {
return;
}
that.restore();
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseMove : function(adj, lab, event) {
if (!config.selectOnHover) {
return;
}
if (adj) {
var elem = lab.getContains();
that.select(adj.id, elem.name, elem.index);
} else {
that.select(false, false, false);
}
}
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onCreateLabel : function(adj, lab) {
var labelConf = config.Label;
var valueArray = lab.getData("valueArray");
var acumLeft = $.reduce(valueArray, function(dataAndEvents, deepDataAndEvents) {
return dataAndEvents + deepDataAndEvents[0];
}, 0);
var acumRight = $.reduce(valueArray, function(dataAndEvents, deepDataAndEvents) {
return dataAndEvents + deepDataAndEvents[1];
}, 0);
if (lab.getData("prev")) {
var nlbs = {
wrapper : document.createElement("div"),
aggregate : document.createElement("div"),
label : document.createElement("div")
};
/** @type {Element} */
var wrapper = nlbs.wrapper;
/** @type {Element} */
var label = nlbs.label;
/** @type {Element} */
var aggregate = nlbs.aggregate;
/** @type {(CSSStyleDeclaration|null)} */
var wrapperStyle = wrapper.style;
/** @type {(CSSStyleDeclaration|null)} */
var style = label.style;
/** @type {(CSSStyleDeclaration|null)} */
var aggregateStyle = aggregate.style;
nodeLabels[lab.id] = nlbs;
wrapper.appendChild(label);
wrapper.appendChild(aggregate);
if (!config.showLabels(lab.name, acumLeft, acumRight, lab)) {
/** @type {string} */
label.style.display = "none";
}
if (!config.showAggregates(lab.name, acumLeft, acumRight, lab)) {
/** @type {string} */
aggregate.style.display = "none";
}
/** @type {string} */
wrapperStyle.position = "relative";
/** @type {string} */
wrapperStyle.overflow = "visible";
/** @type {string} */
wrapperStyle.fontSize = labelConf.size + "px";
wrapperStyle.fontFamily = labelConf.family;
wrapperStyle.color = labelConf.color;
/** @type {string} */
wrapperStyle.textAlign = "center";
/** @type {string} */
aggregateStyle.position = style.position = "absolute";
adj.style.width = lab.getData("width") + "px";
adj.style.height = lab.getData("height") + "px";
label.innerHTML = lab.name;
adj.appendChild(wrapper);
}
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onPlaceLabel : function(adj, lab) {
if (!lab.getData("prev")) {
return;
}
var labels = nodeLabels[lab.id];
var wrapperStyle = labels.wrapper.style;
var aggregateStyle = labels.label.style;
var style = labels.aggregate.style;
var w = lab.getData("width");
var constrainedHeight = lab.getData("height");
var dimArray = lab.getData("dimArray");
var valArray = lab.getData("valueArray");
var acumLeft = $.reduce(valArray, function(dataAndEvents, deepDataAndEvents) {
return dataAndEvents + deepDataAndEvents[0];
}, 0);
var acumRight = $.reduce(valArray, function(dataAndEvents, deepDataAndEvents) {
return dataAndEvents + deepDataAndEvents[1];
}, 0);
/** @type {number} */
var font = parseInt(wrapperStyle.fontSize, 10);
var styleDeclaration = adj.style;
if (dimArray && valArray) {
if (config.showLabels(lab.name, acumLeft, acumRight, lab)) {
/** @type {string} */
aggregateStyle.display = "";
} else {
/** @type {string} */
aggregateStyle.display = "none";
}
var aggValue = config.showAggregates(lab.name, acumLeft, acumRight, lab);
if (aggValue !== false) {
/** @type {string} */
style.display = "";
} else {
/** @type {string} */
style.display = "none";
}
/** @type {string} */
wrapperStyle.width = style.width = aggregateStyle.width = adj.style.width = w + "px";
/** @type {string} */
style.left = aggregateStyle.left = -w / 2 + "px";
/** @type {number} */
var i = 0;
var l = valArray.length;
/** @type {number} */
var acum = 0;
/** @type {number} */
var leftAcum = 0;
for (;i < l;i++) {
if (dimArray[i][0] > 0) {
acum += valArray[i][0];
leftAcum += dimArray[i][0];
}
}
/** @type {string} */
style.top = -font - config.labelOffset + "px";
/** @type {string} */
aggregateStyle.top = config.labelOffset + leftAcum + "px";
/** @type {string} */
adj.style.top = parseInt(adj.style.top, 10) - leftAcum + "px";
/** @type {string} */
adj.style.height = wrapperStyle.height = leftAcum + "px";
labels.aggregate.innerHTML = aggValue !== true ? aggValue : acum;
}
}
});
var testNode = delegate.canvas.getSize();
var margin = config.Margin;
delegate.config.offsetY = -testNode.height / 2 + margin.bottom + (config.showLabels && config.labelOffset + config.Label.size);
/** @type {number} */
delegate.config.offsetX = (margin.right - margin.left) / 2;
this.delegate = delegate;
this.canvas = this.delegate.canvas;
},
/**
* @param {Object} json
* @return {undefined}
*/
loadJSON : function(json) {
/** @type {number} */
var prefix = $.time();
/** @type {Array} */
var ch = [];
var delegate = this.delegate;
var name = $.splat(json.label);
var color = $.splat(json.color || this.colors);
var config = this.config;
/** @type {boolean} */
var gradient = !!config.type.split(":")[1];
var animate = config.animate;
/** @type {number} */
var i = 0;
var values = json.values;
var valuesLen = values.length;
for (;i < valuesLen - 1;i++) {
var value = values[i];
var prev = values[i - 1];
var next = values[i + 1];
var valLeft = $.splat(values[i].values);
var valRight = $.splat(values[i + 1].values);
var valArray = $.zip(valLeft, valRight);
/** @type {number} */
var D = 0;
/** @type {number} */
var C = 0;
ch.push({
id : prefix + value.label,
name : value.label,
data : {
value : valArray,
"$valueArray" : valArray,
"$colorArray" : color,
"$stringArray" : name,
"$next" : next.label,
"$prev" : prev ? prev.label : false,
"$config" : config,
"$gradient" : gradient
},
children : []
});
}
var root = {
id : prefix + "$root",
name : "",
data : {
"$type" : "none",
"$width" : 1,
"$height" : 1
},
children : ch
};
delegate.loadJSON(root);
this.normalizeDims();
delegate.compute();
delegate.select(delegate.root);
if (animate) {
delegate.fx.animate({
modes : ["node-property:height:dimArray"],
duration : 1500
});
}
},
/**
* @param {Object} json
* @param {Object} onComplete
* @return {undefined}
*/
updateJSON : function(json, onComplete) {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
var delegate = this.delegate;
var graph = delegate.graph;
var extended = json.label && $.splat(json.label);
var values = json.values;
var animate = this.config.animate;
var that = this;
var hashValues = {};
/** @type {number} */
var i = 0;
var valuesLen = values.length;
for (;i < valuesLen;i++) {
hashValues[values[i].label] = values[i];
}
graph.eachNode(function(n) {
var v = hashValues[n.name];
var original = n.getData("stringArray");
var attributes = n.getData("valueArray");
var next = n.getData("next");
if (v) {
v.values = $.splat(v.values);
$.each(attributes, function(a, key) {
a[0] = v.values[key];
if (extended) {
original[key] = extended[key];
}
});
n.setData("valueArray", attributes);
}
if (next) {
v = hashValues[next];
if (v) {
$.each(attributes, function(vec, i) {
vec[1] = v.values[i];
});
}
}
});
this.normalizeDims();
delegate.compute();
delegate.select(delegate.root);
if (animate) {
delegate.fx.animate({
modes : ["node-property:height:dimArray"],
duration : 1500,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
if (onComplete) {
onComplete.onComplete();
}
}
});
}
},
/**
* @param {string} flags
* @param {Object} scope
* @return {undefined}
*/
filter : function(flags, scope) {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
if (this.config.Tips.enable) {
this.delegate.tips.hide();
}
this.select(false, false, false);
var filter = $.splat(flags);
var root = this.delegate.graph.getNode(this.delegate.root);
var that = this;
this.normalizeDims();
root.eachAdjacency(function(adj) {
var n = adj.nodeTo;
var dimArray = n.getData("dimArray", "end");
var stringArray = n.getData("stringArray");
n.setData("dimArray", $.map(dimArray, function(dataAndEvents, i) {
return $.indexOf(filter, stringArray[i]) > -1 ? dataAndEvents : [0, 0];
}), "end");
});
this.delegate.fx.animate({
modes : ["node-property:dimArray"],
duration : 1500,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
if (scope) {
scope.onComplete();
}
}
});
},
/**
* @param {Object} callback
* @return {undefined}
*/
restore : function(callback) {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
if (this.config.Tips.enable) {
this.delegate.tips.hide();
}
this.select(false, false, false);
this.normalizeDims();
var that = this;
this.delegate.fx.animate({
modes : ["node-property:height:dimArray"],
duration : 1500,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
if (callback) {
callback.onComplete();
}
}
});
},
/**
* @param {?} id
* @param {boolean} lab
* @param {boolean} index
* @return {undefined}
*/
select : function(id, lab, index) {
if (!this.config.selectOnHover) {
return;
}
var s = this.selected;
if (s.id != id || (s.name != lab || s.index != index)) {
s.id = id;
/** @type {boolean} */
s.name = lab;
/** @type {boolean} */
s.index = index;
this.delegate.graph.eachNode(function(n) {
n.setData("border", false);
});
if (id) {
var n = this.delegate.graph.getNode(id);
n.setData("border", s);
/** @type {string} */
var link = index === 0 ? "prev" : "next";
link = n.getData(link);
if (link) {
n = this.delegate.graph.getByName(link);
if (n) {
n.setData("border", {
name : lab,
index : 1 - index
});
}
}
}
this.delegate.plot();
}
},
/**
* @return {?}
*/
getLegend : function() {
var legend = {};
var n;
this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(adj) {
n = adj.nodeTo;
});
var colors = n.getData("colorArray");
var colorsLen = colors.length;
$.each(n.getData("stringArray"), function(s, i) {
legend[s] = colors[i % colorsLen];
});
return legend;
},
/**
* @return {?}
*/
getMaxValue : function() {
/** @type {number} */
var maxValue = 0;
this.delegate.graph.eachNode(function(n) {
var attributes = n.getData("valueArray");
/** @type {number} */
var y = 0;
/** @type {number} */
var x = 0;
$.each(attributes, function(dataAndEvents) {
y += +dataAndEvents[0];
x += +dataAndEvents[1];
});
var acum = x > y ? x : y;
maxValue = maxValue > acum ? maxValue : acum;
});
return maxValue;
},
/**
* @return {undefined}
*/
normalizeDims : function() {
var root = this.delegate.graph.getNode(this.delegate.root);
/** @type {number} */
var z = 0;
root.eachAdjacency(function() {
z++;
});
var maxValue = this.getMaxValue() || 1;
var $cont = this.delegate.canvas.getSize();
var config = this.config;
var margin = config.Margin;
var labelOffset = config.labelOffset + config.Label.size;
/** @type {number} */
var recurring = ($cont.width - (margin.left + margin.right)) / z;
var animate = config.animate;
/** @type {number} */
var height = $cont.height - (margin.top + margin.bottom) - (config.showAggregates && labelOffset) - (config.showLabels && labelOffset);
this.delegate.graph.eachNode(function(n) {
/** @type {number} */
var y = 0;
/** @type {number} */
var x = 0;
/** @type {Array} */
var animateValue = [];
$.each(n.getData("valueArray"), function(dataAndEvents) {
y += +dataAndEvents[0];
x += +dataAndEvents[1];
animateValue.push([0, 0]);
});
var acum = x > y ? x : y;
n.setData("width", recurring);
if (animate) {
n.setData("height", acum * height / maxValue, "end");
n.setData("dimArray", $.map(n.getData("valueArray"), function(n) {
return[n[0] * height / maxValue, n[1] * height / maxValue];
}), "end");
var dimArray = n.getData("dimArray");
if (!dimArray) {
n.setData("dimArray", animateValue);
}
} else {
n.setData("height", acum * height / maxValue);
n.setData("dimArray", $.map(n.getData("valueArray"), function(n) {
return[n[0] * height / maxValue, n[1] * height / maxValue];
}));
}
});
}
});
Options.BarChart = {
$extend : true,
animate : true,
type : "stacked",
labelOffset : 3,
barsOffset : 0,
hoveredColor : "#9fd4ff",
orientation : "horizontal",
showAggregates : true,
showLabels : true,
Tips : {
enable : false,
/** @type {function (): undefined} */
onShow : $.empty,
/** @type {function (): undefined} */
onHide : $.empty
},
Events : {
enable : false,
/** @type {function (): undefined} */
onClick : $.empty
}
};
$jit.ST.Plot.NodeTypes.implement({
"barchart-stacked" : {
/**
* @param {?} node
* @param {?} lab
* @return {undefined}
*/
render : function(node, lab) {
var pos = node.pos.getc(true);
var width = node.getData("width");
var height = node.getData("height");
var algnPos = this.getAlignedPos(pos, width, height);
var x = algnPos.x;
var y = algnPos.y;
var dimArray = node.getData("dimArray");
var valueArray = node.getData("valueArray");
var colorArray = node.getData("colorArray");
var colorLength = colorArray.length;
var stringArray = node.getData("stringArray");
var ctx = lab.getCtx();
var opt = {};
var border = node.getData("border");
var gradient = node.getData("gradient");
var config = node.getData("config");
/** @type {boolean} */
var isH = config.orientation == "horizontal";
var aggregates = config.showAggregates;
var showLabels = config.showLabels;
var label = config.Label;
if (colorArray && (dimArray && stringArray)) {
/** @type {number} */
var i = 0;
var l = dimArray.length;
/** @type {number} */
var acum = 0;
/** @type {number} */
var valAcum = 0;
for (;i < l;i++) {
ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];
if (gradient) {
var linear;
if (isH) {
linear = ctx.createLinearGradient(x + acum + dimArray[i] / 2, y, x + acum + dimArray[i] / 2, y + height);
} else {
linear = ctx.createLinearGradient(x, y - acum - dimArray[i] / 2, x + width, y - acum - dimArray[i] / 2);
}
var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)), function(dataAndEvents) {
return dataAndEvents * 0.5 >> 0;
}));
linear.addColorStop(0, color);
linear.addColorStop(0.5, colorArray[i % colorLength]);
linear.addColorStop(1, color);
ctx.fillStyle = linear;
}
if (isH) {
ctx.fillRect(x + acum, y, dimArray[i], height);
} else {
ctx.fillRect(x, y - acum - dimArray[i], width, dimArray[i]);
}
if (border && border.name == stringArray[i]) {
opt.acum = acum;
opt.dimValue = dimArray[i];
}
acum += dimArray[i] || 0;
valAcum += valueArray[i] || 0;
}
if (border) {
ctx.save();
/** @type {number} */
ctx.lineWidth = 2;
ctx.strokeStyle = border.color;
if (isH) {
ctx.strokeRect(x + opt.acum + 1, y + 1, opt.dimValue - 2, height - 2);
} else {
ctx.strokeRect(x + 1, y - opt.acum - opt.dimValue + 1, width - 2, opt.dimValue - 2);
}
ctx.restore();
}
if (label.type == "Native") {
ctx.save();
ctx.fillStyle = ctx.strokeStyle = label.color;
/** @type {string} */
ctx.font = label.style + " " + label.size + "px " + label.family;
/** @type {string} */
ctx.textBaseline = "middle";
var aggValue = aggregates(node.name, valAcum, node);
if (aggValue !== false) {
aggValue = aggValue !== true ? aggValue : valAcum;
if (isH) {
/** @type {string} */
ctx.textAlign = "right";
ctx.fillText(aggValue, x + acum - config.labelOffset, y + height / 2);
} else {
/** @type {string} */
ctx.textAlign = "center";
ctx.fillText(aggValue, x + width / 2, y - height - label.size / 2 - config.labelOffset);
}
}
if (showLabels(node.name, valAcum, node)) {
if (isH) {
/** @type {string} */
ctx.textAlign = "center";
ctx.translate(x - config.labelOffset - label.size / 2, y + height / 2);
ctx.rotate(Math.PI / 2);
ctx.fillText(node.name, 0, 0);
} else {
/** @type {string} */
ctx.textAlign = "center";
ctx.fillText(node.name, x + width / 2, y + label.size / 2 + config.labelOffset);
}
}
ctx.restore();
}
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var pos = opt_attributes.pos.getc(true);
var width = opt_attributes.getData("width");
var height = opt_attributes.getData("height");
var algnPos = this.getAlignedPos(pos, width, height);
var x = algnPos.x;
var y = algnPos.y;
var dimArray = opt_attributes.getData("dimArray");
var config = opt_attributes.getData("config");
/** @type {number} */
var dx0 = value.x - x;
/** @type {boolean} */
var horz = config.orientation == "horizontal";
if (horz) {
if (value.x < x || (value.x > x + width || (value.y > y + height || value.y < y))) {
return false;
}
} else {
if (value.x < x || (value.x > x + width || (value.y > y || value.y < y - height))) {
return false;
}
}
/** @type {number} */
var i = 0;
var l = dimArray.length;
var acum = horz ? x : y;
for (;i < l;i++) {
var dimi = dimArray[i];
if (horz) {
acum += dimi;
var intersec = acum;
if (value.x <= intersec) {
return{
name : opt_attributes.getData("stringArray")[i],
color : opt_attributes.getData("colorArray")[i],
value : opt_attributes.getData("valueArray")[i],
label : opt_attributes.name
};
}
} else {
acum -= dimi;
intersec = acum;
if (value.y >= intersec) {
return{
name : opt_attributes.getData("stringArray")[i],
color : opt_attributes.getData("colorArray")[i],
value : opt_attributes.getData("valueArray")[i],
label : opt_attributes.name
};
}
}
}
return false;
}
},
"barchart-grouped" : {
/**
* @param {?} node
* @param {?} lab
* @return {undefined}
*/
render : function(node, lab) {
var pos = node.pos.getc(true);
var width = node.getData("width");
var height = node.getData("height");
var algnPos = this.getAlignedPos(pos, width, height);
var x = algnPos.x;
var y = algnPos.y;
var dimArray = node.getData("dimArray");
var valueArray = node.getData("valueArray");
var valueLength = valueArray.length;
var colorArray = node.getData("colorArray");
var colorLength = colorArray.length;
var stringArray = node.getData("stringArray");
var ctx = lab.getCtx();
var opt = {};
var border = node.getData("border");
var gradient = node.getData("gradient");
var config = node.getData("config");
/** @type {boolean} */
var horz = config.orientation == "horizontal";
var aggregates = config.showAggregates;
var showLabels = config.showLabels;
var label = config.Label;
/** @type {number} */
var fixedDim = (horz ? height : width) / valueLength;
if (colorArray && (dimArray && stringArray)) {
/** @type {number} */
var i = 0;
var l = valueLength;
/** @type {number} */
var X = 0;
/** @type {number} */
var valAcum = 0;
for (;i < l;i++) {
ctx.fillStyle = ctx.strokeStyle = colorArray[i % colorLength];
if (gradient) {
var linear;
if (horz) {
linear = ctx.createLinearGradient(x + dimArray[i] / 2, y + fixedDim * i, x + dimArray[i] / 2, y + fixedDim * (i + 1));
} else {
linear = ctx.createLinearGradient(x + fixedDim * i, y - dimArray[i] / 2, x + fixedDim * (i + 1), y - dimArray[i] / 2);
}
var color = $.rgbToHex($.map($.hexToRgb(colorArray[i % colorLength].slice(1)), function(dataAndEvents) {
return dataAndEvents * 0.5 >> 0;
}));
linear.addColorStop(0, color);
linear.addColorStop(0.5, colorArray[i % colorLength]);
linear.addColorStop(1, color);
ctx.fillStyle = linear;
}
if (horz) {
ctx.fillRect(x, y + fixedDim * i, dimArray[i], fixedDim);
} else {
ctx.fillRect(x + fixedDim * i, y - dimArray[i], fixedDim, dimArray[i]);
}
if (border && border.name == stringArray[i]) {
/** @type {number} */
opt.acum = fixedDim * i;
opt.dimValue = dimArray[i];
}
X += dimArray[i] || 0;
valAcum += valueArray[i] || 0;
}
if (border) {
ctx.save();
/** @type {number} */
ctx.lineWidth = 2;
ctx.strokeStyle = border.color;
if (horz) {
ctx.strokeRect(x + 1, y + opt.acum + 1, opt.dimValue - 2, fixedDim - 2);
} else {
ctx.strokeRect(x + opt.acum + 1, y - opt.dimValue + 1, fixedDim - 2, opt.dimValue - 2);
}
ctx.restore();
}
if (label.type == "Native") {
ctx.save();
ctx.fillStyle = ctx.strokeStyle = label.color;
/** @type {string} */
ctx.font = label.style + " " + label.size + "px " + label.family;
/** @type {string} */
ctx.textBaseline = "middle";
var aggValue = aggregates(node.name, valAcum, node);
if (aggValue !== false) {
aggValue = aggValue !== true ? aggValue : valAcum;
if (horz) {
/** @type {string} */
ctx.textAlign = "right";
ctx.fillText(aggValue, x + Math.max.apply(null, dimArray) - config.labelOffset, y + height / 2);
} else {
/** @type {string} */
ctx.textAlign = "center";
ctx.fillText(aggValue, x + width / 2, y - Math.max.apply(null, dimArray) - label.size / 2 - config.labelOffset);
}
}
if (showLabels(node.name, valAcum, node)) {
if (horz) {
/** @type {string} */
ctx.textAlign = "center";
ctx.translate(x - config.labelOffset - label.size / 2, y + height / 2);
ctx.rotate(Math.PI / 2);
ctx.fillText(node.name, 0, 0);
} else {
/** @type {string} */
ctx.textAlign = "center";
ctx.fillText(node.name, x + width / 2, y + label.size / 2 + config.labelOffset);
}
}
ctx.restore();
}
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var pos = opt_attributes.pos.getc(true);
var width = opt_attributes.getData("width");
var height = opt_attributes.getData("height");
var algnPos = this.getAlignedPos(pos, width, height);
var x = algnPos.x;
var y = algnPos.y;
var codeSegments = opt_attributes.getData("dimArray");
var valueLength = codeSegments.length;
var config = opt_attributes.getData("config");
/** @type {number} */
var dx0 = value.x - x;
/** @type {boolean} */
var horz = config.orientation == "horizontal";
/** @type {number} */
var fixedDim = (horz ? height : width) / valueLength;
if (horz) {
if (value.x < x || (value.x > x + width || (value.y > y + height || value.y < y))) {
return false;
}
} else {
if (value.x < x || (value.x > x + width || (value.y > y || value.y < y - height))) {
return false;
}
}
/** @type {number} */
var i = 0;
var valuesLen = codeSegments.length;
for (;i < valuesLen;i++) {
var delta = codeSegments[i];
if (horz) {
var limit = y + fixedDim * i;
if (value.x <= x + delta && (value.y >= limit && value.y <= limit + fixedDim)) {
return{
name : opt_attributes.getData("stringArray")[i],
color : opt_attributes.getData("colorArray")[i],
value : opt_attributes.getData("valueArray")[i],
label : opt_attributes.name
};
}
} else {
limit = x + fixedDim * i;
if (value.x >= limit && (value.x <= limit + fixedDim && value.y >= y - delta)) {
return{
name : opt_attributes.getData("stringArray")[i],
color : opt_attributes.getData("colorArray")[i],
value : opt_attributes.getData("valueArray")[i],
label : opt_attributes.name
};
}
}
}
return false;
}
}
});
$jit.BarChart = new Class({
st : null,
colors : ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
selected : {},
busy : false,
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
this.controller = this.config = $.merge(Options("Canvas", "Margin", "Label", "BarChart"), {
Label : {
type : "Native"
}
}, controller);
var showLabels = this.config.showLabels;
var typeLabels = $.type(showLabels);
var showAggregates = this.config.showAggregates;
var typeAggregates = $.type(showAggregates);
this.config.showLabels = typeLabels == "function" ? showLabels : $.lambda(showLabels);
this.config.showAggregates = typeAggregates == "function" ? showAggregates : $.lambda(showAggregates);
this.initializeViz();
},
/**
* @return {undefined}
*/
initializeViz : function() {
var config = this.config;
var that = this;
var nodeType = config.type.split(":")[0];
/** @type {boolean} */
var horz = config.orientation == "horizontal";
var nodeLabels = {};
var delegate = new $jit.ST({
injectInto : config.injectInto,
width : config.width,
height : config.height,
orientation : horz ? "left" : "bottom",
levelDistance : 0,
siblingOffset : config.barsOffset,
subtreeOffset : 0,
withLabels : config.Label.type != "Native",
useCanvas : config.useCanvas,
Label : {
type : config.Label.type
},
Node : {
overridable : true,
type : "barchart-" + nodeType,
align : "left",
width : 1,
height : 1
},
Edge : {
type : "none"
},
Tips : {
enable : config.Tips.enable,
type : "Native",
force : true,
/**
* @param {?} from
* @param {?} type
* @param {?} event
* @return {undefined}
*/
onShow : function(from, type, event) {
var lab = event;
config.Tips.onShow(from, lab, type);
}
},
Events : {
enable : true,
type : "Native",
/**
* @param {?} adj
* @param {?} lab
* @param {?} selector
* @return {undefined}
*/
onClick : function(adj, lab, selector) {
if (!config.Events.enable) {
return;
}
var from = lab.getContains();
config.Events.onClick(from, lab, selector);
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseMove : function(adj, lab, event) {
if (!config.hoveredColor) {
return;
}
if (adj) {
var elem = lab.getContains();
that.select(adj.id, elem.name, elem.index);
} else {
that.select(false, false, false);
}
}
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onCreateLabel : function(adj, lab) {
var labelConf = config.Label;
var reversed = lab.getData("valueArray");
var acumLeft = $.reduce(reversed, function(far, near) {
return far + near;
}, 0);
var nlbs = {
wrapper : document.createElement("div"),
aggregate : document.createElement("div"),
label : document.createElement("div")
};
/** @type {Element} */
var wrapper = nlbs.wrapper;
/** @type {Element} */
var label = nlbs.label;
/** @type {Element} */
var aggregate = nlbs.aggregate;
/** @type {(CSSStyleDeclaration|null)} */
var wrapperStyle = wrapper.style;
/** @type {(CSSStyleDeclaration|null)} */
var labelStyle = label.style;
/** @type {(CSSStyleDeclaration|null)} */
var aggregateStyle = aggregate.style;
nodeLabels[lab.id] = nlbs;
wrapper.appendChild(label);
wrapper.appendChild(aggregate);
if (!config.showLabels(lab.name, acumLeft, lab)) {
/** @type {string} */
labelStyle.display = "none";
}
if (!config.showAggregates(lab.name, acumLeft, lab)) {
/** @type {string} */
aggregateStyle.display = "none";
}
/** @type {string} */
wrapperStyle.position = "relative";
/** @type {string} */
wrapperStyle.overflow = "visible";
/** @type {string} */
wrapperStyle.fontSize = labelConf.size + "px";
wrapperStyle.fontFamily = labelConf.family;
wrapperStyle.color = labelConf.color;
/** @type {string} */
wrapperStyle.textAlign = "center";
/** @type {string} */
aggregateStyle.position = labelStyle.position = "absolute";
adj.style.width = lab.getData("width") + "px";
adj.style.height = lab.getData("height") + "px";
/** @type {string} */
aggregateStyle.left = labelStyle.left = "0px";
label.innerHTML = lab.name;
adj.appendChild(wrapper);
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onPlaceLabel : function(adj, lab) {
if (!nodeLabels[lab.id]) {
return;
}
var labels = nodeLabels[lab.id];
var style = labels.wrapper.style;
var labelStyle = labels.label.style;
var aggregateStyle = labels.aggregate.style;
/** @type {boolean} */
var grouped = config.type.split(":")[0] == "grouped";
/** @type {boolean} */
var horz = config.orientation == "horizontal";
var dimArray = lab.getData("dimArray");
var valArray = lab.getData("valueArray");
var w = grouped && horz ? Math.max.apply(null, dimArray) : lab.getData("width");
var height = grouped && !horz ? Math.max.apply(null, dimArray) : lab.getData("height");
/** @type {number} */
var font = parseInt(style.fontSize, 10);
var styleDeclaration = adj.style;
if (dimArray && valArray) {
/** @type {string} */
style.width = aggregateStyle.width = labelStyle.width = adj.style.width = w + "px";
/** @type {number} */
var i = 0;
var l = valArray.length;
/** @type {number} */
var acum = 0;
for (;i < l;i++) {
if (dimArray[i] > 0) {
acum += valArray[i];
}
}
if (config.showLabels(lab.name, acum, lab)) {
/** @type {string} */
labelStyle.display = "";
} else {
/** @type {string} */
labelStyle.display = "none";
}
var aggValue = config.showAggregates(lab.name, acum, lab);
if (aggValue !== false) {
/** @type {string} */
aggregateStyle.display = "";
} else {
/** @type {string} */
aggregateStyle.display = "none";
}
if (config.orientation == "horizontal") {
/** @type {string} */
aggregateStyle.textAlign = "right";
/** @type {string} */
labelStyle.textAlign = "left";
/** @type {string} */
labelStyle.textIndex = aggregateStyle.textIndent = config.labelOffset + "px";
/** @type {string} */
aggregateStyle.top = labelStyle.top = (height - font) / 2 + "px";
/** @type {string} */
adj.style.height = style.height = height + "px";
} else {
/** @type {string} */
aggregateStyle.top = -font - config.labelOffset + "px";
/** @type {string} */
labelStyle.top = config.labelOffset + height + "px";
/** @type {string} */
adj.style.top = parseInt(adj.style.top, 10) - height + "px";
/** @type {string} */
adj.style.height = style.height = height + "px";
}
labels.aggregate.innerHTML = aggValue !== true ? aggValue : acum;
}
}
});
var $cont = delegate.canvas.getSize();
var margin = config.Margin;
if (horz) {
/** @type {number} */
delegate.config.offsetX = $cont.width / 2 - margin.left - (config.showLabels && config.labelOffset + config.Label.size);
/** @type {number} */
delegate.config.offsetY = (margin.bottom - margin.top) / 2;
} else {
delegate.config.offsetY = -$cont.height / 2 + margin.bottom + (config.showLabels && config.labelOffset + config.Label.size);
/** @type {number} */
delegate.config.offsetX = (margin.right - margin.left) / 2;
}
this.delegate = delegate;
this.canvas = this.delegate.canvas;
},
/**
* @param {Object} json
* @return {undefined}
*/
loadJSON : function(json) {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
/** @type {number} */
var prefix = $.time();
/** @type {Array} */
var ch = [];
var delegate = this.delegate;
var name = $.splat(json.label);
var color = $.splat(json.color || this.colors);
var config = this.config;
/** @type {boolean} */
var gradient = !!config.type.split(":")[1];
var animate = config.animate;
/** @type {boolean} */
var isH = config.orientation == "horizontal";
var that = this;
/** @type {number} */
var i = 0;
var values = json.values;
var valuesLen = values.length;
for (;i < valuesLen;i++) {
var value = values[i];
var valArray = $.splat(values[i].values);
/** @type {number} */
var F = 0;
ch.push({
id : prefix + value.label,
name : value.label,
data : {
value : valArray,
"$valueArray" : valArray,
"$colorArray" : color,
"$stringArray" : name,
"$gradient" : gradient,
"$config" : config
},
children : []
});
}
var root = {
id : prefix + "$root",
name : "",
data : {
"$type" : "none",
"$width" : 1,
"$height" : 1
},
children : ch
};
delegate.loadJSON(root);
this.normalizeDims();
delegate.compute();
delegate.select(delegate.root);
if (animate) {
if (isH) {
delegate.fx.animate({
modes : ["node-property:width:dimArray"],
duration : 1500,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
}
});
} else {
delegate.fx.animate({
modes : ["node-property:height:dimArray"],
duration : 1500,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
}
});
}
} else {
/** @type {boolean} */
this.busy = false;
}
},
/**
* @param {Object} json
* @param {Object} onComplete
* @return {undefined}
*/
updateJSON : function(json, onComplete) {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
this.select(false, false, false);
var delegate = this.delegate;
var graph = delegate.graph;
var attributes = json.values;
var animate = this.config.animate;
var that = this;
/** @type {boolean} */
var isH = this.config.orientation == "horizontal";
$.each(attributes, function(v) {
var n = graph.getByName(v.label);
if (n) {
n.setData("valueArray", $.splat(v.values));
if (json.label) {
n.setData("stringArray", $.splat(json.label));
}
}
});
this.normalizeDims();
delegate.compute();
delegate.select(delegate.root);
if (animate) {
if (isH) {
delegate.fx.animate({
modes : ["node-property:width:dimArray"],
duration : 1500,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
if (onComplete) {
onComplete.onComplete();
}
}
});
} else {
delegate.fx.animate({
modes : ["node-property:height:dimArray"],
duration : 1500,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
if (onComplete) {
onComplete.onComplete();
}
}
});
}
}
},
/**
* @param {string} id
* @param {boolean} lab
* @return {undefined}
*/
select : function(id, lab) {
if (!this.config.hoveredColor) {
return;
}
var s = this.selected;
if (s.id != id || s.name != lab) {
/** @type {string} */
s.id = id;
/** @type {boolean} */
s.name = lab;
s.color = this.config.hoveredColor;
this.delegate.graph.eachNode(function(n) {
if (id == n.id) {
n.setData("border", s);
} else {
n.setData("border", false);
}
});
this.delegate.plot();
}
},
/**
* @return {?}
*/
getLegend : function() {
var legend = {};
var n;
this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(adj) {
n = adj.nodeTo;
});
var colors = n.getData("colorArray");
var colorsLen = colors.length;
$.each(n.getData("stringArray"), function(s, i) {
legend[s] = colors[i % colorsLen];
});
return legend;
},
/**
* @return {?}
*/
getMaxValue : function() {
/** @type {number} */
var maxValue = 0;
/** @type {boolean} */
var stacked = this.config.type.split(":")[0] == "stacked";
this.delegate.graph.eachNode(function(n) {
var attributes = n.getData("valueArray");
/** @type {number} */
var acum = 0;
if (!attributes) {
return;
}
if (stacked) {
$.each(attributes, function(v) {
acum += +v;
});
} else {
/** @type {number} */
acum = Math.max.apply(null, attributes);
}
maxValue = maxValue > acum ? maxValue : acum;
});
return maxValue;
},
/**
* @param {string} type
* @return {undefined}
*/
setBarType : function(type) {
/** @type {string} */
this.config.type = type;
this.delegate.config.Node.type = "barchart-" + type.split(":")[0];
},
/**
* @return {undefined}
*/
normalizeDims : function() {
var root = this.delegate.graph.getNode(this.delegate.root);
/** @type {number} */
var l = 0;
root.eachAdjacency(function() {
l++;
});
var maxValue = this.getMaxValue() || 1;
var size = this.delegate.canvas.getSize();
var config = this.config;
var margin = config.Margin;
var marginWidth = margin.left + margin.right;
var marginHeight = margin.top + margin.bottom;
/** @type {boolean} */
var horz = config.orientation == "horizontal";
/** @type {number} */
var fixedDim = (size[horz ? "height" : "width"] - (horz ? marginHeight : marginWidth) - (l - 1) * config.barsOffset) / l;
var animate = config.animate;
/** @type {number} */
var height = size[horz ? "width" : "height"] - (horz ? marginWidth : marginHeight) - (!horz && (config.showAggregates && config.Label.size + config.labelOffset)) - (config.showLabels && config.Label.size + config.labelOffset);
/** @type {string} */
var dim1 = horz ? "height" : "width";
/** @type {string} */
var dim2 = horz ? "width" : "height";
this.delegate.graph.eachNode(function(n) {
/** @type {number} */
var acum = 0;
/** @type {Array} */
var animateValue = [];
$.each(n.getData("valueArray"), function(v) {
acum += +v;
animateValue.push(0);
});
n.setData(dim1, fixedDim);
if (animate) {
n.setData(dim2, acum * height / maxValue, "end");
n.setData("dimArray", $.map(n.getData("valueArray"), function(n) {
return n * height / maxValue;
}), "end");
var dimArray = n.getData("dimArray");
if (!dimArray) {
n.setData("dimArray", animateValue);
}
} else {
n.setData(dim2, acum * height / maxValue);
n.setData("dimArray", $.map(n.getData("valueArray"), function(n) {
return n * height / maxValue;
}));
}
});
}
});
Options.PieChart = {
$extend : true,
animate : true,
offset : 25,
sliceOffset : 0,
labelOffset : 3,
type : "stacked",
hoveredColor : "#9fd4ff",
Events : {
enable : false,
/** @type {function (): undefined} */
onClick : $.empty
},
Tips : {
enable : false,
/** @type {function (): undefined} */
onShow : $.empty,
/** @type {function (): undefined} */
onHide : $.empty
},
showLabels : true,
resizeLabels : false,
updateHeights : false
};
Layout.Radial = new Class({
/**
* @param {?} adj
* @return {undefined}
*/
compute : function(adj) {
var lab = $.splat(adj || ["current", "start", "end"]);
column.compute(this.graph, lab, this.config);
this.graph.computeLevels(this.root, 0, "ignore");
var lengthFunc = this.createLevelDistanceFunc();
this.computeAngularWidths(lab);
this.computePositions(lab, lengthFunc);
},
/**
* @param {?} node
* @param {Object} getLength
* @return {undefined}
*/
computePositions : function(node, getLength) {
var employees = node;
var graph = this.graph;
var root = graph.getNode(this.root);
var parent = this.parent;
var config = this.config;
/** @type {number} */
var i = 0;
var l = employees.length;
for (;i < l;i++) {
var pi = employees[i];
root.setPos($P(0, 0), pi);
root.setData("span", Math.PI * 2, pi);
}
root.angleSpan = {
begin : 0,
end : 2 * Math.PI
};
graph.eachBFS(this.root, function(elem) {
/** @type {number} */
var angleSpan = elem.angleSpan.end - elem.angleSpan.begin;
var angleInit = elem.angleSpan.begin;
var len = getLength(elem);
/** @type {number} */
var totalAngularWidths = 0;
/** @type {Array} */
var subnodes = [];
var maxDim = {};
elem.eachSubnode(function(sib) {
totalAngularWidths += sib._treeAngularWidth;
/** @type {number} */
var i = 0;
var l = employees.length;
for (;i < l;i++) {
var pi = employees[i];
var dim = sib.getData("dim", pi);
maxDim[pi] = pi in maxDim ? dim > maxDim[pi] ? dim : maxDim[pi] : dim;
}
subnodes.push(sib);
}, "ignore");
if (parent && (parent.id == elem.id && (subnodes.length > 0 && subnodes[0].dist))) {
subnodes.sort(function(a, b) {
return(a.dist >= b.dist) - (a.dist <= b.dist);
});
}
/** @type {number} */
var i = 0;
/** @type {number} */
var valuesLen = subnodes.length;
for (;i < valuesLen;i++) {
var child = subnodes[i];
if (!child._flag) {
/** @type {number} */
var angleProportion = child._treeAngularWidth / totalAngularWidths * angleSpan;
var theta = angleInit + angleProportion / 2;
/** @type {number} */
var padIndex = 0;
var l = employees.length;
for (;padIndex < l;padIndex++) {
var pi = employees[padIndex];
child.setPos($P(theta, len), pi);
child.setData("span", angleProportion, pi);
child.setData("dim-quotient", child.getData("dim", pi) / maxDim[pi], pi);
}
child.angleSpan = {
begin : angleInit,
end : angleInit + angleProportion
};
angleInit += angleProportion;
}
}
}, "ignore");
},
/**
* @param {?} prop
* @return {undefined}
*/
setAngularWidthForNodes : function(prop) {
this.graph.eachBFS(this.root, function(elem, i) {
var diamValue = elem.getData("angularWidth", prop[0]) || 5;
/** @type {number} */
elem._angularWidth = diamValue / i;
}, "ignore");
},
/**
* @return {undefined}
*/
setSubtreesAngularWidth : function() {
var paragraph = this;
this.graph.eachNode(function(child) {
paragraph.setSubtreeAngularWidth(child);
}, "ignore");
},
/**
* @param {?} elem
* @return {undefined}
*/
setSubtreeAngularWidth : function(elem) {
var paragraph = this;
var nodeAW = elem._angularWidth;
/** @type {number} */
var sumAW = 0;
elem.eachSubnode(function(child) {
paragraph.setSubtreeAngularWidth(child);
sumAW += child._treeAngularWidth;
}, "ignore");
/** @type {number} */
elem._treeAngularWidth = Math.max(nodeAW, sumAW);
},
/**
* @param {?} prop
* @return {undefined}
*/
computeAngularWidths : function(prop) {
this.setAngularWidthForNodes(prop);
this.setSubtreesAngularWidth();
}
});
$jit.Sunburst = new Class({
Implements : [valid, Extras, Layout.Radial],
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
var $Sunburst = $jit.Sunburst;
var config = {
interpolation : "linear",
levelDistance : 100,
Node : {
type : "multipie",
height : 0
},
Edge : {
type : "none"
},
Label : {
textAlign : "start",
textBaseline : "middle"
}
};
this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller);
var canvasConfig = this.config;
if (canvasConfig.useCanvas) {
this.canvas = canvasConfig.useCanvas;
/** @type {string} */
this.config.labelContainer = this.canvas.id + "-label";
} else {
if (canvasConfig.background) {
canvasConfig.background = $.merge({
type : "Circles"
}, canvasConfig.background);
}
this.canvas = new Canvas(this, canvasConfig);
/** @type {string} */
this.config.labelContainer = (typeof canvasConfig.injectInto == "string" ? canvasConfig.injectInto : canvasConfig.injectInto.id) + "-label";
}
this.graphOptions = {
/** @type {function (number, number): undefined} */
klass : Transform,
Node : {
selected : false,
exist : true,
drawn : true
}
};
this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge);
this.labels = new $Sunburst.Label[canvasConfig.Label.type](this);
this.fx = new $Sunburst.Plot(this, $Sunburst);
this.op = new $Sunburst.Op(this);
/** @type {null} */
this.json = null;
/** @type {null} */
this.root = null;
/** @type {null} */
this.rotated = null;
/** @type {boolean} */
this.busy = false;
this.initializeExtras();
},
/**
* @return {?}
*/
createLevelDistanceFunc : function() {
var ld = this.config.levelDistance;
return function(node) {
return(node._depth + 1) * ld;
};
},
/**
* @return {undefined}
*/
refresh : function() {
this.compute();
this.plot();
},
/**
* @return {undefined}
*/
reposition : function() {
this.compute("end");
},
/**
* @param {number} node
* @param {string} method
* @param {Object} opt
* @return {undefined}
*/
rotate : function(node, method, opt) {
var theta = node.getPos(opt.property || "current").getp(true).theta;
/** @type {number} */
this.rotated = node;
this.rotateAngle(-theta, method, opt);
},
/**
* @param {number} theta
* @param {string} method
* @param {Object} opt
* @return {undefined}
*/
rotateAngle : function(theta, method, opt) {
var z = this;
var options = $.merge(this.config, opt || {}, {
modes : ["polar"]
});
var prop = opt.property || (method === "animate" ? "end" : "current");
if (method === "animate") {
this.fx.animation.pause();
}
this.graph.eachNode(function(obj) {
var p = obj.getPos(prop);
p.theta += theta;
if (p.theta < 0) {
p.theta += Math.PI * 2;
}
});
if (method == "animate") {
this.fx.animate(options);
} else {
if (method == "replot") {
this.fx.plot();
/** @type {boolean} */
this.busy = false;
}
}
},
/**
* @return {undefined}
*/
plot : function() {
this.fx.plot();
}
});
/** @type {boolean} */
$jit.Sunburst.$extend = true;
(function(Hypertree) {
Hypertree.Op = new Class({
Implements : Graph.Op
});
Hypertree.Plot = new Class({
Implements : Graph.Plot
});
Hypertree.Label = {};
Hypertree.Label.Native = new Class({
Implements : Graph.Label.Native,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
this.label = viz.config.Label;
this.config = viz.config;
},
/**
* @param {?} canvas
* @param {Object} node
* @param {?} controller
* @return {undefined}
*/
renderLabel : function(canvas, node, controller) {
var span = node.getData("span");
if (span < Math.PI / 2 && Math.tan(span) * this.config.levelDistance * node._depth < 10) {
return;
}
var ctx = canvas.getCtx();
var innerSize = ctx.measureText(node.name);
if (node.id == this.viz.root) {
/** @type {number} */
var x = -innerSize.width / 2;
/** @type {number} */
var y = 0;
/** @type {number} */
var thetap = 0;
/** @type {number} */
var ld = 0;
} else {
/** @type {number} */
var indent = 5;
/** @type {number} */
ld = controller.levelDistance - indent;
var clone = node.pos.clone();
clone.rho += indent;
var p = clone.getp(true);
var scroll = clone.getc(true);
x = scroll.x;
y = scroll.y;
/** @type {number} */
var pi = Math.PI;
/** @type {boolean} */
var cond = p.theta > pi / 2 && p.theta < 3 * pi / 2;
thetap = cond ? p.theta + pi : p.theta;
if (cond) {
x -= Math.abs(Math.cos(p.theta) * innerSize.width);
y += Math.sin(p.theta) * innerSize.width;
} else {
if (node.id == this.viz.root) {
x -= innerSize.width / 2;
}
}
}
ctx.save();
ctx.translate(x, y);
ctx.rotate(thetap);
ctx.fillText(node.name, 0, 0);
ctx.restore();
}
});
Hypertree.Label.SVG = new Class({
Implements : Graph.Label.SVG,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var offsetCoordinate = lab.pos.getc(true);
var viz = this.viz;
var canvas = this.viz.canvas;
var $cont = canvas.getSize();
var tl = {
x : Math.round(offsetCoordinate.x + $cont.width / 2),
y : Math.round(offsetCoordinate.y + $cont.height / 2)
};
from.setAttribute("x", tl.x);
from.setAttribute("y", tl.y);
var bb = from.getBBox();
if (bb) {
var x = from.getAttribute("x");
var y = from.getAttribute("y");
var p = lab.pos.getp(true);
/** @type {number} */
var pi = Math.PI;
/** @type {boolean} */
var cond = p.theta > pi / 2 && p.theta < 3 * pi / 2;
if (cond) {
from.setAttribute("x", x - bb.width);
from.setAttribute("y", y - bb.height);
} else {
if (lab.id == viz.root) {
from.setAttribute("x", x - bb.width / 2);
}
}
var thetap = cond ? p.theta + pi : p.theta;
if (lab._depth) {
from.setAttribute("transform", "rotate(" + thetap * 360 / (2 * pi) + " " + x + " " + y + ")");
}
}
options.onPlaceLabel(from, lab);
}
});
Hypertree.Label.HTML = new Class({
Implements : Graph.Label.HTML,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.clone();
var canvas = this.viz.canvas;
var height = lab.getData("height");
/** @type {number} */
var ldist = (height || lab._depth == 0 ? height : this.viz.config.levelDistance) / 2;
var $cont = canvas.getSize();
pos.rho += ldist;
pos = pos.getc(true);
var labelPos = {
x : Math.round(pos.x + $cont.width / 2),
y : Math.round(pos.y + $cont.height / 2)
};
var style = from.style;
/** @type {string} */
style.left = labelPos.x + "px";
/** @type {string} */
style.top = labelPos.y + "px";
/** @type {string} */
style.display = this.fitsInCanvas(labelPos, canvas) ? "" : "none";
options.onPlaceLabel(from, lab);
}
});
Hypertree.Plot.NodeTypes = new Class({
none : {
/** @type {function (): undefined} */
render : $.empty,
contains : $.lambda(false),
/**
* @param {Object} node
* @param {?} pos
* @return {?}
*/
anglecontains : function(node, pos) {
/** @type {number} */
var span = node.getData("span") / 2;
var theta = node.pos.theta;
/** @type {number} */
var begin = theta - span;
var end = theta + span;
if (begin < 0) {
begin += Math.PI * 2;
}
/** @type {number} */
var atan = Math.atan2(pos.y, pos.x);
if (atan < 0) {
atan += Math.PI * 2;
}
if (begin > end) {
return atan > begin && atan <= Math.PI * 2 || atan < end;
} else {
return atan > begin && atan < end;
}
}
},
pie : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
/** @type {number} */
var span = adj.getData("span") / 2;
var theta = adj.pos.theta;
/** @type {number} */
var begin = theta - span;
var end = theta + span;
var polarNode = adj.pos.getp(true);
var polar = new Transform(polarNode.rho, begin);
var p4coord = polar.getc(true);
polar.theta = end;
var endPoint = polar.getc(true);
var ctx = lab.getCtx();
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(p4coord.x, p4coord.y);
ctx.moveTo(0, 0);
ctx.lineTo(endPoint.x, endPoint.y);
ctx.moveTo(0, 0);
ctx.arc(0, 0, polarNode.rho * adj.getData("dim-quotient"), begin, end, false);
ctx.fill();
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
if (this.nodeTypes.none.anglecontains.call(this, opt_attributes, value)) {
/** @type {number} */
var rho = Math.sqrt(value.x * value.x + value.y * value.y);
var ld = this.config.levelDistance;
var d = opt_attributes._depth;
return rho <= ld * d;
}
return false;
}
},
multipie : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var height = adj.getData("height");
var ldist = height ? height : this.config.levelDistance;
/** @type {number} */
var span = adj.getData("span") / 2;
var theta = adj.pos.theta;
/** @type {number} */
var begin = theta - span;
var end = theta + span;
var polarNode = adj.pos.getp(true);
var polar = new Transform(polarNode.rho, begin);
var s1 = polar.getc(true);
polar.theta = end;
var pt1 = polar.getc(true);
polar.rho += ldist;
var p4coord = polar.getc(true);
/** @type {number} */
polar.theta = begin;
var endPoint = polar.getc(true);
var ctx = lab.getCtx();
ctx.moveTo(0, 0);
ctx.beginPath();
ctx.arc(0, 0, polarNode.rho, begin, end, false);
ctx.arc(0, 0, polarNode.rho + ldist, end, begin, true);
ctx.moveTo(s1.x, s1.y);
ctx.lineTo(endPoint.x, endPoint.y);
ctx.moveTo(pt1.x, pt1.y);
ctx.lineTo(p4coord.x, p4coord.y);
ctx.fill();
if (adj.collapsed) {
ctx.save();
/** @type {number} */
ctx.lineWidth = 2;
ctx.moveTo(0, 0);
ctx.beginPath();
ctx.arc(0, 0, polarNode.rho + ldist + 5, end - 0.01, begin + 0.01, true);
ctx.stroke();
ctx.restore();
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
if (this.nodeTypes.none.anglecontains.call(this, opt_attributes, value)) {
/** @type {number} */
var rho = Math.sqrt(value.x * value.x + value.y * value.y);
var height = opt_attributes.getData("height");
var ldist = height ? height : this.config.levelDistance;
var ld = this.config.levelDistance;
var d = opt_attributes._depth;
return rho >= ld * d && rho <= ld * d + ldist;
}
return false;
}
},
"gradient-multipie" : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var ctx = lab.getCtx();
var height = adj.getData("height");
var ldist = height ? height : this.config.levelDistance;
var radialGradient = ctx.createRadialGradient(0, 0, adj.getPos().rho, 0, 0, adj.getPos().rho + ldist);
var attributes = $.hexToRgb(adj.getData("color"));
/** @type {Array} */
var ans = [];
$.each(attributes, function(i) {
ans.push(parseInt(i * 0.5, 10));
});
var endColor = $.rgbToHex(ans);
radialGradient.addColorStop(0, endColor);
radialGradient.addColorStop(1, adj.getData("color"));
ctx.fillStyle = radialGradient;
this.nodeTypes.multipie.render.call(this, adj, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
return this.nodeTypes.multipie.contains.call(this, opt_attributes, value);
}
},
"gradient-pie" : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var ctx = lab.getCtx();
var radialGradient = ctx.createRadialGradient(0, 0, 0, 0, 0, adj.getPos().rho);
var attributes = $.hexToRgb(adj.getData("color"));
/** @type {Array} */
var ans = [];
$.each(attributes, function(i) {
ans.push(parseInt(i * 0.5, 10));
});
var endColor = $.rgbToHex(ans);
radialGradient.addColorStop(1, endColor);
radialGradient.addColorStop(0, adj.getData("color"));
ctx.fillStyle = radialGradient;
this.nodeTypes.pie.render.call(this, adj, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
return this.nodeTypes.pie.contains.call(this, opt_attributes, value);
}
}
});
Hypertree.Plot.EdgeTypes = new Class({
/** @type {function (): undefined} */
none : $.empty,
line : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var from = adj.nodeFrom.pos.getc(true);
var lab = adj.nodeTo.pos.getc(true);
this.edgeHelper.line.render(from, lab, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.nodeFrom.pos.getc(true);
var pdataOld = opt_attributes.nodeTo.pos.getc(true);
return this.edgeHelper.line.contains(attributes, pdataOld, value, this.edge.epsilon);
}
},
arrow : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var from = adj.nodeFrom.pos.getc(true);
var lab = adj.nodeTo.pos.getc(true);
var qualifier = adj.getData("dim");
var direction = adj.data.$direction;
var cycle = direction && (direction.length > 1 && direction[0] != adj.nodeFrom.id);
this.edgeHelper.arrow.render(from, lab, qualifier, cycle, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.nodeFrom.pos.getc(true);
var pdataOld = opt_attributes.nodeTo.pos.getc(true);
return this.edgeHelper.arrow.contains(attributes, pdataOld, value, this.edge.epsilon);
}
},
hyperline : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var p = adj.nodeFrom.pos.getc();
var Vec3 = adj.nodeTo.pos.getc();
/** @type {number} */
var qualifier = Math.max(p.norm(), Vec3.norm());
this.edgeHelper.hyperline.render(p.$scale(1 / qualifier), Vec3.$scale(1 / qualifier), qualifier, lab);
},
contains : $.lambda(false)
}
});
})($jit.Sunburst);
$jit.Sunburst.Plot.NodeTypes.implement({
"piechart-stacked" : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var T = adj.pos.getp(true);
var dimArray = adj.getData("dimArray");
var valueArray = adj.getData("valueArray");
var colorArray = adj.getData("colorArray");
var colorLength = colorArray.length;
var stringArray = adj.getData("stringArray");
/** @type {number} */
var span = adj.getData("span") / 2;
var theta = adj.pos.theta;
/** @type {number} */
var begin = theta - span;
var end = theta + span;
var polar = new Transform;
var ctx = lab.getCtx();
var opt = {};
var gradient = adj.getData("gradient");
var border = adj.getData("border");
var config = adj.getData("config");
var showLabels = config.showLabels;
var resizeLabels = config.resizeLabels;
var label = config.Label;
/** @type {number} */
var cx = config.sliceOffset * Math.cos((begin + end) / 2);
/** @type {number} */
var cy = config.sliceOffset * Math.sin((begin + end) / 2);
if (colorArray && (dimArray && stringArray)) {
/** @type {number} */
var i = 0;
var l = dimArray.length;
/** @type {number} */
var acum = 0;
/** @type {number} */
var X = 0;
for (;i < l;i++) {
var dimi = dimArray[i];
var color = colorArray[i % colorLength];
if (dimi <= 0) {
continue;
}
ctx.fillStyle = ctx.strokeStyle = color;
if (gradient && dimi) {
var grad = ctx.createRadialGradient(cx, cy, acum + config.sliceOffset, cx, cy, acum + dimi + config.sliceOffset);
var a = $.hexToRgb(color);
var ans = $.map(a, function(dataAndEvents) {
return dataAndEvents * 0.8 >> 0;
});
var endColor = $.rgbToHex(ans);
grad.addColorStop(0, color);
grad.addColorStop(0.5, color);
grad.addColorStop(1, endColor);
ctx.fillStyle = grad;
}
polar.rho = acum + config.sliceOffset;
/** @type {number} */
polar.theta = begin;
var ah = polar.getc(true);
polar.theta = end;
var O = polar.getc(true);
polar.rho += dimi;
var aj = polar.getc(true);
/** @type {number} */
polar.theta = begin;
var Q = polar.getc(true);
ctx.beginPath();
ctx.arc(cx, cy, acum + 0.01, begin, end, false);
ctx.arc(cx, cy, acum + dimi + 0.01, end, begin, true);
ctx.fill();
if (border && border.name == stringArray[i]) {
opt.acum = acum;
opt.dimValue = dimArray[i];
/** @type {number} */
opt.begin = begin;
opt.end = end;
}
acum += dimi || 0;
X += valueArray[i] || 0;
}
if (border) {
ctx.save();
/** @type {string} */
ctx.globalCompositeOperation = "source-over";
/** @type {number} */
ctx.lineWidth = 2;
ctx.strokeStyle = border.color;
/** @type {number} */
var aa = begin < end ? 1 : -1;
ctx.beginPath();
ctx.arc(cx, cy, opt.acum + 0.01 + 1, opt.begin, opt.end, false);
ctx.arc(cx, cy, opt.acum + opt.dimValue + 0.01 - 1, opt.end, opt.begin, true);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
if (showLabels && label.type == "Native") {
ctx.save();
ctx.fillStyle = ctx.strokeStyle = label.color;
var scale = resizeLabels ? adj.getData("normalizedDim") : 1;
/** @type {number} */
var fontSize = label.size * scale >> 0;
/** @type {number} */
fontSize = fontSize < +resizeLabels ? +resizeLabels : fontSize;
/** @type {string} */
ctx.font = label.style + " " + fontSize + "px " + label.family;
/** @type {string} */
ctx.textBaseline = "middle";
/** @type {string} */
ctx.textAlign = "center";
polar.rho = acum + config.labelOffset + config.sliceOffset;
polar.theta = adj.pos.theta;
var cart = polar.getc(true);
ctx.fillText(adj.name, cart.x, cart.y);
ctx.restore();
}
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
if (this.nodeTypes.none.anglecontains.call(this, opt_attributes, value)) {
/** @type {number} */
var rho = Math.sqrt(value.x * value.x + value.y * value.y);
var ld = this.config.levelDistance;
var d = opt_attributes._depth;
var config = opt_attributes.getData("config");
if (rho <= ld * d + config.sliceOffset) {
var dimArray = opt_attributes.getData("dimArray");
/** @type {number} */
var i = 0;
var l = dimArray.length;
var acum = config.sliceOffset;
for (;i < l;i++) {
var dimi = dimArray[i];
if (rho >= acum && rho <= acum + dimi) {
return{
name : opt_attributes.getData("stringArray")[i],
color : opt_attributes.getData("colorArray")[i],
value : opt_attributes.getData("valueArray")[i],
label : opt_attributes.name
};
}
acum += dimi;
}
}
return false;
}
return false;
}
}
});
$jit.PieChart = new Class({
sb : null,
colors : ["#416D9C", "#70A35E", "#EBB056", "#C74243", "#83548B", "#909291", "#557EAA"],
selected : {},
busy : false,
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
this.controller = this.config = $.merge(Options("Canvas", "PieChart", "Label"), {
Label : {
type : "Native"
}
}, controller);
this.initializeViz();
},
/**
* @return {undefined}
*/
initializeViz : function() {
var config = this.config;
var that = this;
var nodeType = config.type.split(":")[0];
var delegate = new $jit.Sunburst({
injectInto : config.injectInto,
width : config.width,
height : config.height,
useCanvas : config.useCanvas,
withLabels : config.Label.type != "Native",
Label : {
type : config.Label.type
},
Node : {
overridable : true,
type : "piechart-" + nodeType,
width : 1,
height : 1
},
Edge : {
type : "none"
},
Tips : {
enable : config.Tips.enable,
type : "Native",
force : true,
/**
* @param {?} from
* @param {?} type
* @param {?} event
* @return {undefined}
*/
onShow : function(from, type, event) {
var lab = event;
config.Tips.onShow(from, lab, type);
}
},
Events : {
enable : true,
type : "Native",
/**
* @param {?} adj
* @param {?} lab
* @param {?} selector
* @return {undefined}
*/
onClick : function(adj, lab, selector) {
if (!config.Events.enable) {
return;
}
var from = lab.getContains();
config.Events.onClick(from, lab, selector);
},
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
onMouseMove : function(adj, lab, event) {
if (!config.hoveredColor) {
return;
}
if (adj) {
var elem = lab.getContains();
that.select(adj.id, elem.name, elem.index);
} else {
that.select(false, false, false);
}
}
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onCreateLabel : function(adj, lab) {
var labelConf = config.Label;
if (config.showLabels) {
var wrapperStyle = adj.style;
/** @type {string} */
wrapperStyle.fontSize = labelConf.size + "px";
wrapperStyle.fontFamily = labelConf.family;
wrapperStyle.color = labelConf.color;
/** @type {string} */
wrapperStyle.textAlign = "center";
adj.innerHTML = lab.name;
}
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onPlaceLabel : function(adj, lab) {
if (!config.showLabels) {
return;
}
var offsetCoordinate = lab.pos.getp(true);
var dimArray = lab.getData("dimArray");
/** @type {number} */
var span = lab.getData("span") / 2;
var theta = lab.pos.theta;
/** @type {number} */
var begin = theta - span;
var end = theta + span;
var polar = new Transform;
var showLabels = config.showLabels;
var resizeLabels = config.resizeLabels;
var label = config.Label;
if (dimArray) {
/** @type {number} */
var i = 0;
var l = dimArray.length;
/** @type {number} */
var acum = 0;
for (;i < l;i++) {
acum += dimArray[i];
}
var scale = resizeLabels ? lab.getData("normalizedDim") : 1;
/** @type {number} */
var fontSize = label.size * scale >> 0;
/** @type {number} */
fontSize = fontSize < +resizeLabels ? +resizeLabels : fontSize;
/** @type {string} */
adj.style.fontSize = fontSize + "px";
polar.rho = acum + config.labelOffset + config.sliceOffset;
/** @type {number} */
polar.theta = (begin + end) / 2;
offsetCoordinate = polar.getc(true);
var $cont = that.canvas.getSize();
var pos = {
x : Math.round(offsetCoordinate.x + $cont.width / 2),
y : Math.round(offsetCoordinate.y + $cont.height / 2)
};
/** @type {string} */
adj.style.left = pos.x + "px";
/** @type {string} */
adj.style.top = pos.y + "px";
}
}
});
var size = delegate.canvas.getSize();
/** @type {function (...[*]): number} */
var min = Math.min;
/** @type {number} */
delegate.config.levelDistance = min(size.width, size.height) / 2 - config.offset - config.sliceOffset;
this.delegate = delegate;
this.canvas = this.delegate.canvas;
/** @type {string} */
this.canvas.getCtx().globalCompositeOperation = "lighter";
},
/**
* @param {Object} json
* @return {undefined}
*/
loadJSON : function(json) {
/** @type {number} */
var prefix = $.time();
/** @type {Array} */
var ch = [];
var delegate = this.delegate;
var resolveValues = $.splat(json.label);
var length = resolveValues.length;
var color = $.splat(json.color || this.colors);
var colorLength = color.length;
var config = this.config;
/** @type {boolean} */
var gradient = !!config.type.split(":")[1];
var animate = config.animate;
/** @type {boolean} */
var mono = length == 1;
/** @type {number} */
var i = 0;
var values = json.values;
var valuesLen = values.length;
for (;i < valuesLen;i++) {
var val = values[i];
var valArray = $.splat(val.values);
ch.push({
id : prefix + val.label,
name : val.label,
data : {
value : valArray,
"$valueArray" : valArray,
"$colorArray" : mono ? $.splat(color[i % colorLength]) : color,
"$stringArray" : resolveValues,
"$gradient" : gradient,
"$config" : config,
"$angularWidth" : $.reduce(valArray, function(far, near) {
return far + near;
})
},
children : []
});
}
var root = {
id : prefix + "$root",
name : "",
data : {
"$type" : "none",
"$width" : 1,
"$height" : 1
},
children : ch
};
delegate.loadJSON(root);
this.normalizeDims();
delegate.refresh();
if (animate) {
delegate.fx.animate({
modes : ["node-property:dimArray"],
duration : 1500
});
}
},
/**
* @param {Object} json
* @param {Object} onComplete
* @return {undefined}
*/
updateJSON : function(json, onComplete) {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
var delegate = this.delegate;
var graph = delegate.graph;
var attributes = json.values;
var animate = this.config.animate;
var that = this;
$.each(attributes, function(v) {
var n = graph.getByName(v.label);
var vals = $.splat(v.values);
if (n) {
n.setData("valueArray", vals);
n.setData("angularWidth", $.reduce(vals, function(far, near) {
return far + near;
}));
if (json.label) {
n.setData("stringArray", $.splat(json.label));
}
}
});
this.normalizeDims();
if (animate) {
delegate.compute("end");
delegate.fx.animate({
modes : ["node-property:dimArray:span", "linear"],
duration : 1500,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
if (onComplete) {
onComplete.onComplete();
}
}
});
} else {
delegate.refresh();
}
},
/**
* @param {?} id
* @param {boolean} lab
* @return {undefined}
*/
select : function(id, lab) {
if (!this.config.hoveredColor) {
return;
}
var s = this.selected;
if (s.id != id || s.name != lab) {
s.id = id;
/** @type {boolean} */
s.name = lab;
s.color = this.config.hoveredColor;
this.delegate.graph.eachNode(function(n) {
if (id == n.id) {
n.setData("border", s);
} else {
n.setData("border", false);
}
});
this.delegate.plot();
}
},
/**
* @return {?}
*/
getLegend : function() {
var legend = {};
var n;
this.delegate.graph.getNode(this.delegate.root).eachAdjacency(function(adj) {
n = adj.nodeTo;
});
var colors = n.getData("colorArray");
var colorsLen = colors.length;
$.each(n.getData("stringArray"), function(s, i) {
legend[s] = colors[i % colorsLen];
});
return legend;
},
/**
* @return {?}
*/
getMaxValue : function() {
/** @type {number} */
var maxValue = 0;
this.delegate.graph.eachNode(function(n) {
var attributes = n.getData("valueArray");
/** @type {number} */
var acum = 0;
$.each(attributes, function(v) {
acum += +v;
});
maxValue = maxValue > acum ? maxValue : acum;
});
return maxValue;
},
/**
* @return {undefined}
*/
normalizeDims : function() {
var root = this.delegate.graph.getNode(this.delegate.root);
/** @type {number} */
var w = 0;
root.eachAdjacency(function() {
w++;
});
var maxValue = this.getMaxValue() || 1;
var config = this.config;
var animate = config.animate;
var rho = this.delegate.config.levelDistance;
this.delegate.graph.eachNode(function(n) {
/** @type {number} */
var acum = 0;
/** @type {Array} */
var animateValue = [];
$.each(n.getData("valueArray"), function(v) {
acum += +v;
animateValue.push(1);
});
/** @type {boolean} */
var stat = animateValue.length == 1 && !config.updateHeights;
if (animate) {
n.setData("dimArray", $.map(n.getData("valueArray"), function(n) {
return stat ? rho : n * rho / maxValue;
}), "end");
var dimArray = n.getData("dimArray");
if (!dimArray) {
n.setData("dimArray", animateValue);
}
} else {
n.setData("dimArray", $.map(n.getData("valueArray"), function(n) {
return stat ? rho : n * rho / maxValue;
}));
}
n.setData("normalizedDim", acum / maxValue);
});
}
});
Layout.TM = {};
Layout.TM.SliceAndDice = new Class({
/**
* @param {?} adj
* @return {undefined}
*/
compute : function(adj) {
var from = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root);
this.controller.onBeforeCompute(from);
var size = this.canvas.getSize();
var config = this.config;
var width = size.width;
var height = size.height;
this.graph.computeLevels(this.root, 0, "ignore");
from.getPos(adj).setc(-width / 2, -height / 2);
from.setData("width", width, adj);
from.setData("height", height + config.titleHeight, adj);
this.computePositions(from, from, this.layout.orientation, adj);
this.controller.onAfterCompute(from);
},
/**
* @param {?} node
* @param {Object} ch
* @param {string} orn
* @param {Object} prop
* @return {undefined}
*/
computePositions : function(node, ch, orn, prop) {
/** @type {number} */
var totalArea = 0;
node.eachSubnode(function(n) {
totalArea += n.getData("area", prop);
});
var config = this.config;
var offset = config.offset;
var val = node.getData("width", prop);
/** @type {number} */
var value = Math.max(node.getData("height", prop) - config.titleHeight, 0);
/** @type {number} */
var pow = node == ch ? 1 : ch.getData("area", prop) / totalArea;
var result;
var size;
var dim;
var pos;
var pos2;
var posth;
var pos2th;
/** @type {boolean} */
var horizontal = orn == "h";
if (horizontal) {
/** @type {string} */
orn = "v";
/** @type {number} */
result = value;
/** @type {number} */
size = val * pow;
/** @type {string} */
dim = "height";
/** @type {string} */
pos = "y";
/** @type {string} */
pos2 = "x";
posth = config.titleHeight;
/** @type {number} */
pos2th = 0;
} else {
/** @type {string} */
orn = "h";
/** @type {number} */
result = value * pow;
size = val;
/** @type {string} */
dim = "width";
/** @type {string} */
pos = "x";
/** @type {string} */
pos2 = "y";
/** @type {number} */
posth = 0;
pos2th = config.titleHeight;
}
var cpos = ch.getPos(prop);
ch.setData("width", size, prop);
ch.setData("height", result, prop);
/** @type {number} */
var offsetSize = 0;
var tm = this;
ch.eachSubnode(function(n) {
var p = n.getPos(prop);
p[pos] = offsetSize + cpos[pos] + posth;
p[pos2] = cpos[pos2] + pos2th;
tm.computePositions(ch, n, orn, prop);
offsetSize += n.getData(dim, prop);
});
}
});
Layout.TM.Area = {
/**
* @param {string} adj
* @return {undefined}
*/
compute : function(adj) {
adj = adj || "current";
var from = this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root);
this.controller.onBeforeCompute(from);
var config = this.config;
var cs = this.canvas.getSize();
var len = cs.width;
var h = cs.height;
var start = config.offset;
/** @type {number} */
var size = len - start;
/** @type {number} */
var offhght = h - start;
this.graph.computeLevels(this.root, 0, "ignore");
from.getPos(adj).setc(-len / 2, -h / 2);
from.setData("width", len, adj);
from.setData("height", h, adj);
var coord = {
top : -h / 2 + config.titleHeight,
left : -len / 2,
width : size,
height : offhght - config.titleHeight
};
this.computePositions(from, coord, adj);
this.controller.onAfterCompute(from);
},
/**
* @param {string} tail
* @param {?} initElem
* @param {number} w
* @param {?} coord
* @param {?} comp
* @param {Object} prop
* @return {undefined}
*/
computeDim : function(tail, initElem, w, coord, comp, prop) {
if (tail.length + initElem.length == 1) {
var l = tail.length == 1 ? tail : initElem;
this.layoutLast(l, w, coord, prop);
return;
}
if (tail.length >= 2 && initElem.length == 0) {
/** @type {Array} */
initElem = [tail.shift()];
}
if (tail.length == 0) {
if (initElem.length > 0) {
this.layoutRow(initElem, w, coord, prop);
}
return;
}
var c = tail[0];
if (comp(initElem, w) >= comp([c].concat(initElem), w)) {
this.computeDim(tail.slice(1), initElem.concat([c]), w, coord, comp, prop);
} else {
var newCoords = this.layoutRow(initElem, w, coord, prop);
this.computeDim(tail, [], newCoords.dim, newCoords, comp, prop);
}
},
/**
* @param {Array} ch
* @param {number} w
* @return {?}
*/
worstAspectRatio : function(ch, w) {
if (!ch || ch.length == 0) {
return Number.MAX_VALUE;
}
/** @type {number} */
var areaSum = 0;
/** @type {number} */
var maxArea = 0;
/** @type {number} */
var minArea = Number.MAX_VALUE;
/** @type {number} */
var i = 0;
var l = ch.length;
for (;i < l;i++) {
var area = ch[i]._area;
areaSum += area;
minArea = minArea < area ? minArea : area;
maxArea = maxArea > area ? maxArea : area;
}
/** @type {number} */
var sqw = w * w;
/** @type {number} */
var sqAreaSum = areaSum * areaSum;
return Math.max(sqw * maxArea / sqAreaSum, sqAreaSum / (sqw * minArea));
},
/**
* @param {Array} ch
* @param {number} w
* @return {?}
*/
avgAspectRatio : function(ch, w) {
if (!ch || ch.length == 0) {
return Number.MAX_VALUE;
}
/** @type {number} */
var sum = 0;
/** @type {number} */
var i = 0;
var len = ch.length;
for (;i < len;i++) {
var area = ch[i]._area;
/** @type {number} */
var h = area / w;
sum += w > h ? w / h : h / w;
}
return sum / len;
},
/**
* @param {Array} ch
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {undefined}
*/
layoutLast : function(ch, w, coord, prop) {
var child = ch[0];
child.getPos(prop).setc(coord.left, coord.top);
child.setData("width", coord.width, prop);
child.setData("height", coord.height, prop);
}
};
Layout.TM.Squarified = new Class({
Implements : Layout.TM.Area,
/**
* @param {?} node
* @param {Object} coord
* @param {Object} prop
* @return {undefined}
*/
computePositions : function(node, coord, prop) {
var config = this.config;
/** @type {function (...[*]): number} */
var max = Math.max;
if (coord.width >= coord.height) {
/** @type {string} */
this.layout.orientation = "h";
} else {
/** @type {string} */
this.layout.orientation = "v";
}
var ch = node.getSubnodes([1, 1], "ignore");
if (ch.length > 0) {
this.processChildrenLayout(node, ch, coord, prop);
/** @type {number} */
var i = 0;
var l = ch.length;
for (;i < l;i++) {
var chi = ch[i];
var offst = config.offset;
/** @type {number} */
var height = max(chi.getData("height", prop) - offst - config.titleHeight, 0);
/** @type {number} */
var width = max(chi.getData("width", prop) - offst, 0);
var chipos = chi.getPos(prop);
coord = {
width : width,
height : height,
top : chipos.y + config.titleHeight,
left : chipos.x
};
this.computePositions(chi, coord, prop);
}
}
},
/**
* @param {?} dataAndEvents
* @param {Array} ch
* @param {Object} coord
* @param {Object} prop
* @return {undefined}
*/
processChildrenLayout : function(dataAndEvents, ch, coord, prop) {
/** @type {number} */
var parentArea = coord.width * coord.height;
var i;
var l = ch.length;
/** @type {number} */
var totalChArea = 0;
/** @type {Array} */
var chArea = [];
/** @type {number} */
i = 0;
for (;i < l;i++) {
/** @type {number} */
chArea[i] = parseFloat(ch[i].getData("area", prop));
totalChArea += chArea[i];
}
/** @type {number} */
i = 0;
for (;i < l;i++) {
/** @type {number} */
ch[i]._area = parentArea * chArea[i] / totalChArea;
}
var minimumSideValue = this.layout.horizontal() ? coord.height : coord.width;
ch.sort(function(b, a) {
/** @type {number} */
var firstByIndex = a._area - b._area;
return firstByIndex ? firstByIndex : a.id == b.id ? 0 : a.id < b.id ? 1 : -1;
});
/** @type {Array} */
var initElem = [ch[0]];
var tail = ch.slice(1);
this.squarify(tail, initElem, minimumSideValue, coord, prop);
},
/**
* @param {string} tail
* @param {?} initElem
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {undefined}
*/
squarify : function(tail, initElem, w, coord, prop) {
this.computeDim(tail, initElem, w, coord, this.worstAspectRatio, prop);
},
/**
* @param {?} opt_attributes
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {?}
*/
layoutRow : function(opt_attributes, w, coord, prop) {
if (this.layout.horizontal()) {
return this.layoutV(opt_attributes, w, coord, prop);
} else {
return this.layoutH(opt_attributes, w, coord, prop);
}
},
/**
* @param {?} attributes
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {?}
*/
layoutV : function(attributes, w, coord, prop) {
/** @type {number} */
var totalArea = 0;
/**
* @param {number} x
* @return {?}
*/
var rnd = function(x) {
return x;
};
$.each(attributes, function(elem) {
totalArea += elem._area;
});
var width = rnd(totalArea / w);
/** @type {number} */
var top = 0;
/** @type {number} */
var i = 0;
var aLength = attributes.length;
for (;i < aLength;i++) {
var h = rnd(attributes[i]._area / width);
var chi = attributes[i];
chi.getPos(prop).setc(coord.left, coord.top + top);
chi.setData("width", width, prop);
chi.setData("height", h, prop);
top += h;
}
var ans = {
height : coord.height,
width : coord.width - width,
top : coord.top,
left : coord.left + width
};
/** @type {number} */
ans.dim = Math.min(ans.width, ans.height);
if (ans.dim != ans.height) {
this.layout.change();
}
return ans;
},
/**
* @param {?} attributes
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {?}
*/
layoutH : function(attributes, w, coord, prop) {
/** @type {number} */
var totalArea = 0;
$.each(attributes, function(elem) {
totalArea += elem._area;
});
/** @type {number} */
var height = totalArea / w;
var top = coord.top;
/** @type {number} */
var left = 0;
/** @type {number} */
var i = 0;
var aLength = attributes.length;
for (;i < aLength;i++) {
var chi = attributes[i];
/** @type {number} */
w = chi._area / height;
chi.getPos(prop).setc(coord.left + left, top);
chi.setData("width", w, prop);
chi.setData("height", height, prop);
left += w;
}
var ans = {
height : coord.height - height,
width : coord.width,
top : coord.top + height,
left : coord.left
};
/** @type {number} */
ans.dim = Math.min(ans.width, ans.height);
if (ans.dim != ans.width) {
this.layout.change();
}
return ans;
}
});
Layout.TM.Strip = new Class({
Implements : Layout.TM.Area,
/**
* @param {?} node
* @param {Object} coord
* @param {Object} prop
* @return {undefined}
*/
computePositions : function(node, coord, prop) {
var ch = node.getSubnodes([1, 1], "ignore");
var config = this.config;
/** @type {function (...[*]): number} */
var max = Math.max;
if (ch.length > 0) {
this.processChildrenLayout(node, ch, coord, prop);
/** @type {number} */
var i = 0;
var l = ch.length;
for (;i < l;i++) {
var chi = ch[i];
var offst = config.offset;
/** @type {number} */
var height = max(chi.getData("height", prop) - offst - config.titleHeight, 0);
/** @type {number} */
var width = max(chi.getData("width", prop) - offst, 0);
var chipos = chi.getPos(prop);
coord = {
width : width,
height : height,
top : chipos.y + config.titleHeight,
left : chipos.x
};
this.computePositions(chi, coord, prop);
}
}
},
/**
* @param {?} dataAndEvents
* @param {Array} ch
* @param {Object} coord
* @param {Object} prop
* @return {undefined}
*/
processChildrenLayout : function(dataAndEvents, ch, coord, prop) {
/** @type {number} */
var parentArea = coord.width * coord.height;
var i;
var l = ch.length;
/** @type {number} */
var totalChArea = 0;
/** @type {Array} */
var chArea = [];
/** @type {number} */
i = 0;
for (;i < l;i++) {
/** @type {number} */
chArea[i] = +ch[i].getData("area", prop);
totalChArea += chArea[i];
}
/** @type {number} */
i = 0;
for (;i < l;i++) {
/** @type {number} */
ch[i]._area = parentArea * chArea[i] / totalChArea;
}
var side = this.layout.horizontal() ? coord.width : coord.height;
/** @type {Array} */
var initElem = [ch[0]];
var tail = ch.slice(1);
this.stripify(tail, initElem, side, coord, prop);
},
/**
* @param {string} tail
* @param {?} initElem
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {undefined}
*/
stripify : function(tail, initElem, w, coord, prop) {
this.computeDim(tail, initElem, w, coord, this.avgAspectRatio, prop);
},
/**
* @param {?} opt_attributes
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {?}
*/
layoutRow : function(opt_attributes, w, coord, prop) {
if (this.layout.horizontal()) {
return this.layoutH(opt_attributes, w, coord, prop);
} else {
return this.layoutV(opt_attributes, w, coord, prop);
}
},
/**
* @param {?} attributes
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {?}
*/
layoutV : function(attributes, w, coord, prop) {
/** @type {number} */
var totalArea = 0;
$.each(attributes, function(elem) {
totalArea += elem._area;
});
/** @type {number} */
var width = totalArea / w;
/** @type {number} */
var top = 0;
/** @type {number} */
var i = 0;
var aLength = attributes.length;
for (;i < aLength;i++) {
var chi = attributes[i];
/** @type {number} */
var h = chi._area / width;
chi.getPos(prop).setc(coord.left, coord.top + (w - h - top));
chi.setData("width", width, prop);
chi.setData("height", h, prop);
top += h;
}
return{
height : coord.height,
width : coord.width - width,
top : coord.top,
left : coord.left + width,
dim : w
};
},
/**
* @param {?} attributes
* @param {number} w
* @param {?} coord
* @param {Object} prop
* @return {?}
*/
layoutH : function(attributes, w, coord, prop) {
/** @type {number} */
var totalArea = 0;
$.each(attributes, function(elem) {
totalArea += elem._area;
});
/** @type {number} */
var height = totalArea / w;
/** @type {number} */
var top = coord.height - height;
/** @type {number} */
var left = 0;
/** @type {number} */
var i = 0;
var aLength = attributes.length;
for (;i < aLength;i++) {
var chi = attributes[i];
/** @type {number} */
var width = chi._area / height;
chi.getPos(prop).setc(coord.left + left, coord.top + top);
chi.setData("width", width, prop);
chi.setData("height", height, prop);
left += width;
}
return{
height : coord.height - height,
width : coord.width,
top : coord.top,
left : coord.left,
dim : w
};
}
});
Layout.Icicle = new Class({
/**
* @param {?} adj
* @return {undefined}
*/
compute : function(adj) {
adj = adj || "current";
var from = this.graph.getNode(this.root);
var config = this.config;
var size = this.canvas.getSize();
var width = size.width;
var height = size.height;
var offset = config.offset;
var parentWidth = config.constrained ? config.levelsToShow : Number.MAX_VALUE;
this.controller.onBeforeCompute(from);
Graph.Util.computeLevels(this.graph, from.id, 0, "ignore");
/** @type {number} */
var treeDepth = 0;
Graph.Util.eachLevel(from, 0, false, function(dataAndEvents, d) {
if (d > treeDepth) {
/** @type {number} */
treeDepth = d;
}
});
var startNode = this.graph.getNode(this.clickedNode && this.clickedNode.id || from.id);
/** @type {number} */
var maxDepth = Math.min(treeDepth, parentWidth - 1);
var initialDepth = startNode._depth;
if (this.layout.horizontal()) {
this.computeSubtree(startNode, -width / 2, -height / 2, width / (maxDepth + 1), height, initialDepth, maxDepth, adj);
} else {
this.computeSubtree(startNode, -width / 2, -height / 2, width, height / (maxDepth + 1), initialDepth, maxDepth, adj);
}
},
/**
* @param {Object} root
* @param {number} x
* @param {number} y
* @param {number} width
* @param {number} height
* @param {?} initialDepth
* @param {number} maxDepth
* @param {Object} prop
* @return {undefined}
*/
computeSubtree : function(root, x, y, width, height, initialDepth, maxDepth, prop) {
root.getPos(prop).setc(x, y);
root.setData("width", width, prop);
root.setData("height", height, prop);
var nodeLength;
/** @type {number} */
var K = 0;
/** @type {number} */
var totalDim = 0;
var attributes = Graph.Util.getSubnodes(root, [1, 1], "ignore");
if (!attributes.length) {
return;
}
$.each(attributes, function(e) {
totalDim += e.getData("dim");
});
/** @type {number} */
var i = 0;
var aLength = attributes.length;
for (;i < aLength;i++) {
if (this.layout.horizontal()) {
/** @type {number} */
nodeLength = height * attributes[i].getData("dim") / totalDim;
this.computeSubtree(attributes[i], x + width, y, width, nodeLength, initialDepth, maxDepth, prop);
y += nodeLength;
} else {
/** @type {number} */
nodeLength = width * attributes[i].getData("dim") / totalDim;
this.computeSubtree(attributes[i], x, y + height, nodeLength, height, initialDepth, maxDepth, prop);
x += nodeLength;
}
}
}
});
$jit.Icicle = new Class({
Implements : [valid, Extras, Layout.Icicle],
layout : {
orientation : "h",
/**
* @return {?}
*/
vertical : function() {
return this.orientation == "v";
},
/**
* @return {?}
*/
horizontal : function() {
return this.orientation == "h";
},
/**
* @return {undefined}
*/
change : function() {
/** @type {string} */
this.orientation = this.vertical() ? "h" : "v";
}
},
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
var config = {
animate : false,
orientation : "h",
offset : 2,
levelsToShow : Number.MAX_VALUE,
constrained : false,
Node : {
type : "rectangle",
overridable : true
},
Edge : {
type : "none"
},
Label : {
type : "Native"
},
duration : 700,
fps : 45
};
var opts = Options("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label");
this.controller = this.config = $.merge(opts, config, controller);
this.layout.orientation = this.config.orientation;
var canvasConfig = this.config;
if (canvasConfig.useCanvas) {
this.canvas = canvasConfig.useCanvas;
/** @type {string} */
this.config.labelContainer = this.canvas.id + "-label";
} else {
this.canvas = new Canvas(this, canvasConfig);
/** @type {string} */
this.config.labelContainer = (typeof canvasConfig.injectInto == "string" ? canvasConfig.injectInto : canvasConfig.injectInto.id) + "-label";
}
this.graphOptions = {
/** @type {function (number, (number|string)): undefined} */
klass : Vector,
Node : {
selected : false,
exist : true,
drawn : true
}
};
this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge, this.config.Label);
this.labels = new $jit.Icicle.Label[this.config.Label.type](this);
this.fx = new $jit.Icicle.Plot(this, $jit.Icicle);
this.op = new $jit.Icicle.Op(this);
this.group = new $jit.Icicle.Group(this);
/** @type {null} */
this.clickedNode = null;
this.initializeExtras();
},
/**
* @return {undefined}
*/
refresh : function() {
var type = this.config.Label.type;
if (type != "Native") {
var that = this;
this.graph.eachNode(function(from) {
that.labels.hideLabel(from, false);
});
}
this.compute();
this.plot();
},
/**
* @return {undefined}
*/
plot : function() {
this.fx.plot(this.config);
},
/**
* @param {?} node
* @return {undefined}
*/
enter : function(node) {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
var that = this;
var config = this.config;
var callback = {
/**
* @return {undefined}
*/
onComplete : function() {
if (config.request) {
that.compute();
}
if (config.animate) {
that.graph.nodeList.setDataset(["current", "end"], {
alpha : [1, 0]
});
Graph.Util.eachSubgraph(node, function(n) {
n.setData("alpha", 1, "end");
}, "ignore");
that.fx.animate({
duration : 500,
modes : ["node-property:alpha"],
/**
* @return {undefined}
*/
onComplete : function() {
that.clickedNode = node;
that.compute("end");
that.fx.animate({
modes : ["linear", "node-property:width:height"],
duration : 1E3,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
that.clickedNode = node;
}
});
}
});
} else {
that.clickedNode = node;
/** @type {boolean} */
that.busy = false;
that.refresh();
}
}
};
if (config.request) {
this.requestNodes(clickedNode, callback);
} else {
callback.onComplete();
}
},
/**
* @return {undefined}
*/
out : function() {
if (this.busy) {
return;
}
var that = this;
var GUtil = Graph.Util;
var config = this.config;
var graph = this.graph;
var args = GUtil.getParents(graph.getNode(this.clickedNode && this.clickedNode.id || this.root));
var parent = args[0];
var clickedNode = parent;
var previousClickedNode = this.clickedNode;
/** @type {boolean} */
this.busy = true;
/** @type {boolean} */
this.events.hoveredNode = false;
if (!parent) {
/** @type {boolean} */
this.busy = false;
return;
}
callback = {
/**
* @return {undefined}
*/
onComplete : function() {
that.clickedNode = parent;
if (config.request) {
that.requestNodes(parent, {
/**
* @return {undefined}
*/
onComplete : function() {
that.compute();
that.plot();
/** @type {boolean} */
that.busy = false;
}
});
} else {
that.compute();
that.plot();
/** @type {boolean} */
that.busy = false;
}
}
};
if (config.animate) {
this.clickedNode = clickedNode;
this.compute("end");
this.clickedNode = previousClickedNode;
this.fx.animate({
modes : ["linear", "node-property:width:height"],
duration : 1E3,
/**
* @return {undefined}
*/
onComplete : function() {
that.clickedNode = clickedNode;
graph.nodeList.setDataset(["current", "end"], {
alpha : [0, 1]
});
GUtil.eachSubgraph(previousClickedNode, function(n) {
n.setData("alpha", 1);
}, "ignore");
that.fx.animate({
duration : 500,
modes : ["node-property:alpha"],
/**
* @return {undefined}
*/
onComplete : function() {
callback.onComplete();
}
});
}
});
} else {
callback.onComplete();
}
},
/**
* @param {?} node
* @param {?} onComplete
* @return {undefined}
*/
requestNodes : function(node, onComplete) {
var handler = $.merge(this.controller, onComplete);
var recurring = this.config.constrained ? this.config.levelsToShow : Number.MAX_VALUE;
if (handler.request) {
/** @type {Array} */
var leaves = [];
var d = node._depth;
Graph.Util.eachLevel(node, 0, recurring, function(n) {
if (n.drawn && !Graph.Util.anySubnode(n)) {
leaves.push(n);
/** @type {number} */
n._level = n._depth - d;
if (this.config.constrained) {
/** @type {number} */
n._level = recurring - n._level;
}
}
});
this.group.requestNodes(leaves, handler);
} else {
handler.onComplete();
}
}
});
$jit.Icicle.Op = new Class({
Implements : Graph.Op
});
$jit.Icicle.Group = new Class({
/**
* @param {Object} viz
* @return {undefined}
*/
initialize : function(viz) {
/** @type {Object} */
this.viz = viz;
this.canvas = viz.canvas;
this.config = viz.config;
},
/**
* @param {Array} nodes
* @param {?} controller
* @return {undefined}
*/
requestNodes : function(nodes, controller) {
/** @type {number} */
var counter = 0;
var len = nodes.length;
var nodeSelected = {};
/**
* @return {undefined}
*/
var complete = function() {
controller.onComplete();
};
var viz = this.viz;
if (len == 0) {
complete();
}
/** @type {number} */
var i = 0;
for (;i < len;i++) {
nodeSelected[nodes[i].id] = nodes[i];
controller.request(nodes[i].id, nodes[i]._level, {
/**
* @param {number} adj
* @param {?} lab
* @return {undefined}
*/
onComplete : function(adj, lab) {
if (lab && lab.children) {
/** @type {number} */
lab.id = adj;
viz.op.sum(lab, {
type : "nothing"
});
}
if (++counter == len) {
Graph.Util.computeLevels(viz.graph, viz.root, 0);
complete();
}
}
});
}
}
});
$jit.Icicle.Plot = new Class({
Implements : Graph.Plot,
/**
* @param {?} opt
* @param {boolean} animating
* @return {undefined}
*/
plot : function(opt, animating) {
opt = opt || this.viz.controller;
var viz = this.viz;
var graph = viz.graph;
var root = graph.getNode(viz.clickedNode && viz.clickedNode.id || viz.root);
var initialDepth = root._depth;
viz.canvas.clear();
this.plotTree(root, $.merge(opt, {
withLabels : true,
hideLabels : false,
/**
* @param {?} dataAndEvents
* @param {Object} node
* @return {?}
*/
plotSubtree : function(dataAndEvents, node) {
return!viz.config.constrained || node._depth - initialDepth < viz.config.levelsToShow;
}
}), animating);
}
});
$jit.Icicle.Label = {};
$jit.Icicle.Label.Native = new Class({
Implements : Graph.Label.Native,
/**
* @param {?} canvas
* @param {Object} node
* @param {?} opt
* @return {undefined}
*/
renderLabel : function(canvas, node, opt) {
var ctx = canvas.getCtx();
var width = node.getData("width");
var height = node.getData("height");
var size = node.getLabelData("size");
var bbox = ctx.measureText(node.name);
if (height < size * 1.5 || width < bbox.width) {
return;
}
var pos = node.pos.getc(true);
ctx.fillText(node.name, pos.x + width / 2, pos.y + height / 2);
}
});
$jit.Icicle.Label.SVG = new Class({
Implements : Graph.Label.SVG,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var offsetCoordinate = lab.pos.getc(true);
var canvas = this.viz.canvas;
var $cont = canvas.getSize();
var tl = {
x : Math.round(offsetCoordinate.x + $cont.width / 2),
y : Math.round(offsetCoordinate.y + $cont.height / 2)
};
from.setAttribute("x", tl.x);
from.setAttribute("y", tl.y);
options.onPlaceLabel(from, lab);
}
});
$jit.Icicle.Label.HTML = new Class({
Implements : Graph.Label.HTML,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var offsetCoordinate = lab.pos.getc(true);
var canvas = this.viz.canvas;
var $cont = canvas.getSize();
var pos = {
x : Math.round(offsetCoordinate.x + $cont.width / 2),
y : Math.round(offsetCoordinate.y + $cont.height / 2)
};
var aggregateStyle = from.style;
/** @type {string} */
aggregateStyle.left = pos.x + "px";
/** @type {string} */
aggregateStyle.top = pos.y + "px";
/** @type {string} */
aggregateStyle.display = "";
options.onPlaceLabel(from, lab);
}
});
$jit.Icicle.Plot.NodeTypes = new Class({
none : {
/** @type {function (): undefined} */
render : $.empty
},
rectangle : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
render : function(adj, lab, event) {
var config = this.viz.config;
var offset = config.offset;
var width = adj.getData("width");
var height = adj.getData("height");
var border = adj.getData("border");
var pos = adj.pos.getc(true);
var posx = pos.x + offset / 2;
var posy = pos.y + offset / 2;
var ctx = lab.getCtx();
if (width - offset < 2 || height - offset < 2) {
return;
}
if (config.cushion) {
var color = adj.getData("color");
var gradient = ctx.createRadialGradient(posx + (width - offset) / 2, posy + (height - offset) / 2, 1, posx + (width - offset) / 2, posy + (height - offset) / 2, width < height ? height : width);
var fgcolor = $.rgbToHex($.map($.hexToRgb(color), function(dataAndEvents) {
return dataAndEvents * 0.3 >> 0;
}));
gradient.addColorStop(0, color);
gradient.addColorStop(1, fgcolor);
ctx.fillStyle = gradient;
}
if (border) {
ctx.strokeStyle = border;
/** @type {number} */
ctx.lineWidth = 3;
}
ctx.fillRect(posx, posy, Math.max(0, width - offset), Math.max(0, height - offset));
if (border) {
ctx.strokeRect(pos.x, pos.y, width, height);
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
if (this.viz.clickedNode && !$jit.Graph.Util.isDescendantOf(opt_attributes, this.viz.clickedNode.id)) {
return false;
}
var offsetCoordinate = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
return this.nodeHelper.rectangle.contains({
x : offsetCoordinate.x + actual / 2,
y : offsetCoordinate.y + epsilon / 2
}, value, actual, epsilon);
}
}
});
$jit.Icicle.Plot.EdgeTypes = new Class({
/** @type {function (): undefined} */
none : $.empty
});
Layout.ForceDirected = new Class({
/**
* @param {?} $allOptions
* @return {?}
*/
getOptions : function($allOptions) {
var element = this.canvas.getSize();
var originalWidth = element.width;
var originalHeight = element.height;
/** @type {number} */
var count = 0;
this.graph.eachNode(function(dataAndEvents) {
count++;
});
/** @type {number} */
var variance = originalWidth * originalHeight / count;
/** @type {number} */
var mult = Math.sqrt(variance);
var ld = this.config.levelDistance;
return{
width : originalWidth,
height : originalHeight,
tstart : originalWidth * 0.1,
/**
* @param {number} v00
* @return {?}
*/
nodef : function(v00) {
return variance / (v00 || 1);
},
/**
* @param {?} value
* @return {?}
*/
edgef : function(value) {
return mult * (value - ld);
}
};
},
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
compute : function(adj, type) {
var lab = $.splat(adj || ["current", "start", "end"]);
var coord = this.getOptions();
column.compute(this.graph, lab, this.config);
this.graph.computeLevels(this.root, 0, "ignore");
this.graph.eachNode(function(self) {
$.each(lab, function(prop) {
var p = self.getPos(prop);
if (p.equals(Vector.KER)) {
/** @type {number} */
p.x = coord.width / 5 * (Math.random() - 0.5);
/** @type {number} */
p.y = coord.height / 5 * (Math.random() - 0.5);
}
self.disp = {};
$.each(lab, function(timeoutKey) {
self.disp[timeoutKey] = getIndex(0, 0);
});
});
});
this.computePositions(lab, coord, type);
},
/**
* @param {?} node
* @param {Object} prop
* @param {Object} p
* @return {undefined}
*/
computePositions : function(node, prop, p) {
var len = this.config.iterations;
/** @type {number} */
var i = 0;
var jQuery = this;
if (p) {
(function play() {
var pl = p.iter;
/** @type {number} */
var j = 0;
for (;j < pl;j++) {
prop.t = prop.tstart;
if (len) {
prop.t *= 1 - i++ / (len - 1);
}
jQuery.computePositionStep(node, prop);
if (len && i >= len) {
p.onComplete();
return;
}
}
p.onStep(Math.round(i / (len - 1) * 100));
setTimeout(play, 1);
})();
} else {
for (;i < len;i++) {
/** @type {number} */
prop.t = prop.tstart * (1 - i / (len - 1));
this.computePositionStep(node, prop);
}
}
},
/**
* @param {?} attributes
* @param {Object} options
* @return {undefined}
*/
computePositionStep : function(attributes, options) {
var graph = this.graph;
/** @type {function (...[*]): number} */
var mn = Math.min;
/** @type {function (...[*]): number} */
var max = Math.max;
var pos = getIndex(0, 0);
graph.eachNode(function(node) {
$.each(attributes, function(y) {
/** @type {number} */
node.disp[y].x = 0;
/** @type {number} */
node.disp[y].y = 0;
});
graph.eachNode(function(n) {
if (n.id != node.id) {
$.each(attributes, function(prop) {
var p = node.getPos(prop);
var v = n.getPos(prop);
/** @type {number} */
pos.x = p.x - v.x;
/** @type {number} */
pos.y = p.y - v.y;
var x = pos.norm() || 1;
node.disp[prop].$add(pos.$scale(options.nodef(x) / x));
});
}
});
});
/** @type {boolean} */
var T = !!graph.getNode(this.root).visited;
graph.eachNode(function(node) {
node.eachAdjacency(function(adj) {
var child = adj.nodeTo;
if (!!child.visited === T) {
$.each(attributes, function(prop) {
var p = node.getPos(prop);
var v = child.getPos(prop);
/** @type {number} */
pos.x = p.x - v.x;
/** @type {number} */
pos.y = p.y - v.y;
var udataCur = pos.norm() || 1;
node.disp[prop].$add(pos.$scale(-options.edgef(udataCur) / udataCur));
child.disp[prop].$add(pos.$scale(-1));
});
}
});
/** @type {boolean} */
node.visited = !T;
});
var precision = options.t;
/** @type {number} */
var indents = options.width / 2;
/** @type {number} */
var minMargin = options.height / 2;
graph.eachNode(function(event) {
$.each(attributes, function(prop) {
var pos = event.disp[prop];
var I = pos.norm() || 1;
prop = event.getPos(prop);
prop.$add(getIndex(pos.x * mn(Math.abs(pos.x), precision) / I, pos.y * mn(Math.abs(pos.y), precision) / I));
/** @type {number} */
prop.x = mn(indents, max(-indents, prop.x));
/** @type {number} */
prop.y = mn(minMargin, max(-minMargin, prop.y));
});
});
}
});
$jit.ForceDirected = new Class({
Implements : [valid, Extras, Layout.ForceDirected],
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
var $ForceDirected = $jit.ForceDirected;
var config = {
iterations : 50,
levelDistance : 50
};
this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller);
var canvasConfig = this.config;
if (canvasConfig.useCanvas) {
this.canvas = canvasConfig.useCanvas;
/** @type {string} */
this.config.labelContainer = this.canvas.id + "-label";
} else {
if (canvasConfig.background) {
canvasConfig.background = $.merge({
type : "Circles"
}, canvasConfig.background);
}
this.canvas = new Canvas(this, canvasConfig);
/** @type {string} */
this.config.labelContainer = (typeof canvasConfig.injectInto == "string" ? canvasConfig.injectInto : canvasConfig.injectInto.id) + "-label";
}
this.graphOptions = {
/** @type {function (number, (number|string)): undefined} */
klass : Vector,
Node : {
selected : false,
exist : true,
drawn : true
}
};
this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge);
this.labels = new $ForceDirected.Label[canvasConfig.Label.type](this);
this.fx = new $ForceDirected.Plot(this, $ForceDirected);
this.op = new $ForceDirected.Op(this);
/** @type {null} */
this.json = null;
/** @type {boolean} */
this.busy = false;
this.initializeExtras();
},
/**
* @return {undefined}
*/
refresh : function() {
this.compute();
this.plot();
},
/**
* @return {undefined}
*/
reposition : function() {
this.compute("end");
},
/**
* @param {?} lab
* @return {undefined}
*/
computeIncremental : function(lab) {
lab = $.merge({
iter : 20,
property : "end",
/** @type {function (): undefined} */
onStep : $.empty,
/** @type {function (): undefined} */
onComplete : $.empty
}, lab || {});
this.config.onBeforeCompute(this.graph.getNode(this.root));
this.compute(lab.property, lab);
},
/**
* @return {undefined}
*/
plot : function() {
this.fx.plot();
},
/**
* @param {?} opt_attributes
* @return {undefined}
*/
animate : function(opt_attributes) {
this.fx.animate($.merge({
modes : ["linear"]
}, opt_attributes || {}));
}
});
/** @type {boolean} */
$jit.ForceDirected.$extend = true;
(function(Hypertree) {
Hypertree.Op = new Class({
Implements : Graph.Op
});
Hypertree.Plot = new Class({
Implements : Graph.Plot
});
Hypertree.Label = {};
Hypertree.Label.Native = new Class({
Implements : Graph.Label.Native
});
Hypertree.Label.SVG = new Class({
Implements : Graph.Label.SVG,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.getc(true);
var canvas = this.viz.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var $cont = canvas.getSize();
var tl = {
x : Math.round(pos.x * sx + ox + $cont.width / 2),
y : Math.round(pos.y * sy + oy + $cont.height / 2)
};
from.setAttribute("x", tl.x);
from.setAttribute("y", tl.y);
options.onPlaceLabel(from, lab);
}
});
Hypertree.Label.HTML = new Class({
Implements : Graph.Label.HTML,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.getc(true);
var canvas = this.viz.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var $cont = canvas.getSize();
var labelPos = {
x : Math.round(pos.x * sx + ox + $cont.width / 2),
y : Math.round(pos.y * sy + oy + $cont.height / 2)
};
var style = from.style;
/** @type {string} */
style.left = labelPos.x + "px";
/** @type {string} */
style.top = labelPos.y + "px";
/** @type {string} */
style.display = this.fitsInCanvas(labelPos, canvas) ? "" : "none";
options.onPlaceLabel(from, lab);
}
});
Hypertree.Plot.NodeTypes = new Class({
none : {
/** @type {function (): undefined} */
render : $.empty,
contains : $.lambda(false)
},
circle : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("dim");
this.nodeHelper.circle.render("fill", lab, qualifier, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("dim");
return this.nodeHelper.circle.contains(attributes, value, actual);
}
},
ellipse : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("width");
var cycle = adj.getData("height");
this.nodeHelper.ellipse.render("fill", lab, qualifier, cycle, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
return this.nodeHelper.ellipse.contains(attributes, value, actual, epsilon);
}
},
square : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("dim");
this.nodeHelper.square.render("fill", lab, qualifier, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("dim");
return this.nodeHelper.square.contains(attributes, value, actual);
}
},
rectangle : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("width");
var cycle = adj.getData("height");
this.nodeHelper.rectangle.render("fill", lab, qualifier, cycle, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
return this.nodeHelper.rectangle.contains(attributes, value, actual, epsilon);
}
},
triangle : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("dim");
this.nodeHelper.triangle.render("fill", lab, qualifier, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("dim");
return this.nodeHelper.triangle.contains(attributes, value, actual);
}
},
star : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("dim");
this.nodeHelper.star.render("fill", lab, qualifier, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("dim");
return this.nodeHelper.star.contains(attributes, value, actual);
}
}
});
Hypertree.Plot.EdgeTypes = new Class({
/** @type {function (): undefined} */
none : $.empty,
line : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var from = adj.nodeFrom.pos.getc(true);
var lab = adj.nodeTo.pos.getc(true);
this.edgeHelper.line.render(from, lab, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.nodeFrom.pos.getc(true);
var pdataOld = opt_attributes.nodeTo.pos.getc(true);
return this.edgeHelper.line.contains(attributes, pdataOld, value, this.edge.epsilon);
}
},
arrow : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var from = adj.nodeFrom.pos.getc(true);
var lab = adj.nodeTo.pos.getc(true);
var qualifier = adj.getData("dim");
var direction = adj.data.$direction;
var cycle = direction && (direction.length > 1 && direction[0] != adj.nodeFrom.id);
this.edgeHelper.arrow.render(from, lab, qualifier, cycle, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.nodeFrom.pos.getc(true);
var pdataOld = opt_attributes.nodeTo.pos.getc(true);
return this.edgeHelper.arrow.contains(attributes, pdataOld, value, this.edge.epsilon);
}
}
});
})($jit.ForceDirected);
$jit.TM = {};
var Hypertree = $jit.TM;
/** @type {boolean} */
$jit.TM.$extend = true;
Hypertree.Base = {
layout : {
orientation : "h",
/**
* @return {?}
*/
vertical : function() {
return this.orientation == "v";
},
/**
* @return {?}
*/
horizontal : function() {
return this.orientation == "h";
},
/**
* @return {undefined}
*/
change : function() {
/** @type {string} */
this.orientation = this.vertical() ? "h" : "v";
}
},
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
var config = {
orientation : "h",
titleHeight : 13,
offset : 2,
levelsToShow : 0,
constrained : false,
animate : false,
Node : {
type : "rectangle",
overridable : true,
width : 3,
height : 3,
color : "#444"
},
Label : {
textAlign : "center",
textBaseline : "top"
},
Edge : {
type : "none"
},
duration : 700,
fps : 45
};
this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", "Fx", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller);
this.layout.orientation = this.config.orientation;
var canvasConfig = this.config;
if (canvasConfig.useCanvas) {
this.canvas = canvasConfig.useCanvas;
/** @type {string} */
this.config.labelContainer = this.canvas.id + "-label";
} else {
if (canvasConfig.background) {
canvasConfig.background = $.merge({
type : "Circles"
}, canvasConfig.background);
}
this.canvas = new Canvas(this, canvasConfig);
/** @type {string} */
this.config.labelContainer = (typeof canvasConfig.injectInto == "string" ? canvasConfig.injectInto : canvasConfig.injectInto.id) + "-label";
}
this.graphOptions = {
/** @type {function (number, (number|string)): undefined} */
klass : Vector,
Node : {
selected : false,
exist : true,
drawn : true
}
};
this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge);
this.labels = new Hypertree.Label[canvasConfig.Label.type](this);
this.fx = new Hypertree.Plot(this);
this.op = new Hypertree.Op(this);
this.group = new Hypertree.Group(this);
this.geom = new Hypertree.Geom(this);
/** @type {null} */
this.clickedNode = null;
/** @type {boolean} */
this.busy = false;
this.initializeExtras();
},
/**
* @return {undefined}
*/
refresh : function() {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
var that = this;
if (this.config.animate) {
this.compute("end");
if (this.config.levelsToShow > 0) {
this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root));
}
this.fx.animate($.merge(this.config, {
modes : ["linear", "node-property:width:height"],
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
}
}));
} else {
var type = this.config.Label.type;
if (type != "Native") {
that = this;
this.graph.eachNode(function(from) {
that.labels.hideLabel(from, false);
});
}
/** @type {boolean} */
this.busy = false;
this.compute();
if (this.config.levelsToShow > 0) {
this.geom.setRightLevelToShow(this.graph.getNode(this.clickedNode && this.clickedNode.id || this.root));
}
this.plot();
}
},
/**
* @return {undefined}
*/
plot : function() {
this.fx.plot();
},
/**
* @param {?} n
* @return {?}
*/
leaf : function(n) {
return n.getSubnodes([1, 1], "ignore").length == 0;
},
/**
* @param {?} n
* @return {undefined}
*/
enter : function(n) {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
var that = this;
var config = this.config;
var graph = this.graph;
var node = n;
var previousClickedNode = this.clickedNode;
var callback = {
/**
* @return {undefined}
*/
onComplete : function() {
if (config.levelsToShow > 0) {
that.geom.setRightLevelToShow(n);
}
if (config.levelsToShow > 0 || config.request) {
that.compute();
}
if (config.animate) {
graph.nodeList.setData("alpha", 0, "end");
n.eachSubgraph(function(n) {
n.setData("alpha", 1, "end");
}, "ignore");
that.fx.animate({
duration : 500,
modes : ["node-property:alpha"],
/**
* @return {undefined}
*/
onComplete : function() {
that.clickedNode = node;
that.compute("end");
that.clickedNode = previousClickedNode;
that.fx.animate({
modes : ["linear", "node-property:width:height"],
duration : 1E3,
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
that.clickedNode = node;
}
});
}
});
} else {
/** @type {boolean} */
that.busy = false;
that.clickedNode = n;
that.refresh();
}
}
};
if (config.request) {
this.requestNodes(node, callback);
} else {
callback.onComplete();
}
},
/**
* @return {undefined}
*/
out : function() {
if (this.busy) {
return;
}
/** @type {boolean} */
this.busy = true;
/** @type {boolean} */
this.events.hoveredNode = false;
var that = this;
var config = this.config;
var graph = this.graph;
var args = graph.getNode(this.clickedNode && this.clickedNode.id || this.root).getParents();
var parent = args[0];
var clickedNode = parent;
var previousClickedNode = this.clickedNode;
if (!parent) {
/** @type {boolean} */
this.busy = false;
return;
}
callback = {
/**
* @return {undefined}
*/
onComplete : function() {
that.clickedNode = parent;
if (config.request) {
that.requestNodes(parent, {
/**
* @return {undefined}
*/
onComplete : function() {
that.compute();
that.plot();
/** @type {boolean} */
that.busy = false;
}
});
} else {
that.compute();
that.plot();
/** @type {boolean} */
that.busy = false;
}
}
};
if (config.levelsToShow > 0) {
this.geom.setRightLevelToShow(parent);
}
if (config.animate) {
this.clickedNode = clickedNode;
this.compute("end");
this.clickedNode = previousClickedNode;
this.fx.animate({
modes : ["linear", "node-property:width:height"],
duration : 1E3,
/**
* @return {undefined}
*/
onComplete : function() {
that.clickedNode = clickedNode;
graph.eachNode(function(n) {
n.setDataset(["current", "end"], {
alpha : [0, 1]
});
}, "ignore");
previousClickedNode.eachSubgraph(function(n) {
n.setData("alpha", 1);
}, "ignore");
that.fx.animate({
duration : 500,
modes : ["node-property:alpha"],
/**
* @return {undefined}
*/
onComplete : function() {
callback.onComplete();
}
});
}
});
} else {
callback.onComplete();
}
},
/**
* @param {Array} node
* @param {?} onComplete
* @return {undefined}
*/
requestNodes : function(node, onComplete) {
var handler = $.merge(this.controller, onComplete);
var lev = this.config.levelsToShow;
if (handler.request) {
/** @type {Array} */
var leaves = [];
var d = node._depth;
node.eachLevel(0, lev, function(n) {
/** @type {number} */
var nodeLevel = lev - (n._depth - d);
if (n.drawn && (!n.anySubnode() && nodeLevel > 0)) {
leaves.push(n);
/** @type {number} */
n._level = nodeLevel;
}
});
this.group.requestNodes(leaves, handler);
} else {
handler.onComplete();
}
},
/**
* @return {undefined}
*/
reposition : function() {
this.compute("end");
}
};
Hypertree.Op = new Class({
Implements : Graph.Op,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
}
});
Hypertree.Geom = new Class({
Implements : Graph.Geom,
/**
* @return {?}
*/
getRightLevelToShow : function() {
return this.viz.config.levelsToShow;
},
/**
* @param {?} node
* @return {undefined}
*/
setRightLevelToShow : function(node) {
var y = this.getRightLevelToShow();
var fx = this.viz.labels;
node.eachLevel(0, y + 1, function(from) {
/** @type {number} */
var x = from._depth - node._depth;
if (x > y) {
/** @type {boolean} */
from.drawn = false;
/** @type {boolean} */
from.exist = false;
/** @type {boolean} */
from.ignore = true;
fx.hideLabel(from, false);
} else {
/** @type {boolean} */
from.drawn = true;
/** @type {boolean} */
from.exist = true;
delete from.ignore;
}
});
/** @type {boolean} */
node.drawn = true;
delete node.ignore;
}
});
Hypertree.Group = new Class({
/**
* @param {Object} viz
* @return {undefined}
*/
initialize : function(viz) {
/** @type {Object} */
this.viz = viz;
this.canvas = viz.canvas;
this.config = viz.config;
},
/**
* @param {Array} nodes
* @param {?} controller
* @return {undefined}
*/
requestNodes : function(nodes, controller) {
/** @type {number} */
var counter = 0;
var len = nodes.length;
var nodeSelected = {};
/**
* @return {undefined}
*/
var complete = function() {
controller.onComplete();
};
var viz = this.viz;
if (len == 0) {
complete();
}
/** @type {number} */
var i = 0;
for (;i < len;i++) {
nodeSelected[nodes[i].id] = nodes[i];
controller.request(nodes[i].id, nodes[i]._level, {
/**
* @param {number} adj
* @param {?} lab
* @return {undefined}
*/
onComplete : function(adj, lab) {
if (lab && lab.children) {
/** @type {number} */
lab.id = adj;
viz.op.sum(lab, {
type : "nothing"
});
}
if (++counter == len) {
viz.graph.computeLevels(viz.root, 0);
complete();
}
}
});
}
}
});
Hypertree.Plot = new Class({
Implements : Graph.Plot,
/**
* @param {Object} viz
* @return {undefined}
*/
initialize : function(viz) {
/** @type {Object} */
this.viz = viz;
this.config = viz.config;
this.node = this.config.Node;
this.edge = this.config.Edge;
this.animation = new Animation;
this.nodeTypes = new Hypertree.Plot.NodeTypes;
this.edgeTypes = new Hypertree.Plot.EdgeTypes;
this.labels = viz.labels;
},
/**
* @param {?} opt
* @param {boolean} animating
* @return {undefined}
*/
plot : function(opt, animating) {
var viz = this.viz;
var graph = viz.graph;
viz.canvas.clear();
this.plotTree(graph.getNode(viz.clickedNode && viz.clickedNode.id || viz.root), $.merge(viz.config, opt || {}, {
withLabels : true,
hideLabels : false,
/**
* @param {?} node
* @param {Object} x
* @return {?}
*/
plotSubtree : function(node, x) {
return node.anySubnode("exist");
}
}), animating);
}
});
Hypertree.Label = {};
Hypertree.Label.Native = new Class({
Implements : Graph.Label.Native,
/**
* @param {Object} viz
* @return {undefined}
*/
initialize : function(viz) {
this.config = viz.config;
this.leaf = viz.leaf;
},
/**
* @param {?} canvas
* @param {Object} node
* @param {?} opt
* @return {undefined}
*/
renderLabel : function(canvas, node, opt) {
if (!this.leaf(node) && !this.config.titleHeight) {
return;
}
var pos = node.pos.getc(true);
var ctx = canvas.getCtx();
var width = node.getData("width");
var constrainedHeight = node.getData("height");
var opposite = pos.x + width / 2;
var posY = pos.y;
ctx.fillText(node.name, opposite, posY, width);
}
});
Hypertree.Label.SVG = new Class({
Implements : Graph.Label.SVG,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
this.leaf = viz.leaf;
this.config = viz.config;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.getc(true);
var canvas = this.viz.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var $cont = canvas.getSize();
var tl = {
x : Math.round(pos.x * sx + ox + $cont.width / 2),
y : Math.round(pos.y * sy + oy + $cont.height / 2)
};
from.setAttribute("x", tl.x);
from.setAttribute("y", tl.y);
if (!this.leaf(lab) && !this.config.titleHeight) {
/** @type {string} */
from.style.display = "none";
}
options.onPlaceLabel(from, lab);
}
});
Hypertree.Label.HTML = new Class({
Implements : Graph.Label.HTML,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
this.leaf = viz.leaf;
this.config = viz.config;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var size = lab.pos.getc(true);
var canvas = this.viz.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var $cont = canvas.getSize();
var pos = {
x : Math.round(size.x * sx + ox + $cont.width / 2),
y : Math.round(size.y * sy + oy + $cont.height / 2)
};
var cs = from.style;
/** @type {string} */
cs.left = pos.x + "px";
/** @type {string} */
cs.top = pos.y + "px";
/** @type {string} */
cs.width = lab.getData("width") * sx + "px";
/** @type {string} */
cs.height = lab.getData("height") * sy + "px";
/** @type {number} */
cs.zIndex = lab._depth * 100;
/** @type {string} */
cs.display = "";
if (!this.leaf(lab) && !this.config.titleHeight) {
/** @type {string} */
from.style.display = "none";
}
options.onPlaceLabel(from, lab);
}
});
Hypertree.Plot.NodeTypes = new Class({
none : {
/** @type {function (): undefined} */
render : $.empty
},
rectangle : {
/**
* @param {?} adj
* @param {?} lab
* @param {?} event
* @return {undefined}
*/
render : function(adj, lab, event) {
var orn = this.viz.leaf(adj);
var config = this.config;
var offst = config.offset;
var titleHeight = config.titleHeight;
var pos = adj.pos.getc(true);
var width = adj.getData("width");
var height = adj.getData("height");
var border = adj.getData("border");
var ctx = lab.getCtx();
var posx = pos.x + offst / 2;
var posy = pos.y + offst / 2;
if (width <= offst || height <= offst) {
return;
}
if (orn) {
if (config.cushion) {
var radgrad = ctx.createRadialGradient(posx + (width - offst) / 2, posy + (height - offst) / 2, 1, posx + (width - offst) / 2, posy + (height - offst) / 2, width < height ? height : width);
var color = adj.getData("color");
var colorend = $.rgbToHex($.map($.hexToRgb(color), function(dataAndEvents) {
return dataAndEvents * 0.2 >> 0;
}));
radgrad.addColorStop(0, color);
radgrad.addColorStop(1, colorend);
ctx.fillStyle = radgrad;
}
ctx.fillRect(posx, posy, width - offst, height - offst);
if (border) {
ctx.save();
ctx.strokeStyle = border;
ctx.strokeRect(posx, posy, width - offst, height - offst);
ctx.restore();
}
} else {
if (titleHeight > 0) {
ctx.fillRect(pos.x + offst / 2, pos.y + offst / 2, width - offst, titleHeight - offst);
if (border) {
ctx.save();
ctx.strokeStyle = border;
ctx.strokeRect(pos.x + offst / 2, pos.y + offst / 2, width - offst, height - offst);
ctx.restore();
}
}
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
if (this.viz.clickedNode && !opt_attributes.isDescendantOf(this.viz.clickedNode.id) || opt_attributes.ignore) {
return false;
}
var offsetCoordinate = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("width");
var leaf = this.viz.leaf(opt_attributes);
var epsilon = leaf ? opt_attributes.getData("height") : this.config.titleHeight;
return this.nodeHelper.rectangle.contains({
x : offsetCoordinate.x + actual / 2,
y : offsetCoordinate.y + epsilon / 2
}, value, actual, epsilon);
}
}
});
Hypertree.Plot.EdgeTypes = new Class({
/** @type {function (): undefined} */
none : $.empty
});
Hypertree.SliceAndDice = new Class({
Implements : [valid, Extras, Hypertree.Base, Layout.TM.SliceAndDice]
});
Hypertree.Squarified = new Class({
Implements : [valid, Extras, Hypertree.Base, Layout.TM.Squarified]
});
Hypertree.Strip = new Class({
Implements : [valid, Extras, Hypertree.Base, Layout.TM.Strip]
});
$jit.RGraph = new Class({
Implements : [valid, Extras, Layout.Radial],
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
var $RGraph = $jit.RGraph;
var config = {
interpolation : "linear",
levelDistance : 100
};
this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", "Fx", "Controller", "Tips", "NodeStyles", "Events", "Navigation", "Label"), config, controller);
var canvasConfig = this.config;
if (canvasConfig.useCanvas) {
this.canvas = canvasConfig.useCanvas;
/** @type {string} */
this.config.labelContainer = this.canvas.id + "-label";
} else {
if (canvasConfig.background) {
canvasConfig.background = $.merge({
type : "Circles"
}, canvasConfig.background);
}
this.canvas = new Canvas(this, canvasConfig);
/** @type {string} */
this.config.labelContainer = (typeof canvasConfig.injectInto == "string" ? canvasConfig.injectInto : canvasConfig.injectInto.id) + "-label";
}
this.graphOptions = {
/** @type {function (number, number): undefined} */
klass : Transform,
Node : {
selected : false,
exist : true,
drawn : true
}
};
this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge);
this.labels = new $RGraph.Label[canvasConfig.Label.type](this);
this.fx = new $RGraph.Plot(this, $RGraph);
this.op = new $RGraph.Op(this);
/** @type {null} */
this.json = null;
/** @type {null} */
this.root = null;
/** @type {boolean} */
this.busy = false;
/** @type {boolean} */
this.parent = false;
this.initializeExtras();
},
/**
* @return {?}
*/
createLevelDistanceFunc : function() {
var ld = this.config.levelDistance;
return function(node) {
return(node._depth + 1) * ld;
};
},
/**
* @return {undefined}
*/
refresh : function() {
this.compute();
this.plot();
},
/**
* @return {undefined}
*/
reposition : function() {
this.compute("end");
},
/**
* @return {undefined}
*/
plot : function() {
this.fx.plot();
},
/**
* @param {?} id
* @return {?}
*/
getNodeAndParentAngle : function(id) {
/** @type {boolean} */
var theta = false;
var node = this.graph.getNode(id);
var codeSegments = node.getParents();
var p = codeSegments.length > 0 ? codeSegments[0] : false;
if (p) {
var previous = p.pos.getc();
var projection = node.pos.getc();
var newPos = previous.add(projection.scale(-1));
/** @type {number} */
theta = Math.atan2(newPos.y, newPos.x);
if (theta < 0) {
theta += 2 * Math.PI;
}
}
return{
parent : p,
theta : theta
};
},
/**
* @param {?} par
* @param {string} id
* @return {undefined}
*/
tagChildren : function(par, id) {
if (par.angleSpan) {
/** @type {Array} */
var adjs = [];
par.eachAdjacency(function(elem) {
adjs.push(elem.nodeTo);
}, "ignore");
/** @type {number} */
var len = adjs.length;
/** @type {number} */
var i = 0;
for (;i < len && id != adjs[i].id;i++) {
}
/** @type {number} */
var j = (i + 1) % len;
/** @type {number} */
var k = 0;
for (;id != adjs[j].id;j = (j + 1) % len) {
/** @type {number} */
adjs[j].dist = k++;
}
}
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onClick : function(adj, lab) {
if (this.root != adj && !this.busy) {
/** @type {boolean} */
this.busy = true;
this.root = adj;
var that = this;
this.controller.onBeforeCompute(this.graph.getNode(adj));
var obj = this.getNodeAndParentAngle(adj);
this.tagChildren(obj.parent, adj);
this.parent = obj.parent;
this.compute("end");
/** @type {number} */
var lambda = obj.theta - obj.parent.endPos.theta;
this.graph.eachNode(function(elem) {
elem.endPos.set(elem.endPos.getp().add($P(lambda, 0)));
});
var mode = this.config.interpolation;
lab = $.merge({
/** @type {function (): undefined} */
onComplete : $.empty
}, lab || {});
this.fx.animate($.merge({
hideLabels : true,
modes : [mode]
}, lab, {
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
lab.onComplete();
}
}));
}
}
});
/** @type {boolean} */
$jit.RGraph.$extend = true;
(function(Hypertree) {
Hypertree.Op = new Class({
Implements : Graph.Op
});
Hypertree.Plot = new Class({
Implements : Graph.Plot
});
Hypertree.Label = {};
Hypertree.Label.Native = new Class({
Implements : Graph.Label.Native
});
Hypertree.Label.SVG = new Class({
Implements : Graph.Label.SVG,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.getc(true);
var canvas = this.viz.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var $cont = canvas.getSize();
var tl = {
x : Math.round(pos.x * sx + ox + $cont.width / 2),
y : Math.round(pos.y * sy + oy + $cont.height / 2)
};
from.setAttribute("x", tl.x);
from.setAttribute("y", tl.y);
options.onPlaceLabel(from, lab);
}
});
Hypertree.Label.HTML = new Class({
Implements : Graph.Label.HTML,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.getc(true);
var canvas = this.viz.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var $cont = canvas.getSize();
var labelPos = {
x : Math.round(pos.x * sx + ox + $cont.width / 2),
y : Math.round(pos.y * sy + oy + $cont.height / 2)
};
var style = from.style;
/** @type {string} */
style.left = labelPos.x + "px";
/** @type {string} */
style.top = labelPos.y + "px";
/** @type {string} */
style.display = this.fitsInCanvas(labelPos, canvas) ? "" : "none";
options.onPlaceLabel(from, lab);
}
});
Hypertree.Plot.NodeTypes = new Class({
none : {
/** @type {function (): undefined} */
render : $.empty,
contains : $.lambda(false)
},
circle : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("dim");
this.nodeHelper.circle.render("fill", lab, qualifier, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("dim");
return this.nodeHelper.circle.contains(attributes, value, actual);
}
},
ellipse : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("width");
var cycle = adj.getData("height");
this.nodeHelper.ellipse.render("fill", lab, qualifier, cycle, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
return this.nodeHelper.ellipse.contains(attributes, value, actual, epsilon);
}
},
square : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("dim");
this.nodeHelper.square.render("fill", lab, qualifier, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("dim");
return this.nodeHelper.square.contains(attributes, value, actual);
}
},
rectangle : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("width");
var cycle = adj.getData("height");
this.nodeHelper.rectangle.render("fill", lab, qualifier, cycle, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
return this.nodeHelper.rectangle.contains(attributes, value, actual, epsilon);
}
},
triangle : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var cycle = adj.pos.getc(true);
var qualifier = adj.getData("dim");
this.nodeHelper.triangle.render("fill", cycle, qualifier, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("dim");
return this.nodeHelper.triangle.contains(attributes, value, actual);
}
},
star : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var lab = adj.pos.getc(true);
var qualifier = adj.getData("dim");
this.nodeHelper.star.render("fill", lab, qualifier, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.pos.getc(true);
var actual = opt_attributes.getData("dim");
return this.nodeHelper.star.contains(attributes, value, actual);
}
}
});
Hypertree.Plot.EdgeTypes = new Class({
/** @type {function (): undefined} */
none : $.empty,
line : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var from = adj.nodeFrom.pos.getc(true);
var lab = adj.nodeTo.pos.getc(true);
this.edgeHelper.line.render(from, lab, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.nodeFrom.pos.getc(true);
var pdataOld = opt_attributes.nodeTo.pos.getc(true);
return this.edgeHelper.line.contains(attributes, pdataOld, value, this.edge.epsilon);
}
},
arrow : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var from = adj.nodeFrom.pos.getc(true);
var lab = adj.nodeTo.pos.getc(true);
var qualifier = adj.getData("dim");
var direction = adj.data.$direction;
var cycle = direction && (direction.length > 1 && direction[0] != adj.nodeFrom.id);
this.edgeHelper.arrow.render(from, lab, qualifier, cycle, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var attributes = opt_attributes.nodeFrom.pos.getc(true);
var pdataOld = opt_attributes.nodeTo.pos.getc(true);
return this.edgeHelper.arrow.contains(attributes, pdataOld, value, this.edge.epsilon);
}
}
});
})($jit.RGraph);
/**
* @param {?} c
* @return {?}
*/
Vector.prototype.moebiusTransformation = function(c) {
var num = this.add(c);
var den = c.$conjugate().$prod(this);
den.x++;
return num.$div(den);
};
/**
* @param {?} graph
* @param {Array} pos
* @param {Array} array
* @param {Event} key
* @param {string} flags
* @return {undefined}
*/
Graph.Util.moebiusTransformation = function(graph, pos, array, key, flags) {
this.eachNode(graph, function(obj) {
/** @type {number} */
var i = 0;
for (;i < array.length;i++) {
var p = pos[i].scale(-1);
var prop = key ? key : array[i];
obj.getPos(array[i]).set(obj.getPos(prop).getc().moebiusTransformation(p));
}
}, flags);
};
$jit.Hypertree = new Class({
Implements : [valid, Extras, Layout.Radial],
/**
* @param {?} controller
* @return {undefined}
*/
initialize : function(controller) {
var $Hypertree = $jit.Hypertree;
var config = {
radius : "auto",
offset : 0,
Edge : {
type : "hyperline"
},
duration : 1500,
fps : 35
};
this.controller = this.config = $.merge(Options("Canvas", "Node", "Edge", "Fx", "Tips", "NodeStyles", "Events", "Navigation", "Controller", "Label"), config, controller);
var canvasConfig = this.config;
if (canvasConfig.useCanvas) {
this.canvas = canvasConfig.useCanvas;
/** @type {string} */
this.config.labelContainer = this.canvas.id + "-label";
} else {
if (canvasConfig.background) {
canvasConfig.background = $.merge({
type : "Circles"
}, canvasConfig.background);
}
this.canvas = new Canvas(this, canvasConfig);
/** @type {string} */
this.config.labelContainer = (typeof canvasConfig.injectInto == "string" ? canvasConfig.injectInto : canvasConfig.injectInto.id) + "-label";
}
this.graphOptions = {
/** @type {function (number, number): undefined} */
klass : Transform,
Node : {
selected : false,
exist : true,
drawn : true
}
};
this.graph = new Graph(this.graphOptions, this.config.Node, this.config.Edge);
this.labels = new $Hypertree.Label[canvasConfig.Label.type](this);
this.fx = new $Hypertree.Plot(this, $Hypertree);
this.op = new $Hypertree.Op(this);
/** @type {null} */
this.json = null;
/** @type {null} */
this.root = null;
/** @type {boolean} */
this.busy = false;
this.initializeExtras();
},
/**
* @return {?}
*/
createLevelDistanceFunc : function() {
var r = this.getRadius();
/** @type {number} */
var depth = 0;
/** @type {function (...[*]): number} */
var max = Math.max;
var config = this.config;
this.graph.eachNode(function(node) {
/** @type {number} */
depth = max(node._depth, depth);
}, "ignore");
depth++;
/**
* @param {number} a
* @return {?}
*/
var genDistFunc = function(a) {
return function(node) {
node.scale = r;
var d = node._depth + 1;
/** @type {number} */
var acum = 0;
/** @type {function (*, *): number} */
var pow = Math.pow;
for (;d;) {
acum += pow(a, d--);
}
return acum - config.offset;
};
};
/** @type {number} */
var i = 0.51;
for (;i <= 1;i += 0.01) {
/** @type {number} */
var y = (1 - Math.pow(i, depth)) / (1 - i);
if (y >= 2) {
return genDistFunc(i - 0.01);
}
}
return genDistFunc(0.75);
},
/**
* @return {?}
*/
getRadius : function() {
var rad = this.config.radius;
if (rad !== "auto") {
return rad;
}
var ul = this.canvas.getSize();
return Math.min(ul.width, ul.height) / 2;
},
/**
* @param {boolean} dataAndEvents
* @return {undefined}
*/
refresh : function(dataAndEvents) {
if (dataAndEvents) {
this.reposition();
this.graph.eachNode(function(node) {
node.startPos.rho = node.pos.rho = node.endPos.rho;
node.startPos.theta = node.pos.theta = node.endPos.theta;
});
} else {
this.compute();
}
this.plot();
},
/**
* @return {undefined}
*/
reposition : function() {
this.compute("end");
var vector = this.graph.getNode(this.root).pos.getc().scale(-1);
Graph.Util.moebiusTransformation(this.graph, [vector], ["end"], "end", "ignore");
this.graph.eachNode(function(node) {
if (node.ignore) {
node.endPos.rho = node.pos.rho;
node.endPos.theta = node.pos.theta;
}
});
},
/**
* @return {undefined}
*/
plot : function() {
this.fx.plot();
},
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
onClick : function(adj, lab) {
var to = this.graph.getNode(adj).pos.getc(true);
this.move(to, lab);
},
/**
* @param {?} pos
* @param {Object} opt
* @return {undefined}
*/
move : function(pos, opt) {
var versor = getIndex(pos.x, pos.y);
if (this.busy === false && versor.norm() < 1) {
/** @type {boolean} */
this.busy = true;
var from = this.graph.getClosestNodeToPos(versor);
var that = this;
this.graph.computeLevels(from.id, 0);
this.controller.onBeforeCompute(from);
opt = $.merge({
/** @type {function (): undefined} */
onComplete : $.empty
}, opt || {});
this.fx.animate($.merge({
modes : ["moebius"],
hideLabels : true
}, opt, {
/**
* @return {undefined}
*/
onComplete : function() {
/** @type {boolean} */
that.busy = false;
opt.onComplete();
}
}), versor);
}
}
});
/** @type {boolean} */
$jit.Hypertree.$extend = true;
(function(Hypertree) {
Hypertree.Op = new Class({
Implements : Graph.Op
});
Hypertree.Plot = new Class({
Implements : Graph.Plot
});
Hypertree.Label = {};
Hypertree.Label.Native = new Class({
Implements : Graph.Label.Native,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} canvas
* @param {Object} node
* @param {?} opt
* @return {undefined}
*/
renderLabel : function(canvas, node, opt) {
var ctx = canvas.getCtx();
var coord = node.pos.getc(true);
var s = this.viz.getRadius();
ctx.fillText(node.name, coord.x * s, coord.y * s);
}
});
Hypertree.Label.SVG = new Class({
Implements : Graph.Label.SVG,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.getc(true);
var canvas = this.viz.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var $cont = canvas.getSize();
var r = this.viz.getRadius();
var tl = {
x : Math.round(pos.x * sx * r + ox + $cont.width / 2),
y : Math.round(pos.y * sy * r + oy + $cont.height / 2)
};
from.setAttribute("x", tl.x);
from.setAttribute("y", tl.y);
options.onPlaceLabel(from, lab);
}
});
Hypertree.Label.HTML = new Class({
Implements : Graph.Label.HTML,
/**
* @param {?} viz
* @return {undefined}
*/
initialize : function(viz) {
this.viz = viz;
},
/**
* @param {?} from
* @param {?} lab
* @param {?} options
* @return {undefined}
*/
placeLabel : function(from, lab, options) {
var pos = lab.pos.getc(true);
var canvas = this.viz.canvas;
var ox = canvas.translateOffsetX;
var oy = canvas.translateOffsetY;
var sx = canvas.scaleOffsetX;
var sy = canvas.scaleOffsetY;
var $cont = canvas.getSize();
var r = this.viz.getRadius();
var labelPos = {
x : Math.round(pos.x * sx * r + ox + $cont.width / 2),
y : Math.round(pos.y * sy * r + oy + $cont.height / 2)
};
var style = from.style;
/** @type {string} */
style.left = labelPos.x + "px";
/** @type {string} */
style.top = labelPos.y + "px";
/** @type {string} */
style.display = this.fitsInCanvas(labelPos, canvas) ? "" : "none";
options.onPlaceLabel(from, lab);
}
});
Hypertree.Plot.NodeTypes = new Class({
none : {
/** @type {function (): undefined} */
render : $.empty,
contains : $.lambda(false)
},
circle : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var node = this.node;
var qualifier = adj.getData("dim");
var cycle = adj.pos.getc();
qualifier = node.transform ? qualifier * (1 - cycle.squaredNorm()) : qualifier;
cycle.$scale(adj.scale);
if (qualifier > 0.2) {
this.nodeHelper.circle.render("fill", cycle, qualifier, lab);
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var actual = opt_attributes.getData("dim");
var attributes = opt_attributes.pos.getc().$scale(opt_attributes.scale);
return this.nodeHelper.circle.contains(attributes, value, actual);
}
},
ellipse : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var cycle = adj.pos.getc().$scale(adj.scale);
var qualifier = adj.getData("width");
var fix = adj.getData("height");
this.nodeHelper.ellipse.render("fill", cycle, qualifier, fix, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
var attributes = opt_attributes.pos.getc().$scale(opt_attributes.scale);
return this.nodeHelper.circle.contains(attributes, value, actual, epsilon);
}
},
square : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var node = this.node;
var qualifier = adj.getData("dim");
var cycle = adj.pos.getc();
qualifier = node.transform ? qualifier * (1 - cycle.squaredNorm()) : qualifier;
cycle.$scale(adj.scale);
if (qualifier > 0.2) {
this.nodeHelper.square.render("fill", cycle, qualifier, lab);
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var actual = opt_attributes.getData("dim");
var attributes = opt_attributes.pos.getc().$scale(opt_attributes.scale);
return this.nodeHelper.square.contains(attributes, value, actual);
}
},
rectangle : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var node = this.node;
var qualifier = adj.getData("width");
var fix = adj.getData("height");
var cycle = adj.pos.getc();
qualifier = node.transform ? qualifier * (1 - cycle.squaredNorm()) : qualifier;
fix = node.transform ? fix * (1 - cycle.squaredNorm()) : fix;
cycle.$scale(adj.scale);
if (qualifier > 0.2 && fix > 0.2) {
this.nodeHelper.rectangle.render("fill", cycle, qualifier, fix, lab);
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var actual = opt_attributes.getData("width");
var epsilon = opt_attributes.getData("height");
var attributes = opt_attributes.pos.getc().$scale(opt_attributes.scale);
return this.nodeHelper.rectangle.contains(attributes, value, actual, epsilon);
}
},
triangle : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var node = this.node;
var qualifier = adj.getData("dim");
var cycle = adj.pos.getc();
qualifier = node.transform ? qualifier * (1 - cycle.squaredNorm()) : qualifier;
cycle.$scale(adj.scale);
if (qualifier > 0.2) {
this.nodeHelper.triangle.render("fill", cycle, qualifier, lab);
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var actual = opt_attributes.getData("dim");
var attributes = opt_attributes.pos.getc().$scale(opt_attributes.scale);
return this.nodeHelper.triangle.contains(attributes, value, actual);
}
},
star : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var node = this.node;
var qualifier = adj.getData("dim");
var cycle = adj.pos.getc();
qualifier = node.transform ? qualifier * (1 - cycle.squaredNorm()) : qualifier;
cycle.$scale(adj.scale);
if (qualifier > 0.2) {
this.nodeHelper.star.render("fill", cycle, qualifier, lab);
}
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {?}
*/
contains : function(opt_attributes, value) {
var actual = opt_attributes.getData("dim");
var attributes = opt_attributes.pos.getc().$scale(opt_attributes.scale);
return this.nodeHelper.star.contains(attributes, value, actual);
}
}
});
Hypertree.Plot.EdgeTypes = new Class({
/** @type {function (): undefined} */
none : $.empty,
line : {
/**
* @param {?} adj
* @param {?} type
* @return {undefined}
*/
render : function(adj, type) {
var to = adj.nodeFrom.pos.getc(true);
var from = adj.nodeTo.pos.getc(true);
var r = adj.nodeFrom.scale;
this.edgeHelper.line.render({
x : to.x * r,
y : to.y * r
}, {
x : from.x * r,
y : from.y * r
}, type);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {undefined}
*/
contains : function(opt_attributes, value) {
var to = opt_attributes.nodeFrom.pos.getc(true);
var from = opt_attributes.nodeTo.pos.getc(true);
var r = opt_attributes.nodeFrom.scale;
this.edgeHelper.line.contains({
x : to.x * r,
y : to.y * r
}, {
x : from.x * r,
y : from.y * r
}, value, this.edge.epsilon);
}
},
arrow : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var to = adj.nodeFrom.pos.getc(true);
var from = adj.nodeTo.pos.getc(true);
var r = adj.nodeFrom.scale;
var qualifier = adj.getData("dim");
var direction = adj.data.$direction;
var cycle = direction && (direction.length > 1 && direction[0] != adj.nodeFrom.id);
this.edgeHelper.arrow.render({
x : to.x * r,
y : to.y * r
}, {
x : from.x * r,
y : from.y * r
}, qualifier, cycle, lab);
},
/**
* @param {?} opt_attributes
* @param {?} value
* @return {undefined}
*/
contains : function(opt_attributes, value) {
var to = opt_attributes.nodeFrom.pos.getc(true);
var from = opt_attributes.nodeTo.pos.getc(true);
var r = opt_attributes.nodeFrom.scale;
this.edgeHelper.arrow.contains({
x : to.x * r,
y : to.y * r
}, {
x : from.x * r,
y : from.y * r
}, value, this.edge.epsilon);
}
},
hyperline : {
/**
* @param {?} adj
* @param {?} lab
* @return {undefined}
*/
render : function(adj, lab) {
var from = adj.nodeFrom.pos.getc();
var cycle = adj.nodeTo.pos.getc();
var qualifier = this.viz.getRadius();
this.edgeHelper.hyperline.render(from, cycle, qualifier, lab);
},
contains : $.lambda(false)
}
});
})($jit.Hypertree);
})();
</script>
<!-- Example File -->
<script>
var labelType, useGradients, nativeTextSupport, animate;
(function() {
var ua = navigator.userAgent,
iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
typeOfCanvas = typeof HTMLCanvasElement,
nativeCanvasSupport = (typeOfCanvas == \'object\' || typeOfCanvas == \'function\'),
textSupport = nativeCanvasSupport
&& (typeof document.createElement(\'canvas\').getContext(\'2d\').fillText == \'function\');
//I\'m setting this based on the fact that ExCanvas provides text support for IE
//and that as of today iPhone/iPad current text support is lame
labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? \'Native\' : \'HTML\';
nativeTextSupport = labelType == \'Native\';
useGradients = nativeCanvasSupport;
animate = !(iStuff || !nativeCanvasSupport);
})();
var Log = {
elem: false,
write: function(text){
if (!this.elem)
this.elem = document.getElementById(\'log\');
this.elem.innerHTML = text;
this.elem.style.left = (500 - this.elem.offsetWidth / 2) + \'px\';
}
};
function init(){
//init data
var json = __data_will_locate_here__;
//end
var infovis = document.getElementById(\'infovis\');
var w = infovis.offsetWidth - 50, h = infovis.offsetHeight - 50;
//init Hypertree
var ht = new $jit.Hypertree({
//id of the visualization container
injectInto: \'infovis\',
//canvas width and height
width: w,
height: h,
//Change node and edge styles such as
//color, width and dimensions.
Node: {
dim: 9,
color: "#f00"
},
Edge: {
lineWidth: 2,
color: "#088"
},
onBeforeCompute: function(node){
Log.write("centering");
},
//Attach event handlers and add text to the
//labels. This method is only triggered on label
//creation
onCreateLabel: function(domElement, node){
domElement.innerHTML = node.name;
$jit.util.addEvent(domElement, \'click\', function () {
ht.onClick(node.id, {
onComplete: function() {
ht.controller.onComplete();
}
});
});
},
//Change node styles when labels are placed
//or moved.
onPlaceLabel: function(domElement, node){
var style = domElement.style;
style.display = \'\';
style.cursor = \'pointer\';
if (node._depth <= 1) {
style.fontSize = "0.8em";
style.color = "#ddd";
} else if(node._depth == 2){
style.fontSize = "0.7em";
style.color = "#555";
} else {
style.display = \'none\';
}
var left = parseInt(style.left);
var w = domElement.offsetWidth;
style.left = (left - w / 2) + \'px\';
},
onComplete: function(){
Log.write("Network Map");
//Build the right column relations list.
//This is done by collecting the information (stored in the data property)
//for all the nodes adjacent to the centered node.
var node = ht.graph.getClosestNodeToOrigin("current");
var html = "<h4>" + node.name + "</h4><b>Connections:</b>";
html += "<ul>";
node.eachAdjacency(function(adj){
var child = adj.nodeTo;
if (child.data) {
var rel = (child.data.band == node.name) ? child.data.relation : node.data.relation;
html += "<li>" + child.name + " " + "<div class=\\"relation\\">(relation: " + rel + ")</div></li>";
}
});
html += "</ul>";
$jit.id(\'inner-details\').innerHTML = html;
}
});
//load JSON data.
ht.loadJSON(json);
//compute positions and plot.
ht.refresh();
//end
ht.controller.onComplete();
}
</script>
</head>
<body onload="init();">
<div id="container">
<div id="left-container">
<div class="text">
<h4>
__title_to_replace__
</h4>
<h5>__description_to_replace__</h5>
</div>
<div id="id-list"></div>
<div style="text-align:center;"></div>
</div>
<div id="center-container">
<div id="infovis"></div>
</div>
<div id="right-container">
<div id="inner-details"></div>
</div>
<div id="log"></div>
</div>
</body>
</html>'''.replace('__data_will_locate_here__', json.dumps(dgraph)) \
.replace('__title_to_replace__', messages(language, "pentest_graphs")) \
.replace('__description_to_replace__', messages(language, "graph_message")) \
.replace('__html_title_to_replace__', messages(language, "nettacker_report"))
if version() is 2:
return data.decode('utf8')
return data