|
(function(){ |
|
d3.layout.treemap2 = function() { |
|
d3.layout.hierarchy = function() { |
|
var sort = d3_layout_hierarchySort, children = d3_layout_hierarchyChildren, value = d3_layout_hierarchyValue; |
|
function hierarchy(root) { |
|
var stack = [ root ], nodes = [], node; |
|
root.depth = 0; |
|
while ((node = stack.pop()) != null) { |
|
nodes.push(node); |
|
if ((childs = children.call(hierarchy, node, node.depth)) && (n = childs.length)) { |
|
var n, childs, child; |
|
while (--n >= 0) { |
|
stack.push(child = childs[n]); |
|
child.parent = node; |
|
child.depth = node.depth + 1; |
|
} |
|
if (value) node.value = 0; |
|
node.children = childs; |
|
} else { |
|
if (value) node.value = +value.call(hierarchy, node, node.depth) || 0; |
|
delete node.children; |
|
} |
|
} |
|
d3_layout_hierarchyVisitAfter(root, function(node) { |
|
var childs, parent; |
|
if (sort && (childs = node.children)) childs.sort(sort); |
|
if (value && (parent = node.parent)) parent.value += node.value; |
|
}); |
|
return nodes; |
|
} |
|
hierarchy.sort = function(x) { |
|
if (!arguments.length) return sort; |
|
sort = x; |
|
return hierarchy; |
|
}; |
|
hierarchy.children = function(x) { |
|
if (!arguments.length) return children; |
|
children = x; |
|
return hierarchy; |
|
}; |
|
hierarchy.value = function(x) { |
|
if (!arguments.length) return value; |
|
value = x; |
|
return hierarchy; |
|
}; |
|
hierarchy.revalue = function(root) { |
|
if (value) { |
|
d3_layout_hierarchyVisitBefore(root, function(node) { |
|
if (node.children) node.value = 0; |
|
}); |
|
d3_layout_hierarchyVisitAfter(root, function(node) { |
|
var parent; |
|
if (!node.children) node.value = +value.call(hierarchy, node, node.depth) || 0; |
|
if (parent = node.parent) parent.value += node.value; |
|
}); |
|
} |
|
return root; |
|
}; |
|
return hierarchy; |
|
}; |
|
function d3_layout_hierarchyRebind(object, hierarchy) { |
|
d3.rebind(object, hierarchy, "sort", "children", "value"); |
|
object.nodes = object; |
|
object.links = d3_layout_hierarchyLinks; |
|
return object; |
|
} |
|
function d3_layout_hierarchyVisitBefore(node, callback) { |
|
var nodes = [ node ]; |
|
while ((node = nodes.pop()) != null) { |
|
callback(node); |
|
if ((children = node.children) && (n = children.length)) { |
|
var n, children; |
|
while (--n >= 0) nodes.push(children[n]); |
|
} |
|
} |
|
} |
|
function d3_layout_hierarchyVisitAfter(node, callback) { |
|
var nodes = [ node ], nodes2 = []; |
|
while ((node = nodes.pop()) != null) { |
|
nodes2.push(node); |
|
if ((children = node.children) && (n = children.length)) { |
|
var i = -1, n, children; |
|
while (++i < n) nodes.push(children[i]); |
|
} |
|
} |
|
while ((node = nodes2.pop()) != null) { |
|
callback(node); |
|
} |
|
} |
|
function d3_layout_hierarchyChildren(d) { |
|
return d.children; |
|
} |
|
function d3_layout_hierarchyValue(d) { |
|
return d.value; |
|
} |
|
function d3_layout_hierarchySort(a, b) { |
|
return b.value - a.value; |
|
} |
|
function d3_layout_hierarchyLinks(nodes) { |
|
return d3.merge(nodes.map(function(parent) { |
|
return (parent.children || []).map(function(child) { |
|
return { |
|
source: parent, |
|
target: child |
|
}; |
|
}); |
|
})); |
|
} |
|
d3.layout.partition = function() { |
|
var hierarchy = d3.layout.hierarchy(), size = [ 1, 1 ]; |
|
function position(node, x, dx, dy) { |
|
var children = node.children; |
|
node.x = x; |
|
node.y = node.depth * dy; |
|
node.dx = dx; |
|
node.dy = dy; |
|
if (children && (n = children.length)) { |
|
var i = -1, n, c, d; |
|
dx = node.value ? dx / node.value : 0; |
|
while (++i < n) { |
|
position(c = children[i], x, d = c.value * dx, dy); |
|
x += d; |
|
} |
|
} |
|
} |
|
function depth(node) { |
|
var children = node.children, d = 0; |
|
if (children && (n = children.length)) { |
|
var i = -1, n; |
|
while (++i < n) d = Math.max(d, depth(children[i])); |
|
} |
|
return 1 + d; |
|
} |
|
function partition(d, i) { |
|
var nodes = hierarchy.call(this, d, i); |
|
position(nodes[0], 0, size[0], size[1] / depth(nodes[0])); |
|
return nodes; |
|
} |
|
partition.size = function(x) { |
|
if (!arguments.length) return size; |
|
size = x; |
|
return partition; |
|
}; |
|
return d3_layout_hierarchyRebind(partition, hierarchy); |
|
}; |
|
var hierarchy = d3.layout.hierarchy(), round = Math.round, size = [ 1, 1 ], padding = null, pad = d3_layout_treemapPadNull, sticky = false, stickies, mode = "squarify", ratio = .5 * (1 + Math.sqrt(5)); |
|
function scale(children, k) { |
|
var i = -1, n = children.length, child, area; |
|
while (++i < n) { |
|
area = (child = children[i]).value * (k < 0 ? 0 : k); |
|
child.area = isNaN(area) || area <= 0 ? 0 : area; |
|
} |
|
} |
|
function squarify(node) { |
|
var children = node.children; |
|
if (children && children.length) { |
|
var rect = pad(node), row = [], remaining = children.slice(), child, best = Infinity, score, u = mode === "slice" ? rect.dx : mode === "dice" ? rect.dy : mode === "slice-dice" ? node.depth & 1 ? rect.dy : rect.dx : Math.min(rect.dx, rect.dy), n; |
|
scale(remaining, rect.dx * rect.dy / node.value); |
|
row.area = 0; |
|
while ((n = remaining.length) > 0) { |
|
row.push(child = remaining[n - 1]); |
|
row.area += child.area; |
|
if (mode !== "squarify" || (score = worst(row, u)) <= best) { |
|
remaining.pop(); |
|
best = score; |
|
} else { |
|
row.area -= row.pop().area; |
|
position(row, u, rect, false); |
|
u = Math.min(rect.dx, rect.dy); |
|
row.length = row.area = 0; |
|
best = Infinity; |
|
} |
|
} |
|
if (row.length) { |
|
position(row, u, rect, true); |
|
row.length = row.area = 0; |
|
} |
|
children.forEach(squarify); |
|
} |
|
} |
|
function stickify(node) { |
|
var children = node.children; |
|
if (children && children.length) { |
|
var rect = pad(node), remaining = children.slice(), child, row = []; |
|
scale(remaining, rect.dx * rect.dy / node.value); |
|
row.area = 0; |
|
while (child = remaining.pop()) { |
|
row.push(child); |
|
row.area += child.area; |
|
if (child.z != null) { |
|
position(row, child.z ? rect.dx : rect.dy, rect, !remaining.length); |
|
row.length = row.area = 0; |
|
} |
|
} |
|
children.forEach(stickify); |
|
} |
|
} |
|
function worst(row, u) { |
|
var s = row.area, r, rmax = 0, rmin = Infinity, i = -1, n = row.length; |
|
while (++i < n) { |
|
if (!(r = row[i].area)) continue; |
|
if (r < rmin) rmin = r; |
|
if (r > rmax) rmax = r; |
|
} |
|
s *= s; |
|
u *= u; |
|
return s ? Math.max(u * rmax * ratio / s, s / (u * rmin * ratio)) : Infinity; |
|
} |
|
function position(row, u, rect, flush) { |
|
var i = -1, n = row.length, x = rect.x, y = rect.y, v = u ? round(row.area / u) : 0, o; |
|
if (u == rect.dx) { |
|
if (flush || v > rect.dy) v = rect.dy; |
|
while (++i < n) { |
|
o = row[i]; |
|
o.x = x; |
|
o.y = y; |
|
o.dy = v; |
|
x += o.dx = Math.min(rect.x + rect.dx - x, v ? round(o.area / v) : 0); |
|
} |
|
o.z = true; |
|
o.dx += rect.x + rect.dx - x; |
|
rect.y += v; |
|
rect.dy -= v; |
|
} else { |
|
if (flush || v > rect.dx) v = rect.dx; |
|
while (++i < n) { |
|
o = row[i]; |
|
o.x = x; |
|
o.y = y; |
|
o.dx = v; |
|
y += o.dy = Math.min(rect.y + rect.dy - y, v ? round(o.area / v) : 0); |
|
} |
|
o.z = false; |
|
o.dy += rect.y + rect.dy - y; |
|
rect.x += v; |
|
rect.dx -= v; |
|
} |
|
} |
|
function treemap(d) { |
|
var nodes = stickies || hierarchy(d), root = nodes[0]; |
|
root.x = 0; |
|
root.y = 0; |
|
root.dx = size[0]; |
|
root.dy = size[1]; |
|
if (stickies) hierarchy.revalue(root); |
|
scale([ root ], root.dx * root.dy / root.value); |
|
(stickies ? stickify : squarify)(root); |
|
if (sticky) stickies = nodes; |
|
|
|
// ************************************************ |
|
|
|
var maxDepth = d3.max(nodes.map(function(d){ return d.depth })); |
|
|
|
// loop through all the depths, or hierarchy levels from the deepest level |
|
// to level 1 |
|
for(i = maxDepth; i > 0; i--){ |
|
var parents = d3.set([]); |
|
|
|
// create an array of child nodes for the current depth |
|
var children = nodes.filter(function(d){ return d.depth == i }) |
|
|
|
// get a set of unique parent names for the level |
|
children.forEach(function(child){ |
|
parents.add(child.parent.name) |
|
}) |
|
|
|
var currentParents = parents.values(); |
|
|
|
// calculate the maxArea across all children of each parent |
|
// then, store that maxArea as a property on each child object |
|
currentParents.forEach(function(currentParent) { |
|
var currentChildren = children.filter(function(d) { return d.parent.name == currentParent }); |
|
|
|
var currentMaxArea = d3.max( currentChildren.map(function(d){ return d.area }) ) |
|
|
|
currentChildren.forEach(function(d) { d["maxArea"] = currentMaxArea }); |
|
|
|
}) |
|
|
|
} |
|
console.log("nodes from inside of the treemap2 layout", nodes); |
|
|
|
// ************************************************ |
|
return nodes; |
|
} |
|
treemap.size = function(x) { |
|
if (!arguments.length) return size; |
|
size = x; |
|
return treemap; |
|
}; |
|
treemap.padding = function(x) { |
|
if (!arguments.length) return padding; |
|
function padFunction(node) { |
|
var p = x.call(treemap, node, node.depth); |
|
return p == null ? d3_layout_treemapPadNull(node) : d3_layout_treemapPad(node, typeof p === "number" ? [ p, p, p, p ] : p); |
|
} |
|
function padConstant(node) { |
|
return d3_layout_treemapPad(node, x); |
|
} |
|
var type; |
|
pad = (padding = x) == null ? d3_layout_treemapPadNull : (type = typeof x) === "function" ? padFunction : type === "number" ? (x = [ x, x, x, x ], |
|
padConstant) : padConstant; |
|
return treemap; |
|
}; |
|
treemap.round = function(x) { |
|
if (!arguments.length) return round != Number; |
|
round = x ? Math.round : Number; |
|
return treemap; |
|
}; |
|
treemap.sticky = function(x) { |
|
if (!arguments.length) return sticky; |
|
sticky = x; |
|
stickies = null; |
|
return treemap; |
|
}; |
|
treemap.ratio = function(x) { |
|
if (!arguments.length) return ratio; |
|
ratio = x; |
|
return treemap; |
|
}; |
|
treemap.mode = function(x) { |
|
if (!arguments.length) return mode; |
|
mode = x + ""; |
|
return treemap; |
|
}; |
|
return d3_layout_hierarchyRebind(treemap, hierarchy); |
|
}; |
|
function d3_layout_treemapPadNull(node) { |
|
return { |
|
x: node.x, |
|
y: node.y, |
|
dx: node.dx, |
|
dy: node.dy |
|
}; |
|
} |
|
function d3_layout_treemapPad(node, padding) { |
|
var x = node.x + padding[3], y = node.y + padding[0], dx = node.dx - padding[1] - padding[3], dy = node.dy - padding[0] - padding[2]; |
|
if (dx < 0) { |
|
x += dx / 2; |
|
dx = 0; |
|
} |
|
if (dy < 0) { |
|
y += dy / 2; |
|
dy = 0; |
|
} |
|
return { |
|
x: x, |
|
y: y, |
|
dx: dx, |
|
dy: dy |
|
}; |
|
} |
|
})(); |