Template:Team:Groningen/JAVASCRIPTS/DependencyGraph
/*Mainclass DependencyGraph*/ var DependencyGraph = function () { this.isLocked = false; this.stage = null; this.scene = null;
this.label = null;
this.roots = [];
this.nodeMap = {};
this.categoryMap = null; this.urlDomain = null; this.dx = 58; this.dy = 86;
};
DependencyGraph.prototype = { constructor: DependencyGraph, };
DependencyGraph.Cross = function () {
var n = new createjs.Shape(); n.graphics.setStrokeStyle(9, "square"); n.graphics.beginStroke("#A83838"); n.graphics.moveTo(0, -1.5 * 9); n.graphics.lineTo(0, 1.5 * 9); n.graphics.moveTo(-1.5 * 9, 0); n.graphics.lineTo(1.5 * 9, 0); n.rotation = 45; return n;
};
DependencyGraph.Cross.prototype = { constructor: DependencyGraph.Cross, };
DependencyGraph.Checkmark = function () {
var n = new createjs.Shape(); var rotxy = 0.5 * 9; n.graphics.setStrokeStyle(9, "square"); n.graphics.beginStroke("#A29D52"); n.graphics.moveTo(rotxy, rotxy + -1.5 * 9); n.graphics.lineTo(rotxy, rotxy); n.graphics.lineTo(rotxy + -2.5 * 9, rotxy); n.rotation = 45; return n;
};
DependencyGraph.Checkmark.prototype = { constructor: DependencyGraph.Checkmark, };
/*Subclass Edge*/ DependencyGraph.Edge = function (from, to, dx, dy) {
var successColor = "#686868"; var failColor = "#424242"; var fromn = from.node; var ton = to.node;
var edge = new createjs.Shape(); var yoffset = (fromn.y - ton.y) * 2 / 3; edge.graphics.setStrokeStyle(9, "square");
edge.graphics.beginStroke(to.success ? successColor : failColor); edge.graphics.moveTo(fromn.x, fromn.y); edge.graphics.lineTo(fromn.x, fromn.y - yoffset); edge.graphics.lineTo(ton.x, fromn.y - yoffset); edge.graphics.lineTo(ton.x, ton.y);
return edge; };
DependencyGraph.Edge.prototype = { constructor: DependencyGraph.Edge, };
DependencyGraph.Node = function (popup, ctx) {
var node = new createjs.Shape(); node.graphics.beginFill("#2B2B2B").drawRect(-31/2, -31/2, 31, 31); node.setBounds(-31/2, -31/2, 31, 31);
var show = function (event, popup) { popup.visible = true; if (this.popup != null && this.popup != popup) { this.popup.visible = false; }; this.popup = popup; }; node.on("mouseover", show, ctx, false, popup); popup.on("mouseover", show, ctx, false, popup);
return node;
};
DependencyGraph.Node.prototype = { constructor: DependencyGraph.Node, };
DependencyGraph.NodePopup = function (date, title, link) {
var container = new createjs.Container();
var textColor = "#707070"; var highlightColor = "#BABABA"; var backgroundColor = "#333333";
var xoffset = -58/2; var yoffset = -58/2;
var name = new createjs.Text();
name.text = title; name.font = "normal 21px Arial"; name.color = textColor; name.x = 78 + xoffset; name.y = 24 + yoffset;
var namew = name.getMeasuredWidth(); var nameh = name.getMeasuredHeight();
var hit = new createjs.Shape(); hit.graphics.beginFill(backgroundColor).drawRect(0, 0, namew, nameh); name.hitArea = hit; var changeColor = function (event, color) { name.color = color; }; name.on("mouseover", changeColor, null, false, highlightColor); name.on("mouseout", changeColor, null, false, textColor); name.on("click", function (event, link) { window.location.href = link; }, null, false, link);
var cdate = new createjs.Text();
cdate.text = date; cdate.font = "normal 10px Arial"; cdate.color = textColor; cdate.x = 78 + xoffset; cdate.y = 12.2 + yoffset;
var background = new createjs.Shape();
var w = Math.max(cdate.getMeasuredWidth(), namew) + 78 + 20;
var h = 58;
background.graphics.beginFill(backgroundColor); background.graphics.drawRect(xoffset, yoffset, w, h); background.graphics.beginFill(highlightColor); background.graphics.drawRect(xoffset, yoffset, h, h);
background.on("mouseout", function (event, item) { item.visible = false; }, null, false, container);
container.addChild(background, cdate, name); container.visible = false; container.setBounds(0, 0, 0, 0); return container;
};
DependencyGraph.NodePopup.prototype = { constructor: DependencyGraph.NodePopup, };
DependencyGraph.RootNode = function (category, popup, ctx) {
var container = new createjs.Container(); var catLabel = new createjs.Text(); catLabel.text = category; catLabel.font = "normal 21px Arial"; catLabel.color = "#707070"; catLabel.textAlign = "center"; catLabel.textBaseline = "bottom"; catLabel.rotation = 90; catLabel.x = -catLabel.getMeasuredHeight()/2; catLabel.y = -catLabel.getMeasuredWidth()/2 - 20 - 31/2; container.addChild(catLabel); var rootNode = new DependencyGraph.Node(popup, ctx); container.addChild(rootNode);
return container;
};
DependencyGraph.RootNode.prototype = {
constructor: DependencyGraph.RootNode,
};
/*DependencyGraph Methods*/ DependencyGraph.prototype.Setup = function (settings) { if(this.isLocked) { return; } this.isLocked = true;
this.categoryMap = settings.categorymap; this.urlDomain = settings.urldomain;
this.stage = new createjs.Stage(settings.canvasid);
this.stage.enableMouseOver();
this.scene = new createjs.Container();
var width = this.stage.canvas.width; var height = this.stage.canvas.height;
var dragBox = new createjs.Shape();
dragBox.graphics.beginFill(settings.bgcolor).drawRect(0, 0, width, height);
this.stage.addChild(dragBox);
this.stage.addChild(this.scene);
var offset = new createjs.Point(0, 0);
var ondrag = function(event) {
offset.x = event.stageX - this.scene.x; offset.y = event.stageY - this.scene.y;
};
var drag = function (event) { this.scene.x = event.stageX - offset.x; this.scene.y = event.stageY - offset.y; };
dragBox.on("mousedown", ondrag.bind(this), offset); dragBox.on("pressmove", drag.bind(this), offset); this.scene.on("mousedown", ondrag.bind(this), offset); this.scene.on("pressmove", drag.bind(this), offset);
createjs.Ticker.addEventListener("tick", function (event) { this.stage.update() }.bind(this));
var preload = new createjs.LoadQueue(); preload.addEventListener("fileload", this.handleFileComplete.bind(this)); preload.loadFile(settings.data); };
// 1 make nodes/popups 2 arrange 4 check success 5 make edges DependencyGraph.prototype.handleFileComplete = function (event) { console.log(event.item, event.item.type);
var rawGraph = event.result;
var popups = new createjs.Container();
var ctx = {popup: null}; var nodes = new createjs.Container();
/*prepare nodes*/
for (var i = rawGraph.length - 1; i >= 0; i--) {
var rawNode = rawGraph[i];
rawNode.id = rawNode.category+rawNode.number;
var date = rawNode.date; var title = rawNode.title; var link = this.urlDomain + rawNode.title.replace(/ /g,"_")+"_"+rawNode.id; var popup = new DependencyGraph.NodePopup(date, title, link); popups.addChild(popup);
var category = this.categoryMap ? this.categoryMap[rawNode.category] : rawNode.category;
var node = null; if (rawNode.isroot) { node = new DependencyGraph.RootNode(category, popup, ctx); this.roots.push(rawNode); } else { node = new DependencyGraph.Node(popup, ctx); } nodes.addChild(node);
rawNode.node = node;
rawNode.popup = popup; rawNode.isLeaf = false; rawNode.success = false;
this.nodeMap[rawNode.id] = rawNode; };
this.propagateSuccess(this.roots, this.nodeMap);
this.ArrangeNodes();
/*prepare edges*/
var successEdges = new createjs.Container(); var failEdges = new createjs.Container();
for (var i in this.nodeMap) { var node = this.nodeMap[i];
if (node.next == null) { continue; }
for (var j = node.next.length - 1; j >= 0; j--) { var nodeChild = this.nodeMap[node.next[j]]; var edge = new DependencyGraph.Edge(node, nodeChild, this.dx, this.dy);
if (nodeChild.success) { successEdges.addChild(edge); } else { failEdges.addChild(edge); };
}; };
/* prepare ends */ var ends = new createjs.Container(); for (var i in this.nodeMap) { var node = this.nodeMap[i]; if (node.isLeaf) { var x = node.node.x; var y = node.node.y; var success = node.success; var tmp1 = {node: {x: x, y: y}}; var tmp2 = {node: {x: x, y: y + this.dy / 2}, success: success}; var edge = new DependencyGraph.Edge(tmp1, tmp2, this.dx, this.dy); var end; if (success) { end = new DependencyGraph.Checkmark(); } else { end = new DependencyGraph.Cross(); }; end.x = x; end.y = y + this.dy / 2;
ends.addChild(edge, end); }; };
this.scene.addChild(failEdges, successEdges, ends, nodes, popups);
var half = this.stage.canvas.width / 2; var cbounds = this.scene.getBounds(); this.scene.x = half - Math.abs(cbounds.x + cbounds.width / 2); this.scene.y = -cbounds.y + 20;
};
DependencyGraph.prototype.propagateSuccess = function (roots, map) {
for (var i = roots.length - 1; i >= 0; i--) { this.propagateSuccessRec(roots[i], map); };
}
DependencyGraph.prototype.propagateSuccessRec = function (node, map) {
var success = false; if (node.isVisited) { return node.success; }; node.isVisited = true; if (node.next != null) { if (node.next.length == 0) { success = true; node.isLeaf = true; } else { for (var i = node.next.length - 1; i >= 0; i--) { var child = this.nodeMap[node.next[i]] success = this.propagateSuccessRec(child, map) || success; }; }; } else { node.isLeaf = true; }; node.success = success return success;
};
DependencyGraph.prototype.ArrangeNodes = function () { var xo = this.stage.canvas.width/2-260;
for (var i in this.nodeMap) { var node = this.nodeMap[i];
node.isVisited = false; }
this.CountNodesHelper(this.roots);
for (var i in this.nodeMap) { var node = this.nodeMap[i];
node.isVisited = false; }
this.ArrangeNodesHelper(this.roots,1,xo,4);
};
DependencyGraph.prototype.ArrangeNodesHelper = function (nodes,d,xo,fac) { var left = []; var right = [];
/*sort on success left and fail right*/ for (var i = nodes.length - 1; i >= 0; i--) { var node = nodes[i]; if (node.isVisited) { continue; } node.node.y = d*this.dy;
node.popup.y = node.node.y;
if (node.success) { left.push(node); } else { right.push(node); } };
/* pop a left element from stack unless in a right branch. and repeat precedure on origin node*/ var origin = left.length ? left.pop() : right.pop(); if(!origin) { return; }
var next = []; if (origin.next != null) { for (var i = origin.next.length - 1; i >= 0; i--) { next.push(this.nodeMap[origin.next[i]]); }; };
this.ArrangeNodesHelper(next,d+1,xo,0); /*pass left and right tree count to parent call*/ this.ArrangeNodesHelper(right,d,xo+origin.fac*this.dx,origin.nodeDiv.nR); this.ArrangeNodesHelper(left,d,xo-this.dx*origin.nodeDiv.nL,0);
origin.node.x = xo;
origin.popup.x = xo;
origin.isVisited = true; };
DependencyGraph.prototype.CountNodesHelper = function (nodes) {
var sum = function(o1) { return o1.nL+o1.nM+o1.nR; }
var left = [];
var right = [];
/*sort on success left and fail right*/ for (var i = nodes.length - 1; i >= 0; i--) { var node = nodes[i]; if (node.isVisited) { continue; } if (node.success) { left.push(node); } else { right.push(node); } };
/* pop a left element from stack unless in a right branche. and repeat precedure on origin node*/ var origin = left.length ? left.pop() : right.pop(); if(!origin) { return { nL:0, nM:1, nR:0 }; }
var next = []; if (origin.next != null) { for (var i = origin.next.length - 1; i >= 0; i--) { next.push(this.nodeMap[origin.next[i]]); }; }; var nMiddel = this.CountNodesHelper(next);
/*pass left and right tree count to parent call*/ var nRight; if (right.length != 0) { nRight = this.CountNodesHelper(right); } else { nRight = { nL:0, nM:0, nR:0 } }
var nLeft; if (left.length != 0) { nLeft = this.CountNodesHelper(left); } else { nLeft = { nL:0, nM:0, nR:0 } };
origin.isVisited = true;
origin.nodeDiv = { nL:sum(nLeft)+nMiddel.nL, nM:1, nR:sum(nRight)+nMiddel.nR }
origin.fac = origin.nodeDiv.nR - nRight.nR
return origin.nodeDiv;
};