|
@@ -15,7 +15,9 @@ import { StateObjectCell, State } from 'mol-state';
|
|
|
|
|
|
const StructureAnimationParams = {
|
|
|
rotate: PD.Boolean(false),
|
|
|
- explode: PD.Boolean(false)
|
|
|
+ rotateValue: PD.Numeric(0, { min: 0, max: 360, step: 0.1 }),
|
|
|
+ explode: PD.Boolean(false),
|
|
|
+ explodeValue: PD.Numeric(0, { min: 0, max: 100, step: 0.1 }),
|
|
|
}
|
|
|
type StructureAnimationProps = PD.Values<typeof StructureAnimationParams>
|
|
|
|
|
@@ -38,7 +40,11 @@ function getRootStructure(root: StateObjectCell, state: State) {
|
|
|
return parent && parent.obj ? parent.obj as PluginStateObject.Molecule.Structure : undefined
|
|
|
}
|
|
|
|
|
|
-// TODO this is just for testing purposes
|
|
|
+/**
|
|
|
+ * TODO
|
|
|
+ * - animation class is just for testing purposes, needs better API
|
|
|
+ * - allow per-unit transform `unitTransform: { [unitId: number]: Mat4 }`
|
|
|
+ */
|
|
|
export const StructureAnimation = PluginBehavior.create<StructureAnimationProps>({
|
|
|
name: 'structure-animation',
|
|
|
display: { name: 'Structure Animation', group: 'Animation' },
|
|
@@ -58,62 +64,68 @@ export const StructureAnimation = PluginBehavior.create<StructureAnimationProps>
|
|
|
this.update(params)
|
|
|
}
|
|
|
|
|
|
- rotate(play: boolean) {
|
|
|
+ rotate(rad: number) {
|
|
|
+ const state = this.ctx.state.dataState
|
|
|
+ const reprs = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Representation3D));
|
|
|
+ Mat4.rotate(this.rotMat, this.tmpMat, rad, this.rotVec)
|
|
|
+ for (const r of reprs) {
|
|
|
+ if (!SO.isRepresentation3D(r.obj)) return
|
|
|
+ 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)
|
|
|
+
|
|
|
+ Vec3.copy(this.transVec, structure.data.boundary.sphere.center)
|
|
|
+ Mat4.fromTranslation(this.transMat, this.transVec)
|
|
|
+ Mat4.mul(this.animMat, this.transMat, this.animMat)
|
|
|
+
|
|
|
+ r.obj.data.setState({ transform: this.animMat })
|
|
|
+ this.ctx.canvas3d.add(r.obj.data)
|
|
|
+ this.ctx.canvas3d.requestDraw(true)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ animateRotate(play: boolean) {
|
|
|
if (play) {
|
|
|
- const state = this.ctx.state.dataState
|
|
|
- const reprs = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Representation3D));
|
|
|
- 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 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)
|
|
|
-
|
|
|
- Vec3.copy(this.transVec, structure.data.boundary.sphere.center)
|
|
|
- Mat4.fromTranslation(this.transMat, this.transVec)
|
|
|
- Mat4.mul(this.animMat, this.transMat, this.animMat)
|
|
|
-
|
|
|
- r.obj.data.setState({ transform: this.animMat })
|
|
|
- this.ctx.canvas3d.add(r.obj.data)
|
|
|
- this.ctx.canvas3d.requestDraw(true)
|
|
|
- }
|
|
|
- this.rotateAnimHandle = requestAnimationFrame(rotate)
|
|
|
+ const animateRotate = (t: number) => {
|
|
|
+ this.rotate(degToRad((t / 10) % 360))
|
|
|
+ this.rotateAnimHandle = requestAnimationFrame(animateRotate)
|
|
|
}
|
|
|
- this.rotateAnimHandle = requestAnimationFrame(rotate)
|
|
|
+ this.rotateAnimHandle = requestAnimationFrame(animateRotate)
|
|
|
} else {
|
|
|
cancelAnimationFrame(this.rotateAnimHandle)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- explode(play: boolean) {
|
|
|
+ explode(d: number) {
|
|
|
+ const state = this.ctx.state.dataState
|
|
|
+ const reprs = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Representation3D));
|
|
|
+ for (const r of reprs) {
|
|
|
+ if (!SO.isRepresentation3D(r.obj)) return
|
|
|
+ const structure = getStructure(r, state)
|
|
|
+ if (!structure) continue
|
|
|
+ const rootStructure = getRootStructure(r, state)
|
|
|
+ if (!rootStructure) continue
|
|
|
+
|
|
|
+ Vec3.sub(this.transVec, structure.data.boundary.sphere.center, rootStructure.data.boundary.sphere.center)
|
|
|
+ Vec3.setMagnitude(this.transVec, this.transVec, d)
|
|
|
+ Mat4.fromTranslation(this.animMat, this.transVec)
|
|
|
+
|
|
|
+ r.obj.data.setState({ transform: this.animMat })
|
|
|
+ this.ctx.canvas3d.add(r.obj.data)
|
|
|
+ this.ctx.canvas3d.requestDraw(true)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ animateExplode(play: boolean) {
|
|
|
if (play) {
|
|
|
- const state = this.ctx.state.dataState
|
|
|
- const reprs = state.select(q => q.rootsOfType(PluginStateObject.Molecule.Representation3D));
|
|
|
- const explode = (t: number) => {
|
|
|
- const d = (Math.sin(t * 0.001) + 1) * 5
|
|
|
- for (const r of reprs) {
|
|
|
- if (!SO.isRepresentation3D(r.obj)) return
|
|
|
- const structure = getStructure(r, state)
|
|
|
- if (!structure) continue
|
|
|
- const rootStructure = getRootStructure(r, state)
|
|
|
- if (!rootStructure) continue
|
|
|
-
|
|
|
- Vec3.sub(this.transVec, structure.data.boundary.sphere.center, rootStructure.data.boundary.sphere.center)
|
|
|
- Vec3.setMagnitude(this.transVec, this.transVec, d)
|
|
|
- Mat4.fromTranslation(this.animMat, this.transVec)
|
|
|
-
|
|
|
- r.obj.data.setState({ transform: this.animMat })
|
|
|
- this.ctx.canvas3d.add(r.obj.data)
|
|
|
- this.ctx.canvas3d.requestDraw(true)
|
|
|
- }
|
|
|
- this.explodeAnimHandle = requestAnimationFrame(explode)
|
|
|
+ const animateExplode = (t: number) => {
|
|
|
+ this.explode((Math.sin(t * 0.001) + 1) * 5)
|
|
|
+ this.explodeAnimHandle = requestAnimationFrame(animateExplode)
|
|
|
}
|
|
|
- this.explodeAnimHandle = requestAnimationFrame(explode)
|
|
|
+ this.explodeAnimHandle = requestAnimationFrame(animateExplode)
|
|
|
} else {
|
|
|
cancelAnimationFrame(this.explodeAnimHandle)
|
|
|
}
|
|
@@ -125,11 +137,19 @@ export const StructureAnimation = PluginBehavior.create<StructureAnimationProps>
|
|
|
let updated = PD.areEqual(StructureAnimationParams, this.params, p)
|
|
|
if (this.params.rotate !== p.rotate) {
|
|
|
this.params.rotate = p.rotate
|
|
|
- this.rotate(this.params.rotate)
|
|
|
+ this.animateRotate(this.params.rotate)
|
|
|
}
|
|
|
if (this.params.explode !== p.explode) {
|
|
|
this.params.explode = p.explode
|
|
|
- this.explode(this.params.explode)
|
|
|
+ this.animateExplode(this.params.explode)
|
|
|
+ }
|
|
|
+ if (this.params.rotateValue !== p.rotateValue) {
|
|
|
+ this.params.rotateValue = p.rotateValue
|
|
|
+ this.rotate(degToRad(this.params.rotateValue))
|
|
|
+ }
|
|
|
+ if (this.params.explodeValue !== p.explodeValue) {
|
|
|
+ this.params.explodeValue = p.explodeValue
|
|
|
+ this.explode(this.params.explodeValue)
|
|
|
}
|
|
|
return updated;
|
|
|
}
|