|
I met the same problem, my workaround is start the line to child nodes at the same height of parent node rather than the center of all child nodes.
In function _firstWalk, remove following code in line 429(I made some modify before, so it only can be a approximate range)
midPoint -= tree._getNodeSize(node) / 2;
and in function _getChildrenCenter, modify line 112
return node.prelim + ((node1.prelim - node.prelim) + tree._getNodeSize(node1)) / 2;
->
return node.prelim
Hope it helps.
|
|
|
|
|
ECONode = function (id, pid, dsc, w, h, c, bc, target, meta) {
this.id = id;
this.pid = pid;
this.dsc = dsc;
this.w = w;
this.h = h;
this.c = c;
this.bc = bc;
this.target = target;
this.meta = meta;
this.dbIndex = 0;
this.XPosition = 0;
this.YPosition = 0;
this.prelim = 0;
this.modifier = 0;
this.leftNeighbor = null;
this.rightNeighbor = null;
this.nodeParent = null;
this.nodeChildren = [];
this.isCollapsed = false;
this.canCollapse = false;
this.isSelected = false;
};
ECONode.prototype._getLevel = function () {
if (this.nodeParent.id == -1) {
return 0;
}
else return this.nodeParent._getLevel() + 1;
};
ECONode.prototype._isAncestorCollapsed = function () {
if (this.nodeParent.isCollapsed) {
return true;
} else {
if (this.nodeParent.id == -1) {
return false;
} else {
return this.nodeParent._isAncestorCollapsed();
}
}
};
ECONode.prototype._setAncestorsExpanded = function () {
if (this.nodeParent.id == -1) {
return;
} else {
this.nodeParent.isCollapsed = false;
return this.nodeParent._setAncestorsExpanded();
}
};
ECONode.prototype._isAncestor = function (id) {
if (this.nodeParent.id == id) {
return true;
} else {
if (this.nodeParent.id == -1) {
return false;
} else {
return this.nodeParent._isAncestor(id);
}
}
};
ECONode.prototype._getChildrenCount = function () {
if (this.isCollapsed) {
return 0;
}
if (this.nodeChildren == null) {
return 0;
} else {
return this.nodeChildren.length;
}
};
ECONode.prototype._getLeftSibling = function () {
if (this.leftNeighbor != null && this.leftNeighbor.nodeParent == this.nodeParent) {
return this.leftNeighbor;
} else {
return null;
}
};
ECONode.prototype._getRightSibling = function () {
if (this.rightNeighbor != null && this.rightNeighbor.nodeParent == this.nodeParent) {
return this.rightNeighbor;
} else {
return null;
}
};
ECONode.prototype._getChildAt = function (i) {
return this.nodeChildren[i];
};
ECONode.prototype._getChildrenCenter = function (tree) {
node = this._getFirstChild();
node1 = this._getLastChild();
return node.prelim + ((node1.prelim - node.prelim) + tree._getNodeSize(node1)) / 2;
};
ECONode.prototype._getFirstChild = function () {
return this._getChildAt(0);
};
ECONode.prototype._getLastChild = function () {
return this._getChildAt(this._getChildrenCount() - 1);
};
ECONode.prototype._drawChildrenLinks = function (tree) {
var s = [];
var xa = 0, ya = 0, xb = 0, yb = 0, xc = 0, yc = 0, xd = 0, yd = 0;
var node1 = null;
switch (tree.config.iRootOrientation) {
case ECOTree.RO_TOP:
xa = this.XPosition + (this.w / 2);
ya = this.YPosition + this.h;
break;
case ECOTree.RO_BOTTOM:
xa = this.XPosition + (this.w / 2);
ya = this.YPosition;
break;
case ECOTree.RO_RIGHT:
xa = this.XPosition;
ya = this.YPosition + (this.h / 2);
break;
case ECOTree.RO_LEFT:
xa = this.XPosition + this.w;
ya = this.YPosition + (this.h / 2);
break;
}
for (var k = 0; k < this.nodeChildren.length; k++) {
node1 = this.nodeChildren[k];
switch (tree.config.iRootOrientation) {
case ECOTree.RO_TOP:
xd = xc = node1.XPosition + (node1.w / 2);
yd = node1.YPosition;
xb = xa;
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
yb = yc = yd - tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_BOTTOM:
yb = yc = ya + tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_CENTER:
yb = yc = ya + (yd - ya) / 2;
break;
}
break;
case ECOTree.RO_BOTTOM:
xd = xc = node1.XPosition + (node1.w / 2);
yd = node1.YPosition + node1.h;
xb = xa;
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
yb = yc = yd + tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_BOTTOM:
yb = yc = ya - tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_CENTER:
yb = yc = yd + (ya - yd) / 2;
break;
}
break;
case ECOTree.RO_RIGHT:
xd = node1.XPosition + node1.w;
yd = yc = node1.YPosition + (node1.h / 2);
yb = ya;
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
xb = xc = xd + tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_BOTTOM:
xb = xc = xa - tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_CENTER:
xb = xc = xd + (xa - xd) / 2;
break;
}
break;
case ECOTree.RO_LEFT:
xd = node1.XPosition;
yd = yc = node1.YPosition + (node1.h / 2);
yb = ya;
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
xb = xc = xd - tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_BOTTOM:
xb = xc = xa + tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_CENTER:
xb = xc = xa + (xd - xa) / 2;
break;
}
break;
}
tree.ctx.save();
tree.ctx.strokeStyle = tree.config.linkColor;
tree.ctx.beginPath();
switch (tree.config.linkType) {
case "M":
tree.ctx.moveTo(xa, ya);
tree.ctx.lineTo(xb, yb);
tree.ctx.lineTo(xc, yc);
tree.ctx.lineTo(xd, yd);
break;
case "B":
tree.ctx.moveTo(xa, ya);
tree.ctx.bezierCurveTo(xb, yb, xc, yc, xd, yd);
break;
}
tree.ctx.stroke();
tree.ctx.restore();
}
return s.join('');
};
ECOTree = function (obj, elm) {
this.config = {
iMaxDepth : 100,
iLevelSeparation : 40,
iSiblingSeparation : 40,
iSubtreeSeparation : 80,
iRootOrientation : ECOTree.RO_TOP,
iNodeJustification : ECOTree.NJ_TOP,
topXCorrection : 0,
topYCorrection : 0,
topXAdjustment : 0,
topYAdjustment : 0,
linkType : "M",
linkColor : "blue",
nodeColor : "#CCCCFF",
nodeFill : ECOTree.NF_GRADIENT,
nodeBorderColor : "blue",
nodeSelColor : "#FFFFCC",
nodeRadius : 5,
levelColors : ["#5555FF","#8888FF","#AAAAFF","#CCCCFF"],
levelBorderColors : ["#5555FF","#8888FF","#AAAAFF","#CCCCFF"],
colorStyle : ECOTree.CS_NODE,
useTarget : true,
searchMode : ECOTree.SM_DSC,
selectMode : ECOTree.SL_MULTIPLE,
defaultNodeWidth : 80,
defaultNodeHeight : 40,
defaultTarget : 'javascript:void(0);',
expandedImage : './img/less.gif',
collapsedImage : './img/plus.gif',
transImage : './img/trans.gif'
};
if (jQuery("#eco_tree_ruler_span").length == 0) {
jQuery("body").append("<span id='eco_tree_ruler_span' class='econode' style='visibility:hidden'></span>");
}
this.version = "1.5-icb-3";
this.obj = obj;
this.treeContainer = jQuery("#" + elm);
this.self = this;
this.ctx = null;
this.canvasoffsetTop = 0;
this.canvasoffsetLeft = 0;
this.chartHeight = -1;
this.chartWidth = -1;
this.maxLevelHeight = [];
this.maxLevelWidth = [];
this.previousLevelNode = [];
this.rootYOffset = 0;
this.rootXOffset = 0;
this.nDatabaseNodes = [];
this.mapIDs = {};
this.root = new ECONode(-1, null, null, 2, 2);
this.iSelectedNode = -1;
this.iLastSearch = 0;
};
ECOTree.RO_TOP = 0;
ECOTree.RO_BOTTOM = 1;
ECOTree.RO_RIGHT = 2;
ECOTree.RO_LEFT = 3;
ECOTree.NJ_TOP = 0;
ECOTree.NJ_CENTER = 1;
ECOTree.NJ_BOTTOM = 2;
ECOTree.NF_GRADIENT = 0;
ECOTree.NF_FLAT = 1;
ECOTree.CS_NODE = 0;
ECOTree.CS_LEVEL = 1;
ECOTree.SM_DSC = 0;
ECOTree.SM_META = 1;
ECOTree.SM_BOTH = 2;
ECOTree.SL_MULTIPLE = 0;
ECOTree.SL_SINGLE = 1;
ECOTree.SL_NONE = 2;
ECOTree._roundedRect = function (ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x, y + radius);
ctx.lineTo(x, y + height - radius);
ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
ctx.lineTo(x + width - radius, y + height);
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
ctx.lineTo(x + width, y + radius);
ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
ctx.lineTo(x + radius, y);
ctx.quadraticCurveTo(x, y, x, y + radius);
ctx.fill();
ctx.stroke();
};
ECOTree._canvasNodeClickHandler = function (tree, target, nodeid) {
if (target != nodeid) {
return;
}
tree.selectNode(nodeid, true);
};
ECOTree._firstWalk = function (tree, node, level) {
var leftSibling = null;
node.XPosition = 0;
node.YPosition = 0;
node.prelim = 0;
node.modifier = 0;
node.leftNeighbor = null;
node.rightNeighbor = null;
tree._setLevelHeight(node, level);
tree._setLevelWidth(node, level);
tree._setNeighbors(node, level);
if (node._getChildrenCount() == 0 || level == tree.config.iMaxDepth) {
leftSibling = node._getLeftSibling();
if (leftSibling != null) {
node.prelim = leftSibling.prelim + tree._getNodeSize(leftSibling) + tree.config.iSiblingSeparation;
} else {
node.prelim = 0;
}
} else {
var n = node._getChildrenCount();
for (var i = 0; i < n; i++) {
var iChild = node._getChildAt(i);
ECOTree._firstWalk(tree, iChild, level + 1);
}
var midPoint = node._getChildrenCenter(tree);
midPoint -= tree._getNodeSize(node) / 2;
leftSibling = node._getLeftSibling();
if (leftSibling != null) {
node.prelim = leftSibling.prelim + tree._getNodeSize(leftSibling) + tree.config.iSiblingSeparation;
node.modifier = node.prelim - midPoint;
ECOTree._apportion(tree, node, level);
} else {
node.prelim = midPoint;
}
}
};
ECOTree._apportion = function (tree, node, level) {
var firstChild = node._getFirstChild();
var firstChildLeftNeighbor = firstChild.leftNeighbor;
var j = 1;
for (var k = tree.config.iMaxDepth - level; firstChild != null && firstChildLeftNeighbor != null && j <= k;) {
var modifierSumRight = 0;
var modifierSumLeft = 0;
var rightAncestor = firstChild;
var leftAncestor = firstChildLeftNeighbor;
for (var l = 0; l < j; l++) {
rightAncestor = rightAncestor.nodeParent;
leftAncestor = leftAncestor.nodeParent;
modifierSumRight += rightAncestor.modifier;
modifierSumLeft += leftAncestor.modifier;
}
var totalGap = (firstChildLeftNeighbor.prelim + modifierSumLeft +
tree._getNodeSize(firstChildLeftNeighbor) + tree.config.iSubtreeSeparation) -
(firstChild.prelim + modifierSumRight);
if (totalGap > 0) {
var subtreeAux = node;
var numSubtrees = 0;
for (; subtreeAux != null && subtreeAux != leftAncestor; subtreeAux = subtreeAux._getLeftSibling()) {
numSubtrees++;
}
if (subtreeAux != null) {
var subtreeMoveAux = node;
var singleGap = totalGap / numSubtrees;
for (; subtreeMoveAux != leftAncestor; subtreeMoveAux = subtreeMoveAux._getLeftSibling()) {
subtreeMoveAux.prelim += totalGap;
subtreeMoveAux.modifier += totalGap;
totalGap -= singleGap;
}
}
}
j++;
if (firstChild._getChildrenCount() == 0) {
firstChild = tree._getLeftmost(node, 0, j);
} else {
firstChild = firstChild._getFirstChild();
}
if (firstChild != null) {
firstChildLeftNeighbor = firstChild.leftNeighbor;
}
}
};
ECOTree._secondWalk = function (tree, node, level, X, Y) {
if (level <= tree.config.iMaxDepth) {
var xTmp = tree.rootXOffset + node.prelim + X;
var yTmp = tree.rootYOffset + Y;
var maxsizeTmp = 0;
var nodesizeTmp = 0;
var corrTmp = 0;
var flag = false;
switch (tree.config.iRootOrientation) {
case ECOTree.RO_TOP:
case ECOTree.RO_BOTTOM:
maxsizeTmp = tree.maxLevelHeight[level];
nodesizeTmp = node.h;
break;
case ECOTree.RO_RIGHT:
case ECOTree.RO_LEFT:
maxsizeTmp = tree.maxLevelWidth[level];
flag = true;
nodesizeTmp = node.w;
break;
}
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
node.XPosition = xTmp;
node.YPosition = yTmp;
break;
case ECOTree.NJ_CENTER:
node.XPosition = xTmp;
node.YPosition = yTmp + (maxsizeTmp - nodesizeTmp) / 2;
break;
case ECOTree.NJ_BOTTOM:
node.XPosition = xTmp;
node.YPosition = (yTmp + maxsizeTmp) - nodesizeTmp;
break;
}
if (flag) {
var swapTmp = node.XPosition;
node.XPosition = node.YPosition;
node.YPosition = swapTmp;
}
switch (tree.config.iRootOrientation) {
case ECOTree.RO_BOTTOM:
node.YPosition = -node.YPosition - nodesizeTmp;
break;
case ECOTree.RO_RIGHT:
node.XPosition = -node.XPosition - nodesizeTmp;
break;
}
if (node._getChildrenCount() != 0) {
ECOTree._secondWalk(tree, node._getFirstChild(), level + 1, X + node.modifier,
Y + maxsizeTmp + tree.config.iLevelSeparation);
}
var rightSibling = node._getRightSibling();
if (rightSibling != null) {
ECOTree._secondWalk(tree, rightSibling, level, X, Y);
}
if (node.XPosition < 0) {
corrTmp = 0 - node.XPosition;
if (corrTmp > tree.config.topXCorrection) {
tree.config.topXCorrection = corrTmp;
}
}
if (node.YPosition < 0) {
corrTmp = 0 - node.YPosition;
if (corrTmp > tree.config.topYCorrection) {
tree.config.topYCorrection = corrTmp;
}
}
}
};
ECOTree._thirdWalk = function (tree, node, level) {
if (level <= tree.config.iMaxDepth) {
node.XPosition = node.XPosition + tree.config.topXCorrection;
node.YPosition = node.YPosition + tree.config.topYCorrection;
if (node._getChildrenCount() != 0) {
ECOTree._thirdWalk(tree, node._getFirstChild(), level + 1);
}
var rightSibling = node._getRightSibling();
if (rightSibling != null) {
ECOTree._thirdWalk(tree, rightSibling, level);
}
}
};
ECOTree.prototype._positionTree = function () {
this.maxLevelHeight = [];
this.maxLevelWidth = [];
this.previousLevelNode = [];
ECOTree._firstWalk(this.self, this.root, 0);
switch (this.config.iRootOrientation) {
case ECOTree.RO_TOP:
case ECOTree.RO_LEFT:
this.rootXOffset = this.config.topXAdjustment + this.root.XPosition;
this.rootYOffset = this.config.topYAdjustment + this.root.YPosition;
break;
case ECOTree.RO_BOTTOM:
case ECOTree.RO_RIGHT:
this.rootXOffset = this.config.topXAdjustment + this.root.XPosition;
this.rootYOffset = this.config.topYAdjustment + this.root.YPosition;
}
this.config.topXCorrection = 0;
this.config.topYCorrection = 0;
ECOTree._secondWalk(this.self, this.root, 0, 0, 0);
if ((this.config.topXCorrection > 0) || (this.config.topYCorrection > 0)) {
ECOTree._thirdWalk(this.self, this.root, 0);
}
};
ECOTree.prototype._setLevelHeight = function (node, level) {
if (this.maxLevelHeight[level] == null) {
this.maxLevelHeight[level] = 0;
}
if (this.maxLevelHeight[level] < node.h) {
this.maxLevelHeight[level] = node.h;
}
};
ECOTree.prototype._setLevelWidth = function (node, level) {
if (this.maxLevelWidth[level] == null) {
this.maxLevelWidth[level] = 0;
}
if (this.maxLevelWidth[level] < node.w) {
this.maxLevelWidth[level] = node.w;
}
};
ECOTree.prototype._setNeighbors = function(node, level) {
node.leftNeighbor = this.previousLevelNode[level];
if (node.leftNeighbor != null) {
node.leftNeighbor.rightNeighbor = node;
}
this.previousLevelNode[level] = node;
};
ECOTree.prototype._getNodeSize = function (node) {
switch (this.config.iRootOrientation) {
case ECOTree.RO_TOP:
case ECOTree.RO_BOTTOM:
return node.w;
case ECOTree.RO_RIGHT:
case ECOTree.RO_LEFT:
return node.h;
}
return 0;
};
ECOTree.prototype._getLeftmost = function (node, level, maxlevel) {
if (level >= maxlevel) {
return node;
}
if (node._getChildrenCount() == 0) {
return null;
}
var n = node._getChildrenCount();
for (var i = 0; i < n; i++) {
var iChild = node._getChildAt(i);
var leftmostDescendant = this._getLeftmost(iChild, level + 1, maxlevel);
if (leftmostDescendant != null) {
return leftmostDescendant;
}
}
return null;
};
ECOTree.prototype._selectNodeInt = function (dbindex, flagToggle) {
if (this.config.selectMode == ECOTree.SL_SINGLE) {
if ((this.iSelectedNode != dbindex) && (this.iSelectedNode != -1)) {
this.nDatabaseNodes[this.iSelectedNode].isSelected = false;
}
this.iSelectedNode = (this.nDatabaseNodes[dbindex].isSelected && flagToggle) ? -1 : dbindex;
}
this.nDatabaseNodes[dbindex].isSelected = (flagToggle) ? !this.nDatabaseNodes[dbindex].isSelected : true;
};
ECOTree.prototype._collapseAllInt = function (flag) {
var node = null;
for (var n = 0; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
if (node.canCollapse) {
node.isCollapsed = flag;
}
}
this.UpdateTree();
};
ECOTree.prototype._selectAllInt = function (flag) {
var node = null;
for (var k = 0; k < this.nDatabaseNodes.length; k++) {
node = this.nDatabaseNodes[k];
node.isSelected = flag;
}
this.iSelectedNode = -1;
this.UpdateTree();
};
ECOTree.prototype._drawTree = function () {
var s = [];
var node = null;
var color = "";
var border = "";
for (var n = 0; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
switch (this.config.colorStyle) {
case ECOTree.CS_NODE:
color = node.c;
border = node.bc;
break;
case ECOTree.CS_LEVEL:
var iColor = node._getLevel() % this.config.levelColors.length;
color = this.config.levelColors[iColor];
iColor = node._getLevel() % this.config.levelBorderColors.length;
border = this.config.levelBorderColors[iColor];
break;
}
if (!node._isAncestorCollapsed()) {
this.ctx.save();
this.ctx.strokeStyle = border;
switch (this.config.nodeFill) {
case ECOTree.NF_GRADIENT:
var lgradient = this.ctx.createLinearGradient(node.XPosition, 0, node.XPosition + node.w, 0);
lgradient.addColorStop(0.0, ((node.isSelected) ? this.config.nodeSelColor : color));
lgradient.addColorStop(1.0, "#F5FFF5");
this.ctx.fillStyle = lgradient;
break;
case ECOTree.NF_FLAT:
this.ctx.fillStyle = ((node.isSelected) ? this.config.nodeSelColor : color);
break;
}
ECOTree._roundedRect(this.ctx, node.XPosition, node.YPosition, node.w, node.h, this.config.nodeRadius);
this.ctx.restore();
s.push('<div id="' + node.id + '" class="econode" style="position:absolute;top:' + (node.YPosition + this.canvasoffsetTop) + 'px; left:' + (node.XPosition + this.canvasoffsetLeft) + 'px; width:' + node.w + '; height:' + node.h + ';z-index:100;" ');
if (this.config.selectMode != ECOTree.SL_NONE) {
s.push('onclick="javascript:ECOTree._canvasNodeClickHandler(' + this.obj + ',event.target.id,\'' + node.id + '\');" ');
}
s.push('>');
s.push('<font face=Verdana size=1>');
if (node.canCollapse) {
s.push('<a id="c' + node.id + '" href="javascript:' + this.obj + '.collapseNode(\'' + node.id + '\', true);" >');
s.push('<img border=0 src="' + ((node.isCollapsed) ? this.config.collapsedImage : this.config.expandedImage) + '" >');
s.push('</a>');
s.push('<img src="' + this.config.transImage + '" >');
}
if (node.target && this.config.useTarget) {
s.push('<a id="t' + node.id + '" href="' + node.target + '">');
s.push(node.dsc);
s.push('</a>');
} else {
s.push(node.dsc);
}
s.push('</font>');
s.push('</div>');
if (!node.isCollapsed) {
s.push(node._drawChildrenLinks(this.self));
}
}
}
return s.join('');
};
ECOTree.prototype._calcWidthAndHeight = function () {
this.chartWidth = 0;
this.chartHeight = 0;
for (var n = 0; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
if (!node._isAncestorCollapsed()) {
this.chartWidth = Math.max(this.chartWidth, node.XPosition + node.w);
this.chartHeight = Math.max(this.chartHeight, node.YPosition + node.h);
}
}
this.chartWidth = Math.round(this.chartWidth) + 2;
this.chartHeight = Math.round(this.chartHeight) + 2;
};
ECOTree.prototype.UpdateTree = function () {
this.treeContainer.empty();
this._positionTree();
this._calcWidthAndHeight();
this.treeContainer.css({
'position': 'relative',
'width': this.chartWidth,
'height': this.chartHeight,
'overflow': 'hidden'
});
var canvas = document.createElement('canvas');
jQuery(canvas).attr('width', this.chartWidth).attr('height', this.chartHeight).attr('id', 'ECOTreecanvas').appendTo(this.treeContainer);
if (typeof G_vmlCanvasManager != "undefined") {
canvas = G_vmlCanvasManager.initElement(canvas);
}
if (canvas && canvas.getContext) {
this.ctx = canvas.getContext("2d");
var h = this._drawTree();
this.treeContainer.append(h);
}
var that = this;
var node = $('div.econode');
node.draggable({
cursor : 'pointer',
distance : 5,
revert: "invalid",
containment:this.treeContainer,
helper: function(event){
return $( "<div class='drag-hover'>"+that._getNodeById(this.id).dsc+"</div>" );
}
});
node.droppable({
accept: 'div.econode',
hoverClass: 'drop-hover',
drop: function( event, ui ) {
that.changeParent($(ui.draggable).attr("id"),$(this).attr("id"));
that.UpdateTree();
}
});
};
ECOTree.prototype.add = function (id, pid, dsc, w, h, c, bc, target, meta) {
var nw = w || this.config.defaultNodeWidth;
var nh = h || this.config.defaultNodeHeight;
if (nw == -1 || nh == -1) {
var ruler = jQuery("#eco_tree_ruler_span");
ruler.css({'width' : '', 'height' : ''});
if (nw != -1) {
ruler.css({'width' : nw});
}
if (nh != -1) {
ruler.css({'height' : nh});
}
ruler.html(dsc);
if (nw == -1) {
nw = ruler.innerWidth() + 18;
}
if (nh == -1) {
nh = ruler.innerHeight() + 4;
}
}
var color = c || this.config.nodeColor;
var border = bc || this.config.nodeBorderColor;
var tg = (this.config.useTarget) ? ((typeof target == "undefined") ? (this.config.defaultTarget) : target) : null;
var metadata = (typeof meta != "undefined") ? meta : "";
var pnode = null;
if (pid == -1) {
pnode = this.root;
} else {
for (var k = 0; k < this.nDatabaseNodes.length; k++) {
if (this.nDatabaseNodes[k].id == pid) {
pnode = this.nDatabaseNodes[k];
break;
}
}
}
var node = new ECONode(id, pid, dsc, nw, nh, color, border, tg, metadata);
node.nodeParent = pnode;
pnode.canCollapse = true;
var i = this.nDatabaseNodes.length;
node.dbIndex = this.mapIDs[id] = i;
this.nDatabaseNodes[i] = node;
var h = pnode.nodeChildren.length;
pnode.nodeChildren[h] = node;
};
ECOTree.prototype._getNodeById = function(id,retIndex){
if(this.mapIDs[id])
return retIndex?this.mapIDs[id]:this.nDatabaseNodes[this.mapIDs[id]];
for (var k = 0; k < this.nDatabaseNodes.length; k++) {
if (this.nDatabaseNodes[k].id == id)
return retIndex?k:this.nDatabaseNodes[k];
}
return null;
};
ECOTree.prototype._getChildById = function(node,chid,retIndex){
for (var k = 0; k < node.nodeChildren.length; k++) {
if (node.nodeChildren[k].id == chid)
return retIndex?k:node.nodeChildren[k];
}
return null;
};
ECOTree.prototype._remapNodes = function(){
this.mapIDs = {};
for(var i=0;i<this.nDatabaseNodes.length;i++)
this.mapIDs[this.nDatabaseNodes[i].id] = i;
};
ECOTree.prototype.removeNode = function(nodeid) {
var node_index = this._getNodeById(nodeid,true);
if(node_index !== null){
var node = this.nDatabaseNodes[node_index];
this.nDatabaseNodes.splice (node_index, 1);
this._remapNodes();
var pnode = this._getNodeById(node.pid);
if(pnode !== null){
for(var m=0;m<pnode.nodeChildren.length;m++){
if(pnode.nodeChildren[m].id == node.id){
pnode.nodeChildren.splice (m, 1);
if(!pnode.nodeChildren.length)
pnode.canCollapse = false;
break;
}
}
}
for(var i=0;i < node.nodeChildren.length; i++){
this.removeNode(node.nodeChildren[i].id);
}
}
};
ECOTree.prototype.changeParent = function(nodeid,pid){
var node = this._getNodeById(nodeid);
var pswitchnode = this._getNodeById(pid);
if(!pswitchnode._isAncestor(node.id)){
if(node !== null && pswitchnode !== null){
var pnode = this._getNodeById(node.pid);
if(pnode !== null){
var index_child = this._getChildById(pnode,nodeid,true);
if(index_child !== null){
pnode.nodeChildren.splice(index_child, 1);
if(!pnode.nodeChildren.length)
pnode.canCollapse = false;
}
}
node.nodeParent = pswitchnode;
node.pid = pid;
pswitchnode.nodeChildren[pswitchnode.nodeChildren.length] = node;
pswitchnode.canCollapse = true;
}
}
};
ECOTree.prototype.searchNodes = function (str) {
var node = null;
var m = this.config.searchMode;
var sm = (this.config.selectMode == ECOTree.SL_SINGLE);
if (typeof str == "undefined") return;
if (str == "") return;
var found = false;
var n = (sm) ? this.iLastSearch : 0;
if (n == this.nDatabaseNodes.length) n = this.iLastSeach = 0;
str = str.toLocaleUpperCase();
for (; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
if (node.dsc.toLocaleUpperCase().indexOf(str) != -1 && ((m == ECOTree.SM_DSC) || (m == ECOTree.SM_BOTH))) {
node._setAncestorsExpanded();
this._selectNodeInt(node.dbIndex, false);
found = true;
}
if (node.meta.toLocaleUpperCase().indexOf(str) != -1 && ((m == ECOTree.SM_META) || (m == ECOTree.SM_BOTH))) {
node._setAncestorsExpanded();
this._selectNodeInt(node.dbIndex, false);
found = true;
}
if (sm && found) {
this.iLastSearch = n + 1;
break;
}
}
this.UpdateTree();
};
ECOTree.prototype.selectAll = function () {
if (this.config.selectMode != ECOTree.SL_MULTIPLE) {
return;
}
this._selectAllInt(true);
};
ECOTree.prototype.unselectAll = function () {
this._selectAllInt(false);
};
ECOTree.prototype.collapseAll = function () {
this._collapseAllInt(true);
};
ECOTree.prototype.expandAll = function () {
this._collapseAllInt(false);
};
ECOTree.prototype.collapseNode = function (nodeid, upd) {
var dbindex = this.mapIDs[nodeid];
this.nDatabaseNodes[dbindex].isCollapsed = !this.nDatabaseNodes[dbindex].isCollapsed;
if (upd) {
this.UpdateTree();
}
};
ECOTree.prototype.selectNode = function (nodeid, upd) {
this._selectNodeInt(this.mapIDs[nodeid], true);
if (upd) {
this.UpdateTree();
}
};
ECOTree.prototype.setNodeTitle = function (nodeid, title, upd) {
var dbindex = this.mapIDs[nodeid];
this.nDatabaseNodes[dbindex].dsc = title;
if (upd) {
this.UpdateTree();
}
};
ECOTree.prototype.setNodeMetadata = function (nodeid, meta, upd) {
var dbindex = this.mapIDs[nodeid];
this.nDatabaseNodes[dbindex].meta = meta;
if (upd) {
this.UpdateTree();
}
};
ECOTree.prototype.setNodeTarget = function (nodeid, target, upd) {
var dbindex = this.mapIDs[nodeid];
this.nDatabaseNodes[dbindex].target = target;
if (upd) {
this.UpdateTree();
}
};
ECOTree.prototype.setNodeColors = function (nodeid, color, border, upd) {
var dbindex = this.mapIDs[nodeid];
if (color) {
this.nDatabaseNodes[dbindex].c = color;
}
if (border) {
this.nDatabaseNodes[dbindex].bc = border;
}
if (upd) {
this.UpdateTree();
}
};
ECOTree.prototype.getSelectedNodes = function () {
var node = null;
var selection = [];
var selnode = null;
for (var n = 0; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
if (node.isSelected) {
selnode = {
"id" : node.id,
"dsc" : node.dsc,
"meta" : node.meta
};
selection[selection.length] = selnode;
}
}
return selection;
};
demo page:
<html>
<head>
<title>ECOTree Simple Tree 1</title>
<script type="text/javascript" src="js/jquery-2.0.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.10.3.js"></script>
<script type="text/javascript" src="js/ECOTree.js"></script>
<link type="text/css" rel="stylesheet" href="themes/ui-darkness/jquery-ui-1.10.3.css" />
<link type="text/css" rel="stylesheet" href="css/ECOTree.css" />
<script>
var myTree = null;
function CreateTree() {
myTree = new ECOTree('myTree','myTreeContainer');
myTree.add("level0",-1,"level0",-1,-1);
myTree.add("level1","level0","level1",-1,-1);
myTree.add("level1_1","level0","level1_1",-1,-1);
myTree.add("level2","level1","level2",-1,-1);
myTree.add("level3","level2","level2",-1,-1);
myTree.add("level32","level2","level2",-1,-1);
myTree.add("level33","level2","level2",-1,-1);
myTree.add("level22","level1_1","level2",-1,-1);
myTree.add("level23","level1","level2",-1,-1);
myTree.add("level4","level33","level2",-1,-1);
myTree.removeNode("level32");
myTree.UpdateTree();
}
</script>
</head>
<body onload="CreateTree();">
<div id="myTreeContainer"></div>
</body>
</html>
|
|
|
|
|
Hola Emilio, excelente trabajo!
Una consulta, se puede configurar el Árbol para que se COMBINEN los nodos iguales.
Por ejemplo, cuando de un Nodo (Nivel-1) voy a la opción de abajo (Nivel-2) y ese nodo es el mismo al que llegaría desde otro nodo de Nivel-1 de mas abajo que el primero, pero yendo para arriba.
me explico?
En todo caso mando una imagen para que quede mas claro.
Gracias!
|
|
|
|
|
Hello Emilio
first, very nice tree you made
but i found a problem in node color
if i need every node color to be different
how to do that?
i tried modifying this line in sample4.html that i downloaded
t.add(4,1,'lichens',400,200,"#FF0000","#FF0000","","");
but it doesn't work
thanks
|
|
|
|
|
Hey, it's me (I invented Walker's Algorithm, gosh, almost 25 years ago).
I'd like to do a Wikipedia page on the topic, and include some images of great tress people have drawn. I like the ones at the top of this article (how might I get permission to use them freely?), and wonder what other beautiful trees people might have that I could use for illustration -- with full attribution to whoever created them.
It gives me great pleasure to see this code downloaded here more than 350,000 times.
My best to all - John Q.
|
|
|
|
|
I noticed if the node's iLevelSeparation is huge, the tree starts way too far from top canvas. Can we position the tree's top yPosition? How?
Thanks for the great code
|
|
|
|
|
Hi, do you know a solution for chrome ?
Many thanks.
|
|
|
|
|
Hello,in the article it said that
Sample include
"In the download you can find several simple examples you can play with. All the images in this article are made with the code on the examples. There is an advanced example which will let you play with almost all the options in the component. The data in the samples has been obtained in the Wikipedia."
here has already offered six simple example,they are so perfect! how can I find more example and advanced example? Could you offer some web url? Or how to search themin Wikipedia?
Thank you!
|
|
|
|
|
Great job, it works fine with Firefox,Chrome, but do not see any node IE.9. Could some help me? You may attach the latest release ? Thanks
info@sagt3k.com
|
|
|
|
|
I could not get this to render properly in ie9 either. when render is set to "AUTO", ie9 would render as VML (as did all versions of IE), which just was not working properly.
Since ie9 supports canvas, i changed the getAutoRenderMode function to check for the ability to create canvas, rather than checking browser. I feel this sort of approach is more future proof anyway.
Also, I noticed that ie8 does not render VML very well. To get around this, I added a javascript function that would change meta[http-equiv="X-UA-Compatible" to ie7 when the page was opened in ie8.
|
|
|
|
|
I have used this subtree . it is good to use but the problem i am facing is to delete the node. does any one know how to remove the node
|
|
|
|
|
![Go to Parent](https://www.codeproject.com/App_Themes/CodeProject/Img/arrow-up24.png) aad this code:
ECOTree.prototype._getNodeById = function(id,retIndex){
if(this.mapIDs[id])
return retIndex?this.mapIDs[id]:this.nDatabaseNodes[this.mapIDs[id]];
for (var k = 0; k < this.nDatabaseNodes.length; k++) {
if (this.nDatabaseNodes[k].id == id)
return retIndex?k:this.nDatabaseNodes[k];
}
return null;
};
ECOTree.prototype._getChildById = function(node,chid,retIndex){
for (var k = 0; k < node.nodeChildren.length; k++) {
if (node.nodeChildren[k].id == chid)
return retIndex?k:node.nodeChildren[k];
}
return null;
};
ECOTree.prototype._remapNodes = function(){
this.mapIDs = {};
for(var i=0;i<this.nDatabaseNodes.length;i++)
this.mapIDs[this.nDatabaseNodes[i].id] = i;
};
ECOTree.prototype.removeNode = function(nodeid) {
var node_index = this._getNodeById(nodeid,true);
if(node_index !== null){
var node = this.nDatabaseNodes[node_index];
this.nDatabaseNodes.splice (node_index, 1);
this._remapNodes();
var pnode = this._getNodeById(node.pid);
if(pnode !== null){
for(var m=0;m<pnode.nodeChildren.length;m++){
if(pnode.nodeChildren[m].id == node.id){
pnode.nodeChildren.splice (m, 1);
if(!pnode.nodeChildren.length)
pnode.canCollapse = false;
break;
}
}
}
for(var i=0;i < node.nodeChildren.length; i++){
this.removeNode(node.nodeChildren[i].id);
}
}
};
ECOTree.prototype.changeParent = function(nodeid,pid){
var node = this._getNodeById(nodeid);
var pswitchnode = this._getNodeById(pid);
if(node !== null && pswitchnode !== null){
var pnode = this._getNodeById(node.pid);
if(pnode !== null){
var index_child = this._getChildById(pnode,nodeid,true);
if(index_child !== null)
pnode.nodeChildren.splice(index_child, 1);
}
node.nodeParent = pswitchnode;
node.pid = pid;
node.siblingIndex = node.nodeParent.length;
pswitchnode.nodeChildren[pswitchnode.nodeChildren.length] = node;
}
};
|
|
|
|
|
It's fine but unfortunately not compatible with google chrome
|
|
|
|
|
Hi, do you have a solution for chrome ?
Thanks
|
|
|
|
|
Hi,
To get this work in chrome just add the following line in _getAutoRenderMode function:
var is_ch = /chrome/.test(navigator.userAgent.toLowerCase());
Then modify line 368 (add is_ch test):
if (is_ff || is_ch) r = "CANVAS";
and line 708 (remove "{" and "}" chars from style definition):
s.push('<div id="' + node.id + '" class="econode" style="top:'+(node.YPosition+this.canvasoffsetTop)+'; left:'+(node.XPosition+this.canvasoffsetLeft)+'; width:'+node.w+'; height:'+node.h+';" ');
Hope this helps.
|
|
|
|
|
Your fix works. 10/10 ![Smile | :)](https://codeproject.global.ssl.fastly.net/script/Forums/Images/smiley_smile.gif)
|
|
|
|
|
Hi
Anyone know how to get this to run under safari on apple mac/iOS
The tree works fine but the nodes and lines don't display
Thanks
Shaun
|
|
|
|
|
I have not tested my solution (see message just above) to get this work with Chrome in Safari, but using the same strategy and only changing the browser detection to Safari, or maybe even better generalizing to detect webkit browsers, should work.
|
|
|
|
|
Do similar to chrome fix.
|
|
|
|
|
This is perfect!
But I have got some problem while reading the source code.
Can someone explain how the "apportion" function works?
Thanks.
|
|
|
|
|
|
|
Really good solution but having display issues in Firefox.
1. How can you prevent the nodes being displayed outside boundaries of display/i.e. off screen
2. Once you add a good few nodes they loose their node color (ie blank)
Any suggestions anyone? Could not find any 1.5 code base, only a solution that required jsQuery and I could not seem to get it to work.
|
|
|
|
|
hi!
is it possible to add text to the lines between the nodes of the tree?
how?
thanks
|
|
|
|
|
Here's a minor update that specifically enables some things I needed to do. It adds more node options such as the provision for HTML in each node box, overriding text color, a combination of level and fixed coloring and some other stuff
ECONode = function (id, pid, dsc, w, h, c, bc, target, meta, noCollapse, nodeHTML, forceColor, textColor) {
this.id = id;
this.pid = pid;
this.dsc = dsc;
this.w = w;
this.h = h;
this.c = c;
this.bc = bc;
this.target = target;
this.meta = meta;
this.noCollapse = ((typeof noCollapse != "undefined") ? noCollapse : true);
this.nodeHTML = ((typeof nodeHTML != "undefined") ? nodeHTML : "");
this.forceColor = ((typeof forceColor != "undefined") ? forceColor : false);
this.textColor = textColor;
this.siblingIndex = 0;
this.dbIndex = 0;
this.XPosition = 0;
this.YPosition = 0;
this.prelim = 0;
this.modifier = 0;
this.leftNeighbor = null;
this.rightNeighbor = null;
this.nodeParent = null;
this.nodeChildren = [];
this.isCollapsed = false;
this.canCollapse = false;
this.isSelected = false;
}
ECONode.prototype._getLevel = function () {
if (this.nodeParent.id == -1) {
return 0;
}
else return this.nodeParent._getLevel() + 1;
}
ECONode.prototype._isAncestorCollapsed = function () {
if (this.nodeParent.isCollapsed) {
return true;
} else {
if (this.nodeParent.id == -1) {
return false;
} else {
return this.nodeParent._isAncestorCollapsed();
}
}
}
ECONode.prototype._setAncestorsExpanded = function () {
if (this.nodeParent.id == -1) {
return;
} else {
this.nodeParent.isCollapsed = false;
return this.nodeParent._setAncestorsExpanded();
}
}
ECONode.prototype._getChildrenCount = function () {
if (this.isCollapsed) {
return 0;
}
if (this.nodeChildren == null) {
return 0;
} else {
return this.nodeChildren.length;
}
}
ECONode.prototype._getLeftSibling = function () {
if (this.leftNeighbor != null && this.leftNeighbor.nodeParent == this.nodeParent) {
return this.leftNeighbor;
} else {
return null;
}
}
ECONode.prototype._getRightSibling = function () {
if (this.rightNeighbor != null && this.rightNeighbor.nodeParent == this.nodeParent) {
return this.rightNeighbor;
} else {
return null;
}
}
ECONode.prototype._getChildAt = function (i) {
return this.nodeChildren[i];
}
ECONode.prototype._getChildrenCenter = function (tree) {
node = this._getFirstChild();
node1 = this._getLastChild();
return node.prelim + ((node1.prelim - node.prelim) + tree._getNodeSize(node1)) / 2;
}
ECONode.prototype._getFirstChild = function () {
return this._getChildAt(0);
}
ECONode.prototype._getLastChild = function () {
return this._getChildAt(this._getChildrenCount() - 1);
}
ECONode.prototype._drawChildrenLinks = function (tree) {
var s = [];
var xa = 0, ya = 0, xb = 0, yb = 0, xc = 0, yc = 0, xd = 0, yd = 0;
var node1 = null;
switch (tree.config.iRootOrientation) {
case ECOTree.RO_TOP:
xa = this.XPosition + (this.w / 2);
ya = this.YPosition + this.h;
break;
case ECOTree.RO_BOTTOM:
xa = this.XPosition + (this.w / 2);
ya = this.YPosition;
break;
case ECOTree.RO_RIGHT:
xa = this.XPosition;
ya = this.YPosition + (this.h / 2);
break;
case ECOTree.RO_LEFT:
xa = this.XPosition + this.w;
ya = this.YPosition + (this.h / 2);
break;
}
for (var k = 0; k < this.nodeChildren.length; k++) {
node1 = this.nodeChildren[k];
switch (tree.config.iRootOrientation) {
case ECOTree.RO_TOP:
xd = xc = node1.XPosition + (node1.w / 2);
yd = node1.YPosition;
xb = xa;
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
yb = yc = yd - tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_BOTTOM:
yb = yc = ya + tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_CENTER:
yb = yc = ya + (yd - ya) / 2;
break;
}
break;
case ECOTree.RO_BOTTOM:
xd = xc = node1.XPosition + (node1.w / 2);
yd = node1.YPosition + node1.h;
xb = xa;
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
yb = yc = yd + tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_BOTTOM:
yb = yc = ya - tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_CENTER:
yb = yc = yd + (ya - yd) / 2;
break;
}
break;
case ECOTree.RO_RIGHT:
xd = node1.XPosition + node1.w;
yd = yc = node1.YPosition + (node1.h / 2);
yb = ya;
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
xb = xc = xd + tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_BOTTOM:
xb = xc = xa - tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_CENTER:
xb = xc = xd + (xa - xd) / 2;
break;
}
break;
case ECOTree.RO_LEFT:
xd = node1.XPosition;
yd = yc = node1.YPosition + (node1.h / 2);
yb = ya;
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
xb = xc = xd - tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_BOTTOM:
xb = xc = xa + tree.config.iLevelSeparation / 2;
break;
case ECOTree.NJ_CENTER:
xb = xc = xa + (xd - xa) / 2;
break;
}
break;
}
tree.ctx.save();
tree.ctx.strokeStyle = tree.config.linkColor;
tree.ctx.beginPath();
switch (tree.config.linkType) {
case "M":
tree.ctx.moveTo(xa, ya);
tree.ctx.lineTo(xb, yb);
tree.ctx.lineTo(xc, yc);
tree.ctx.lineTo(xd, yd);
break;
case "B":
tree.ctx.moveTo(xa, ya);
tree.ctx.bezierCurveTo(xb, yb, xc, yc, xd, yd);
break;
}
tree.ctx.stroke();
tree.ctx.restore();
}
return s.join('');
}
ECOTree = function (obj, elm) {
this.config = {
iMaxDepth: 100,
iLevelSeparation: 40,
iSiblingSeparation: 40,
iSubtreeSeparation: 80,
iRootOrientation: ECOTree.RO_TOP,
iNodeJustification: ECOTree.NJ_TOP,
topXCorrection: 0,
topYCorrection: 0,
topXAdjustment: 0,
topYAdjustment: 0,
linkType: "M",
linkColor: "blue",
nodeColor: "#CCCCFF",
nodeFill: ECOTree.NF_GRADIENT,
nodeBorderColor: "blue",
nodeSelColor: "#FFFFCC",
textColor: "#000000",
nodeRadius: 5,
levelColors: ["#5555FF", "#8888FF", "#AAAAFF", "#CCCCFF"],
levelBorderColors: ["#5555FF", "#8888FF", "#AAAAFF", "#CCCCFF"],
colorStyle: ECOTree.CS_NODE,
useTarget: true,
searchMode: ECOTree.SM_DSC,
selectMode: ECOTree.SL_MULTIPLE,
defaultNodeWidth: 80,
defaultNodeHeight: 40,
defaultTarget: 'javascript:void(0);',
expandedImage: './img/less.gif',
collapsedImage: './img/plus.gif',
transImage: './img/trans.gif'
};
if (jQuery("#eco_tree_ruler_span").length == 0) {
jQuery("body").append("<span id='eco_tree_ruler_span' class='econode' style='visibility:hidden'></span>");
}
this.version = "1.5-icb";
this.obj = obj;
this.treeContainer = jQuery("#" + elm);
this.self = this;
this.ctx = null;
this.canvasoffsetTop = 0;
this.canvasoffsetLeft = 0;
this.chartHeight = -1;
this.chartWidth = -1;
this.maxLevelHeight = [];
this.maxLevelWidth = [];
this.previousLevelNode = [];
this.rootYOffset = 0;
this.rootXOffset = 0;
this.nDatabaseNodes = [];
this.mapIDs = {};
this.root = new ECONode(-1, null, null, 2, 2);
this.iSelectedNode = -1;
this.iLastSearch = 0;
}
ECOTree.RO_TOP = 0;
ECOTree.RO_BOTTOM = 1;
ECOTree.RO_RIGHT = 2;
ECOTree.RO_LEFT = 3;
ECOTree.NJ_TOP = 0;
ECOTree.NJ_CENTER = 1;
ECOTree.NJ_BOTTOM = 2;
ECOTree.NF_GRADIENT = 0;
ECOTree.NF_FLAT = 1;
ECOTree.CS_NODE = 0;
ECOTree.CS_LEVEL = 1;
ECOTree.SM_DSC = 0;
ECOTree.SM_META = 1;
ECOTree.SM_BOTH = 2;
ECOTree.SL_MULTIPLE = 0;
ECOTree.SL_SINGLE = 1;
ECOTree.SL_NONE = 2;
ECOTree._roundedRect = function (ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x, y + radius);
ctx.lineTo(x, y + height - radius);
ctx.quadraticCurveTo(x, y + height, x + radius, y + height);
ctx.lineTo(x + width - radius, y + height);
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height - radius);
ctx.lineTo(x + width, y + radius);
ctx.quadraticCurveTo(x + width, y, x + width - radius, y);
ctx.lineTo(x + radius, y);
ctx.quadraticCurveTo(x, y, x, y + radius);
ctx.fill();
ctx.stroke();
}
ECOTree._canvasNodeClickHandler = function (tree, target, nodeid) {
if (target != nodeid) {
return;
}
tree.selectNode(nodeid, true);
}
ECOTree._firstWalk = function (tree, node, level) {
var leftSibling = null;
node.XPosition = 0;
node.YPosition = 0;
node.prelim = 0;
node.modifier = 0;
node.leftNeighbor = null;
node.rightNeighbor = null;
tree._setLevelHeight(node, level);
tree._setLevelWidth(node, level);
tree._setNeighbors(node, level);
if (node._getChildrenCount() == 0 || level == tree.config.iMaxDepth) {
leftSibling = node._getLeftSibling();
if (leftSibling != null) {
node.prelim = leftSibling.prelim + tree._getNodeSize(leftSibling) + tree.config.iSiblingSeparation;
} else {
node.prelim = 0;
}
} else {
var n = node._getChildrenCount();
for (var i = 0; i < n; i++) {
var iChild = node._getChildAt(i);
ECOTree._firstWalk(tree, iChild, level + 1);
}
var midPoint = node._getChildrenCenter(tree);
midPoint -= tree._getNodeSize(node) / 2;
leftSibling = node._getLeftSibling();
if (leftSibling != null) {
node.prelim = leftSibling.prelim + tree._getNodeSize(leftSibling) + tree.config.iSiblingSeparation;
node.modifier = node.prelim - midPoint;
ECOTree._apportion(tree, node, level);
} else {
node.prelim = midPoint;
}
}
}
ECOTree._apportion = function (tree, node, level) {
var firstChild = node._getFirstChild();
var firstChildLeftNeighbor = firstChild.leftNeighbor;
var j = 1;
for (var k = tree.config.iMaxDepth - level; firstChild != null && firstChildLeftNeighbor != null && j <= k; ) {
var modifierSumRight = 0;
var modifierSumLeft = 0;
var rightAncestor = firstChild;
var leftAncestor = firstChildLeftNeighbor;
for (var l = 0; l < j; l++) {
rightAncestor = rightAncestor.nodeParent;
leftAncestor = leftAncestor.nodeParent;
modifierSumRight += rightAncestor.modifier;
modifierSumLeft += leftAncestor.modifier;
}
var totalGap = (firstChildLeftNeighbor.prelim + modifierSumLeft +
tree._getNodeSize(firstChildLeftNeighbor) + tree.config.iSubtreeSeparation) -
(firstChild.prelim + modifierSumRight);
if (totalGap > 0) {
var subtreeAux = node;
var numSubtrees = 0;
for (; subtreeAux != null && subtreeAux != leftAncestor; subtreeAux = subtreeAux._getLeftSibling()) {
numSubtrees++;
}
if (subtreeAux != null) {
var subtreeMoveAux = node;
var singleGap = totalGap / numSubtrees;
for (; subtreeMoveAux != leftAncestor; subtreeMoveAux = subtreeMoveAux._getLeftSibling()) {
subtreeMoveAux.prelim += totalGap;
subtreeMoveAux.modifier += totalGap;
totalGap -= singleGap;
}
}
}
j++;
if (firstChild._getChildrenCount() == 0) {
firstChild = tree._getLeftmost(node, 0, j);
} else {
firstChild = firstChild._getFirstChild();
}
if (firstChild != null) {
firstChildLeftNeighbor = firstChild.leftNeighbor;
}
}
}
ECOTree._secondWalk = function (tree, node, level, X, Y) {
if (level <= tree.config.iMaxDepth) {
var xTmp = tree.rootXOffset + node.prelim + X;
var yTmp = tree.rootYOffset + Y;
var maxsizeTmp = 0;
var nodesizeTmp = 0;
var corrTmp = 0;
var flag = false;
switch (tree.config.iRootOrientation) {
case ECOTree.RO_TOP:
case ECOTree.RO_BOTTOM:
maxsizeTmp = tree.maxLevelHeight[level];
nodesizeTmp = node.h;
break;
case ECOTree.RO_RIGHT:
case ECOTree.RO_LEFT:
maxsizeTmp = tree.maxLevelWidth[level];
flag = true;
nodesizeTmp = node.w;
break;
}
switch (tree.config.iNodeJustification) {
case ECOTree.NJ_TOP:
node.XPosition = xTmp;
node.YPosition = yTmp;
break;
case ECOTree.NJ_CENTER:
node.XPosition = xTmp;
node.YPosition = yTmp + (maxsizeTmp - nodesizeTmp) / 2;
break;
case ECOTree.NJ_BOTTOM:
node.XPosition = xTmp;
node.YPosition = (yTmp + maxsizeTmp) - nodesizeTmp;
break;
}
if (flag) {
var swapTmp = node.XPosition;
node.XPosition = node.YPosition;
node.YPosition = swapTmp;
}
switch (tree.config.iRootOrientation) {
case ECOTree.RO_BOTTOM:
node.YPosition = -node.YPosition - nodesizeTmp;
break;
case ECOTree.RO_RIGHT:
node.XPosition = -node.XPosition - nodesizeTmp;
break;
}
if (node._getChildrenCount() != 0) {
ECOTree._secondWalk(tree, node._getFirstChild(), level + 1, X + node.modifier,
Y + maxsizeTmp + tree.config.iLevelSeparation);
}
var rightSibling = node._getRightSibling();
if (rightSibling != null) {
ECOTree._secondWalk(tree, rightSibling, level, X, Y);
}
if (node.XPosition < 0) {
corrTmp = 0 - node.XPosition;
if (corrTmp > tree.config.topXCorrection) {
tree.config.topXCorrection = corrTmp;
}
}
if (node.YPosition < 0) {
corrTmp = 0 - node.YPosition;
if (corrTmp > tree.config.topYCorrection) {
tree.config.topYCorrection = corrTmp;
}
}
}
}
ECOTree._thirdWalk = function (tree, node, level) {
if (level <= tree.config.iMaxDepth) {
node.XPosition = node.XPosition + tree.config.topXCorrection;
node.YPosition = node.YPosition + tree.config.topYCorrection;
if (node._getChildrenCount() != 0) {
ECOTree._thirdWalk(tree, node._getFirstChild(), level + 1);
}
var rightSibling = node._getRightSibling();
if (rightSibling != null) {
ECOTree._thirdWalk(tree, rightSibling, level);
}
}
}
ECOTree.prototype._positionTree = function () {
this.maxLevelHeight = [];
this.maxLevelWidth = [];
this.previousLevelNode = [];
ECOTree._firstWalk(this.self, this.root, 0);
switch (this.config.iRootOrientation) {
case ECOTree.RO_TOP:
case ECOTree.RO_LEFT:
this.rootXOffset = this.config.topXAdjustment + this.root.XPosition;
this.rootYOffset = this.config.topYAdjustment + this.root.YPosition;
break;
case ECOTree.RO_BOTTOM:
case ECOTree.RO_RIGHT:
this.rootXOffset = this.config.topXAdjustment + this.root.XPosition;
this.rootYOffset = this.config.topYAdjustment + this.root.YPosition;
}
this.config.topXCorrection = 0;
this.config.topYCorrection = 0;
ECOTree._secondWalk(this.self, this.root, 0, 0, 0);
if ((this.config.topXCorrection > 0) || (this.config.topYCorrection > 0)) {
ECOTree._thirdWalk(this.self, this.root, 0);
}
}
ECOTree.prototype._setLevelHeight = function (node, level) {
if (this.maxLevelHeight[level] == null) {
this.maxLevelHeight[level] = 0;
}
if (this.maxLevelHeight[level] < node.h) {
this.maxLevelHeight[level] = node.h;
}
}
ECOTree.prototype._setLevelWidth = function (node, level) {
if (this.maxLevelWidth[level] == null) {
this.maxLevelWidth[level] = 0;
}
if (this.maxLevelWidth[level] < node.w) {
this.maxLevelWidth[level] = node.w;
}
}
ECOTree.prototype._setNeighbors = function (node, level) {
node.leftNeighbor = this.previousLevelNode[level];
if (node.leftNeighbor != null) {
node.leftNeighbor.rightNeighbor = node;
}
this.previousLevelNode[level] = node;
}
ECOTree.prototype._getNodeSize = function (node) {
switch (this.config.iRootOrientation) {
case ECOTree.RO_TOP:
case ECOTree.RO_BOTTOM:
return node.w;
case ECOTree.RO_RIGHT:
case ECOTree.RO_LEFT:
return node.h;
}
return 0;
}
ECOTree.prototype._getLeftmost = function (node, level, maxlevel) {
if (level >= maxlevel) {
return node;
}
if (node._getChildrenCount() == 0) {
return null;
}
var n = node._getChildrenCount();
for (var i = 0; i < n; i++) {
var iChild = node._getChildAt(i);
var leftmostDescendant = this._getLeftmost(iChild, level + 1, maxlevel);
if (leftmostDescendant != null) {
return leftmostDescendant;
}
}
return null;
}
ECOTree.prototype._selectNodeInt = function (dbindex, flagToggle) {
if (this.config.selectMode == ECOTree.SL_SINGLE) {
if ((this.iSelectedNode != dbindex) && (this.iSelectedNode != -1)) {
this.nDatabaseNodes[this.iSelectedNode].isSelected = false;
}
this.iSelectedNode = (this.nDatabaseNodes[dbindex].isSelected && flagToggle) ? -1 : dbindex;
}
this.nDatabaseNodes[dbindex].isSelected = (flagToggle) ? !this.nDatabaseNodes[dbindex].isSelected : true;
}
ECOTree.prototype._collapseAllInt = function (flag) {
var node = null;
for (var n = 0; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
if (node.canCollapse) {
node.isCollapsed = flag;
}
}
this.UpdateTree();
}
ECOTree.prototype._selectAllInt = function (flag) {
var node = null;
for (var k = 0; k < this.nDatabaseNodes.length; k++) {
node = this.nDatabaseNodes[k];
node.isSelected = flag;
}
this.iSelectedNode = -1;
this.UpdateTree();
}
ECOTree.prototype._drawTree = function () {
var s = [];
var node = null;
var color = "";
var border = "";
var textColor = "";
for (var n = 0; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
textColor = node.textColor;
switch (this.config.colorStyle) {
case ECOTree.CS_NODE:
color = node.c;
border = node.bc;
break;
case ECOTree.CS_LEVEL:
if (node.forceColor == true) {
color = node.c;
border = node.bc;
} else {
var iColor = node._getLevel() % this.config.levelColors.length;
color = this.config.levelColors[iColor];
iColor = node._getLevel() % this.config.levelBorderColors.length;
border = this.config.levelBorderColors[iColor];
}
break;
}
if (!node._isAncestorCollapsed()) {
this.ctx.save();
this.ctx.strokeStyle = border;
switch (this.config.nodeFill) {
case ECOTree.NF_GRADIENT:
var lgradient = this.ctx.createLinearGradient(node.XPosition, 0, node.XPosition + node.w, 0);
lgradient.addColorStop(0.0, ((node.isSelected) ? this.config.nodeSelColor : color));
lgradient.addColorStop(1.0, "#F5FFF5");
this.ctx.fillStyle = lgradient;
break;
case ECOTree.NF_FLAT:
this.ctx.fillStyle = ((node.isSelected) ? this.config.nodeSelColor : color);
break;
}
ECOTree._roundedRect(this.ctx, node.XPosition, node.YPosition, node.w, node.h, this.config.nodeRadius);
this.ctx.restore();
s.push('<div id="' + node.id + '" class="econode" style="position:absolute;top:' + (node.YPosition + this.canvasoffsetTop) + 'px; left:' + (node.XPosition + this.canvasoffsetLeft) + 'px; width:' + node.w + '; height:' + node.h + ';z-index:100;" ');
if (this.config.selectMode != ECOTree.SL_NONE) {
s.push('onclick="javascript:ECOTree._canvasNodeClickHandler(' + this.obj + ',event.target.id,\'' + node.id + '\');" ');
}
s.push('>');
s.push('<font face=Verdana size=1>');
if (node.canCollapse) {
s.push('<a id="c' + node.id + '" href="javascript:' + this.obj + '.collapseNode(\'' + node.id + '\', true);" >');
s.push('<img border=0 src="' + ((node.isCollapsed) ? this.config.collapsedImage : this.config.expandedImage) + '" >');
s.push('</a>');
s.push('<img src="' + this.config.transImage + '" >');
}
if (node.target && this.config.useTarget) {
s.push('<a id="t' + node.id + '" href="' + node.target + '" style="color:' + textColor + '">');
s.push(node.dsc);
s.push('</a>');
} else {
s.push('<span style="color:' + textColor + '">');
s.push(node.dsc);
s.push('</span>');
}
s.push('</font>');
if (node.nodeHTML != "") {
s.push('<div>');
s.push(node.nodeHTML);
s.push('</div>');
}
s.push('</div>');
if (!node.isCollapsed) {
s.push(node._drawChildrenLinks(this.self));
}
}
}
return s.join('');
}
ECOTree.prototype._calcWidthAndHeight = function () {
this.chartWidth = 0;
this.chartHeight = 0;
for (var n = 0; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
if (!node._isAncestorCollapsed()) {
this.chartWidth = Math.max(this.chartWidth, node.XPosition + node.w);
this.chartHeight = Math.max(this.chartHeight, node.YPosition + node.h);
}
}
this.chartWidth += 2;
this.chartHeight += 2;
}
ECOTree.prototype.UpdateTree = function () {
this.treeContainer.empty();
this._positionTree();
this._calcWidthAndHeight();
this.treeContainer.css({
'position': 'relative',
'width': this.chartWidth,
'height': this.chartHeight,
'overflow': 'hidden'
});
var canvas = document.createElement('canvas');
jQuery(canvas).attr('width', 2000).attr('height', 7000).attr('id', 'ECOTreecanvas').appendTo(this.treeContainer);
if (jQuery.browser.msie) {
canvas = G_vmlCanvasManager.initElement(canvas);
}
if (canvas && canvas.getContext) {
this.ctx = canvas.getContext("2d");
var h = this._drawTree();
this.treeContainer.append(h);
}
}
ECOTree.prototype.add = function (id, pid, dsc, w, h, c, bc, target, meta, noCollapse, nodeHTML, forceColor, textColor) {
var nw = w || this.config.defaultNodeWidth;
var nh = h || this.config.defaultNodeHeight;
if (nw == -1 || nh == -1) {
var ruler = jQuery("#eco_tree_ruler_span");
ruler.css({ 'width': '', 'height': '' });
if (nw != -1) {
ruler.css({ 'width': nw });
}
if (nh != -1) {
ruler.css({ 'height': nh });
}
ruler.html(dsc);
if (nw == -1) {
nw = ruler.innerWidth() + 18;
}
if (nh == -1) {
nh = ruler.innerHeight() + 4;
}
}
textColor = textColor || this.config.textColor;
var color = c || this.config.nodeColor;
var border = bc || this.config.nodeBorderColor;
var tg = (this.config.useTarget) ? ((typeof target == "undefined") ? (this.config.defaultTarget) : target) : null;
var metadata = (typeof meta != "undefined") ? meta : "";
var pnode = null;
if (pid == -1) {
pnode = this.root;
} else {
for (var k = 0; k < this.nDatabaseNodes.length; k++) {
if (this.nDatabaseNodes[k].id == pid) {
pnode = this.nDatabaseNodes[k];
break;
}
}
}
var node = new ECONode(id, pid, dsc, nw, nh, color, border, tg, metadata, noCollapse, nodeHTML, forceColor, textColor);
node.nodeParent = pnode;
if (noCollapse == false) {
pnode.canCollapse = true;
};
var i = this.nDatabaseNodes.length;
node.dbIndex = this.mapIDs[id] = i;
this.nDatabaseNodes[i] = node;
var h = pnode.nodeChildren.length;
node.siblingIndex = h;
pnode.nodeChildren[h] = node;
}
ECOTree.prototype.searchNodes = function (str) {
var node = null;
var m = this.config.searchMode;
var sm = (this.config.selectMode == ECOTree.SL_SINGLE);
if (typeof str == "undefined") return;
if (str == "") return;
var found = false;
var n = (sm) ? this.iLastSearch : 0;
if (n == this.nDatabaseNodes.length) n = this.iLastSeach = 0;
str = str.toLocaleUpperCase();
for (; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
if (node.dsc.toLocaleUpperCase().indexOf(str) != -1 && ((m == ECOTree.SM_DSC) || (m == ECOTree.SM_BOTH))) {
node._setAncestorsExpanded();
this._selectNodeInt(node.dbIndex, false);
found = true;
}
if (node.meta.toLocaleUpperCase().indexOf(str) != -1 && ((m == ECOTree.SM_META) || (m == ECOTree.SM_BOTH))) {
node._setAncestorsExpanded();
this._selectNodeInt(node.dbIndex, false);
found = true;
}
if (sm && found) {
this.iLastSearch = n + 1;
break;
}
}
this.UpdateTree();
}
ECOTree.prototype.selectAll = function () {
if (this.config.selectMode != ECOTree.SL_MULTIPLE) {
return;
}
this._selectAllInt(true);
}
ECOTree.prototype.unselectAll = function () {
this._selectAllInt(false);
}
ECOTree.prototype.collapseAll = function () {
this._collapseAllInt(true);
}
ECOTree.prototype.expandAll = function () {
this._collapseAllInt(false);
}
ECOTree.prototype.collapseNode = function (nodeid, upd) {
var dbindex = this.mapIDs[nodeid];
this.nDatabaseNodes[dbindex].isCollapsed = !this.nDatabaseNodes[dbindex].isCollapsed;
if (upd) {
this.UpdateTree();
}
}
ECOTree.prototype.selectNode = function (nodeid, upd) {
this._selectNodeInt(this.mapIDs[nodeid], true);
if (upd) {
this.UpdateTree();
}
}
ECOTree.prototype.setNodeTitle = function (nodeid, title, upd) {
var dbindex = this.mapIDs[nodeid];
this.nDatabaseNodes[dbindex].dsc = title;
if (upd) {
this.UpdateTree();
}
}
ECOTree.prototype.setNodeMetadata = function (nodeid, meta, upd) {
var dbindex = this.mapIDs[nodeid];
this.nDatabaseNodes[dbindex].meta = meta;
if (upd) {
this.UpdateTree();
}
}
ECOTree.prototype.setNodeTarget = function (nodeid, target, upd) {
var dbindex = this.mapIDs[nodeid];
this.nDatabaseNodes[dbindex].target = target;
if (upd) {
this.UpdateTree();
}
}
ECOTree.prototype.setNodeColors = function (nodeid, color, border, upd) {
var dbindex = this.mapIDs[nodeid];
if (color) {
this.nDatabaseNodes[dbindex].c = color;
}
if (border) {
this.nDatabaseNodes[dbindex].bc = border;
}
if (upd) {
this.UpdateTree();
}
}
ECOTree.prototype.getSelectedNodes = function () {
var node = null;
var selection = [];
var selnode = null;
for (var n = 0; n < this.nDatabaseNodes.length; n++) {
node = this.nDatabaseNodes[n];
if (node.isSelected) {
selnode = {
"id": node.id,
"dsc": node.dsc,
"meta": node.meta
};
selection[selection.length] = selnode;
}
}
return selection;
}
|
|
|
|
|