Skip to content
Snippets Groups Projects
Commit bde78f4f authored by David Sehnal's avatar David Sehnal
Browse files

mol-plugin: added animation setup and teardown

parent 7ef1d906
No related branches found
No related tags found
No related merge requests found
...@@ -95,9 +95,40 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({ ...@@ -95,9 +95,40 @@ export const AnimateAssemblyUnwind = PluginStateAnimation.create({
durationInMs: PD.Numeric(3000, { min: 100, max: 10000, step: 100}) durationInMs: PD.Numeric(3000, { min: 100, max: 10000, step: 100})
}), }),
initialState: () => ({ t: 0 }), 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) { async apply(animState, t, ctx) {
const state = ctx.plugin.state.dataState; 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)); .filter(c => c.transform.transformer === StateTransforms.Representation.UnwindStructureAssemblyRepresentation3D));
if (anims.length === 0) { if (anims.length === 0) {
...@@ -127,6 +158,37 @@ export const AnimateUnitsExplode = PluginStateAnimation.create({ ...@@ -127,6 +158,37 @@ export const AnimateUnitsExplode = PluginStateAnimation.create({
durationInMs: PD.Numeric(3000, { min: 100, max: 10000, step: 100}) durationInMs: PD.Numeric(3000, { min: 100, max: 10000, step: 100})
}), }),
initialState: () => ({ t: 0 }), 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) { async apply(animState, t, ctx) {
const state = ctx.plugin.state.dataState; const state = ctx.plugin.state.dataState;
const anims = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Structure.Representation3DState) const anims = state.selectQ(q => q.rootsOfType(PluginStateObject.Molecule.Structure.Representation3DState)
......
...@@ -88,30 +88,41 @@ class PluginAnimationManager extends PluginComponent<PluginAnimationManager.Stat ...@@ -88,30 +88,41 @@ class PluginAnimationManager extends PluginComponent<PluginAnimationManager.Stat
this.start(); this.start();
} }
start() { async start() {
this.updateState({ animationState: 'playing' }); this.updateState({ animationState: 'playing' });
if (!this.context.behaviors.state.isAnimating.value) { if (!this.context.behaviors.state.isAnimating.value) {
this.context.behaviors.state.isAnimating.next(true); this.context.behaviors.state.isAnimating.next(true);
} }
this.triggerUpdate(); this.triggerUpdate();
const anim = this._current.anim;
if (anim.setup) {
await anim.setup(this._current.paramValues, this.context);
}
this._current.lastTime = 0; this._current.lastTime = 0;
this._current.startedTime = -1; 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); requestAnimationFrame(this.animate);
} }
stop() { async stop() {
if (typeof this._frame !== 'undefined') cancelAnimationFrame(this._frame); 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') { 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.updateState({ animationState: 'stopped' });
this.triggerUpdate(); this.triggerUpdate();
} }
if (this.context.behaviors.state.isAnimating.value) {
this.context.behaviors.state.isAnimating.next(false);
}
} }
get isAnimating() { get isAnimating() {
......
...@@ -18,6 +18,10 @@ interface PluginStateAnimation<P = any, S = any> { ...@@ -18,6 +18,10 @@ interface PluginStateAnimation<P = any, S = any> {
params: (ctx: PluginContext) => PD.For<P>, params: (ctx: PluginContext) => PD.For<P>,
initialState(params: P, ctx: PluginContext): S, 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. * Apply the current frame and modify the state.
* @param t Current absolute time since the animation started. * @param t Current absolute time since the animation started.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment