浏览代码

added basic wrapper

David Sehnal 6 年之前
父节点
当前提交
783b94ede7

+ 44 - 0
src/apps/basic-wrapper/index.html

@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <meta charset="utf-8" />
+        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+        <title>Mol* Viewer</title>
+        <style>
+            * {
+                margin: 0;
+                padding: 0;
+                box-sizing: border-box;
+            }
+            #app {
+                position: absolute;
+                left: 100px;
+                top: 100px;
+                width: 600px;
+                height: 600px;
+                border: 1px solid #ccc;
+            }
+        </style>
+        <link rel="stylesheet" type="text/css" href="app.css" />
+        <script type="text/javascript" src="./index.js"></script>
+    </head>
+    <body>
+        <button id='spin'>Toggle Spin</button>
+        <button id='asym'>Load Asym Unit</button>
+        <button id='asm'>Load Assemly 1</button>
+        <div id="app"></div>
+        <script>            
+            var pdbId = '5ire', assemblyId= '1';
+            var url = 'https://www.ebi.ac.uk/pdbe/static/entry/' + pdbId + '_updated.cif';
+
+            BasicMolStarWrapper.init('app' /** or document.getElementById('app') */);
+            BasicMolStarWrapper.setBackground(0xffffff);
+            BasicMolStarWrapper.loadCif(url, assemblyId);
+            BasicMolStarWrapper.toggleSpin();
+
+            document.getElementById('spin').onclick = () => BasicMolStarWrapper.toggleSpin();
+            document.getElementById('asym').onclick = () => BasicMolStarWrapper.loadCif(url);
+            document.getElementById('asm').onclick = () => BasicMolStarWrapper.loadCif(url, assemblyId);
+        </script>
+    </body>
+</html>

+ 77 - 0
src/apps/basic-wrapper/index.ts

@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { createPlugin, DefaultPluginSpec } from 'mol-plugin';
+import './index.html'
+import { PluginContext } from 'mol-plugin/context';
+import { PluginCommands } from 'mol-plugin/command';
+import { StateTransforms } from 'mol-plugin/state/transforms';
+import { StructureRepresentation3DHelpers } from 'mol-plugin/state/transforms/representation';
+import { StateTree } from 'mol-state';
+import { Color } from 'mol-util/color';
+require('mol-plugin/skin/light.scss')
+
+class BasicWrapper {
+    plugin: PluginContext;
+    stateTemplate: StateTree;
+
+    init(target: string | HTMLElement) {
+        this.plugin = createPlugin(typeof target === 'string' ? document.getElementById(target)! : target, {
+            ...DefaultPluginSpec,
+            initialLayout: {
+                isExpanded: false,
+                showControls: false
+            }
+        });
+
+        const state = this.plugin.state.dataState.build();
+        const visualRoot = state.toRoot()
+            .apply(StateTransforms.Data.Download, { url: '', isBinary: false }, { ref: 'url' })
+            .apply(StateTransforms.Data.ParseCif)
+            .apply(StateTransforms.Model.TrajectoryFromMmCif)
+            .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 })
+            .apply(StateTransforms.Model.StructureAssemblyFromModel, { id: '' }, { ref: 'asm' })
+
+        visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-sequence' })
+            .apply(StateTransforms.Representation.StructureRepresentation3D,
+                StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'cartoon'));
+        visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'atomic-het' })
+            .apply(StateTransforms.Representation.StructureRepresentation3D,
+                StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick'));
+        visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'water' })
+            .apply(StateTransforms.Representation.StructureRepresentation3D,
+                StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'ball-and-stick', { alpha: 0.51 }));
+        visualRoot.apply(StateTransforms.Model.StructureComplexElement, { type: 'spheres' })
+            .apply(StateTransforms.Representation.StructureRepresentation3D,
+                StructureRepresentation3DHelpers.getDefaultParamsStatic(this.plugin, 'spacefill'));
+
+        this.stateTemplate = state.getTree();
+    }
+
+    async loadCif(url: string, assemblyId?: string) {
+        const state = this.stateTemplate.build();
+
+        state.to('url').update(StateTransforms.Data.Download, p => ({ ...p, url }));
+        state.to('asm').update(StateTransforms.Model.StructureAssemblyFromModel, p => ({ ...p, id: assemblyId }));
+
+        await PluginCommands.State.Update.dispatch(this.plugin, { state: this.plugin.state.dataState, tree: state });
+
+        PluginCommands.Camera.Reset.dispatch(this.plugin, { });
+    }
+
+    setBackground(color: number) {
+        PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { backgroundColor: Color(color) } });
+    }
+
+    toggleSpin() {
+        const trackball = this.plugin.canvas3d.props.trackball;
+        const spinning = trackball.spin;
+        PluginCommands.Canvas3D.SetSettings.dispatch(this.plugin, { settings: { trackball: { ...trackball, spin: !trackball.spin } } });
+        if (!spinning) PluginCommands.Camera.Reset.dispatch(this.plugin, { });
+    }
+}
+
+(window as any).BasicMolStarWrapper = new BasicWrapper();

+ 3 - 3
src/mol-plugin/state/transforms/model.ts

@@ -104,19 +104,19 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({
     to: SO.Molecule.Structure,
     params(a) {
         if (!a) {
-            return { id: PD.Text('', { label: 'Assembly Id', description: 'Assembly Id. If none specified (undefined or empty string), the asymmetric unit is used.' }) };
+            return { id: PD.makeOptional(PD.Text('', { label: 'Assembly Id', description: 'Assembly Id. If none specified (undefined or empty string), the asymmetric unit is used.' })) };
         }
         const model = a.data;
         const ids = model.symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]);
         if (!ids.length) ids.push(['deposited', 'Deposited'])
-        return { id: PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' }) };
+        return { id: PD.makeOptional(PD.Select(ids[0][0], ids, { label: 'Asm Id', description: 'Assembly Id' })) };
     }
 })({
     apply({ a, params }, plugin: PluginContext) {
         return Task.create('Build Assembly', async ctx => {
             const model = a.data;
             const id = params.id;
-            const asm = ModelSymmetry.findAssembly(model, id);
+            const asm = ModelSymmetry.findAssembly(model, id || '');
             if (!!id && id !== 'deposited' && !asm) throw new Error(`Assembly '${id}' not found`);
 
             const base = Structure.ofModel(model);

+ 3 - 3
src/mol-plugin/ui/controls.tsx

@@ -24,15 +24,15 @@ export class TrajectoryControls extends PluginComponent {
             <button className='msp-btn msp-btn-link' onClick={() => PluginCommands.State.ApplyAction.dispatch(this.plugin, {
                 state: this.plugin.state.dataState,
                 action: UpdateTrajectory.create({ action: 'advance', by: -1 })
-            })}>◀</button>
+            })} title='Previou Model'>◀</button>
             <button className='msp-btn msp-btn-link' onClick={() => PluginCommands.State.ApplyAction.dispatch(this.plugin, {
                 state: this.plugin.state.dataState,
                 action: UpdateTrajectory.create({ action: 'reset' })
-            })}>↻</button>
+            })} title='First Model'>↻</button>
             <button className='msp-btn msp-btn-link' onClick={() => PluginCommands.State.ApplyAction.dispatch(this.plugin, {
                 state: this.plugin.state.dataState,
                 action: UpdateTrajectory.create({ action: 'advance', by: +1 })
-            })}>►</button><br />
+            })} title='Next Model'>►</button><br />
         </div>
     }
 }

+ 1 - 0
webpack.config.js

@@ -87,6 +87,7 @@ function createNodeApp(name) { return createNodeEntryPoint('index', `apps/${name
 
 module.exports = [
     createApp('viewer'),
+    createApp('basic-wrapper'),
     createNodeApp('state-docs'),
     createApp('model-server-query'),