UNPKG

8.39 kBJavaScriptView Raw
1import * as is from '../is';
2import Selector from '../selector';
3
4let elesfn = ({
5 nodes: function( selector ){
6 return this.filter( ele => ele.isNode() ).filter( selector );
7 },
8
9 edges: function( selector ){
10 return this.filter( ele => ele.isEdge() ).filter( selector );
11 },
12
13 // internal helper to get nodes and edges as separate collections with single iteration over elements
14 byGroup: function(){
15 let nodes = this.spawn();
16 let edges = this.spawn();
17
18 for( let i = 0; i < this.length; i++ ){
19 let ele = this[i];
20
21 if( ele.isNode() ){
22 nodes.push(ele);
23 } else {
24 edges.push(ele);
25 }
26 }
27
28 return { nodes, edges };
29 },
30
31 filter: function( filter, thisArg ){
32 if( filter === undefined ){ // check this first b/c it's the most common/performant case
33 return this;
34 } else if( is.string( filter ) || is.elementOrCollection( filter ) ){
35 return new Selector( filter ).filter( this );
36 } else if( is.fn( filter ) ){
37 let filterEles = this.spawn();
38 let eles = this;
39
40 for( let i = 0; i < eles.length; i++ ){
41 let ele = eles[ i ];
42 let include = thisArg ? filter.apply( thisArg, [ ele, i, eles ] ) : filter( ele, i, eles );
43
44 if( include ){
45 filterEles.push( ele );
46 }
47 }
48
49 return filterEles;
50 }
51
52 return this.spawn(); // if not handled by above, give 'em an empty collection
53 },
54
55 not: function( toRemove ){
56 if( !toRemove ){
57 return this;
58 } else {
59
60 if( is.string( toRemove ) ){
61 toRemove = this.filter( toRemove );
62 }
63
64 let elements = this.spawn();
65
66 for( let i = 0; i < this.length; i++ ){
67 let element = this[ i ];
68
69 let remove = toRemove.has(element);
70 if( !remove ){
71 elements.push( element );
72 }
73 }
74
75 return elements;
76 }
77
78 },
79
80 absoluteComplement: function(){
81 let cy = this.cy();
82
83 return cy.mutableElements().not( this );
84 },
85
86 intersect: function( other ){
87 // if a selector is specified, then filter by it instead
88 if( is.string( other ) ){
89 let selector = other;
90 return this.filter( selector );
91 }
92
93 let elements = this.spawn();
94 let col1 = this;
95 let col2 = other;
96 let col1Smaller = this.length < other.length;
97 let colS = col1Smaller ? col1 : col2;
98 let colL = col1Smaller ? col2 : col1;
99
100 for( let i = 0; i < colS.length; i++ ){
101 let ele = colS[i];
102
103 if( colL.has(ele) ){
104 elements.push(ele);
105 }
106 }
107
108 return elements;
109 },
110
111 xor: function( other ){
112 let cy = this._private.cy;
113
114 if( is.string( other ) ){
115 other = cy.$( other );
116 }
117
118 let elements = this.spawn();
119 let col1 = this;
120 let col2 = other;
121
122 let add = function( col, other ){
123 for( let i = 0; i < col.length; i++ ){
124 let ele = col[ i ];
125 let id = ele._private.data.id;
126 let inOther = other.hasElementWithId( id );
127
128 if( !inOther ){
129 elements.push( ele );
130 }
131 }
132
133 };
134
135 add( col1, col2 );
136 add( col2, col1 );
137
138 return elements;
139 },
140
141 diff: function( other ){
142 let cy = this._private.cy;
143
144 if( is.string( other ) ){
145 other = cy.$( other );
146 }
147
148 let left = this.spawn();
149 let right = this.spawn();
150 let both = this.spawn();
151 let col1 = this;
152 let col2 = other;
153
154 let add = function( col, other, retEles ){
155
156 for( let i = 0; i < col.length; i++ ){
157 let ele = col[ i ];
158 let id = ele._private.data.id;
159 let inOther = other.hasElementWithId( id );
160
161 if( inOther ){
162 both.merge( ele );
163 } else {
164 retEles.push( ele );
165 }
166 }
167
168 };
169
170 add( col1, col2, left );
171 add( col2, col1, right );
172
173 return { left, right, both };
174 },
175
176 add: function( toAdd ){
177 let cy = this._private.cy;
178
179 if( !toAdd ){
180 return this;
181 }
182
183 if( is.string( toAdd ) ){
184 let selector = toAdd;
185 toAdd = cy.mutableElements().filter( selector );
186 }
187
188 let elements = this.spawnSelf();
189
190 for( let i = 0; i < toAdd.length; i++ ){
191 let ele = toAdd[i];
192
193 let add = !this.has(ele);
194 if( add ){
195 elements.push(ele);
196 }
197 }
198
199 return elements;
200 },
201
202 // in place merge on calling collection
203 merge: function( toAdd ){
204 let _p = this._private;
205 let cy = _p.cy;
206
207 if( !toAdd ){
208 return this;
209 }
210
211 if( toAdd && is.string( toAdd ) ){
212 let selector = toAdd;
213 toAdd = cy.mutableElements().filter( selector );
214 }
215
216 let map = _p.map;
217
218 for( let i = 0; i < toAdd.length; i++ ){
219 let toAddEle = toAdd[ i ];
220 let id = toAddEle._private.data.id;
221 let add = !map.has( id );
222
223 if( add ){
224 let index = this.length++;
225
226 this[ index ] = toAddEle;
227
228 map.set( id, { ele: toAddEle, index: index } );
229 }
230 }
231
232 return this; // chaining
233 },
234
235 unmergeAt: function( i ){
236 let ele = this[i];
237 let id = ele.id();
238 let _p = this._private;
239 let map = _p.map;
240
241 // remove ele
242 this[ i ] = undefined;
243 map.delete( id );
244
245 let unmergedLastEle = i === this.length - 1;
246
247 // replace empty spot with last ele in collection
248 if( this.length > 1 && !unmergedLastEle ){
249 let lastEleI = this.length - 1;
250 let lastEle = this[ lastEleI ];
251 let lastEleId = lastEle._private.data.id;
252
253 this[ lastEleI ] = undefined;
254 this[ i ] = lastEle;
255 map.set( lastEleId, { ele: lastEle, index: i } );
256 }
257
258 // the collection is now 1 ele smaller
259 this.length--;
260
261 return this;
262 },
263
264 // remove single ele in place in calling collection
265 unmergeOne: function( ele ){
266 ele = ele[0];
267
268 let _p = this._private;
269 let id = ele._private.data.id;
270 let map = _p.map;
271 let entry = map.get( id );
272
273 if( !entry ){
274 return this; // no need to remove
275 }
276
277 let i = entry.index;
278
279 this.unmergeAt(i);
280
281 return this;
282 },
283
284 // remove eles in place on calling collection
285 unmerge: function( toRemove ){
286 let cy = this._private.cy;
287
288 if( !toRemove ){
289 return this;
290 }
291
292 if( toRemove && is.string( toRemove ) ){
293 let selector = toRemove;
294 toRemove = cy.mutableElements().filter( selector );
295 }
296
297 for( let i = 0; i < toRemove.length; i++ ){
298 this.unmergeOne( toRemove[ i ] );
299 }
300
301 return this; // chaining
302 },
303
304 unmergeBy: function( toRmFn ){
305 for( let i = this.length - 1; i >= 0; i-- ){
306 let ele = this[i];
307
308 if( toRmFn(ele) ){
309 this.unmergeAt(i);
310 }
311 }
312
313 return this;
314 },
315
316 map: function( mapFn, thisArg ){
317 let arr = [];
318 let eles = this;
319
320 for( let i = 0; i < eles.length; i++ ){
321 let ele = eles[ i ];
322 let ret = thisArg ? mapFn.apply( thisArg, [ ele, i, eles ] ) : mapFn( ele, i, eles );
323
324 arr.push( ret );
325 }
326
327 return arr;
328 },
329
330 reduce: function( fn, initialValue ){
331 let val = initialValue;
332 let eles = this;
333
334 for( let i = 0; i < eles.length; i++ ){
335 val = fn( val, eles[i], i, eles );
336 }
337
338 return val;
339 },
340
341 max: function( valFn, thisArg ){
342 let max = -Infinity;
343 let maxEle;
344 let eles = this;
345
346 for( let i = 0; i < eles.length; i++ ){
347 let ele = eles[ i ];
348 let val = thisArg ? valFn.apply( thisArg, [ ele, i, eles ] ) : valFn( ele, i, eles );
349
350 if( val > max ){
351 max = val;
352 maxEle = ele;
353 }
354 }
355
356 return {
357 value: max,
358 ele: maxEle
359 };
360 },
361
362 min: function( valFn, thisArg ){
363 let min = Infinity;
364 let minEle;
365 let eles = this;
366
367 for( let i = 0; i < eles.length; i++ ){
368 let ele = eles[ i ];
369 let val = thisArg ? valFn.apply( thisArg, [ ele, i, eles ] ) : valFn( ele, i, eles );
370
371 if( val < min ){
372 min = val;
373 minEle = ele;
374 }
375 }
376
377 return {
378 value: min,
379 ele: minEle
380 };
381 }
382});
383
384// aliases
385let fn = elesfn;
386fn[ 'u' ] = fn[ '|' ] = fn[ '+' ] = fn.union = fn.or = fn.add;
387fn[ '\\' ] = fn[ '!' ] = fn[ '-' ] = fn.difference = fn.relativeComplement = fn.subtract = fn.not;
388fn[ 'n' ] = fn[ '&' ] = fn[ '.' ] = fn.and = fn.intersection = fn.intersect;
389fn[ '^' ] = fn[ '(+)' ] = fn[ '(-)' ] = fn.symmetricDifference = fn.symdiff = fn.xor;
390fn.fnFilter = fn.filterFn = fn.stdFilter = fn.filter;
391fn.complement = fn.abscomp = fn.absoluteComplement;
392
393export default elesfn;