From 2a23f67318c00c733ba88d0f202ccc45b93866c5 Mon Sep 17 00:00:00 2001 From: Valentin Perrelle <valentin.perrelle@cea.fr> Date: Tue, 21 Jul 2020 20:05:30 +0200 Subject: [PATCH] [dive] improves layout animations --- ivette/src/frama-c/dive/Dive.tsx | 43 +++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/ivette/src/frama-c/dive/Dive.tsx b/ivette/src/frama-c/dive/Dive.tsx index b828c718631..f194a2c51ea 100644 --- a/ivette/src/frama-c/dive/Dive.tsx +++ b/ivette/src/frama-c/dive/Dive.tsx @@ -233,7 +233,7 @@ class Dive { /* eslint-disable no-restricted-syntax */ receiveGraph(data: any): Cytoscape.CollectionReturnValue { - let newEles = this.cy.collection(); + let newNodes = this.cy.collection(); for (const node of data.nodes) { @@ -255,7 +255,7 @@ class Dive { ele = this.cy.add({ group: 'nodes', data: { ...node, parent } }); this.addTips(ele); - newEles = ele.union(newEles); + newNodes = ele.union(newNodes); } // Add a node for the user to ask for more dependencies @@ -267,26 +267,24 @@ class Dive { data: { id: idmore, parent: ele.data('parent') }, classes: 'more', }); - newEles = elemore.union(newEles); - const depmore = this.cy.add({ + newNodes = elemore.union(newNodes); + this.cy.add({ group: 'edges', data: { source: idmore, target: node.id }, }); - newEles = this.cy.add(depmore).union(newEles); } } for (const dep of data.deps) { - const ele = this.cy.add({ + this.cy.add({ data: { ...dep, source: dep.src, target: dep.dst }, group: 'edges', classes: dep.kind, }); - newEles = this.cy.add(ele).union(newEles); } - return newEles; + return newNodes; } receiveData(data: any): void { @@ -295,14 +293,14 @@ class Dive { for (const id of data.sub) this.remove(this.cy.$id(id)); - const newEles = this.receiveGraph(data.add); + const newNodes = this.receiveGraph(data.add); this.cy.endBatch(); this.selectNode(this.cy.$id(data.root)); - if (newEles) - this.recomputeLayout(); + if (newNodes) + this.recomputeLayout(newNodes); } get layout(): string { @@ -318,16 +316,31 @@ class Dive { name: layout, fit: true, animate: true, - randomize: true, /* Not all layouts supports that */ + randomize: false, /* Keep previous positions if layout supports it */ ...extendedOptions, }; this.recomputeLayout(); } - recomputeLayout(): void { - if (this.layoutOptions && this.cy.container()) - this.cy.layout(this.layoutOptions).run(); + recomputeLayout(newNodes: Cytoscape.Collection = this.cy.collection()): void { + if (this.layoutOptions && this.cy.container()) { + /* Animate opacity from 0 to 100 for new elements */ + const newEles = newNodes.union(newNodes.neighborhood('edge')); + newEles.style('opacity', 0); + + this.cy.layout({ + animationEasing: 'ease-in-out-quad', + /* Do not move new nodes */ + animateFilter: (node: Cytoscape.Singular) => !newNodes.contains(node), + /* But make them appear slowly */ + stop: () => newEles.animate({ + style: { opacity: 1.0 }, + duration: 500, + }), + ...this.layoutOptions, + } as unknown as Cytoscape.LayoutOptions).run(); + } } async exec<In, Out>( -- GitLab