1
- import arrayify from "./arrayify " ;
1
+ import { Selection } from "./index " ;
2
2
import constant from "../constant" ;
3
3
4
4
var keyPrefix = "$" ; // Protect against keys like “__proto__”.
5
5
6
- function bindIndex ( parent , update , enter , exit , data ) {
6
+ function bindIndex ( parent , group , enter , update , exit , data ) {
7
7
var i = 0 ,
8
8
node ,
9
- nodeLength = update . length ,
10
- dataLength = data . length ,
11
- minLength = Math . min ( nodeLength , dataLength ) ;
12
-
13
- // Clear the enter and exit arrays, and then initialize to the new length.
14
- enter . length = 0 , enter . length = dataLength ;
15
- exit . length = 0 , exit . length = nodeLength ;
9
+ groupLength = group . length ,
10
+ dataLength = data . length ;
16
11
17
- for ( ; i < minLength ; ++ i ) {
18
- if ( node = update [ i ] ) {
12
+ // Put any non-null nodes that fit into update.
13
+ // Put any null nodes into enter.
14
+ // Put any remaining data into enter.
15
+ for ( ; i < dataLength ; ++ i ) {
16
+ if ( node = group [ i ] ) {
19
17
node . __data__ = data [ i ] ;
18
+ update [ i ] = node ;
20
19
} else {
21
20
enter [ i ] = new EnterNode ( parent , data [ i ] ) ;
22
21
}
23
22
}
24
23
25
- // Note: we don’t need to delete update[i] here because this loop only
26
- // runs when the data length is greater than the node length.
27
- for ( ; i < dataLength ; ++ i ) {
28
- enter [ i ] = new EnterNode ( parent , data [ i ] ) ;
29
- }
30
-
31
- // Note: and, we don’t need to delete update[i] here because immediately
32
- // following this loop we set the update length to data length.
33
- for ( ; i < nodeLength ; ++ i ) {
34
- if ( node = update [ i ] ) {
35
- exit [ i ] = update [ i ] ;
24
+ // Put any non-null nodes that don’t fit into exit.
25
+ for ( ; i < groupLength ; ++ i ) {
26
+ if ( node = group [ i ] ) {
27
+ exit [ i ] = node ;
36
28
}
37
29
}
38
-
39
- update . length = dataLength ;
40
30
}
41
31
42
- function bindKey ( parent , update , enter , exit , data , key ) {
32
+ function bindKey ( parent , group , enter , update , exit , data , key ) {
43
33
var i ,
44
34
node ,
45
- dataLength = data . length ,
46
- nodeLength = update . length ,
47
35
nodeByKeyValue = { } ,
48
- keyValues = new Array ( nodeLength ) ,
36
+ groupLength = group . length ,
37
+ dataLength = data . length ,
38
+ keyValues = new Array ( groupLength ) ,
49
39
keyValue ;
50
40
51
- // Clear the enter and exit arrays, and then initialize to the new length.
52
- enter . length = 0 , enter . length = dataLength ;
53
- exit . length = 0 , exit . length = nodeLength ;
54
-
55
- // Compute the keys for each node.
56
- for ( i = 0 ; i < nodeLength ; ++ i ) {
57
- if ( node = update [ i ] ) {
58
- keyValues [ i ] = keyValue = keyPrefix + key . call ( node , node . __data__ , i , update ) ;
59
-
60
- // Is this a duplicate of a key we’ve previously seen?
61
- // If so, this node is moved to the exit selection.
62
- if ( nodeByKeyValue [ keyValue ] ) {
63
- exit [ i ] = node ;
64
- }
65
-
66
- // Otherwise, record the mapping from key to node.
67
- else {
41
+ // Compute the key for each node.
42
+ // If multiple nodes have the same key, only the first one counts.
43
+ for ( i = 0 ; i < groupLength ; ++ i ) {
44
+ if ( node = group [ i ] ) {
45
+ keyValues [ i ] = keyValue = keyPrefix + key . call ( node , node . __data__ , i , group ) ;
46
+ if ( ! nodeByKeyValue [ keyValue ] ) {
68
47
nodeByKeyValue [ keyValue ] = node ;
69
48
}
70
49
}
71
50
}
72
51
73
- // Now clear the update array and initialize to the new length.
74
- update . length = 0 , update . length = dataLength ;
75
-
76
- // Compute the keys for each datum.
52
+ // Compute the key for each datum.
53
+ // If multiple data have the same key, only the first one counts.
77
54
for ( i = 0 ; i < dataLength ; ++ i ) {
78
55
keyValue = keyPrefix + key . call ( parent , data [ i ] , i , data ) ;
79
56
@@ -97,46 +74,53 @@ function bindKey(parent, update, enter, exit, data, key) {
97
74
98
75
// Take any remaining nodes that were not bound to data,
99
76
// and place them in the exit selection.
100
- for ( i = 0 ; i < nodeLength ; ++ i ) {
101
- if ( ( node = nodeByKeyValue [ keyValues [ i ] ] ) !== true ) {
77
+ for ( i = 0 ; i < groupLength ; ++ i ) {
78
+ if ( ( node = group [ i ] ) && ( nodeByKeyValue [ keyValues [ i ] ] !== true ) ) {
102
79
exit [ i ] = node ;
103
80
}
104
81
}
105
82
}
106
83
107
84
export default function ( value , key ) {
108
85
if ( ! value ) {
109
- var data = new Array ( this . size ( ) ) , i = - 1 ;
110
- this . each ( function ( d ) { data [ ++ i ] = d ; } ) ;
86
+ data = new Array ( this . size ( ) ) , j = - 1 ;
87
+ this . each ( function ( d ) { data [ ++ j ] = d ; } ) ;
111
88
return data ;
112
89
}
113
90
114
91
var bind = key ? bindKey : bindIndex ,
115
92
parents = this . _parents ,
116
- update = arrayify ( this ) ,
117
- enter = ( this . _enter = this . enter ( ) ) . _groups ,
118
- exit = ( this . _exit = this . exit ( ) ) . _groups ;
93
+ groups = this . _groups ;
119
94
120
95
if ( typeof value !== "function" ) value = constant ( value ) ;
121
96
122
- for ( var m = update . length , j = 0 ; j < m ; ++ j ) {
123
- var group = update [ j ] ,
124
- parent = parents [ j ] ;
97
+ for ( var m = groups . length , update = new Array ( m ) , enter = new Array ( m ) , exit = new Array ( m ) , j = 0 ; j < m ; ++ j ) {
98
+ var parent = parents [ j ] ,
99
+ group = groups [ j ] ,
100
+ groupLength = group . length ,
101
+ data = value . call ( parent , parent && parent . __data__ , j , parents ) ,
102
+ dataLength = data . length ,
103
+ enterGroup = enter [ j ] = new Array ( dataLength ) ,
104
+ updateGroup = update [ j ] = new Array ( dataLength ) ,
105
+ exitGroup = exit [ j ] = new Array ( groupLength ) ;
125
106
126
- bind ( parent , group , enter [ j ] , exit [ j ] , value . call ( parent , parent && parent . __data__ , j , parents ) , key ) ;
107
+ bind ( parent , group , enterGroup , updateGroup , exitGroup , data , key ) ;
127
108
128
109
// Now connect the enter nodes to their following update node, such that
129
110
// appendChild can insert the materialized enter node before this node,
130
111
// rather than at the end of the parent node.
131
- for ( var n = group . length , i0 = 0 , i1 = 0 , previous , next ; i0 < n ; ++ i0 ) {
132
- if ( previous = enter [ j ] [ i0 ] ) {
112
+ for ( var i0 = 0 , i1 = 0 , previous , next ; i0 < dataLength ; ++ i0 ) {
113
+ if ( previous = enterGroup [ i0 ] ) {
133
114
if ( i0 >= i1 ) i1 = i0 + 1 ;
134
- while ( ! ( next = group [ i1 ] ) && ++ i1 < n ) ;
115
+ while ( ! ( next = updateGroup [ i1 ] ) && ++ i1 < dataLength ) ;
135
116
previous . _next = next || null ;
136
117
}
137
118
}
138
119
}
139
120
121
+ this . _groups = update ;
122
+ ( this . _enter = new Selection ( enter , parents ) ) . _update = this ;
123
+ this . _exit = new Selection ( exit , parents ) ;
140
124
return this ;
141
125
}
142
126
0 commit comments