state.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { State, StateTransform, StateTransformer } from '../mol-state';
  7. import { PluginStateObject as SO } from '../mol-plugin-state/objects';
  8. import { Camera } from '../mol-canvas3d/camera';
  9. import { PluginBehavior } from './behavior';
  10. import { Canvas3DProps } from '../mol-canvas3d/canvas3d';
  11. import { PluginCommands } from './commands';
  12. import { PluginAnimationManager } from '../mol-plugin-state/manager/animation';
  13. import { ParamDefinition as PD } from '../mol-util/param-definition';
  14. import { UUID } from '../mol-util';
  15. import { InteractivityManager } from '../mol-plugin-state/manager/interactivity';
  16. import { produce } from 'immer';
  17. import { StructureFocusSnapshot } from '../mol-plugin-state/manager/structure/focus';
  18. import { merge } from 'rxjs';
  19. export { PluginState };
  20. class PluginState {
  21. private get animation() { return this.plugin.managers.animation; }
  22. readonly data: State;
  23. readonly behaviors: State;
  24. readonly events = {
  25. cell: {
  26. stateUpdated: merge(this.data.events.cell.stateUpdated, this.behaviors.events.cell.stateUpdated),
  27. created: merge(this.data.events.cell.created, this.behaviors.events.cell.created),
  28. removed: merge(this.data.events.cell.removed, this.behaviors.events.cell.removed),
  29. },
  30. object: {
  31. created: merge(this.data.events.object.created, this.behaviors.events.object.created),
  32. removed: merge(this.data.events.object.removed, this.behaviors.events.object.removed),
  33. updated: merge(this.data.events.object.updated, this.behaviors.events.object.updated)
  34. }
  35. } as const
  36. getSnapshot(params?: PluginState.GetSnapshotParams): PluginState.Snapshot {
  37. const p = { ...PluginState.DefaultGetSnapshotParams, ...params };
  38. return {
  39. id: UUID.create22(),
  40. data: p.data ? this.data.getSnapshot() : void 0,
  41. behaviour: p.behavior ? this.behaviors.getSnapshot() : void 0,
  42. animation: p.animation ? this.animation.getSnapshot() : void 0,
  43. startAnimation: p.startAnimation ? !!p.startAnimation : void 0,
  44. camera: p.camera ? {
  45. current: this.plugin.canvas3d!.camera.getSnapshot(),
  46. transitionStyle: p.cameraTranstion.name,
  47. transitionDurationInMs: (params && params.cameraTranstion && params.cameraTranstion.name === 'animate') ? params.cameraTranstion.params.durationInMs : undefined
  48. } : void 0,
  49. canvas3d: p.canvas3d ? { props: this.plugin.canvas3d?.props } : void 0,
  50. interactivity: p.interactivity ? { props: this.plugin.managers.interactivity.props } : void 0,
  51. structureFocus: this.plugin.managers.structure.focus.getSnapshot(),
  52. durationInMs: params && params.durationInMs
  53. };
  54. }
  55. async setSnapshot(snapshot: PluginState.Snapshot) {
  56. await this.animation.stop();
  57. if (snapshot.behaviour) await this.plugin.runTask(this.behaviors.setSnapshot(snapshot.behaviour));
  58. if (snapshot.data) await this.plugin.runTask(this.data.setSnapshot(snapshot.data));
  59. if (snapshot.canvas3d) {
  60. if (snapshot.canvas3d.props) await PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: snapshot.canvas3d.props });
  61. }
  62. if (snapshot.interactivity) {
  63. if (snapshot.interactivity.props) this.plugin.managers.interactivity.setProps(snapshot.interactivity.props);
  64. }
  65. if (snapshot.structureFocus) {
  66. this.plugin.managers.structure.focus.setSnapshot(snapshot.structureFocus);
  67. }
  68. if (snapshot.animation) {
  69. this.animation.setSnapshot(snapshot.animation);
  70. }
  71. if (snapshot.camera) {
  72. PluginCommands.Camera.Reset(this.plugin, {
  73. snapshot: snapshot.camera.current,
  74. durationMs: snapshot.camera.transitionStyle === 'animate'
  75. ? snapshot.camera.transitionDurationInMs
  76. : void 0
  77. });
  78. }
  79. if (snapshot.startAnimation) {
  80. this.animation.start();
  81. }
  82. }
  83. updateTransform(state: State, a: StateTransform.Ref, params: any, canUndo?: string | boolean) {
  84. const tree = state.build().to(a).update(params);
  85. return PluginCommands.State.Update(this.plugin, { state, tree, options: { canUndo } });
  86. }
  87. updateBehavior<T extends StateTransformer>(behavior: T, params: (old: StateTransformer.Params<T>) => (void | StateTransformer.Params<T>)) {
  88. const tree = this.behaviors.build();
  89. if (!this.behaviors.tree.transforms.has(behavior.id)) {
  90. const defaultParams = behavior.createDefaultParams(void 0 as any, this.plugin);
  91. tree.to(PluginBehavior.getCategoryId(behavior)).apply(behavior, produce(defaultParams, params) as any, { ref: behavior.id });
  92. } else {
  93. tree.to(behavior.id).update(params);
  94. }
  95. return this.plugin.runTask(this.behaviors.updateTree(tree));
  96. }
  97. dispose() {
  98. this.data.dispose();
  99. this.behaviors.dispose();
  100. this.animation.dispose();
  101. }
  102. constructor(private plugin: import('./context').PluginContext) {
  103. this.data = State.create(new SO.Root({ }), { runTask: plugin.runTask, globalContext: plugin });
  104. this.behaviors = State.create(new PluginBehavior.Root({ }), { runTask: plugin.runTask, globalContext: plugin, rootState: { isLocked: true } });
  105. }
  106. }
  107. namespace PluginState {
  108. export type CameraTransitionStyle = 'instant' | 'animate'
  109. export const GetSnapshotParams = {
  110. durationInMs: PD.Numeric(1500, { min: 100, max: 15000, step: 100 }, { label: 'Duration in ms' }),
  111. data: PD.Boolean(true),
  112. behavior: PD.Boolean(false),
  113. animation: PD.Boolean(true),
  114. startAnimation: PD.Boolean(false),
  115. canvas3d: PD.Boolean(true),
  116. interactivity: PD.Boolean(true),
  117. camera: PD.Boolean(true),
  118. cameraTranstion: PD.MappedStatic('animate', {
  119. animate: PD.Group({
  120. durationInMs: PD.Numeric(250, { min: 100, max: 5000, step: 500 }, { label: 'Duration in ms' }),
  121. }),
  122. instant: PD.Group({ })
  123. }, { options: [['animate', 'Animate'], ['instant', 'Instant']] })
  124. };
  125. export type GetSnapshotParams = Partial<PD.Values<typeof GetSnapshotParams>>
  126. export const DefaultGetSnapshotParams = PD.getDefaultValues(GetSnapshotParams);
  127. export interface Snapshot {
  128. id: UUID,
  129. data?: State.Snapshot,
  130. behaviour?: State.Snapshot,
  131. animation?: PluginAnimationManager.Snapshot,
  132. startAnimation?: boolean,
  133. camera?: {
  134. current: Camera.Snapshot,
  135. transitionStyle: CameraTransitionStyle,
  136. transitionDurationInMs?: number
  137. },
  138. canvas3d?: {
  139. props?: Canvas3DProps
  140. },
  141. interactivity?: {
  142. props?: InteractivityManager.Props
  143. },
  144. structureFocus?: StructureFocusSnapshot,
  145. durationInMs?: number
  146. }
  147. }