diff --git a/package-lock.json b/package-lock.json index 4d591a55215d505271ecf6a6c0714d886142aa28..8dd941ab943fd2727d03938f79af7d152d4c532c 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/src/mol-plugin/behavior/dynamic/animation.ts b/src/mol-plugin/behavior/dynamic/animation.ts index b3696db3fa84d878a261e282cb5202d454c4bd3a..e79562ce6dbd3399cdd0fe101696407b58b12b8a 100644 --- a/src/mol-plugin/behavior/dynamic/animation.ts +++ b/src/mol-plugin/behavior/dynamic/animation.ts @@ -11,74 +11,93 @@ import { degToRad } from 'mol-math/misc'; import { Mat4, Vec3 } from 'mol-math/linear-algebra'; import { PluginStateObject as SO, PluginStateObject } from '../../state/objects'; import { StateSelection } from 'mol-state/state/selection'; +import { StateObjectCell, State } from 'mol-state'; + +const StructureAnimationParams = { + rotate: PD.Boolean(false) +} +type StructureAnimationProps = PD.Values<typeof StructureAnimationParams> + +function getRootStructure(root: StateObjectCell, state: State) { + let parent: StateObjectCell | undefined + while (true) { + const _parent = StateSelection.findAncestorOfType(state.tree, state.cells, root.transform.ref, [PluginStateObject.Molecule.Structure]) + if (_parent) { + parent = _parent + root = _parent + } else { + break + } + } + if (!parent || !parent.obj) return + return parent.obj as PluginStateObject.Molecule.Structure +} // TODO this is just for testing purposes -export const Animation = PluginBehavior.create<{ play: boolean }>({ - name: 'animation', - display: { name: 'Animation', group: 'Animation' }, - ctor: class extends PluginBehavior.Handler<{ play: boolean }> { +export const StructureAnimation = PluginBehavior.create<StructureAnimationProps>({ + name: 'structure-animation', + display: { name: 'Structure Animation', group: 'Animation' }, + ctor: class extends PluginBehavior.Handler<StructureAnimationProps> { private tmpMat = Mat4.identity() private rotMat = Mat4.identity() private transMat = Mat4.identity() - private animMat = Mat4.identity() + private rotAnimMat = Mat4.identity() private transVec = Vec3.zero() private rotVec = Vec3.create(0, 1, 0) - private animHandle = -1 - constructor(protected ctx: PluginContext, protected params: { play: boolean }) { + private rotateAnimHandle = -1 + + constructor(protected ctx: PluginContext, protected params: StructureAnimationProps) { super(ctx, params) this.update(params) } - animate(play: boolean) { + rotate(play: boolean) { if (play) { const state = this.ctx.state.dataState const reprs = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Representation3D)); - const anim = (t: number) => { + const rotate = (t: number) => { const rad = degToRad((t / 10) % 360) Mat4.rotate(this.rotMat, this.tmpMat, rad, this.rotVec) for (const r of reprs) { if (!SO.isRepresentation3D(r.obj)) return - const parent = StateSelection.findAncestorOfType(state.tree, state.cells, r.transform.ref, [PluginStateObject.Molecule.Structure]) - if (!parent || !parent.obj) continue - const structure = parent.obj as PluginStateObject.Molecule.Structure + const structure = getRootStructure(r, state) + if (!structure) continue Vec3.negate(this.transVec, Vec3.copy(this.transVec, structure.data.boundary.sphere.center)) Mat4.fromTranslation(this.transMat, this.transVec) - Mat4.mul(this.animMat, this.rotMat, this.transMat) + Mat4.mul(this.rotAnimMat, this.rotMat, this.transMat) Vec3.copy(this.transVec, structure.data.boundary.sphere.center) Mat4.fromTranslation(this.transMat, this.transVec) - Mat4.mul(this.animMat, this.transMat, this.animMat) + Mat4.mul(this.rotAnimMat, this.transMat, this.rotAnimMat) - r.obj.data.setState({ transform: this.animMat }) + r.obj.data.setState({ transform: this.rotAnimMat }) this.ctx.canvas3d.add(r.obj.data) this.ctx.canvas3d.requestDraw(true) } - this.animHandle = requestAnimationFrame(anim) + this.rotateAnimHandle = requestAnimationFrame(rotate) } - this.animHandle = requestAnimationFrame(anim) + this.rotateAnimHandle = requestAnimationFrame(rotate) } else { - cancelAnimationFrame(this.animHandle) + cancelAnimationFrame(this.rotateAnimHandle) } } register(): void { } - update(p: { play: boolean }) { - let updated = this.params.play !== p.play - this.params.play = p.play + update(p: StructureAnimationProps) { + let updated = this.params.rotate !== p.rotate + this.params.rotate = p.rotate if (updated) { - this.animate(this.params.play) + this.rotate(this.params.rotate) } return updated; } unregister() { - cancelAnimationFrame(this.animHandle) + cancelAnimationFrame(this.rotateAnimHandle) } }, - params: () => ({ - play: PD.Boolean(false) - }) + params: () => StructureAnimationParams }); \ No newline at end of file diff --git a/src/mol-plugin/index.ts b/src/mol-plugin/index.ts index cf3507b2ab977f373ee533a3e1841312ea427d37..a22b53ddb3b17f0e3ffbb1d2ecb591f09c0d74c5 100644 --- a/src/mol-plugin/index.ts +++ b/src/mol-plugin/index.ts @@ -37,7 +37,7 @@ const DefaultSpec: PluginSpec = { PluginSpec.Behavior(PluginBehaviors.Representation.SelectLoci), PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider), PluginSpec.Behavior(PluginBehaviors.Camera.FocusLociOnSelect, { minRadius: 20, extraRadius: 4 }), - PluginSpec.Behavior(PluginBehaviors.Animation.Animation, { play: false }), + PluginSpec.Behavior(PluginBehaviors.Animation.StructureAnimation, { rotate: false }), PluginSpec.Behavior(PluginBehaviors.CustomProps.PDBeStructureQualityReport, { autoAttach: true }), PluginSpec.Behavior(PluginBehaviors.CustomProps.RCSBAssemblySymmetry, { autoAttach: true }), ]