Ver Fonte

mol-plugin: added animation setup and teardown

David Sehnal há 6 anos atrás
pai
commit
bde78f4f1f

+ 63 - 1
src/mol-plugin/state/animation/built-in.ts

@@ -95,9 +95,40 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({
         durationInMs: PD.Numeric(3000, { min: 100, max: 10000, step: 100})
     }),
     initialState: () => ({ t: 0 }),
+    async setup(_, plugin) {
+        const state = plugin.state.dataState;
+        const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D));
+
+        const update = state.build();
+        let changed = false;
+        for (const r of reprs) {
+            const unwinds = state.select(StateSelection.Generators.byValue(r)
+                .children()
+                .filter(c => c.transform.transformer === StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D));
+            if (unwinds.length > 0) continue;
+
+            changed = true;
+            update.to(r.transform.ref)
+                .apply(StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D, { t: 0 }, { props: { tag: 'animate-assembly-unwind' } });
+        }
+
+        if (!changed) return;
+
+        return plugin.runTask(state.updateTree(update));
+    },
+    async teardown(_, plugin) {
+        const state = plugin.state.dataState;
+        const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3DState)
+            .filter(c => c.transform.props.tag === 'animate-assembly-unwind'));
+        if (reprs.length === 0) return;
+
+        const update = state.build();
+        for (const r of reprs) update.delete(r.transform.ref);
+        return plugin.runTask(state.updateTree(update));
+    },
     async apply(animState, t, ctx) {
         const state = ctx.plugin.state.dataState;
-        const anims = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Structure.Representation3DState)
+        const anims = state.selectQ(q => q.ofType(PluginStateObject.Molecule.Structure.Representation3DState)
             .filter(c => c.transform.transformer === StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D));
 
         if (anims.length === 0) {
@@ -127,6 +158,37 @@ export const AnimateUnitsExplode = PluginStateAnimation.create({
         durationInMs: PD.Numeric(3000, { min: 100, max: 10000, step: 100})
     }),
     initialState: () => ({ t: 0 }),
+    async setup(_, plugin) {
+        const state = plugin.state.dataState;
+        const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3D));
+
+        const update = state.build();
+        let changed = false;
+        for (const r of reprs) {
+            const unwinds = state.select(StateSelection.Generators.byValue(r)
+                .children()
+                .filter(c => c.transform.transformer === StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D));
+            if (unwinds.length > 0) continue;
+
+            changed = true;
+            update.to(r.transform.ref)
+                .apply(StateTransforms.Representation.ExplodeStructureRepresentation3D, { t: 0 }, { props: { tag: 'animate-units-explode' } });
+        }
+
+        if (!changed) return;
+
+        return plugin.runTask(state.updateTree(update));
+    },
+    async teardown(_, plugin) {
+        const state = plugin.state.dataState;
+        const reprs = state.select(StateSelection.Generators.ofType(PluginStateObject.Molecule.Structure.Representation3DState)
+            .filter(c => c.transform.props.tag === 'animate-units-explode'));
+        if (reprs.length === 0) return;
+
+        const update = state.build();
+        for (const r of reprs) update.delete(r.transform.ref);
+        return plugin.runTask(state.updateTree(update));
+    },
     async apply(animState, t, ctx) {
         const state = ctx.plugin.state.dataState;
         const anims = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Structure.Representation3DState)

+ 17 - 6
src/mol-plugin/state/animation/manager.ts

@@ -88,30 +88,41 @@ class PluginAnimationManager extends PluginComponent<PluginAnimationManager.Stat
         this.start();
     }
 
-    start() {
+    async start() {
         this.updateState({ animationState: 'playing' });
         if (!this.context.behaviors.state.isAnimating.value) {
             this.context.behaviors.state.isAnimating.next(true);
         }
         this.triggerUpdate();
 
+        const anim = this._current.anim;
+        if (anim.setup) {
+            await anim.setup(this._current.paramValues, this.context);
+        }
+
         this._current.lastTime = 0;
         this._current.startedTime = -1;
-        this._current.state = this._current.anim.initialState(this._current.paramValues, this.context);
+        this._current.state = this._current.anim.initialState(anim, this.context);
 
         requestAnimationFrame(this.animate);
     }
 
-    stop() {
+    async stop() {
         if (typeof this._frame !== 'undefined') cancelAnimationFrame(this._frame);
-        if (this.context.behaviors.state.isAnimating.value) {
-            this.context.behaviors.state.isAnimating.next(false);
-        }
 
         if (this.state.animationState !== 'stopped') {
+            const anim = this._current.anim;
+            if (anim.teardown) {
+                await anim.teardown(this._current.paramValues, this.context);
+            }
+
             this.updateState({ animationState: 'stopped' });
             this.triggerUpdate();
         }
+
+        if (this.context.behaviors.state.isAnimating.value) {
+            this.context.behaviors.state.isAnimating.next(false);
+        }
     }
 
     get isAnimating() {

+ 4 - 0
src/mol-plugin/state/animation/model.ts

@@ -18,6 +18,10 @@ interface PluginStateAnimation<P = any, S = any> {
     params: (ctx: PluginContext) => PD.For<P>,
     initialState(params: P, ctx: PluginContext): S,
 
+    // TODO: support state in setup/teardown?
+    setup?(params: P, ctx: PluginContext): void | Promise<void>,
+    teardown?(params: P, ctx: PluginContext): void | Promise<void>,
+
     /**
      * Apply the current frame and modify the state.
      * @param t Current absolute time since the animation started.