Simplify subclassing of hierarchy layout.

The subclasses can't use the same object as the parent class, because they are
functions. But, there's no reason to duplicate the code that rebinds the methods
onto the subclass.
This commit is contained in:
Mike Bostock 2011-06-11 11:31:42 -07:00
Родитель 953bebb17c
Коммит d756caa0d8
9 изменённых файлов: 170 добавлений и 73 удалений

Просмотреть файл

@ -529,17 +529,13 @@ d3.layout.partition = function() {
return nodes;
}
partition.sort = d3.rebind(partition, hierarchy.sort);
partition.children = d3.rebind(partition, hierarchy.children);
partition.value = d3.rebind(partition, hierarchy.value);
partition.size = function(x) {
if (!arguments.length) return size;
size = x;
return partition;
};
return partition;
return d3_layout_hierarchyRebind(partition, hierarchy);
};
d3.layout.pie = function() {
var value = Number,
@ -1054,6 +1050,15 @@ d3.layout.hierarchy = function() {
return hierarchy;
}
// A method assignment helper for hierarchy subclasses.
function d3_layout_hierarchyRebind(object, hierarchy) {
object.sort = d3.rebind(object, hierarchy.sort);
object.children = d3.rebind(object, hierarchy.children);
object.links = d3_layout_hierarchyLinks;
object.value = d3.rebind(object, hierarchy.value);
return object;
}
function d3_layout_hierarchyChildren(d) {
return d.children;
}
@ -1065,8 +1070,17 @@ function d3_layout_hierarchyValue(d) {
function d3_layout_hierarchySort(a, b) {
return b.value - a.value;
}
// Returns an array source+target objects for the specified nodes.
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.pack = function() {
var hierarchy = d3.layout.hierarchy(),
var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort),
size = [1, 1];
function pack(d, i) {
@ -1087,17 +1101,13 @@ d3.layout.pack = function() {
return nodes;
}
pack.sort = d3.rebind(pack, hierarchy.sort);
pack.children = d3.rebind(pack, hierarchy.children);
pack.value = d3.rebind(pack, hierarchy.value);
pack.size = function(x) {
if (!arguments.length) return size;
size = x;
return pack;
};
return pack.sort(d3_layout_packSort);
return d3_layout_hierarchyRebind(pack, hierarchy);
};
function d3_layout_packSort(a, b) {
@ -1310,10 +1320,6 @@ d3.layout.cluster = function() {
return nodes;
}
cluster.sort = d3.rebind(cluster, hierarchy.sort);
cluster.children = d3.rebind(cluster, hierarchy.children);
cluster.links = d3_layout_treeLinks;
cluster.separation = function(x) {
if (!arguments.length) return separation;
separation = x;
@ -1326,7 +1332,7 @@ d3.layout.cluster = function() {
return cluster;
};
return cluster;
return d3_layout_hierarchyRebind(cluster, hierarchy);
};
function d3_layout_clusterY(children) {
@ -1465,7 +1471,7 @@ d3.layout.tree = function() {
deep = d3_layout_treeSearch(root, d3_layout_treeDeepest),
x0 = left.x - separation(left, right) / 2,
x1 = right.x + separation(right, left) / 2,
y1 = deep.depth;
y1 = deep.depth || 1;
// Clear temporary layout variables; transform x and y.
d3_layout_treeVisitAfter(root, function(node) {
@ -1477,10 +1483,6 @@ d3.layout.tree = function() {
return nodes;
}
tree.sort = d3.rebind(tree, hierarchy.sort);
tree.children = d3.rebind(tree, hierarchy.children);
tree.links = d3_layout_treeLinks;
tree.separation = function(x) {
if (!arguments.length) return separation;
separation = x;
@ -1493,18 +1495,9 @@ d3.layout.tree = function() {
return tree;
};
return tree;
return d3_layout_hierarchyRebind(tree, hierarchy);
};
// Returns an array source+target objects for the specified nodes.
function d3_layout_treeLinks(nodes) {
return d3.merge(nodes.map(function(parent) {
return (parent.children || []).map(function(child) {
return {source: parent, target: child};
});
}));
}
function d3_layout_treeSeparation(a, b) {
return a.parent == b.parent ? 1 : 2;
}
@ -1740,10 +1733,6 @@ d3.layout.treemap = function() {
return nodes;
}
treemap.sort = d3.rebind(treemap, hierarchy.sort);
treemap.children = d3.rebind(treemap, hierarchy.children);
treemap.value = d3.rebind(treemap, hierarchy.value);
treemap.size = function(x) {
if (!arguments.length) return size;
size = x;
@ -1769,6 +1758,6 @@ d3.layout.treemap = function() {
return treemap;
};
return treemap;
return d3_layout_hierarchyRebind(treemap, hierarchy);
};
})()

2
d3.layout.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -0,0 +1,119 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Node-Link Tree</title>
<script type="text/javascript" src="../../d3.js"></script>
<script type="text/javascript" src="../../d3.layout.js"></script>
<style type="text/css">
.node {
stroke: #fff;
stroke-width: 2px;
}
.link {
fill: none;
stroke: #000;
}
</style>
</head>
<body>
<script type="text/javascript">
var w = 960,
h = 500,
root = {},
data = [root],
tree = d3.layout.tree().size([w - 20, h - 20]),
diagonal = d3.svg.diagonal(),
duration = 750,
timer = setInterval(update, duration);
var vis = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(10, 10)");
vis.selectAll("circle")
.data(tree(root))
.enter().append("svg:circle")
.attr("class", "node")
.attr("r", 3.5)
.attr("cx", x)
.attr("cy", y);
function update() {
if (data.length >= 500) return clearInterval(timer);
// Add a new datum to a random parent.
var d = {id: data.length}, parent = data[~~(Math.random() * data.length)];
if (parent.children) parent.children.push(d); else parent.children = [d];
data.push(d);
// Compute the new tree layout. We'll stash the old layout in the data.
var nodes = tree(root);
// Update the nodes…
var node = vis.selectAll("circle.node")
.data(nodes, nodeId);
// Enter any new nodes at the parent's previous position.
node.enter().append("svg:circle")
.attr("class", "node")
.attr("r", 3.5)
.attr("cx", function(d) { return d.parent.data.x0; })
.attr("cy", function(d) { return d.parent.data.y0; })
.transition()
.duration(duration)
.attr("cx", x)
.attr("cy", y);
// Transition nodes to their new position.
node.transition()
.duration(duration)
.attr("cx", x)
.attr("cy", y);
// Update the links…
var link = vis.selectAll("path.link")
.data(tree.links(nodes), linkId);
// Enter any new links at the parent's previous position.
link.enter().insert("svg:path", "circle")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: d.source.data.x0, y: d.source.data.y0};
return diagonal({source: o, target: o});
})
.transition()
.duration(duration)
.attr("d", diagonal);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
}
function linkId(d) {
return d.source.data.id + "-" + d.target.data.id;
}
function nodeId(d) {
return d.data.id;
}
function x(d) {
return d.data.x0 = d.x;
}
function y(d) {
return d.data.y0 = d.y;
}
</script>
</body>
</html>

Просмотреть файл

@ -39,10 +39,6 @@ d3.layout.cluster = function() {
return nodes;
}
cluster.sort = d3.rebind(cluster, hierarchy.sort);
cluster.children = d3.rebind(cluster, hierarchy.children);
cluster.links = d3_layout_treeLinks;
cluster.separation = function(x) {
if (!arguments.length) return separation;
separation = x;
@ -55,7 +51,7 @@ d3.layout.cluster = function() {
return cluster;
};
return cluster;
return d3_layout_hierarchyRebind(cluster, hierarchy);
};
function d3_layout_clusterY(children) {

Просмотреть файл

@ -78,6 +78,15 @@ d3.layout.hierarchy = function() {
return hierarchy;
}
// A method assignment helper for hierarchy subclasses.
function d3_layout_hierarchyRebind(object, hierarchy) {
object.sort = d3.rebind(object, hierarchy.sort);
object.children = d3.rebind(object, hierarchy.children);
object.links = d3_layout_hierarchyLinks;
object.value = d3.rebind(object, hierarchy.value);
return object;
}
function d3_layout_hierarchyChildren(d) {
return d.children;
}
@ -89,3 +98,12 @@ function d3_layout_hierarchyValue(d) {
function d3_layout_hierarchySort(a, b) {
return b.value - a.value;
}
// Returns an array source+target objects for the specified nodes.
function d3_layout_hierarchyLinks(nodes) {
return d3.merge(nodes.map(function(parent) {
return (parent.children || []).map(function(child) {
return {source: parent, target: child};
});
}));
}

Просмотреть файл

@ -1,5 +1,5 @@
d3.layout.pack = function() {
var hierarchy = d3.layout.hierarchy(),
var hierarchy = d3.layout.hierarchy().sort(d3_layout_packSort),
size = [1, 1];
function pack(d, i) {
@ -20,17 +20,13 @@ d3.layout.pack = function() {
return nodes;
}
pack.sort = d3.rebind(pack, hierarchy.sort);
pack.children = d3.rebind(pack, hierarchy.children);
pack.value = d3.rebind(pack, hierarchy.value);
pack.size = function(x) {
if (!arguments.length) return size;
size = x;
return pack;
};
return pack.sort(d3_layout_packSort);
return d3_layout_hierarchyRebind(pack, hierarchy);
};
function d3_layout_packSort(a, b) {

Просмотреть файл

@ -38,15 +38,11 @@ d3.layout.partition = function() {
return nodes;
}
partition.sort = d3.rebind(partition, hierarchy.sort);
partition.children = d3.rebind(partition, hierarchy.children);
partition.value = d3.rebind(partition, hierarchy.value);
partition.size = function(x) {
if (!arguments.length) return size;
size = x;
return partition;
};
return partition;
return d3_layout_hierarchyRebind(partition, hierarchy);
};

Просмотреть файл

@ -113,7 +113,7 @@ d3.layout.tree = function() {
deep = d3_layout_treeSearch(root, d3_layout_treeDeepest),
x0 = left.x - separation(left, right) / 2,
x1 = right.x + separation(right, left) / 2,
y1 = deep.depth;
y1 = deep.depth || 1;
// Clear temporary layout variables; transform x and y.
d3_layout_treeVisitAfter(root, function(node) {
@ -125,10 +125,6 @@ d3.layout.tree = function() {
return nodes;
}
tree.sort = d3.rebind(tree, hierarchy.sort);
tree.children = d3.rebind(tree, hierarchy.children);
tree.links = d3_layout_treeLinks;
tree.separation = function(x) {
if (!arguments.length) return separation;
separation = x;
@ -141,18 +137,9 @@ d3.layout.tree = function() {
return tree;
};
return tree;
return d3_layout_hierarchyRebind(tree, hierarchy);
};
// Returns an array source+target objects for the specified nodes.
function d3_layout_treeLinks(nodes) {
return d3.merge(nodes.map(function(parent) {
return (parent.children || []).map(function(child) {
return {source: parent, target: child};
});
}));
}
function d3_layout_treeSeparation(a, b) {
return a.parent == b.parent ? 1 : 2;
}

Просмотреть файл

@ -141,10 +141,6 @@ d3.layout.treemap = function() {
return nodes;
}
treemap.sort = d3.rebind(treemap, hierarchy.sort);
treemap.children = d3.rebind(treemap, hierarchy.children);
treemap.value = d3.rebind(treemap, hierarchy.value);
treemap.size = function(x) {
if (!arguments.length) return size;
size = x;
@ -170,5 +166,5 @@ d3.layout.treemap = function() {
return treemap;
};
return treemap;
return d3_layout_hierarchyRebind(treemap, hierarchy);
};