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:
Родитель
1d15c3f6ef
Коммит
b28a1dbfe0
7
alt.html
7
alt.html
|
@ -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
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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче