1 | import * as util from '../util';
|
2 | import * as is from '../is';
|
3 | import Promise from '../promise';
|
4 |
|
5 | const styfn = {};
|
6 |
|
7 |
|
8 | const TRUE = 't';
|
9 | const FALSE = 'f';
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | styfn.apply = function( eles ){
|
16 | let self = this;
|
17 | let _p = self._private;
|
18 | let cy = _p.cy;
|
19 | let updatedEles = cy.collection();
|
20 |
|
21 | if( _p.newStyle ){
|
22 | _p.contextStyles = {};
|
23 | _p.propDiffs = {};
|
24 |
|
25 | self.cleanElements( eles, true );
|
26 | }
|
27 |
|
28 | for( let ie = 0; ie < eles.length; ie++ ){
|
29 | let ele = eles[ ie ];
|
30 |
|
31 | let cxtMeta = self.getContextMeta( ele );
|
32 |
|
33 | if( cxtMeta.empty ){
|
34 | continue;
|
35 | }
|
36 |
|
37 | let cxtStyle = self.getContextStyle( cxtMeta );
|
38 | let app = self.applyContextStyle( cxtMeta, cxtStyle, ele );
|
39 |
|
40 | if( !_p.newStyle ){
|
41 | self.updateTransitions( ele, app.diffProps );
|
42 | }
|
43 |
|
44 | let hintsDiff = self.updateStyleHints( ele );
|
45 |
|
46 | if( hintsDiff ){
|
47 | updatedEles.push( ele );
|
48 | }
|
49 |
|
50 | }
|
51 |
|
52 | _p.newStyle = false;
|
53 |
|
54 | return updatedEles;
|
55 | };
|
56 |
|
57 | styfn.getPropertiesDiff = function( oldCxtKey, newCxtKey ){
|
58 | let self = this;
|
59 | let cache = self._private.propDiffs = self._private.propDiffs || {};
|
60 | let dualCxtKey = oldCxtKey + '-' + newCxtKey;
|
61 | let cachedVal = cache[ dualCxtKey ];
|
62 |
|
63 | if( cachedVal ){
|
64 | return cachedVal;
|
65 | }
|
66 |
|
67 | let diffProps = [];
|
68 | let addedProp = {};
|
69 |
|
70 | for( let i = 0; i < self.length; i++ ){
|
71 | let cxt = self[ i ];
|
72 | let oldHasCxt = oldCxtKey[ i ] === TRUE;
|
73 | let newHasCxt = newCxtKey[ i ] === TRUE;
|
74 | let cxtHasDiffed = oldHasCxt !== newHasCxt;
|
75 | let cxtHasMappedProps = cxt.mappedProperties.length > 0;
|
76 |
|
77 | if( cxtHasDiffed || ( newHasCxt && cxtHasMappedProps )){
|
78 | let props;
|
79 |
|
80 | if( cxtHasDiffed && cxtHasMappedProps ){
|
81 | props = cxt.properties;
|
82 | } else if( cxtHasDiffed ){
|
83 | props = cxt.properties;
|
84 | } else if( cxtHasMappedProps ){
|
85 | props = cxt.mappedProperties;
|
86 | }
|
87 |
|
88 | for( let j = 0; j < props.length; j++ ){
|
89 | let prop = props[ j ];
|
90 | let name = prop.name;
|
91 |
|
92 |
|
93 |
|
94 |
|
95 | let laterCxtOverrides = false;
|
96 | for( let k = i + 1; k < self.length; k++ ){
|
97 | let laterCxt = self[ k ];
|
98 | let hasLaterCxt = newCxtKey[ k ] === TRUE;
|
99 |
|
100 | if( !hasLaterCxt ){ continue; }
|
101 |
|
102 | laterCxtOverrides = laterCxt.properties[ prop.name ] != null;
|
103 |
|
104 | if( laterCxtOverrides ){ break; }
|
105 | }
|
106 |
|
107 | if( !addedProp[ name ] && !laterCxtOverrides ){
|
108 | addedProp[ name ] = true;
|
109 | diffProps.push( name );
|
110 | }
|
111 | }
|
112 | }
|
113 |
|
114 | }
|
115 |
|
116 | cache[ dualCxtKey ] = diffProps;
|
117 | return diffProps;
|
118 | };
|
119 |
|
120 | styfn.getContextMeta = function( ele ){
|
121 | let self = this;
|
122 | let cxtKey = '';
|
123 | let diffProps;
|
124 | let prevKey = ele._private.styleCxtKey || '';
|
125 |
|
126 | if( self._private.newStyle ){
|
127 | prevKey = '';
|
128 | }
|
129 |
|
130 |
|
131 | for( let i = 0; i < self.length; i++ ){
|
132 | let context = self[ i ];
|
133 | let contextSelectorMatches = context.selector && context.selector.matches( ele );
|
134 |
|
135 | if( contextSelectorMatches ){
|
136 | cxtKey += TRUE;
|
137 | } else {
|
138 | cxtKey += FALSE;
|
139 | }
|
140 | }
|
141 |
|
142 | diffProps = self.getPropertiesDiff( prevKey, cxtKey );
|
143 |
|
144 | ele._private.styleCxtKey = cxtKey;
|
145 |
|
146 | return {
|
147 | key: cxtKey,
|
148 | diffPropNames: diffProps,
|
149 | empty: diffProps.length === 0
|
150 | };
|
151 | };
|
152 |
|
153 |
|
154 | styfn.getContextStyle = function( cxtMeta ){
|
155 | let cxtKey = cxtMeta.key;
|
156 | let self = this;
|
157 | let cxtStyles = this._private.contextStyles = this._private.contextStyles || {};
|
158 |
|
159 |
|
160 | if( cxtStyles[ cxtKey ] ){ return cxtStyles[ cxtKey ]; }
|
161 |
|
162 | let style = {
|
163 | _private: {
|
164 | key: cxtKey
|
165 | }
|
166 | };
|
167 |
|
168 | for( let i = 0; i < self.length; i++ ){
|
169 | let cxt = self[ i ];
|
170 | let hasCxt = cxtKey[ i ] === TRUE;
|
171 |
|
172 | if( !hasCxt ){ continue; }
|
173 |
|
174 | for( let j = 0; j < cxt.properties.length; j++ ){
|
175 | let prop = cxt.properties[ j ];
|
176 |
|
177 | style[ prop.name ] = prop;
|
178 | }
|
179 | }
|
180 |
|
181 | cxtStyles[ cxtKey ] = style;
|
182 | return style;
|
183 | };
|
184 |
|
185 | styfn.applyContextStyle = function( cxtMeta, cxtStyle, ele ){
|
186 | let self = this;
|
187 | let diffProps = cxtMeta.diffPropNames;
|
188 | let retDiffProps = {};
|
189 | let types = self.types;
|
190 |
|
191 | for( let i = 0; i < diffProps.length; i++ ){
|
192 | let diffPropName = diffProps[ i ];
|
193 | let cxtProp = cxtStyle[ diffPropName ];
|
194 | let eleProp = ele.pstyle( diffPropName );
|
195 |
|
196 | if( !cxtProp ){
|
197 | if( !eleProp ){
|
198 | continue;
|
199 |
|
200 | } else if( eleProp.bypass ){
|
201 | cxtProp = { name: diffPropName, deleteBypassed: true };
|
202 | } else {
|
203 | cxtProp = { name: diffPropName, delete: true };
|
204 | }
|
205 | }
|
206 |
|
207 |
|
208 | if( eleProp === cxtProp ){ continue; }
|
209 |
|
210 |
|
211 | if(
|
212 | cxtProp.mapped === types.fn
|
213 | && eleProp != null
|
214 | && eleProp.mapping != null
|
215 | && eleProp.mapping.value === cxtProp.value
|
216 | ){
|
217 | let mapping = eleProp.mapping;
|
218 | let fnValue = mapping.fnValue = cxtProp.value( ele );
|
219 |
|
220 | if( fnValue === mapping.prevFnValue ){ continue; }
|
221 | }
|
222 |
|
223 | let retDiffProp = retDiffProps[ diffPropName ] = {
|
224 | prev: eleProp
|
225 | };
|
226 |
|
227 | self.applyParsedProperty( ele, cxtProp );
|
228 |
|
229 | retDiffProp.next = ele.pstyle( diffPropName );
|
230 |
|
231 | if( retDiffProp.next && retDiffProp.next.bypass ){
|
232 | retDiffProp.next = retDiffProp.next.bypassed;
|
233 | }
|
234 | }
|
235 |
|
236 | return {
|
237 | diffProps: retDiffProps
|
238 | };
|
239 | };
|
240 |
|
241 | styfn.updateStyleHints = function(ele){
|
242 | let _p = ele._private;
|
243 | let self = this;
|
244 | let propNames = self.propertyGroupNames;
|
245 | let propGrKeys = self.propertyGroupKeys;
|
246 | let propHash = ( ele, propNames, seedKey ) => self.getPropertiesHash( ele, propNames, seedKey );
|
247 | let oldStyleKey = _p.styleKey;
|
248 |
|
249 | if( ele.removed() ){ return false; }
|
250 |
|
251 | let isNode = _p.group === 'nodes';
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 | let overriddenStyles = ele._private.style;
|
258 |
|
259 | propNames = Object.keys( overriddenStyles );
|
260 |
|
261 | for( let i = 0; i < propGrKeys.length; i++ ){
|
262 | let grKey = propGrKeys[i];
|
263 |
|
264 | _p.styleKeys[ grKey ] = [ util.DEFAULT_HASH_SEED, util.DEFAULT_HASH_SEED_ALT ];
|
265 | }
|
266 |
|
267 | let updateGrKey1 = (val, grKey) => _p.styleKeys[ grKey ][0] = util.hashInt( val, _p.styleKeys[ grKey ][0] );
|
268 | let updateGrKey2 = (val, grKey) => _p.styleKeys[ grKey ][1] = util.hashIntAlt( val, _p.styleKeys[ grKey ][1] );
|
269 |
|
270 | let updateGrKey = (val, grKey) => {
|
271 | updateGrKey1(val, grKey);
|
272 | updateGrKey2(val, grKey);
|
273 | };
|
274 |
|
275 | let updateGrKeyWStr = (strVal, grKey) => {
|
276 | for( let j = 0; j < strVal.length; j++ ){
|
277 | let ch = strVal.charCodeAt(j);
|
278 |
|
279 | updateGrKey1(ch, grKey);
|
280 | updateGrKey2(ch, grKey);
|
281 | }
|
282 | };
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 | let N = 2000000000;
|
290 | let cleanNum = val => (-128 < val && val < 128) && Math.floor(val) !== val ? N - ((val * 1024) | 0) : val;
|
291 |
|
292 | for( let i = 0; i < propNames.length; i++ ){
|
293 | let name = propNames[i];
|
294 | let parsedProp = overriddenStyles[ name ];
|
295 |
|
296 | if( parsedProp == null ){ continue; }
|
297 |
|
298 | let propInfo = this.properties[name];
|
299 | let type = propInfo.type;
|
300 | let grKey = propInfo.groupKey;
|
301 | let normalizedNumberVal;
|
302 |
|
303 | if( propInfo.hashOverride != null ){
|
304 | normalizedNumberVal = propInfo.hashOverride(ele, parsedProp);
|
305 | } else if( parsedProp.pfValue != null ){
|
306 | normalizedNumberVal = parsedProp.pfValue;
|
307 | }
|
308 |
|
309 |
|
310 | let numberVal = propInfo.enums == null ? parsedProp.value : null;
|
311 | let haveNormNum = normalizedNumberVal != null;
|
312 | let haveUnitedNum = numberVal != null;
|
313 | let haveNum = haveNormNum || haveUnitedNum;
|
314 | let units = parsedProp.units;
|
315 |
|
316 |
|
317 |
|
318 | if( type.number && haveNum && !type.multiple ){
|
319 | let v = haveNormNum ? normalizedNumberVal : numberVal;
|
320 |
|
321 | updateGrKey(cleanNum(v), grKey);
|
322 |
|
323 | if( !haveNormNum && units != null ){
|
324 | updateGrKeyWStr(units, grKey);
|
325 | }
|
326 | } else {
|
327 | updateGrKeyWStr(parsedProp.strValue, grKey);
|
328 | }
|
329 | }
|
330 |
|
331 |
|
332 |
|
333 |
|
334 | let hash = [ util.DEFAULT_HASH_SEED, util.DEFAULT_HASH_SEED_ALT ];
|
335 |
|
336 | for( let i = 0; i < propGrKeys.length; i++ ){
|
337 | let grKey = propGrKeys[i];
|
338 | let grHash = _p.styleKeys[ grKey ];
|
339 |
|
340 | hash[0] = util.hashInt( grHash[0], hash[0] );
|
341 | hash[1] = util.hashIntAlt( grHash[1], hash[1] );
|
342 | }
|
343 |
|
344 | _p.styleKey = util.combineHashes(hash[0], hash[1]);
|
345 |
|
346 |
|
347 |
|
348 |
|
349 | let sk = _p.styleKeys;
|
350 |
|
351 | _p.labelDimsKey = util.combineHashesArray(sk.labelDimensions);
|
352 |
|
353 | let labelKeys = propHash( ele, ['label'], sk.labelDimensions );
|
354 |
|
355 | _p.labelKey = util.combineHashesArray(labelKeys);
|
356 | _p.labelStyleKey = util.combineHashesArray(util.hashArrays(sk.commonLabel, labelKeys));
|
357 |
|
358 | if( !isNode ){
|
359 | let sourceLabelKeys = propHash( ele, ['source-label'], sk.labelDimensions );
|
360 | _p.sourceLabelKey = util.combineHashesArray(sourceLabelKeys);
|
361 | _p.sourceLabelStyleKey = util.combineHashesArray(util.hashArrays(sk.commonLabel, sourceLabelKeys));
|
362 |
|
363 | let targetLabelKeys = propHash( ele, ['target-label'], sk.labelDimensions );
|
364 | _p.targetLabelKey = util.combineHashesArray(targetLabelKeys);
|
365 | _p.targetLabelStyleKey = util.combineHashesArray(util.hashArrays(sk.commonLabel, targetLabelKeys));
|
366 | }
|
367 |
|
368 |
|
369 |
|
370 |
|
371 | if( isNode ){
|
372 | let { nodeBody, nodeBorder, backgroundImage, compound, pie } = _p.styleKeys;
|
373 |
|
374 | let nodeKeys = [ nodeBody, nodeBorder, backgroundImage, compound, pie ].filter(k => k != null).reduce(util.hashArrays, [
|
375 | util.DEFAULT_HASH_SEED,
|
376 | util.DEFAULT_HASH_SEED_ALT
|
377 | ]);
|
378 | _p.nodeKey = util.combineHashesArray(nodeKeys);
|
379 |
|
380 | _p.hasPie = pie != null && pie[0] !== util.DEFAULT_HASH_SEED && pie[1] !== util.DEFAULT_HASH_SEED_ALT;
|
381 | }
|
382 |
|
383 | return oldStyleKey !== _p.styleKey;
|
384 | };
|
385 |
|
386 | styfn.clearStyleHints = function(ele){
|
387 | let _p = ele._private;
|
388 |
|
389 | _p.styleKeys = {};
|
390 | _p.styleKey = null;
|
391 | _p.labelKey = null;
|
392 | _p.labelStyleKey = null;
|
393 | _p.sourceLabelKey = null;
|
394 | _p.sourceLabelStyleKey = null;
|
395 | _p.targetLabelKey = null;
|
396 | _p.targetLabelStyleKey = null;
|
397 | _p.nodeKey = null;
|
398 | _p.hasPie = null;
|
399 | };
|
400 |
|
401 |
|
402 |
|
403 |
|
404 |
|
405 |
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 |
|
416 |
|
417 | styfn.applyParsedProperty = function( ele, parsedProp ){
|
418 | let self = this;
|
419 | let prop = parsedProp;
|
420 | let style = ele._private.style;
|
421 | let flatProp;
|
422 | let types = self.types;
|
423 | let type = self.properties[ prop.name ].type;
|
424 | let propIsBypass = prop.bypass;
|
425 | let origProp = style[ prop.name ];
|
426 | let origPropIsBypass = origProp && origProp.bypass;
|
427 | let _p = ele._private;
|
428 | let flatPropMapping = 'mapping';
|
429 |
|
430 | let getVal = p => {
|
431 | if( p == null ){
|
432 | return null;
|
433 | } else if( p.pfValue != null ){
|
434 | return p.pfValue;
|
435 | } else {
|
436 | return p.value;
|
437 | }
|
438 | };
|
439 |
|
440 | let checkTriggers = () => {
|
441 | let fromVal = getVal(origProp);
|
442 | let toVal = getVal(prop);
|
443 |
|
444 | self.checkTriggers( ele, prop.name, fromVal, toVal );
|
445 | };
|
446 |
|
447 |
|
448 | if(
|
449 | parsedProp.name === 'curve-style'
|
450 | && ele.isEdge()
|
451 | && (
|
452 | (
|
453 | parsedProp.value !== 'bezier'
|
454 | && ele.isLoop()
|
455 | ) || (
|
456 | parsedProp.value === 'haystack'
|
457 | && ( ele.source().isParent() || ele.target().isParent() )
|
458 | )
|
459 | )
|
460 | ){
|
461 | prop = parsedProp = this.parse( parsedProp.name, 'bezier', propIsBypass );
|
462 | }
|
463 |
|
464 | if( prop.delete ){
|
465 | style[ prop.name ] = undefined;
|
466 |
|
467 | checkTriggers();
|
468 |
|
469 | return true;
|
470 | }
|
471 |
|
472 | if( prop.deleteBypassed ){
|
473 | if( !origProp ){
|
474 | checkTriggers();
|
475 |
|
476 | return true;
|
477 |
|
478 | } else if( origProp.bypass ){
|
479 | origProp.bypassed = undefined;
|
480 |
|
481 | checkTriggers();
|
482 |
|
483 | return true;
|
484 |
|
485 | } else {
|
486 | return false;
|
487 | }
|
488 | }
|
489 |
|
490 |
|
491 | if( prop.deleteBypass ){
|
492 | if( !origProp ){
|
493 | checkTriggers();
|
494 |
|
495 | return true;
|
496 |
|
497 | } else if( origProp.bypass ){
|
498 |
|
499 | style[ prop.name ] = origProp.bypassed;
|
500 |
|
501 | checkTriggers();
|
502 |
|
503 | return true;
|
504 |
|
505 | } else {
|
506 | return false;
|
507 | }
|
508 | }
|
509 |
|
510 | let printMappingErr = function(){
|
511 | util.warn( 'Do not assign mappings to elements without corresponding data (i.e. ele `' + ele.id() + '` has no mapping for property `' + prop.name + '` with data field `' + prop.field + '`); try a `[' + prop.field + ']` selector to limit scope to elements with `' + prop.field + '` defined' );
|
512 | };
|
513 |
|
514 |
|
515 | switch( prop.mapped ){
|
516 | case types.mapData: {
|
517 |
|
518 | let fields = prop.field.split( '.' );
|
519 | let fieldVal = _p.data;
|
520 |
|
521 | for( let i = 0; i < fields.length && fieldVal; i++ ){
|
522 | let field = fields[ i ];
|
523 | fieldVal = fieldVal[ field ];
|
524 | }
|
525 |
|
526 | if( fieldVal == null ){
|
527 | printMappingErr();
|
528 | return false;
|
529 | }
|
530 |
|
531 | let percent;
|
532 | if( !is.number( fieldVal ) ){
|
533 | util.warn('Do not use continuous mappers without specifying numeric data (i.e. `' + prop.field + ': ' + fieldVal + '` for `' + ele.id() + '` is non-numeric)');
|
534 | return false;
|
535 | } else {
|
536 | let fieldWidth = prop.fieldMax - prop.fieldMin;
|
537 |
|
538 | if( fieldWidth === 0 ){
|
539 | percent = 0;
|
540 | } else {
|
541 | percent = (fieldVal - prop.fieldMin) / fieldWidth;
|
542 | }
|
543 | }
|
544 |
|
545 |
|
546 | if( percent < 0 ){
|
547 | percent = 0;
|
548 | } else if( percent > 1 ){
|
549 | percent = 1;
|
550 | }
|
551 |
|
552 | if( type.color ){
|
553 | let r1 = prop.valueMin[0];
|
554 | let r2 = prop.valueMax[0];
|
555 | let g1 = prop.valueMin[1];
|
556 | let g2 = prop.valueMax[1];
|
557 | let b1 = prop.valueMin[2];
|
558 | let b2 = prop.valueMax[2];
|
559 | let a1 = prop.valueMin[3] == null ? 1 : prop.valueMin[3];
|
560 | let a2 = prop.valueMax[3] == null ? 1 : prop.valueMax[3];
|
561 |
|
562 | let clr = [
|
563 | Math.round( r1 + (r2 - r1) * percent ),
|
564 | Math.round( g1 + (g2 - g1) * percent ),
|
565 | Math.round( b1 + (b2 - b1) * percent ),
|
566 | Math.round( a1 + (a2 - a1) * percent )
|
567 | ];
|
568 |
|
569 | flatProp = {
|
570 | bypass: prop.bypass,
|
571 | name: prop.name,
|
572 | value: clr,
|
573 | strValue: 'rgb(' + clr[0] + ', ' + clr[1] + ', ' + clr[2] + ')'
|
574 | };
|
575 |
|
576 | } else if( type.number ){
|
577 | let calcValue = prop.valueMin + (prop.valueMax - prop.valueMin) * percent;
|
578 | flatProp = this.parse( prop.name, calcValue, prop.bypass, flatPropMapping );
|
579 |
|
580 | } else {
|
581 | return false;
|
582 | }
|
583 |
|
584 | if( !flatProp ){
|
585 | printMappingErr();
|
586 | return false;
|
587 | }
|
588 |
|
589 | flatProp.mapping = prop;
|
590 | prop = flatProp;
|
591 |
|
592 | break;
|
593 | }
|
594 |
|
595 |
|
596 | case types.data: {
|
597 |
|
598 | let fields = prop.field.split( '.' );
|
599 | let fieldVal = _p.data;
|
600 |
|
601 | for( let i = 0; i < fields.length && fieldVal; i++ ){
|
602 | let field = fields[ i ];
|
603 | fieldVal = fieldVal[ field ];
|
604 | }
|
605 |
|
606 | if( fieldVal != null ){
|
607 | flatProp = this.parse( prop.name, fieldVal, prop.bypass, flatPropMapping );
|
608 | }
|
609 |
|
610 | if( !flatProp ){
|
611 | printMappingErr();
|
612 | return false;
|
613 | }
|
614 |
|
615 | flatProp.mapping = prop;
|
616 | prop = flatProp;
|
617 |
|
618 | break;
|
619 | }
|
620 |
|
621 | case types.fn: {
|
622 | let fn = prop.value;
|
623 | let fnRetVal = prop.fnValue != null ? prop.fnValue : fn( ele );
|
624 |
|
625 | prop.prevFnValue = fnRetVal;
|
626 |
|
627 | if( fnRetVal == null ){
|
628 | util.warn('Custom function mappers may not return null (i.e. `' + prop.name + '` for ele `' + ele.id() + '` is null)');
|
629 | return false;
|
630 | }
|
631 |
|
632 | flatProp = this.parse( prop.name, fnRetVal, prop.bypass, flatPropMapping );
|
633 |
|
634 | if( !flatProp ){
|
635 | util.warn('Custom function mappers may not return invalid values for the property type (i.e. `' + prop.name + '` for ele `' + ele.id() + '` is invalid)');
|
636 | return false;
|
637 | }
|
638 |
|
639 | flatProp.mapping = util.copy( prop );
|
640 | prop = flatProp;
|
641 |
|
642 | break;
|
643 | }
|
644 |
|
645 | case undefined:
|
646 | break;
|
647 |
|
648 | default:
|
649 | return false;
|
650 | }
|
651 |
|
652 |
|
653 | if( propIsBypass ){
|
654 | if( origPropIsBypass ){
|
655 | prop.bypassed = origProp.bypassed;
|
656 | } else {
|
657 | prop.bypassed = origProp;
|
658 | }
|
659 |
|
660 | style[ prop.name ] = prop;
|
661 |
|
662 | } else {
|
663 | if( origPropIsBypass ){
|
664 | origProp.bypassed = prop;
|
665 | } else {
|
666 | style[ prop.name ] = prop;
|
667 | }
|
668 | }
|
669 |
|
670 | checkTriggers();
|
671 |
|
672 | return true;
|
673 | };
|
674 |
|
675 | styfn.cleanElements = function( eles, keepBypasses ){
|
676 | for( let i = 0; i < eles.length; i++ ){
|
677 | let ele = eles[i];
|
678 |
|
679 | this.clearStyleHints(ele);
|
680 |
|
681 | ele.dirtyCompoundBoundsCache();
|
682 | ele.dirtyBoundingBoxCache();
|
683 |
|
684 | if( !keepBypasses ){
|
685 | ele._private.style = {};
|
686 | } else {
|
687 | let style = ele._private.style;
|
688 | let propNames = Object.keys(style);
|
689 |
|
690 | for( let j = 0; j < propNames.length; j++ ){
|
691 | let propName = propNames[j];
|
692 | let eleProp = style[ propName ];
|
693 |
|
694 | if( eleProp != null ){
|
695 | if( eleProp.bypass ){
|
696 | eleProp.bypassed = null;
|
697 | } else {
|
698 | style[ propName ] = null;
|
699 | }
|
700 | }
|
701 | }
|
702 | }
|
703 | }
|
704 | };
|
705 |
|
706 |
|
707 | styfn.update = function(){
|
708 | let cy = this._private.cy;
|
709 | let eles = cy.mutableElements();
|
710 |
|
711 | eles.updateStyle();
|
712 | };
|
713 |
|
714 |
|
715 | styfn.updateTransitions = function( ele, diffProps ){
|
716 | let self = this;
|
717 | let _p = ele._private;
|
718 | let props = ele.pstyle( 'transition-property' ).value;
|
719 | let duration = ele.pstyle( 'transition-duration' ).pfValue;
|
720 | let delay = ele.pstyle( 'transition-delay' ).pfValue;
|
721 |
|
722 | if( props.length > 0 && duration > 0 ){
|
723 |
|
724 | let style = {};
|
725 |
|
726 |
|
727 | let anyPrev = false;
|
728 | for( let i = 0; i < props.length; i++ ){
|
729 | let prop = props[ i ];
|
730 | let styProp = ele.pstyle( prop );
|
731 | let diffProp = diffProps[ prop ];
|
732 |
|
733 | if( !diffProp ){ continue; }
|
734 |
|
735 | let prevProp = diffProp.prev;
|
736 | let fromProp = prevProp;
|
737 | let toProp = diffProp.next != null ? diffProp.next : styProp;
|
738 | let diff = false;
|
739 | let initVal;
|
740 | let initDt = 0.000001;
|
741 |
|
742 | if( !fromProp ){ continue; }
|
743 |
|
744 |
|
745 | if( is.number( fromProp.pfValue ) && is.number( toProp.pfValue ) ){
|
746 | diff = toProp.pfValue - fromProp.pfValue;
|
747 | initVal = fromProp.pfValue + initDt * diff;
|
748 |
|
749 |
|
750 | } else if( is.number( fromProp.value ) && is.number( toProp.value ) ){
|
751 | diff = toProp.value - fromProp.value;
|
752 | initVal = fromProp.value + initDt * diff;
|
753 |
|
754 |
|
755 | } else if( is.array( fromProp.value ) && is.array( toProp.value ) ){
|
756 | diff = fromProp.value[0] !== toProp.value[0]
|
757 | || fromProp.value[1] !== toProp.value[1]
|
758 | || fromProp.value[2] !== toProp.value[2]
|
759 | ;
|
760 |
|
761 | initVal = fromProp.strValue;
|
762 | }
|
763 |
|
764 |
|
765 | if( diff ){
|
766 | style[ prop ] = toProp.strValue;
|
767 | this.applyBypass( ele, prop, initVal );
|
768 | anyPrev = true;
|
769 | }
|
770 |
|
771 | }
|
772 |
|
773 |
|
774 | if( !anyPrev ){ return; }
|
775 |
|
776 | _p.transitioning = true;
|
777 |
|
778 | ( new Promise(function( resolve ){
|
779 | if( delay > 0 ){
|
780 | ele.delayAnimation( delay ).play().promise().then( resolve );
|
781 | } else {
|
782 | resolve();
|
783 | }
|
784 | }) ).then(function(){
|
785 | return ele.animation( {
|
786 | style: style,
|
787 | duration: duration,
|
788 | easing: ele.pstyle( 'transition-timing-function' ).value,
|
789 | queue: false
|
790 | } ).play().promise();
|
791 | }).then(function(){
|
792 |
|
793 | self.removeBypasses( ele, props );
|
794 | ele.emitAndNotify('style');
|
795 |
|
796 |
|
797 | _p.transitioning = false;
|
798 | });
|
799 |
|
800 | } else if( _p.transitioning ){
|
801 | this.removeBypasses( ele, props );
|
802 | ele.emitAndNotify('style');
|
803 |
|
804 | _p.transitioning = false;
|
805 | }
|
806 | };
|
807 |
|
808 | styfn.checkTrigger = function( ele, name, fromValue, toValue, getTrigger, onTrigger ){
|
809 | let prop = this.properties[ name ];
|
810 | let triggerCheck = getTrigger( prop );
|
811 |
|
812 | if( triggerCheck != null && triggerCheck( fromValue, toValue ) ){
|
813 | onTrigger(prop);
|
814 | }
|
815 | };
|
816 |
|
817 | styfn.checkZOrderTrigger = function( ele, name, fromValue, toValue ){
|
818 | this.checkTrigger( ele, name, fromValue, toValue, prop => prop.triggersZOrder, () => {
|
819 | this._private.cy.notify('zorder', ele);
|
820 | });
|
821 | };
|
822 |
|
823 | styfn.checkBoundsTrigger = function( ele, name, fromValue, toValue ){
|
824 | this.checkTrigger( ele, name, fromValue, toValue, prop => prop.triggersBounds, prop => {
|
825 | ele.dirtyCompoundBoundsCache();
|
826 | ele.dirtyBoundingBoxCache();
|
827 |
|
828 |
|
829 |
|
830 | if(
|
831 | ( name === 'curve-style' && (fromValue === 'bezier' || toValue === 'bezier') )
|
832 | && prop.triggersBoundsOfParallelBeziers
|
833 | ){
|
834 | ele.parallelEdges().forEach(pllEdge => {
|
835 | if( pllEdge.isBundledBezier() ){
|
836 | pllEdge.dirtyBoundingBoxCache();
|
837 | }
|
838 | });
|
839 | }
|
840 | } );
|
841 | };
|
842 |
|
843 | styfn.checkTriggers = function( ele, name, fromValue, toValue ){
|
844 | ele.dirtyStyleCache();
|
845 |
|
846 | this.checkZOrderTrigger( ele, name, fromValue, toValue );
|
847 | this.checkBoundsTrigger( ele, name, fromValue, toValue );
|
848 | };
|
849 |
|
850 | export default styfn;
|