index.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import '../../mol-util/polyfill';
  8. import { createPlugin } from '../../mol-plugin';
  9. import { DefaultPluginSpec } from '../../mol-plugin/spec';
  10. import './index.html';
  11. import { PluginContext } from '../../mol-plugin/context';
  12. import { PluginCommands } from '../../mol-plugin/commands';
  13. import { PluginSpec } from '../../mol-plugin/spec';
  14. import { PluginConfig } from '../../mol-plugin/config';
  15. import { ObjectKeys } from '../../mol-util/type-helpers';
  16. import { PluginLayoutControlsDisplay } from '../../mol-plugin/layout';
  17. import { BuiltInTrajectoryFormat } from '../../mol-plugin-state/formats/trajectory';
  18. import { Structure } from '../../mol-model/structure';
  19. import { PluginStateTransform, PluginStateObject as PSO } from '../../mol-plugin-state/objects';
  20. import { ParamDefinition as PD } from '../../mol-util/param-definition';
  21. import { Task } from '../../mol-task';
  22. import { StateObject } from '../../mol-state';
  23. import { ViewportComponent, StructurePreset, ShowButtons } from './viewport';
  24. import { PluginBehaviors } from '../../mol-plugin/behavior';
  25. import { ColorNames } from '../../mol-util/color/names';
  26. import { Color } from '../../mol-util/color';
  27. require('mol-plugin-ui/skin/light.scss');
  28. export { PLUGIN_VERSION as version } from '../../mol-plugin/version';
  29. export { setProductionMode, setDebugMode } from '../../mol-util/debug';
  30. const DefaultViewerOptions = {
  31. extensions: ObjectKeys({}),
  32. layoutIsExpanded: true,
  33. layoutShowControls: true,
  34. layoutShowRemoteState: true,
  35. layoutControlsDisplay: 'reactive' as PluginLayoutControlsDisplay,
  36. layoutShowSequence: true,
  37. layoutShowLog: true,
  38. layoutShowLeftPanel: true,
  39. viewportShowExpand: PluginConfig.Viewport.ShowExpand.defaultValue,
  40. viewportShowControls: PluginConfig.Viewport.ShowControls.defaultValue,
  41. viewportShowSettings: PluginConfig.Viewport.ShowSettings.defaultValue,
  42. viewportShowSelectionMode: PluginConfig.Viewport.ShowSelectionMode.defaultValue,
  43. viewportShowAnimation: PluginConfig.Viewport.ShowAnimation.defaultValue,
  44. pluginStateServer: PluginConfig.State.DefaultServer.defaultValue,
  45. volumeStreamingServer: PluginConfig.VolumeStreaming.DefaultServer.defaultValue,
  46. pdbProvider: PluginConfig.Download.DefaultPdbProvider.defaultValue,
  47. emdbProvider: PluginConfig.Download.DefaultEmdbProvider.defaultValue,
  48. };
  49. class Viewer {
  50. plugin: PluginContext
  51. constructor(elementOrId: string | HTMLElement, colors = [Color(0x992211), Color(0xDDDDDD)], showButtons = true) {
  52. const o = { ...DefaultViewerOptions, ...{
  53. layoutIsExpanded: false,
  54. layoutShowControls: false,
  55. layoutShowRemoteState: false,
  56. layoutShowSequence: true,
  57. layoutShowLog: false,
  58. layoutShowLeftPanel: true,
  59. viewportShowExpand: true,
  60. viewportShowControls: false,
  61. viewportShowSettings: false,
  62. viewportShowSelectionMode: false,
  63. viewportShowAnimation: false,
  64. } };
  65. const defaultSpec = DefaultPluginSpec();
  66. const spec: PluginSpec = {
  67. actions: [...defaultSpec.actions],
  68. behaviors: [
  69. PluginSpec.Behavior(PluginBehaviors.Representation.HighlightLoci, { mark: false }),
  70. PluginSpec.Behavior(PluginBehaviors.Representation.DefaultLociLabelProvider),
  71. PluginSpec.Behavior(PluginBehaviors.Camera.FocusLoci),
  72. PluginSpec.Behavior(PluginBehaviors.CustomProps.StructureInfo),
  73. PluginSpec.Behavior(PluginBehaviors.CustomProps.Interactions),
  74. PluginSpec.Behavior(PluginBehaviors.CustomProps.SecondaryStructure),
  75. ],
  76. animations: [...defaultSpec.animations || []],
  77. customParamEditors: defaultSpec.customParamEditors,
  78. layout: {
  79. initial: {
  80. isExpanded: o.layoutIsExpanded,
  81. showControls: o.layoutShowControls,
  82. controlsDisplay: o.layoutControlsDisplay,
  83. },
  84. controls: {
  85. ...defaultSpec.layout && defaultSpec.layout.controls,
  86. top: o.layoutShowSequence ? undefined : 'none',
  87. bottom: o.layoutShowLog ? undefined : 'none',
  88. left: o.layoutShowLeftPanel ? undefined : 'none',
  89. }
  90. },
  91. components: {
  92. ...defaultSpec.components,
  93. remoteState: o.layoutShowRemoteState ? 'default' : 'none',
  94. viewport: {
  95. view: ViewportComponent
  96. }
  97. },
  98. config: [
  99. [PluginConfig.Viewport.ShowExpand, o.viewportShowExpand],
  100. [PluginConfig.Viewport.ShowControls, o.viewportShowControls],
  101. [PluginConfig.Viewport.ShowSettings, o.viewportShowSettings],
  102. [PluginConfig.Viewport.ShowSelectionMode, o.viewportShowSelectionMode],
  103. [PluginConfig.Viewport.ShowAnimation, o.viewportShowAnimation],
  104. [PluginConfig.State.DefaultServer, o.pluginStateServer],
  105. [PluginConfig.State.CurrentServer, o.pluginStateServer],
  106. [PluginConfig.VolumeStreaming.DefaultServer, o.volumeStreamingServer],
  107. [PluginConfig.Download.DefaultPdbProvider, o.pdbProvider],
  108. [PluginConfig.Download.DefaultEmdbProvider, o.emdbProvider],
  109. [ShowButtons, showButtons]
  110. ]
  111. };
  112. const element = typeof elementOrId === 'string'
  113. ? document.getElementById(elementOrId)
  114. : elementOrId;
  115. if (!element) throw new Error(`Could not get element with id '${elementOrId}'`);
  116. this.plugin = createPlugin(element, spec);
  117. (this.plugin.customState as any) = {
  118. colorPalette: {
  119. name: 'colors',
  120. params: { list: { colors } }
  121. }
  122. };
  123. this.plugin.behaviors.canvas3d.initialized.subscribe(v => {
  124. if (v) {
  125. PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: {
  126. renderer: {
  127. ...this.plugin.canvas3d!.props.renderer,
  128. backgroundColor: ColorNames.white,
  129. },
  130. camera: {
  131. ...this.plugin.canvas3d!.props.camera,
  132. helper: { axes: { name: 'off', params: {} } }
  133. }
  134. } });
  135. }
  136. });
  137. }
  138. async loadStructuresFromUrlsAndMerge(sources: { url: string, format: BuiltInTrajectoryFormat, isBinary?: boolean }[]) {
  139. const structures: { ref: string }[] = [];
  140. for (const { url, format, isBinary } of sources) {
  141. const data = await this.plugin.builders.data.download({ url, isBinary });
  142. const trajectory = await this.plugin.builders.structure.parseTrajectory(data, format);
  143. const model = await this.plugin.builders.structure.createModel(trajectory);
  144. const modelProperties = await this.plugin.builders.structure.insertModelProperties(model);
  145. const structure = await this.plugin.builders.structure.createStructure(modelProperties || model);
  146. const structureProperties = await this.plugin.builders.structure.insertStructureProperties(structure);
  147. structures.push({ ref: structureProperties?.ref || structure.ref });
  148. }
  149. // remove current structuresfrom hierarchy as they will be merged
  150. // TODO only works with using loadStructuresFromUrlsAndMerge once
  151. // need some more API metho to work with the hierarchy
  152. this.plugin.managers.structure.hierarchy.updateCurrent(this.plugin.managers.structure.hierarchy.current.structures, 'remove');
  153. const dependsOn = structures.map(({ ref }) => ref);
  154. const data = this.plugin.state.data.build().toRoot().apply(MergeStructures, { structures }, { dependsOn });
  155. const structure = await data.commit();
  156. const structureProperties = await this.plugin.builders.structure.insertStructureProperties(structure);
  157. this.plugin.behaviors.canvas3d.initialized.subscribe(async v => {
  158. await this.plugin.builders.structure.representation.applyPreset(structureProperties || structure, StructurePreset);
  159. });
  160. }
  161. }
  162. type MergeStructures = typeof MergeStructures
  163. const MergeStructures = PluginStateTransform.BuiltIn({
  164. name: 'merge-structures',
  165. display: { name: 'Merge Structures', description: 'Merge Structure' },
  166. from: PSO.Root,
  167. to: PSO.Molecule.Structure,
  168. params: {
  169. structures: PD.ObjectList({
  170. ref: PD.Text('')
  171. }, ({ ref }) => ref, { isHidden: true })
  172. }
  173. })({
  174. apply({ params, dependencies }) {
  175. return Task.create('Merge Structures', async ctx => {
  176. if (params.structures.length === 0) return StateObject.Null;
  177. const first = dependencies![params.structures[0].ref].data as Structure;
  178. const builder = Structure.Builder({ masterModel: first.models[0] });
  179. for (const { ref } of params.structures) {
  180. const s = dependencies![ref].data as Structure;
  181. for (const unit of s.units) {
  182. // TODO invariantId
  183. builder.addUnit(unit.kind, unit.model, unit.conformation.operator, unit.elements, unit.traits);
  184. }
  185. }
  186. const structure = builder.getStructure();
  187. return new PSO.Molecule.Structure(structure, { label: 'Merged Structure' });
  188. });
  189. }
  190. });
  191. (window as any).DockingViewer = Viewer;
  192. export { Viewer as DockingViewer };