|
1 // TODO data(null) for clearing data? |
|
2 d3_selectionPrototype.data = function(data, join) { |
|
3 var enter = [], |
|
4 update = [], |
|
5 exit = []; |
|
6 |
|
7 function bind(group, groupData) { |
|
8 var i, |
|
9 n = group.length, |
|
10 m = groupData.length, |
|
11 n0 = Math.min(n, m), |
|
12 n1 = Math.max(n, m), |
|
13 updateNodes = [], |
|
14 enterNodes = [], |
|
15 exitNodes = [], |
|
16 node, |
|
17 nodeData; |
|
18 |
|
19 if (join) { |
|
20 var nodeByKey = {}, |
|
21 keys = [], |
|
22 key, |
|
23 j = groupData.length; |
|
24 |
|
25 for (i = -1; ++i < n;) { |
|
26 key = join.call(node = group[i], node.__data__, i); |
|
27 if (key in nodeByKey) { |
|
28 exitNodes[j++] = node; // duplicate key |
|
29 } else { |
|
30 nodeByKey[key] = node; |
|
31 } |
|
32 keys.push(key); |
|
33 } |
|
34 |
|
35 for (i = -1; ++i < m;) { |
|
36 node = nodeByKey[key = join.call(groupData, nodeData = groupData[i], i)]; |
|
37 if (node) { |
|
38 node.__data__ = nodeData; |
|
39 updateNodes[i] = node; |
|
40 enterNodes[i] = exitNodes[i] = null; |
|
41 } else { |
|
42 enterNodes[i] = d3_selection_dataNode(nodeData); |
|
43 updateNodes[i] = exitNodes[i] = null; |
|
44 } |
|
45 delete nodeByKey[key]; |
|
46 } |
|
47 |
|
48 for (i = -1; ++i < n;) { |
|
49 if (keys[i] in nodeByKey) { |
|
50 exitNodes[i] = group[i]; |
|
51 } |
|
52 } |
|
53 } else { |
|
54 for (i = -1; ++i < n0;) { |
|
55 node = group[i]; |
|
56 nodeData = groupData[i]; |
|
57 if (node) { |
|
58 node.__data__ = nodeData; |
|
59 updateNodes[i] = node; |
|
60 enterNodes[i] = exitNodes[i] = null; |
|
61 } else { |
|
62 enterNodes[i] = d3_selection_dataNode(nodeData); |
|
63 updateNodes[i] = exitNodes[i] = null; |
|
64 } |
|
65 } |
|
66 for (; i < m; ++i) { |
|
67 enterNodes[i] = d3_selection_dataNode(groupData[i]); |
|
68 updateNodes[i] = exitNodes[i] = null; |
|
69 } |
|
70 for (; i < n1; ++i) { |
|
71 exitNodes[i] = group[i]; |
|
72 enterNodes[i] = updateNodes[i] = null; |
|
73 } |
|
74 } |
|
75 |
|
76 enterNodes.update |
|
77 = updateNodes; |
|
78 |
|
79 enterNodes.parentNode |
|
80 = updateNodes.parentNode |
|
81 = exitNodes.parentNode |
|
82 = group.parentNode; |
|
83 |
|
84 enter.push(enterNodes); |
|
85 update.push(updateNodes); |
|
86 exit.push(exitNodes); |
|
87 } |
|
88 |
|
89 var i = -1, |
|
90 n = this.length, |
|
91 group; |
|
92 if (typeof data === "function") { |
|
93 while (++i < n) { |
|
94 bind(group = this[i], data.call(group, group.parentNode.__data__, i)); |
|
95 } |
|
96 } else { |
|
97 while (++i < n) { |
|
98 bind(group = this[i], data); |
|
99 } |
|
100 } |
|
101 |
|
102 var selection = d3_selection(update); |
|
103 selection.enter = function() { return d3_selection_enter(enter); }; |
|
104 selection.exit = function() { return d3_selection(exit); }; |
|
105 return selection; |
|
106 }; |
|
107 |
|
108 function d3_selection_dataNode(data) { |
|
109 return {__data__: data}; |
|
110 } |