|
import * as util from '../util'; |
|
import * as is from '../is'; |
|
import Promise from '../promise'; |
|
|
|
const styfn = {}; |
|
|
|
|
|
const TRUE = 't'; |
|
const FALSE = 'f'; |
|
|
|
|
|
|
|
|
|
|
|
styfn.apply = function( eles ){ |
|
let self = this; |
|
let _p = self._private; |
|
let cy = _p.cy; |
|
let updatedEles = cy.collection(); |
|
|
|
for( let ie = 0; ie < eles.length; ie++ ){ |
|
let ele = eles[ ie ]; |
|
let cxtMeta = self.getContextMeta( ele ); |
|
|
|
if( cxtMeta.empty ){ |
|
continue; |
|
} |
|
|
|
let cxtStyle = self.getContextStyle( cxtMeta ); |
|
let app = self.applyContextStyle( cxtMeta, cxtStyle, ele ); |
|
|
|
if( ele._private.appliedInitStyle ){ |
|
self.updateTransitions( ele, app.diffProps ); |
|
} else { |
|
ele._private.appliedInitStyle = true; |
|
} |
|
|
|
let hintsDiff = self.updateStyleHints( ele ); |
|
|
|
if( hintsDiff ){ |
|
updatedEles.push( ele ); |
|
} |
|
|
|
} |
|
|
|
return updatedEles; |
|
}; |
|
|
|
styfn.getPropertiesDiff = function( oldCxtKey, newCxtKey ){ |
|
let self = this; |
|
let cache = self._private.propDiffs = self._private.propDiffs || {}; |
|
let dualCxtKey = oldCxtKey + '-' + newCxtKey; |
|
let cachedVal = cache[ dualCxtKey ]; |
|
|
|
if( cachedVal ){ |
|
return cachedVal; |
|
} |
|
|
|
let diffProps = []; |
|
let addedProp = {}; |
|
|
|
for( let i = 0; i < self.length; i++ ){ |
|
let cxt = self[ i ]; |
|
let oldHasCxt = oldCxtKey[ i ] === TRUE; |
|
let newHasCxt = newCxtKey[ i ] === TRUE; |
|
let cxtHasDiffed = oldHasCxt !== newHasCxt; |
|
let cxtHasMappedProps = cxt.mappedProperties.length > 0; |
|
|
|
if( cxtHasDiffed || ( newHasCxt && cxtHasMappedProps )){ |
|
let props; |
|
|
|
if( cxtHasDiffed && cxtHasMappedProps ){ |
|
props = cxt.properties; |
|
} else if( cxtHasDiffed ){ |
|
props = cxt.properties; |
|
} else if( cxtHasMappedProps ){ |
|
props = cxt.mappedProperties; |
|
} |
|
|
|
for( let j = 0; j < props.length; j++ ){ |
|
let prop = props[ j ]; |
|
let name = prop.name; |
|
|
|
|
|
|
|
|
|
let laterCxtOverrides = false; |
|
for( let k = i + 1; k < self.length; k++ ){ |
|
let laterCxt = self[ k ]; |
|
let hasLaterCxt = newCxtKey[ k ] === TRUE; |
|
|
|
if( !hasLaterCxt ){ continue; } |
|
|
|
laterCxtOverrides = laterCxt.properties[ prop.name ] != null; |
|
|
|
if( laterCxtOverrides ){ break; } |
|
} |
|
|
|
if( !addedProp[ name ] && !laterCxtOverrides ){ |
|
addedProp[ name ] = true; |
|
diffProps.push( name ); |
|
} |
|
} |
|
} |
|
|
|
} |
|
|
|
cache[ dualCxtKey ] = diffProps; |
|
return diffProps; |
|
}; |
|
|
|
styfn.getContextMeta = function( ele ){ |
|
let self = this; |
|
let cxtKey = ''; |
|
let diffProps; |
|
let prevKey = ele._private.styleCxtKey || ''; |
|
|
|
|
|
for( let i = 0; i < self.length; i++ ){ |
|
let context = self[ i ]; |
|
let contextSelectorMatches = context.selector && context.selector.matches( ele ); |
|
|
|
if( contextSelectorMatches ){ |
|
cxtKey += TRUE; |
|
} else { |
|
cxtKey += FALSE; |
|
} |
|
} |
|
|
|
diffProps = self.getPropertiesDiff( prevKey, cxtKey ); |
|
|
|
ele._private.styleCxtKey = cxtKey; |
|
|
|
return { |
|
key: cxtKey, |
|
diffPropNames: diffProps, |
|
empty: diffProps.length === 0 |
|
}; |
|
}; |
|
|
|
|
|
styfn.getContextStyle = function( cxtMeta ){ |
|
let cxtKey = cxtMeta.key; |
|
let self = this; |
|
let cxtStyles = this._private.contextStyles = this._private.contextStyles || {}; |
|
|
|
|
|
if( cxtStyles[ cxtKey ] ){ return cxtStyles[ cxtKey ]; } |
|
|
|
let style = { |
|
_private: { |
|
key: cxtKey |
|
} |
|
}; |
|
|
|
for( let i = 0; i < self.length; i++ ){ |
|
let cxt = self[ i ]; |
|
let hasCxt = cxtKey[ i ] === TRUE; |
|
|
|
if( !hasCxt ){ continue; } |
|
|
|
for( let j = 0; j < cxt.properties.length; j++ ){ |
|
let prop = cxt.properties[ j ]; |
|
|
|
style[ prop.name ] = prop; |
|
} |
|
} |
|
|
|
cxtStyles[ cxtKey ] = style; |
|
return style; |
|
}; |
|
|
|
styfn.applyContextStyle = function( cxtMeta, cxtStyle, ele ){ |
|
let self = this; |
|
let diffProps = cxtMeta.diffPropNames; |
|
let retDiffProps = {}; |
|
let types = self.types; |
|
|
|
for( let i = 0; i < diffProps.length; i++ ){ |
|
let diffPropName = diffProps[ i ]; |
|
let cxtProp = cxtStyle[ diffPropName ]; |
|
let eleProp = ele.pstyle( diffPropName ); |
|
|
|
if( !cxtProp ){ |
|
if( !eleProp ){ |
|
continue; |
|
|
|
} else if( eleProp.bypass ){ |
|
cxtProp = { name: diffPropName, deleteBypassed: true }; |
|
} else { |
|
cxtProp = { name: diffPropName, delete: true }; |
|
} |
|
} |
|
|
|
|
|
if( eleProp === cxtProp ){ continue; } |
|
|
|
|
|
if( |
|
cxtProp.mapped === types.fn |
|
&& eleProp != null |
|
&& eleProp.mapping != null |
|
&& eleProp.mapping.value === cxtProp.value |
|
){ |
|
let mapping = eleProp.mapping; |
|
let fnValue = mapping.fnValue = cxtProp.value( ele ); |
|
|
|
if( fnValue === mapping.prevFnValue ){ continue; } |
|
} |
|
|
|
let retDiffProp = retDiffProps[ diffPropName ] = { |
|
prev: eleProp |
|
}; |
|
|
|
self.applyParsedProperty( ele, cxtProp ); |
|
|
|
retDiffProp.next = ele.pstyle( diffPropName ); |
|
|
|
if( retDiffProp.next && retDiffProp.next.bypass ){ |
|
retDiffProp.next = retDiffProp.next.bypassed; |
|
} |
|
} |
|
|
|
return { |
|
diffProps: retDiffProps |
|
}; |
|
}; |
|
|
|
styfn.updateStyleHints = function(ele){ |
|
let _p = ele._private; |
|
let self = this; |
|
let propNames = self.propertyGroupNames; |
|
let propGrKeys = self.propertyGroupKeys; |
|
let propHash = ( ele, propNames, seedKey ) => self.getPropertiesHash( ele, propNames, seedKey ); |
|
let oldStyleKey = _p.styleKey; |
|
|
|
if( ele.removed() ){ return false; } |
|
|
|
let isNode = _p.group === 'nodes'; |
|
|
|
|
|
|
|
|
|
|
|
let overriddenStyles = ele._private.style; |
|
|
|
propNames = Object.keys( overriddenStyles ); |
|
|
|
for( let i = 0; i < propGrKeys.length; i++ ){ |
|
let grKey = propGrKeys[i]; |
|
|
|
_p.styleKeys[ grKey ] = [ util.DEFAULT_HASH_SEED, util.DEFAULT_HASH_SEED_ALT ]; |
|
} |
|
|
|
let updateGrKey1 = (val, grKey) => _p.styleKeys[ grKey ][0] = util.hashInt( val, _p.styleKeys[ grKey ][0] ); |
|
let updateGrKey2 = (val, grKey) => _p.styleKeys[ grKey ][1] = util.hashIntAlt( val, _p.styleKeys[ grKey ][1] ); |
|
|
|
let updateGrKey = (val, grKey) => { |
|
updateGrKey1(val, grKey); |
|
updateGrKey2(val, grKey); |
|
}; |
|
|
|
let updateGrKeyWStr = (strVal, grKey) => { |
|
for( let j = 0; j < strVal.length; j++ ){ |
|
let ch = strVal.charCodeAt(j); |
|
|
|
updateGrKey1(ch, grKey); |
|
updateGrKey2(ch, grKey); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
let N = 2000000000; |
|
let cleanNum = val => (-128 < val && val < 128) && Math.floor(val) !== val ? N - ((val * 1024) | 0) : val; |
|
|
|
for( let i = 0; i < propNames.length; i++ ){ |
|
let name = propNames[i]; |
|
let parsedProp = overriddenStyles[ name ]; |
|
|
|
if( parsedProp == null ){ continue; } |
|
|
|
let propInfo = this.properties[name]; |
|
let type = propInfo.type; |
|
let grKey = propInfo.groupKey; |
|
let normalizedNumberVal; |
|
|
|
if( propInfo.hashOverride != null ){ |
|
normalizedNumberVal = propInfo.hashOverride(ele, parsedProp); |
|
} else if( parsedProp.pfValue != null ){ |
|
normalizedNumberVal = parsedProp.pfValue; |
|
} |
|
|
|
|
|
let numberVal = propInfo.enums == null ? parsedProp.value : null; |
|
let haveNormNum = normalizedNumberVal != null; |
|
let haveUnitedNum = numberVal != null; |
|
let haveNum = haveNormNum || haveUnitedNum; |
|
let units = parsedProp.units; |
|
|
|
|
|
|
|
if( type.number && haveNum && !type.multiple ){ |
|
let v = haveNormNum ? normalizedNumberVal : numberVal; |
|
|
|
updateGrKey(cleanNum(v), grKey); |
|
|
|
if( !haveNormNum && units != null ){ |
|
updateGrKeyWStr(units, grKey); |
|
} |
|
} else { |
|
updateGrKeyWStr(parsedProp.strValue, grKey); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
let hash = [ util.DEFAULT_HASH_SEED, util.DEFAULT_HASH_SEED_ALT ]; |
|
|
|
for( let i = 0; i < propGrKeys.length; i++ ){ |
|
let grKey = propGrKeys[i]; |
|
let grHash = _p.styleKeys[ grKey ]; |
|
|
|
hash[0] = util.hashInt( grHash[0], hash[0] ); |
|
hash[1] = util.hashIntAlt( grHash[1], hash[1] ); |
|
} |
|
|
|
_p.styleKey = util.combineHashes(hash[0], hash[1]); |
|
|
|
|
|
|
|
|
|
let sk = _p.styleKeys; |
|
|
|
_p.labelDimsKey = util.combineHashesArray(sk.labelDimensions); |
|
|
|
let labelKeys = propHash( ele, ['label'], sk.labelDimensions ); |
|
|
|
_p.labelKey = util.combineHashesArray(labelKeys); |
|
_p.labelStyleKey = util.combineHashesArray(util.hashArrays(sk.commonLabel, labelKeys)); |
|
|
|
if( !isNode ){ |
|
let sourceLabelKeys = propHash( ele, ['source-label'], sk.labelDimensions ); |
|
_p.sourceLabelKey = util.combineHashesArray(sourceLabelKeys); |
|
_p.sourceLabelStyleKey = util.combineHashesArray(util.hashArrays(sk.commonLabel, sourceLabelKeys)); |
|
|
|
let targetLabelKeys = propHash( ele, ['target-label'], sk.labelDimensions ); |
|
_p.targetLabelKey = util.combineHashesArray(targetLabelKeys); |
|
_p.targetLabelStyleKey = util.combineHashesArray(util.hashArrays(sk.commonLabel, targetLabelKeys)); |
|
} |
|
|
|
|
|
|
|
|
|
if( isNode ){ |
|
let { nodeBody, nodeBorder, nodeOutline, backgroundImage, compound, pie } = _p.styleKeys; |
|
|
|
let nodeKeys = [ nodeBody, nodeBorder, nodeOutline, backgroundImage, compound, pie ].filter(k => k != null).reduce(util.hashArrays, [ |
|
util.DEFAULT_HASH_SEED, |
|
util.DEFAULT_HASH_SEED_ALT |
|
]); |
|
_p.nodeKey = util.combineHashesArray(nodeKeys); |
|
|
|
_p.hasPie = pie != null && pie[0] !== util.DEFAULT_HASH_SEED && pie[1] !== util.DEFAULT_HASH_SEED_ALT; |
|
} |
|
|
|
return oldStyleKey !== _p.styleKey; |
|
}; |
|
|
|
styfn.clearStyleHints = function(ele){ |
|
let _p = ele._private; |
|
|
|
_p.styleCxtKey = ''; |
|
_p.styleKeys = {}; |
|
_p.styleKey = null; |
|
_p.labelKey = null; |
|
_p.labelStyleKey = null; |
|
_p.sourceLabelKey = null; |
|
_p.sourceLabelStyleKey = null; |
|
_p.targetLabelKey = null; |
|
_p.targetLabelStyleKey = null; |
|
_p.nodeKey = null; |
|
_p.hasPie = null; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
styfn.applyParsedProperty = function( ele, parsedProp ){ |
|
let self = this; |
|
let prop = parsedProp; |
|
let style = ele._private.style; |
|
let flatProp; |
|
let types = self.types; |
|
let type = self.properties[ prop.name ].type; |
|
let propIsBypass = prop.bypass; |
|
let origProp = style[ prop.name ]; |
|
let origPropIsBypass = origProp && origProp.bypass; |
|
let _p = ele._private; |
|
let flatPropMapping = 'mapping'; |
|
|
|
let getVal = p => { |
|
if( p == null ){ |
|
return null; |
|
} else if( p.pfValue != null ){ |
|
return p.pfValue; |
|
} else { |
|
return p.value; |
|
} |
|
}; |
|
|
|
let checkTriggers = () => { |
|
let fromVal = getVal(origProp); |
|
let toVal = getVal(prop); |
|
|
|
self.checkTriggers( ele, prop.name, fromVal, toVal ); |
|
}; |
|
|
|
|
|
if( |
|
parsedProp.name === 'curve-style' |
|
&& ele.isEdge() |
|
&& ( |
|
( |
|
parsedProp.value !== 'bezier' |
|
&& ele.isLoop() |
|
) || ( |
|
parsedProp.value === 'haystack' |
|
&& ( ele.source().isParent() || ele.target().isParent() ) |
|
) |
|
) |
|
){ |
|
prop = parsedProp = this.parse( parsedProp.name, 'bezier', propIsBypass ); |
|
} |
|
|
|
if( prop.delete ){ |
|
style[ prop.name ] = undefined; |
|
|
|
checkTriggers(); |
|
|
|
return true; |
|
} |
|
|
|
if( prop.deleteBypassed ){ |
|
if( !origProp ){ |
|
checkTriggers(); |
|
|
|
return true; |
|
|
|
} else if( origProp.bypass ){ |
|
origProp.bypassed = undefined; |
|
|
|
checkTriggers(); |
|
|
|
return true; |
|
|
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
|
|
if( prop.deleteBypass ){ |
|
if( !origProp ){ |
|
checkTriggers(); |
|
|
|
return true; |
|
|
|
} else if( origProp.bypass ){ |
|
|
|
style[ prop.name ] = origProp.bypassed; |
|
|
|
checkTriggers(); |
|
|
|
return true; |
|
|
|
} else { |
|
return false; |
|
} |
|
} |
|
|
|
let printMappingErr = function(){ |
|
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' ); |
|
}; |
|
|
|
|
|
switch( prop.mapped ){ |
|
case types.mapData: { |
|
|
|
let fields = prop.field.split( '.' ); |
|
let fieldVal = _p.data; |
|
|
|
for( let i = 0; i < fields.length && fieldVal; i++ ){ |
|
let field = fields[ i ]; |
|
fieldVal = fieldVal[ field ]; |
|
} |
|
|
|
if( fieldVal == null ){ |
|
printMappingErr(); |
|
return false; |
|
} |
|
|
|
let percent; |
|
if( !is.number( fieldVal ) ){ |
|
util.warn('Do not use continuous mappers without specifying numeric data (i.e. `' + prop.field + ': ' + fieldVal + '` for `' + ele.id() + '` is non-numeric)'); |
|
return false; |
|
} else { |
|
let fieldWidth = prop.fieldMax - prop.fieldMin; |
|
|
|
if( fieldWidth === 0 ){ |
|
percent = 0; |
|
} else { |
|
percent = (fieldVal - prop.fieldMin) / fieldWidth; |
|
} |
|
} |
|
|
|
|
|
if( percent < 0 ){ |
|
percent = 0; |
|
} else if( percent > 1 ){ |
|
percent = 1; |
|
} |
|
|
|
if( type.color ){ |
|
let r1 = prop.valueMin[0]; |
|
let r2 = prop.valueMax[0]; |
|
let g1 = prop.valueMin[1]; |
|
let g2 = prop.valueMax[1]; |
|
let b1 = prop.valueMin[2]; |
|
let b2 = prop.valueMax[2]; |
|
let a1 = prop.valueMin[3] == null ? 1 : prop.valueMin[3]; |
|
let a2 = prop.valueMax[3] == null ? 1 : prop.valueMax[3]; |
|
|
|
let clr = [ |
|
Math.round( r1 + (r2 - r1) * percent ), |
|
Math.round( g1 + (g2 - g1) * percent ), |
|
Math.round( b1 + (b2 - b1) * percent ), |
|
Math.round( a1 + (a2 - a1) * percent ) |
|
]; |
|
|
|
flatProp = { |
|
bypass: prop.bypass, |
|
name: prop.name, |
|
value: clr, |
|
strValue: 'rgb(' + clr[0] + ', ' + clr[1] + ', ' + clr[2] + ')' |
|
}; |
|
|
|
} else if( type.number ){ |
|
let calcValue = prop.valueMin + (prop.valueMax - prop.valueMin) * percent; |
|
flatProp = this.parse( prop.name, calcValue, prop.bypass, flatPropMapping ); |
|
|
|
} else { |
|
return false; |
|
} |
|
|
|
if( !flatProp ){ |
|
printMappingErr(); |
|
return false; |
|
} |
|
|
|
flatProp.mapping = prop; |
|
prop = flatProp; |
|
|
|
break; |
|
} |
|
|
|
|
|
case types.data: { |
|
|
|
let fields = prop.field.split( '.' ); |
|
let fieldVal = _p.data; |
|
|
|
for( let i = 0; i < fields.length && fieldVal; i++ ){ |
|
let field = fields[ i ]; |
|
fieldVal = fieldVal[ field ]; |
|
} |
|
|
|
if( fieldVal != null ){ |
|
flatProp = this.parse( prop.name, fieldVal, prop.bypass, flatPropMapping ); |
|
} |
|
|
|
if( !flatProp ){ |
|
printMappingErr(); |
|
return false; |
|
} |
|
|
|
flatProp.mapping = prop; |
|
prop = flatProp; |
|
|
|
break; |
|
} |
|
|
|
case types.fn: { |
|
let fn = prop.value; |
|
let fnRetVal = prop.fnValue != null ? prop.fnValue : fn( ele ); |
|
|
|
prop.prevFnValue = fnRetVal; |
|
|
|
if( fnRetVal == null ){ |
|
util.warn('Custom function mappers may not return null (i.e. `' + prop.name + '` for ele `' + ele.id() + '` is null)'); |
|
return false; |
|
} |
|
|
|
flatProp = this.parse( prop.name, fnRetVal, prop.bypass, flatPropMapping ); |
|
|
|
if( !flatProp ){ |
|
util.warn('Custom function mappers may not return invalid values for the property type (i.e. `' + prop.name + '` for ele `' + ele.id() + '` is invalid)'); |
|
return false; |
|
} |
|
|
|
flatProp.mapping = util.copy( prop ); |
|
prop = flatProp; |
|
|
|
break; |
|
} |
|
|
|
case undefined: |
|
break; |
|
|
|
default: |
|
return false; |
|
} |
|
|
|
|
|
if( propIsBypass ){ |
|
if( origPropIsBypass ){ |
|
prop.bypassed = origProp.bypassed; |
|
} else { |
|
prop.bypassed = origProp; |
|
} |
|
|
|
style[ prop.name ] = prop; |
|
|
|
} else { |
|
if( origPropIsBypass ){ |
|
origProp.bypassed = prop; |
|
} else { |
|
style[ prop.name ] = prop; |
|
} |
|
} |
|
|
|
checkTriggers(); |
|
|
|
return true; |
|
}; |
|
|
|
styfn.cleanElements = function( eles, keepBypasses ){ |
|
for( let i = 0; i < eles.length; i++ ){ |
|
let ele = eles[i]; |
|
|
|
this.clearStyleHints(ele); |
|
|
|
ele.dirtyCompoundBoundsCache(); |
|
ele.dirtyBoundingBoxCache(); |
|
|
|
if( !keepBypasses ){ |
|
ele._private.style = {}; |
|
} else { |
|
let style = ele._private.style; |
|
let propNames = Object.keys(style); |
|
|
|
for( let j = 0; j < propNames.length; j++ ){ |
|
let propName = propNames[j]; |
|
let eleProp = style[ propName ]; |
|
|
|
if( eleProp != null ){ |
|
if( eleProp.bypass ){ |
|
eleProp.bypassed = null; |
|
} else { |
|
style[ propName ] = null; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
}; |
|
|
|
|
|
styfn.update = function(){ |
|
let cy = this._private.cy; |
|
let eles = cy.mutableElements(); |
|
|
|
eles.updateStyle(); |
|
}; |
|
|
|
|
|
styfn.updateTransitions = function( ele, diffProps ){ |
|
let self = this; |
|
let _p = ele._private; |
|
let props = ele.pstyle( 'transition-property' ).value; |
|
let duration = ele.pstyle( 'transition-duration' ).pfValue; |
|
let delay = ele.pstyle( 'transition-delay' ).pfValue; |
|
|
|
if( props.length > 0 && duration > 0 ){ |
|
|
|
let style = {}; |
|
|
|
|
|
let anyPrev = false; |
|
for( let i = 0; i < props.length; i++ ){ |
|
let prop = props[ i ]; |
|
let styProp = ele.pstyle( prop ); |
|
let diffProp = diffProps[ prop ]; |
|
|
|
if( !diffProp ){ continue; } |
|
|
|
let prevProp = diffProp.prev; |
|
let fromProp = prevProp; |
|
let toProp = diffProp.next != null ? diffProp.next : styProp; |
|
let diff = false; |
|
let initVal; |
|
let initDt = 0.000001; |
|
|
|
if( !fromProp ){ continue; } |
|
|
|
|
|
if( is.number( fromProp.pfValue ) && is.number( toProp.pfValue ) ){ |
|
diff = toProp.pfValue - fromProp.pfValue; |
|
initVal = fromProp.pfValue + initDt * diff; |
|
|
|
|
|
} else if( is.number( fromProp.value ) && is.number( toProp.value ) ){ |
|
diff = toProp.value - fromProp.value; |
|
initVal = fromProp.value + initDt * diff; |
|
|
|
|
|
} else if( is.array( fromProp.value ) && is.array( toProp.value ) ){ |
|
diff = fromProp.value[0] !== toProp.value[0] |
|
|| fromProp.value[1] !== toProp.value[1] |
|
|| fromProp.value[2] !== toProp.value[2] |
|
; |
|
|
|
initVal = fromProp.strValue; |
|
} |
|
|
|
|
|
if( diff ){ |
|
style[ prop ] = toProp.strValue; |
|
this.applyBypass( ele, prop, initVal ); |
|
anyPrev = true; |
|
} |
|
|
|
} |
|
|
|
|
|
if( !anyPrev ){ return; } |
|
|
|
_p.transitioning = true; |
|
|
|
( new Promise(function( resolve ){ |
|
if( delay > 0 ){ |
|
ele.delayAnimation( delay ).play().promise().then( resolve ); |
|
} else { |
|
resolve(); |
|
} |
|
}) ).then(function(){ |
|
return ele.animation( { |
|
style: style, |
|
duration: duration, |
|
easing: ele.pstyle( 'transition-timing-function' ).value, |
|
queue: false |
|
} ).play().promise(); |
|
}).then(function(){ |
|
|
|
self.removeBypasses( ele, props ); |
|
ele.emitAndNotify('style'); |
|
|
|
|
|
_p.transitioning = false; |
|
}); |
|
|
|
} else if( _p.transitioning ){ |
|
this.removeBypasses( ele, props ); |
|
ele.emitAndNotify('style'); |
|
|
|
_p.transitioning = false; |
|
} |
|
}; |
|
|
|
styfn.checkTrigger = function( ele, name, fromValue, toValue, getTrigger, onTrigger ){ |
|
let prop = this.properties[ name ]; |
|
let triggerCheck = getTrigger( prop ); |
|
|
|
if( triggerCheck != null && triggerCheck( fromValue, toValue ) ){ |
|
onTrigger(prop); |
|
} |
|
}; |
|
|
|
styfn.checkZOrderTrigger = function( ele, name, fromValue, toValue ){ |
|
this.checkTrigger( ele, name, fromValue, toValue, prop => prop.triggersZOrder, () => { |
|
this._private.cy.notify('zorder', ele); |
|
}); |
|
}; |
|
|
|
styfn.checkBoundsTrigger = function( ele, name, fromValue, toValue ){ |
|
this.checkTrigger( ele, name, fromValue, toValue, prop => prop.triggersBounds, prop => { |
|
ele.dirtyCompoundBoundsCache(); |
|
ele.dirtyBoundingBoxCache(); |
|
|
|
|
|
|
|
if( |
|
prop.triggersBoundsOfParallelBeziers |
|
&& ( name === 'curve-style' && (fromValue === 'bezier' || toValue === 'bezier') ) |
|
){ |
|
ele.parallelEdges().forEach(pllEdge => { |
|
if( pllEdge.isBundledBezier() ){ |
|
pllEdge.dirtyBoundingBoxCache(); |
|
} |
|
}); |
|
} |
|
|
|
if( |
|
prop.triggersBoundsOfConnectedEdges |
|
&& ( name === 'display' && (fromValue === 'none' || toValue === 'none') ) |
|
){ |
|
ele.connectedEdges().forEach(edge => { |
|
edge.dirtyBoundingBoxCache(); |
|
}); |
|
} |
|
|
|
}); |
|
}; |
|
|
|
styfn.checkTriggers = function( ele, name, fromValue, toValue ){ |
|
ele.dirtyStyleCache(); |
|
|
|
this.checkZOrderTrigger( ele, name, fromValue, toValue ); |
|
this.checkBoundsTrigger( ele, name, fromValue, toValue ); |
|
}; |
|
|
|
export default styfn; |
|
|