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

wip reworking snapshots

parent 017c0ba8
No related branches found
No related tags found
No related merge requests found
......@@ -14,6 +14,8 @@ import { RxEventHelper } from 'mol-util/rx-event-helper';
import { Canvas3DProps } from 'mol-canvas3d/canvas3d';
import { PluginCommands } from './command';
import { PluginAnimationManager } from './state/animation/manager';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { UUID } from 'mol-util';
export { PluginState }
class PluginState {
......@@ -40,31 +42,42 @@ class PluginState {
}
}
getSnapshot(): PluginState.Snapshot {
getSnapshot(params?: Partial<PluginState.GetSnapshotParams>): PluginState.Snapshot {
const p = { ...PluginState.DefaultGetSnapshotParams, ...params };
return {
data: this.dataState.getSnapshot(),
behaviour: this.behaviorState.getSnapshot(),
animation: this.animation.getSnapshot(),
cameraSnapshots: this.cameraSnapshots.getStateSnapshot(),
canvas3d: {
camera: this.plugin.canvas3d.camera.getSnapshot(),
viewport: this.plugin.canvas3d.props
}
id: UUID.create22(),
data: p.data ? this.dataState.getSnapshot() : void 0,
behaviour: p.behavior ? this.behaviorState.getSnapshot() : void 0,
animation: p.animation ? this.animation.getSnapshot() : void 0,
camera: p.camera ? {
current: this.plugin.canvas3d.camera.getSnapshot(),
transitionStyle: p.cameraTranstionStyle ? p.cameraTranstionStyle : 'instant'
} : void 0,
cameraSnapshots: p.cameraSnapshots ? this.cameraSnapshots.getStateSnapshot() : void 0,
canvas3d: p.canvas3d ? {
props: this.plugin.canvas3d.props
} : void 0
};
}
async setSnapshot(snapshot: PluginState.Snapshot) {
this.animation.stop();
if (snapshot.behaviour) await this.plugin.runTask(this.behaviorState.setSnapshot(snapshot.behaviour));
if (snapshot.data) await this.plugin.runTask(this.dataState.setSnapshot(snapshot.data));
if (snapshot.cameraSnapshots) this.cameraSnapshots.setStateSnapshot(snapshot.cameraSnapshots);
if (snapshot.canvas3d) {
if (snapshot.canvas3d.viewport) PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: snapshot.canvas3d.viewport || { } });
if (snapshot.canvas3d.camera) this.plugin.canvas3d.camera.setState(snapshot.canvas3d.camera);
if (snapshot.canvas3d.props) await PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: snapshot.canvas3d.props || { } });
}
this.plugin.canvas3d.requestDraw(true);
if (snapshot.cameraSnapshots) this.cameraSnapshots.setStateSnapshot(snapshot.cameraSnapshots);
if (snapshot.animation) {
this.animation.setSnapshot(snapshot.animation);
}
if (snapshot.camera) {
await PluginCommands.Camera.SetSnapshot.dispatch(this.plugin, {
snapshot: snapshot.camera.current,
durationMs: snapshot.camera.transitionStyle === 'animate' ? 250 : void 0
});
}
}
dispose() {
......@@ -95,14 +108,32 @@ class PluginState {
namespace PluginState {
export type Kind = 'data' | 'behavior'
export type CameraTransitionStyle = 'instant' | 'animate'
export const GetSnapshotParams = {
data: PD.Boolean(true),
behavior: PD.Boolean(false),
animation: PD.Boolean(true),
canvas3d: PD.Boolean(true),
camera: PD.Boolean(true),
// TODO: make camera snapshots same as the StateSnapshots with "child states?"
cameraSnapshots: PD.Boolean(false),
cameraTranstionStyle: PD.Select<CameraTransitionStyle>('animate', [['animate', 'Animate'], ['instant', 'Instant']])
};
export type GetSnapshotParams = PD.Value<typeof GetSnapshotParams>
export const DefaultGetSnapshotParams = PD.getDefaultValues(GetSnapshotParams);
export interface Snapshot {
id: UUID,
data?: State.Snapshot,
behaviour?: State.Snapshot,
animation?: PluginAnimationManager.Snapshot,
camera?: {
current: Camera.Snapshot,
transitionStyle: CameraTransitionStyle
},
cameraSnapshots?: CameraSnapshotManager.StateSnapshot,
canvas3d?: {
camera?: Camera.Snapshot,
viewport?: Canvas3DProps
props?: Canvas3DProps
}
}
}
......@@ -103,8 +103,11 @@ class PluginAnimationManager extends PluginComponent<PluginAnimationManager.Stat
stop() {
this.context.canvas3d.setSceneAnimating(false);
if (typeof this._frame !== 'undefined') cancelAnimationFrame(this._frame);
this.updateState({ animationState: 'stopped' });
this.triggerUpdate();
if (this.state.animationState !== 'stopped') {
this.updateState({ animationState: 'stopped' });
this.triggerUpdate();
}
}
get isAnimating() {
......
......@@ -11,7 +11,7 @@ import { PluginComponent } from 'mol-plugin/component';
export { PluginStateSnapshotManager }
class PluginStateSnapshotManager extends PluginComponent<{ entries: OrderedMap<string, PluginStateSnapshotManager.Entry> }> {
class PluginStateSnapshotManager extends PluginComponent<{ current?: UUID | undefined, entries: OrderedMap<string, PluginStateSnapshotManager.Entry> }> {
readonly events = {
changed: this.ev()
};
......@@ -22,40 +22,85 @@ class PluginStateSnapshotManager extends PluginComponent<{ entries: OrderedMap<s
remove(id: string) {
if (!this.state.entries.has(id)) return;
this.updateState({ entries: this.state.entries.delete(id) });
this.updateState({
current: this.state.current === id ? void 0 : this.state.current,
entries: this.state.entries.delete(id)
});
this.events.changed.next();
}
add(e: PluginStateSnapshotManager.Entry) {
this.updateState({ entries: this.state.entries.set(e.id, e) });
this.updateState({ current: e.snapshot.id, entries: this.state.entries.set(e.snapshot.id, e) });
this.events.changed.next();
}
clear() {
if (this.state.entries.size === 0) return;
this.updateState({ entries: OrderedMap<string, PluginStateSnapshotManager.Entry>() });
this.updateState({ current: void 0, entries: OrderedMap<string, PluginStateSnapshotManager.Entry>() });
this.events.changed.next();
}
setCurrent(id: string) {
const e = this.getEntry(id);
if (e) {
this.updateState({ current: id as UUID });
this.events.changed.next();
}
return e && e.snapshot;
}
setRemoteSnapshot(snapshot: PluginStateSnapshotManager.RemoteSnapshot): PluginState.Snapshot | undefined {
this.clear();
const entries = this.state.entries.withMutations(m => {
for (const e of snapshot.entries) {
m.set(e.snapshot.id, e);
}
});
const current = snapshot.current
? snapshot.current
: snapshot.entries.length > 0
? snapshot.entries[0].snapshot.id
: void 0;
this.updateState({ current, entries });
this.events.changed.next();
if (!current) return;
const ret = this.getEntry(current);
return ret && ret.snapshot;
}
getRemoteSnapshot(options?: { name?: string, description?: string }): PluginStateSnapshotManager.RemoteSnapshot {
// TODO: diffing and all that fancy stuff
return {
timestamp: +new Date(),
name: options && options.name,
description: options && options.description,
current: this.state.current,
entries: this.state.entries.valueSeq().toArray()
};
}
constructor() {
super({ entries: OrderedMap<string, PluginStateSnapshotManager.Entry>() });
super({ current: void 0, entries: OrderedMap<string, PluginStateSnapshotManager.Entry>() });
}
}
namespace PluginStateSnapshotManager {
export interface Entry {
id: UUID,
timestamp: string,
timestamp: number,
name?: string,
description?: string,
snapshot: PluginState.Snapshot
}
export function Entry(snapshot: PluginState.Snapshot, name?: string, description?: string): Entry {
return { id: UUID.create22(), timestamp: new Date().toLocaleString(), name, snapshot, description };
return { timestamp: +new Date(), name, snapshot, description };
}
export interface StateSnapshot {
export interface RemoteSnapshot {
timestamp: number,
name?: string,
description?: string,
current: UUID | undefined,
entries: Entry[]
}
}
\ No newline at end of file
......@@ -161,7 +161,7 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
})({
canAutoUpdate({ a, oldParams, newParams }) {
// TODO: other criteria as well?
return a.data.elementCount < 10000 && oldParams.type.name === newParams.type.name;
return a.data.elementCount < 10000 || oldParams.type.name === newParams.type.name;
},
apply({ a, params }, plugin: PluginContext) {
return Task.create('Structure Representation', async ctx => {
......
......@@ -110,9 +110,9 @@ class LocalStateSnapshotList extends PluginUIComponent<{ }, { }> {
render() {
return <ul style={{ listStyle: 'none' }} className='msp-state-list'>
{this.plugin.state.snapshots.state.entries.valueSeq().map(e =><li key={e!.id}>
<button className='msp-btn msp-btn-block msp-form-control' onClick={this.apply(e!.id)}>{e!.name || e!.timestamp} <small>{e!.description}</small></button>
<button onClick={this.remove(e!.id)} className='msp-btn msp-btn-link msp-state-list-remove-button'>
{this.plugin.state.snapshots.state.entries.valueSeq().map(e =><li key={e!.snapshot.id}>
<button className='msp-btn msp-btn-block msp-form-control' onClick={this.apply(e!.snapshot.id)}>{e!.name || new Date(e!.timestamp).toLocaleString()} <small>{e!.description}</small></button>
<button onClick={this.remove(e!.snapshot.id)} className='msp-btn msp-btn-link msp-state-list-remove-button'>
<span className='msp-icon msp-icon-remove' />
</button>
</li>)}
......
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