Don't store data on the dom. Remove getters. (d3.alt)

I removed the internal flat storage of the nodes; now there is only the
two-dimensional groups array, which can be inspected from the outside. For
ease of implementation, I removed the old getters that allowed you to query
attributes (etc.) since it doesn't make as much sense to do that when the
selection is grouped. And anyway, that was primarily intended for debugging
purposes. You can still use `each` for iteration.
This commit is contained in:
Michael Bostock 2010-10-23 17:00:04 -07:00
Родитель 1d15c3f6ef
Коммит b28a1dbfe0
2 изменённых файлов: 106 добавлений и 125 удалений

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

@ -23,9 +23,10 @@ span.enter("td")
.append("span")
.text(function(d, i) { return d; });
console.log(span
.remove()
.text(function(d, i) { return Math.random(); }));
span.remove() // removes spans and selects parent td
.text(function(d, i) { return Math.random(); })
.transition()
.attr("height", 200);
</script>
</body>

224
d3.alt.js
Просмотреть файл

@ -1,10 +1,7 @@
(function(_) {
var d3 = _.d3 = {},
d3_document = [document],
d3_root = d3_selection([d3_document]);
d3_document.data = [];
d3_root = d3_selection([[document]]);
d3.version = "0.1.0";
@ -36,13 +33,13 @@
d3.select = function(query) {
return typeof query == "string"
? d3_root.select(query)
: d3_selection([[query]], d3_root); // assume node
: d3_selection([[query]]); // assume node
};
d3.selectAll = function(query) {
return typeof query == "string"
? d3_root.selectAll(query)
: d3_selection([d3_array(query)], d3_root); // assume node[]
: d3_selection([d3_array(query)]); // assume node[]
};
d3.transition = function() {
@ -50,58 +47,77 @@
};
function d3_selection(groups) {
var nodes = d3_blend(groups);
var i = -1,
n = groups.length,
group;
// Initialize the data, if needed.
while (++i < n) if (!(group = groups[i]).data) group.data = [];
function select(select) {
return d3_selection(groups.map(function(group) {
var subgroup = group.map(function(node) {
if (!node) return null;
var subnode = select(node); // TODO pass index?
if (subnode) subnode.__data__ = node.__data__;
return subnode;
});
subgroup.parent = group.parent;
var subgroups = [],
subgroup,
group,
node;
for (var j = 0, m = groups.length; j < m; j++) {
group = groups[j];
subgroups.push(subgroup = []);
subgroup.parentNode = group.parentNode;
subgroup.parentData = group.parentData;
subgroup.data = group.data;
return subgroup;
}), nodes);
for (var i = 0, n = group.length; i < n; i++) {
if (node = group[i]) subgroup.push(select(node));
}
}
return d3_selection(subgroups);
}
function selectAll(selectAll) {
return d3_selection(nodes.map(function(node) {
if (!node) return null;
var subgroup = selectAll(node); // TODO pass index?
subgroup.parent = node;
subgroup.data = node.__data__;
return subgroup;
}), nodes);
var subgroups = [],
subgroup,
group,
node;
for (var j = 0, m = groups.length; j < m; j++) {
group = groups[j];
for (var i = 0, n = group.length; i < n; i++) {
if (node = group[i]) {
subgroups.push(subgroup = selectAll(node));
subgroup.parentNode = node;
subgroup.parentData = group.data[i];
subgroup.data = [];
}
}
}
return d3_selection(subgroups);
}
// TODO select(function)?
nodes.select = function(query) {
groups.select = function(query) {
return select(function(node) {
return node.querySelector(query);
});
};
// TODO selectAll(function)?
nodes.selectAll = function(query) {
groups.selectAll = function(query) {
return selectAll(function(node) {
return d3_array(node.querySelectorAll(query));
});
};
// TODO key
nodes.data = function(data) {
if (arguments.length < 1) {
return nodes.map(function(node) {
return node.__data__;
});
}
groups.data = function(data) {
var i = -1,
n = groups.length,
group,
enter = [],
update = [],
exit = [];
function bind(group, groupData) {
function bind(group) {
var i = 0,
n = group.length,
m = groupData.length,
m = group.data.length,
n0 = Math.min(n, m),
n1 = Math.max(n, m),
updateNodes = [],
@ -110,87 +126,68 @@
node;
function append(e) {
return group.parent.appendChild(e);
return group.parentNode.appendChild(e);
}
if (groupData == null) {
// TODO what does enter, exit, update mean when data is removed?
while (++i < n) delete group[i].__data__;
} else {
for (; i < n0; i++) {
node = updateNodes[i] = group[i];
node.__data__ = groupData[i];
enterNodes[i] = exitNodes[i] = null;
}
for (; i < m; i++) {
enterNodes[i] = {appendChild: append, __data__: groupData[i]};
updateNodes[i] = exitNodes[i] = null;
}
for (; i < n1; i++) {
exitNodes[i] = group[i];
enterNodes[i] = updateNodes[i] = null;
}
for (; i < n0; i++) {
node = updateNodes[i] = group[i];
enterNodes[i] = exitNodes[i] = null;
}
for (; i < m; i++) {
enterNodes[i] = {appendChild: append};
updateNodes[i] = exitNodes[i] = null;
}
for (; i < n1; i++) {
exitNodes[i] = group[i];
enterNodes[i] = updateNodes[i] = null;
}
updateNodes.data = enterNodes.data = exitNodes.data = group.data;
enter.push(enterNodes);
update.push(updateNodes);
exit.push(exitNodes);
}
var i = -1,
n = groups.length,
enter = [],
update = [],
exit = [];
if (typeof data == "function") {
while (++i < n) {
var group = groups[i];
bind(group, data.call(group, group.data, i));
group = groups[i];
group.data = data.call(group.parentNode, group.parentData, i);
bind(group);
}
} else {
while (++i < n) {
bind(groups[i], data);
group = groups[i];
group.data = data;
bind(group);
}
}
nodes.enter = function(name) {
return d3_selection(enter, nodes).append(name);
var selection = d3_selection(update);
selection.enter = function(name) {
return d3_selection(enter).append(name);
};
nodes.update = function() {
return d3_selection(update, nodes);
selection.exit = function() {
return d3_selection(exit);
};
nodes.exit = function() {
return d3_selection(exit, nodes);
};
return nodes;
return selection;
};
// TODO mask forEach? or rename for eachData?
// TODO offer the same semantics for map, reduce, etc.?
nodes.each = function(callback) {
groups.each = function(callback) {
for (var j = 0, m = groups.length; j < m; j++) {
var group = groups[j];
for (var i = 0, n = group.length; i < n; i++) {
var node = group[i];
if (node) callback.call(node, node.__data__, i);
if (node) callback.call(node, group.data[i], i);
}
}
return nodes;
return groups;
};
nodes.attr = function(name, value) {
groups.attr = function(name, value) {
name = d3.ns.qualify(name);
if (arguments.length < 2) {
return nodes.map(name.local
? function(e) { return e.getAttributeNS(name.space, name.local); }
: function(e) { return e.getAttribute(name); });
}
function attrNull() {
this.removeAttribute(name);
}
@ -219,19 +216,13 @@
else this.setAttributeNS(name.space, name.local, x);
}
return nodes.each(value == null
return groups.each(value == null
? (name.local ? attrNullNS : attrNull) : (typeof value == "function"
? (name.local ? attrFunctionNS : attrFunction)
: (name.local ? attrConstantNS : attrConstant)));
};
nodes.style = function(name, value, priority) {
if (arguments.length < 2) {
return nodes.map(function(e) {
return window.getComputedStyle(e, null).getPropertyValue(name);
});
}
groups.style = function(name, value, priority) {
if (arguments.length < 3) priority = null;
function styleNull() {
@ -248,18 +239,13 @@
else this.style.setProperty(name, x, priority);
}
return nodes.each(value == null
return groups.each(value == null
? styleNull : (typeof value == "function"
? styleFunction : styleConstant));
};
// TODO text(function)
nodes.text = function(value) {
if (arguments.length < 1) {
return nodes.map(function(e) {
return e.textContent;
});
}
groups.text = function(value) {
function textNull() {
while (this.lastChild) this.removeChild(this.lastChild);
@ -274,20 +260,14 @@
if (x != null) this.appendChild(document.createTextNode(x));
}
nodes.each(textNull);
return value == null ? nodes
: nodes.each(typeof value == "function"
groups.each(textNull);
return value == null ? groups
: groups.each(typeof value == "function"
? textFunction : textConstant);
};
// TODO html(function)
nodes.html = function(value) {
if (arguments.length < 1) {
return nodes.map(function(e) {
return e.innerHTML;
});
}
groups.html = function(value) {
function htmlConstant() {
this.innerHTML = value;
@ -297,13 +277,13 @@
this.innerHTML = value.apply(this, arguments);
}
return nodes.each(typeof value == "function"
return groups.each(typeof value == "function"
? htmlFunction : htmlConstant);
};
// TODO append(node)?
// TODO append(function)?
nodes.append = function(name) {
groups.append = function(name) {
name = d3.ns.qualify(name);
function append(node) {
@ -320,7 +300,7 @@
// TODO remove(query)?
// TODO remove(node)?
// TODO remove(function)?
nodes.remove = function() {
groups.remove = function() {
return select(function(node) {
var parent = node.parentNode;
parent.removeChild(node);
@ -333,16 +313,16 @@
// TODO filter, slice?
nodes.transition = function() {
return d3_transition(nodes);
groups.transition = function() {
return d3_transition(groups);
};
return nodes;
return groups;
}
// TODO namespace transitions; cancel collisions
// TODO easing
function d3_transition(nodes) {
function d3_transition(groups) {
var transition = {},
tweens = {},
timeout = setTimeout(start, 1),
@ -360,7 +340,7 @@
var elapsed = Date.now() - then,
clear = true,
k = -1;
nodes.each(function(d, i) {
groups.each(function(d, i) {
var t = (elapsed - delay[++k]) / duration[k]; // TODO easing
if (t >= 1) { t = 1; delay[k] = Infinity; }
else { clear = false; if (t < 0) return; }
@ -373,13 +353,13 @@
var delayMin = Infinity,
k = -1;
if (typeof value == "function") {
nodes.each(function(d, i) {
groups.each(function(d, i) {
var x = delay[++k] = +value.apply(this, arguments);
if (x < delayMin) delayMin = x;
});
} else {
delayMin = +value;
nodes.each(function(d, i) {
groups.each(function(d, i) {
delay[++k] = delayMin;
});
}
@ -392,13 +372,13 @@
var k = -1;
if (typeof value == "function") {
durationMax = 0;
nodes.each(function(d, i) {
groups.each(function(d, i) {
var x = duration[++k] = +value.apply(this, arguments);
if (x > durationMax) durationMax = x;
});
} else {
durationMax = +value;
nodes.each(function(d, i) {
groups.each(function(d, i) {
duration[++k] = durationMax;
});
}
@ -454,7 +434,7 @@
}
name = d3.ns.qualify(name);
nodes.each(typeof value == "function"
groups.each(typeof value == "function"
? (name.local ? attrFunctionNS : attrFunction)
: (name.local ? attrConstantNS : attrConstant));
@ -463,7 +443,7 @@
// TODO inherit easing
transition.select = function(query) {
var k, t = d3_transition(nodes.select(query));
var k, t = d3_transition(groups.select(query));
k = -1; t.delay(function(d, i) { return delay[++k]; });
k = -1; t.duration(function(d, i) { return duration[++k]; });
return t;
@ -471,7 +451,7 @@
// TODO inherit easing
transition.selectAll = function(query) {
var k, t = d3_transition(nodes.selectAll(query));
var k, t = d3_transition(groups.selectAll(query));
k = -1; t.delay(function(d, i) { return delay[i ? k : ++k]; })
k = -1; t.duration(function(d, i) { return duration[i ? k : ++k]; });
return t;