cytoscape
Version:
Graph theory (a.k.a. network) library for analysis and visualisation
157 lines (118 loc) • 3.97 kB
JavaScript
let BRp = {};
BRp.registerCalculationListeners = function(){
let cy = this.cy;
let elesToUpdate = cy.collection();
let r = this;
let enqueue = function( eles, dirtyStyleCaches = true ){
elesToUpdate.merge( eles );
if( dirtyStyleCaches ){
for( let i = 0; i < eles.length; i++ ){
let ele = eles[i];
let _p = ele._private;
let rstyle = _p.rstyle;
rstyle.clean = false;
rstyle.cleanConnected = false;
}
}
};
r.binder( cy )
.on('bounds.* dirty.*', function onDirtyBounds( e ){
let ele = e.target;
enqueue( ele );
})
.on('style.* background.*', function onDirtyStyle( e ){
let ele = e.target;
enqueue( ele, false );
})
;
let updateEleCalcs = function( willDraw ){
if( willDraw ){
let fns = r.onUpdateEleCalcsFns;
// because we need to have up-to-date style (e.g. stylesheet mappers)
// before calculating rendered style (and pstyle might not be called yet)
elesToUpdate.cleanStyle();
for( let i = 0; i < elesToUpdate.length; i++ ){
let ele = elesToUpdate[i];
let rstyle = ele._private.rstyle;
if( ele.isNode() && !rstyle.cleanConnected ){
enqueue( ele.connectedEdges() );
rstyle.cleanConnected = true;
}
}
if( fns ){ for( let i = 0; i < fns.length; i++ ){
let fn = fns[i];
fn( willDraw, elesToUpdate );
} }
r.recalculateRenderedStyle( elesToUpdate );
elesToUpdate = cy.collection();
}
};
r.flushRenderedStyleQueue = function(){
updateEleCalcs(true);
};
r.beforeRender( updateEleCalcs, r.beforeRenderPriorities.eleCalcs );
};
BRp.onUpdateEleCalcs = function( fn ){
let fns = this.onUpdateEleCalcsFns = this.onUpdateEleCalcsFns || [];
fns.push( fn );
};
BRp.recalculateRenderedStyle = function( eles, useCache ){
let isCleanConnected = ele => ele._private.rstyle.cleanConnected;
let edges = [];
let nodes = [];
// the renderer can't be used for calcs when destroyed, e.g. ele.boundingBox()
if( this.destroyed ){ return; }
// use cache by default for perf
if( useCache === undefined ){ useCache = true; }
for( let i = 0; i < eles.length; i++ ){
let ele = eles[ i ];
let _p = ele._private;
let rstyle = _p.rstyle;
// an edge may be implicitly dirty b/c of one of its connected nodes
// (and a request for recalc may come in between frames)
if( ele.isEdge() && (!isCleanConnected(ele.source()) || !isCleanConnected(ele.target())) ){
rstyle.clean = false;
}
// only update if dirty and in graph
if( (useCache && rstyle.clean) || ele.removed() ){ continue; }
// only update if not display: none
if( ele.pstyle('display').value === 'none' ){ continue; }
if( _p.group === 'nodes' ){
nodes.push( ele );
} else { // edges
edges.push( ele );
}
rstyle.clean = true;
}
// update node data from projections
for( let i = 0; i < nodes.length; i++ ){
let ele = nodes[i];
let _p = ele._private;
let rstyle = _p.rstyle;
let pos = ele.position();
this.recalculateNodeLabelProjection( ele );
rstyle.nodeX = pos.x;
rstyle.nodeY = pos.y;
rstyle.nodeW = ele.pstyle( 'width' ).pfValue;
rstyle.nodeH = ele.pstyle( 'height' ).pfValue;
}
this.recalculateEdgeProjections( edges );
// update edge data from projections
for( let i = 0; i < edges.length; i++ ){
let ele = edges[ i ];
let _p = ele._private;
let rstyle = _p.rstyle;
let rs = _p.rscratch;
// update rstyle positions
rstyle.srcX = rs.arrowStartX;
rstyle.srcY = rs.arrowStartY;
rstyle.tgtX = rs.arrowEndX;
rstyle.tgtY = rs.arrowEndY;
rstyle.midX = rs.midX;
rstyle.midY = rs.midY;
rstyle.labelAngle = rs.labelAngle;
rstyle.sourceLabelAngle = rs.sourceLabelAngle;
rstyle.targetLabelAngle = rs.targetLabelAngle;
}
};
export default BRp;