|
@@ -11,25 +11,21 @@ import './favicon.ico'
|
|
import { PluginContext } from 'molstar/lib/mol-plugin/context';
|
|
import { PluginContext } from 'molstar/lib/mol-plugin/context';
|
|
import { PluginCommands } from 'molstar/lib/mol-plugin/command';
|
|
import { PluginCommands } from 'molstar/lib/mol-plugin/command';
|
|
import { PluginBehaviors } from 'molstar/lib/mol-plugin/behavior';
|
|
import { PluginBehaviors } from 'molstar/lib/mol-plugin/behavior';
|
|
-import { StateTransforms } from 'molstar/lib/mol-plugin/state/transforms';
|
|
|
|
-import { PluginStateObject as PSO } from 'molstar/lib/mol-plugin/state/objects';
|
|
|
|
import { AnimateModelIndex } from 'molstar/lib/mol-plugin/state/animation/built-in';
|
|
import { AnimateModelIndex } from 'molstar/lib/mol-plugin/state/animation/built-in';
|
|
-import { StateBuilder, StateSelection } from 'molstar/lib/mol-state';
|
|
|
|
-import { LoadParams, SupportedFormats, StateElements, StructureViewerState } from './helpers';
|
|
|
|
|
|
+import { SupportedFormats, StructureViewerState, StructureViewerProps } from './types';
|
|
import { ControlsWrapper, ViewportWrapper } from './ui/controls';
|
|
import { ControlsWrapper, ViewportWrapper } from './ui/controls';
|
|
-import { Scheduler } from 'molstar/lib/mol-task';
|
|
|
|
-import { InitVolumeStreaming, CreateVolumeStreamingInfo } from 'molstar/lib/mol-plugin/behavior/dynamic/volume-streaming/transformers';
|
|
|
|
-import { ParamDefinition as PD } from 'molstar/lib/mol-util/param-definition';
|
|
|
|
import { PluginSpec } from 'molstar/lib/mol-plugin/spec';
|
|
import { PluginSpec } from 'molstar/lib/mol-plugin/spec';
|
|
import { StructureRepresentationInteraction } from 'molstar/lib/mol-plugin/behavior/dynamic/selection/structure-representation-interaction';
|
|
import { StructureRepresentationInteraction } from 'molstar/lib/mol-plugin/behavior/dynamic/selection/structure-representation-interaction';
|
|
-import { Model } from 'molstar/lib/mol-model/structure';
|
|
|
|
|
|
+
|
|
import { ColorNames } from 'molstar/lib/mol-util/color/names';
|
|
import { ColorNames } from 'molstar/lib/mol-util/color/names';
|
|
-import { StructureControlsHelper } from './ui/structure';
|
|
|
|
|
|
+import { StructureView } from './helpers/structure';
|
|
import ReactDOM = require('react-dom');
|
|
import ReactDOM = require('react-dom');
|
|
import React = require('react');
|
|
import React = require('react');
|
|
|
|
+import { ModelLoader } from './helpers/model';
|
|
|
|
+import { VolumeData } from './helpers/volume';
|
|
require('./skin/rcsb.scss')
|
|
require('./skin/rcsb.scss')
|
|
|
|
|
|
-export const DefaultStructureViewerProps = {
|
|
|
|
|
|
+export const DefaultStructureViewerProps: StructureViewerProps = {
|
|
// volumeServerUrl: 'https://ds.litemol.org/',
|
|
// volumeServerUrl: 'https://ds.litemol.org/',
|
|
volumeServerUrl: '//alpha-maps.rcsb.org/',
|
|
volumeServerUrl: '//alpha-maps.rcsb.org/',
|
|
modelUrlProvider: (pdbId: string) => {
|
|
modelUrlProvider: (pdbId: string) => {
|
|
@@ -41,8 +37,8 @@ export const DefaultStructureViewerProps = {
|
|
format: 'bcif' as SupportedFormats
|
|
format: 'bcif' as SupportedFormats
|
|
}
|
|
}
|
|
},
|
|
},
|
|
|
|
+ showOpenFileControls: false,
|
|
}
|
|
}
|
|
-export type StructureViewerProps = typeof DefaultStructureViewerProps
|
|
|
|
|
|
|
|
export class StructureViewer {
|
|
export class StructureViewer {
|
|
private readonly plugin: PluginContext;
|
|
private readonly plugin: PluginContext;
|
|
@@ -51,6 +47,8 @@ export class StructureViewer {
|
|
constructor(target: string | HTMLElement, props: Partial<StructureViewerProps> = {}) {
|
|
constructor(target: string | HTMLElement, props: Partial<StructureViewerProps> = {}) {
|
|
target = typeof target === 'string' ? document.getElementById(target)! : target
|
|
target = typeof target === 'string' ? document.getElementById(target)! : target
|
|
|
|
|
|
|
|
+ this.props = { ...DefaultStructureViewerProps, ...props }
|
|
|
|
+
|
|
this.plugin = new PluginContext({
|
|
this.plugin = new PluginContext({
|
|
...DefaultPluginSpec,
|
|
...DefaultPluginSpec,
|
|
behaviors: [
|
|
behaviors: [
|
|
@@ -73,7 +71,7 @@ export class StructureViewer {
|
|
initial: {
|
|
initial: {
|
|
isExpanded: false,
|
|
isExpanded: false,
|
|
showControls: true,
|
|
showControls: true,
|
|
- outsideControls: false
|
|
|
|
|
|
+ controlsDisplay: 'reactive'
|
|
},
|
|
},
|
|
controls: {
|
|
controls: {
|
|
left: 'none',
|
|
left: 'none',
|
|
@@ -85,91 +83,24 @@ export class StructureViewer {
|
|
});
|
|
});
|
|
|
|
|
|
(this.plugin.customState as StructureViewerState) = {
|
|
(this.plugin.customState as StructureViewerState) = {
|
|
- structureControlsHelper: new StructureControlsHelper(this.plugin),
|
|
|
|
- experimentalData: this.experimentalData
|
|
|
|
|
|
+ props: this.props,
|
|
|
|
+ modelLoader: new ModelLoader(this.plugin),
|
|
|
|
+ structureView: new StructureView(this.plugin),
|
|
|
|
+ volumeData: new VolumeData(this.plugin)
|
|
};
|
|
};
|
|
|
|
|
|
- this.props = { ...DefaultStructureViewerProps, ...props }
|
|
|
|
-
|
|
|
|
ReactDOM.render(React.createElement(Plugin, { plugin: this.plugin }), target)
|
|
ReactDOM.render(React.createElement(Plugin, { plugin: this.plugin }), target)
|
|
|
|
|
|
const renderer = this.plugin.canvas3d.props.renderer;
|
|
const renderer = this.plugin.canvas3d.props.renderer;
|
|
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: ColorNames.white } } });
|
|
PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: ColorNames.white } } });
|
|
}
|
|
}
|
|
|
|
|
|
- get state() {
|
|
|
|
- return this.plugin.state.dataState;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private download(b: StateBuilder.To<PSO.Root>, url: string, isBinary: boolean) {
|
|
|
|
- return b.apply(StateTransforms.Data.Download, { url, isBinary })
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private model(b: StateBuilder.To<PSO.Data.Binary | PSO.Data.String>, format: SupportedFormats) {
|
|
|
|
- const isMmcif = format === 'cif' || format === 'bcif'
|
|
|
|
- const parsed = isMmcif
|
|
|
|
- ? b.apply(StateTransforms.Data.ParseCif).apply(StateTransforms.Model.TrajectoryFromMmCif, {}, { ref: StateElements.Trajectory })
|
|
|
|
- : b.apply(StateTransforms.Model.TrajectoryFromPDB, {}, { ref: StateElements.Trajectory });
|
|
|
|
-
|
|
|
|
- return parsed
|
|
|
|
- .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 }, { ref: StateElements.Model });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private applyState(tree: StateBuilder) {
|
|
|
|
- return PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree });
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- async load({ url, format = 'cif', assemblyId = 'deposited' }: LoadParams) {
|
|
|
|
- if (!url) return
|
|
|
|
-
|
|
|
|
- const state = this.plugin.state.dataState;
|
|
|
|
- await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state, ref: state.tree.root.ref });
|
|
|
|
-
|
|
|
|
- const isBinary = format === 'bcif'
|
|
|
|
- const modelTree = this.model(this.download(state.build().toRoot(), url, isBinary), format);
|
|
|
|
- await this.applyState(modelTree);
|
|
|
|
-
|
|
|
|
- await (this.plugin.customState as StructureViewerState).structureControlsHelper.setAssembly(assemblyId)
|
|
|
|
-
|
|
|
|
- Scheduler.setImmediate(() => PluginCommands.Camera.Reset.dispatch(this.plugin, { }));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
async loadPdbId(pdbId: string, assemblyId = 'deposited') {
|
|
async loadPdbId(pdbId: string, assemblyId = 'deposited') {
|
|
- return this.load({
|
|
|
|
|
|
+ const p = this.props.modelUrlProvider(pdbId)
|
|
|
|
+ return (this.plugin.customState as StructureViewerState).modelLoader.load({
|
|
|
|
+ fileOrUrl: p.url,
|
|
|
|
+ format: p.format,
|
|
assemblyId,
|
|
assemblyId,
|
|
- ...this.props.modelUrlProvider(pdbId),
|
|
|
|
})
|
|
})
|
|
}
|
|
}
|
|
-
|
|
|
|
- experimentalData = {
|
|
|
|
- init: async () => {
|
|
|
|
- const model = this.state.select(StateElements.Model)[0].obj;
|
|
|
|
- const asm = this.state.select(StateElements.Assembly)[0].obj;
|
|
|
|
- if (!model || !asm) return
|
|
|
|
-
|
|
|
|
- const m = model.data as Model
|
|
|
|
- const d = m.sourceData.data
|
|
|
|
- const hasXrayMap = d.pdbx_database_status.status_code_sf.value(0) === 'REL'
|
|
|
|
- let hasEmMap = false
|
|
|
|
- for (let i = 0, il = d.pdbx_database_related._rowCount; i < il; ++i) {
|
|
|
|
- if (d.pdbx_database_related.db_name.value(i).toUpperCase() === 'EMDB') {
|
|
|
|
- hasEmMap = true
|
|
|
|
- break
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (hasXrayMap || hasEmMap) {
|
|
|
|
- const params = PD.getDefaultValues(InitVolumeStreaming.definition.params!(asm, this.plugin));
|
|
|
|
- params.defaultView = 'selection-box';
|
|
|
|
- params.options.behaviorRef = StateElements.VolumeStreaming;
|
|
|
|
- params.options.serverUrl = this.props.volumeServerUrl
|
|
|
|
- await this.plugin.runTask(this.state.applyAction(InitVolumeStreaming, params, StateElements.Assembly));
|
|
|
|
- }
|
|
|
|
- },
|
|
|
|
- remove: async () => {
|
|
|
|
- const r = this.state.select(StateSelection.Generators.ofTransformer(CreateVolumeStreamingInfo))[0];
|
|
|
|
- if (!r) return;
|
|
|
|
- await PluginCommands.State.RemoveObject.dispatch(this.plugin, { state: this.state, ref: r.transform.ref });
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
}
|
|
}
|