index.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { createPlugin, DefaultPluginSpec } from 'mol-plugin';
  7. import './index.html'
  8. import { PluginContext } from 'mol-plugin/context';
  9. import { PluginCommands } from 'mol-plugin/command';
  10. import { StateTransforms } from 'mol-plugin/state/transforms';
  11. import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/representation';
  12. import { Color } from 'mol-util/color';
  13. import { PluginStateObject as PSO } from 'mol-plugin/state/objects';
  14. import { AnimateModelIndex } from 'mol-plugin/state/animation/built-in';
  15. import { StateBuilder } from 'mol-state';
  16. import { StripedResidues } from './coloring';
  17. require('mol-plugin/skin/light.scss')
  18. type SupportedFormats = 'cif' | 'pdb'
  19. type LoadParams = { url: string, format?: SupportedFormats, assemblyId?: string }
  20. class BasicWrapper {
  21. plugin: PluginContext;
  22. init(target: string | HTMLElement) {
  23. this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
  24. ...DefaultPluginSpec,
  25. layout: {
  26. initial: {
  27. isExpanded: false,
  28. showControls: false
  29. }
  30. }
  31. });
  32. this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.add(StripedResidues.Descriptor.name, StripedResidues.colorTheme!);
  33. this.plugin.lociLabels.addProvider(StripedResidues.labelProvider);
  34. this.plugin.customModelProperties.register(StripedResidues.propertyProvider);
  35. }
  36. private download(b: StateBuilder.To<PSO.Root>, url: string) {
  37. return b.apply(StateTransforms.Data.Download, { url, isBinary: false })
  38. }
  39. private parse(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats, assemblyId: string) {
  40. const parsed = format === 'cif'
  41. ? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif)
  42. : b.apply(StateTransforms.Model.TrajectoryFromPDB);
  43. return parsed
  44. .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
  45. .apply(StateTransforms.Model.CustomModelProperties, { properties: [StripedResidues.Descriptor.name] }, { ref: 'props', props: { isGhost: false } })
  46. .apply(StateTransforms.Model.StructureAssemblyFromModel, { id: assemblyId || 'deposited' }, { ref: 'asm' });
  47. }
  48. private visual(visualRoot: StateBuilder.To<PSO.Molecule.Structure>) {
  49. visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
  50. .apply(StateTransforms.Representation.StructureRepresentation3D,
  51. StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'));
  52. visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
  53. .apply(StateTransforms.Representation.StructureRepresentation3D,
  54. StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'));
  55. visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
  56. .apply(StateTransforms.Representation.StructureRepresentation3D,
  57. StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick', { alpha: 0.51 }));
  58. visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' })
  59. .apply(StateTransforms.Representation.StructureRepresentation3D,
  60. StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill'));
  61. return visualRoot;
  62. }
  63. private loadedParams: LoadParams = { url: '', format: 'cif', assemblyId: '' };
  64. async load({ url, format = 'cif', assemblyId = '' }: LoadParams) {
  65. let loadType: 'full' | 'update' = 'full';
  66. const state = this.plugin.state.dataState;
  67. if (this.loadedParams.url !== url || this.loadedParams.format !== format) {
  68. loadType = 'full';
  69. } else if (this.loadedParams.url === url) {
  70. if (state.select('asm').length > 0) loadType = 'update';
  71. }
  72. let tree: StateBuilder.Root;
  73. if (loadType === 'full') {
  74. await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
  75. tree = state.build();
  76. this.visual(this.parse(this.download(tree.toRoot(), url), format, assemblyId));
  77. } else {
  78. tree = state.build();
  79. tree.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId || 'deposited' }));
  80. }
  81. await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
  82. this.loadedParams = { url, format, assemblyId };
  83. PluginCommands.Camera.Reset.dispatch(this.plugin, { });
  84. }
  85. setBackground(color: number) {
  86. PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { backgroundColor: Color(color) } });
  87. }
  88. toggleSpin() {
  89. const trackball = this.plugin.canvas3d.props.trackball;
  90. const spinning = trackball.spin;
  91. PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
  92. if (!spinning) PluginCommands.Camera.Reset.dispatch(this.plugin, { });
  93. }
  94. animate = {
  95. modelIndex: {
  96. maxFPS: 8,
  97. onceForward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'forward' } } }) },
  98. onceBackward: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'once', params: { direction: 'backward' } } }) },
  99. palindrome: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'palindrome', params: {} } }) },
  100. loop: () => { this.plugin.state.animation.play(AnimateModelIndex, { maxFPS: Math.max(0.5, this.animate.modelIndex.maxFPS | 0), mode: { name: 'loop', params: {} } }) },
  101. stop: () => this.plugin.state.animation.stop()
  102. }
  103. }
  104. coloring = {
  105. applyStripes: async () => {
  106. const state = this.plugin.state.dataState;
  107. const visuals = state.selectQ(q => q.ofTransformer(StateTransforms.Representation.StructureRepresentation3D));
  108. const tree = state.build();
  109. const colorTheme = { name: StripedResidues.Descriptor.name, params: this.plugin.structureRepresentation.themeCtx.colorThemeRegistry.get(StripedResidues.Descriptor.name).defaultValues };
  110. for (const v of visuals) {
  111. tree.to(v).update(old => ({ ...old, colorTheme }));
  112. }
  113. await PluginCommands.State.Update.dispatch(this.plugin, { state, tree });
  114. }
  115. }
  116. }
  117. (window as any).BasicMolStarWrapper = new BasicWrapper();