diff --git a/src/examples/proteopedia-wrapper/index.html b/src/examples/proteopedia-wrapper/index.html index 1b9ba990352c5377637e68ebca0d98e04b6d5d4b..009eb5bf8193a534a6a2c21e342e1c47cfb29e6d 100644 --- a/src/examples/proteopedia-wrapper/index.html +++ b/src/examples/proteopedia-wrapper/index.html @@ -47,7 +47,7 @@ <body> <div id='controls'> <h3>Source</h3> - <input type='text' id='url' placeholder='url' /> + <input type='text' id='url' placeholder='url' style='width: 400px' /> <input type='text' id='assemblyId' placeholder='assembly id' /> <select id='format'> <option value='cif' selected>CIF</option> @@ -57,7 +57,9 @@ <div id="app"></div> <script> // create an instance of the plugin - var MolStarProteopediaWrapper = new MolStarProteopediaWrapper(); + var PluginWrapper = new MolStarProteopediaWrapper(); + + console.log('Wrapper version', MolStarProteopediaWrapper.VERSION_MAJOR); function $(id) { return document.getElementById(id); } @@ -76,22 +78,22 @@ // var format = 'pdb'; // var assemblyId = 'deposited'; - MolStarProteopediaWrapper.init('app' /** or document.getElementById('app') */); - MolStarProteopediaWrapper.setBackground(0xffffff); - MolStarProteopediaWrapper.load({ url: url, format: format, assemblyId: assemblyId }); - MolStarProteopediaWrapper.toggleSpin(); + PluginWrapper.init('app' /** or document.getElementById('app') */); + PluginWrapper.setBackground(0xffffff); + PluginWrapper.load({ url: url, format: format, assemblyId: assemblyId }); + PluginWrapper.toggleSpin(); - MolStarProteopediaWrapper.events.modelInfo.subscribe(function (info) { + PluginWrapper.events.modelInfo.subscribe(function (info) { console.log('Model Info', info); }); - addControl('Load Asym Unit', () => MolStarProteopediaWrapper.load({ url: url, format: format })); - addControl('Load Assembly', () => MolStarProteopediaWrapper.load({ url: url, format: format, assemblyId: assemblyId })); + addControl('Load Asym Unit', () => PluginWrapper.load({ url: url, format: format })); + addControl('Load Assembly', () => PluginWrapper.load({ url: url, format: format, assemblyId: assemblyId })); addSeparator(); addHeader('Camera'); - addControl('Toggle Spin', () => MolStarProteopediaWrapper.toggleSpin()); + addControl('Toggle Spin', () => PluginWrapper.toggleSpin()); addSeparator(); @@ -99,19 +101,35 @@ // adjust this number to make the animation faster or slower // requires to "restart" the animation if changed - MolStarProteopediaWrapper.animate.modelIndex.maxFPS = 30; + PluginWrapper.animate.modelIndex.maxFPS = 30; - addControl('Play To End', () => MolStarProteopediaWrapper.animate.modelIndex.onceForward()); - addControl('Play To Start', () => MolStarProteopediaWrapper.animate.modelIndex.onceBackward()); - addControl('Play Palindrome', () => MolStarProteopediaWrapper.animate.modelIndex.palindrome()); - addControl('Play Loop', () => MolStarProteopediaWrapper.animate.modelIndex.loop()); - addControl('Stop', () => MolStarProteopediaWrapper.animate.modelIndex.stop()); + addControl('Play To End', () => PluginWrapper.animate.modelIndex.onceForward()); + addControl('Play To Start', () => PluginWrapper.animate.modelIndex.onceBackward()); + addControl('Play Palindrome', () => PluginWrapper.animate.modelIndex.palindrome()); + addControl('Play Loop', () => PluginWrapper.animate.modelIndex.loop()); + addControl('Stop', () => PluginWrapper.animate.modelIndex.stop()); addSeparator(); addHeader('Misc'); - addControl('Apply Evo Cons', () => MolStarProteopediaWrapper.coloring.evolutionaryConservation()); - addControl('Default Visuals', () => MolStarProteopediaWrapper.updateStyle()); + addControl('Apply Evo Cons', () => PluginWrapper.coloring.evolutionaryConservation()); + addControl('Default Visuals', () => PluginWrapper.updateStyle()); + + addSeparator(); + addHeader('State'); + + var snapshot; + addControl('Create Snapshot', () => { + snapshot = PluginWrapper.snapshot.get(); + // could use JSON.stringify(snapshot) and upload the data + }); + addControl('Apply Snapshot', () => { + if (!snapshot) return; + PluginWrapper.snapshot.set(snapshot); + + // or download snapshot using fetch or ajax or whatever + // or PluginWrapper.snapshot.download(url); + }); //////////////////////////////////////////////////////// diff --git a/src/examples/proteopedia-wrapper/index.ts b/src/examples/proteopedia-wrapper/index.ts index 335e2a48b0c201ed3e553e1b73902b6850d114c2..4dab779502595d42eac36a28a0b4c6d90c9cd88f 100644 --- a/src/examples/proteopedia-wrapper/index.ts +++ b/src/examples/proteopedia-wrapper/index.ts @@ -18,6 +18,7 @@ import { EvolutionaryConservation } from './annotation'; import { LoadParams, SupportedFormats, RepresentationStyle, ModelInfo } from './helpers'; import { RxEventHelper } from 'mol-util/rx-event-helper'; import { ControlsWrapper } from './ui/controls'; +import { PluginState } from 'mol-plugin/state'; require('mol-plugin/skin/light.scss') class MolStarProteopediaWrapper { @@ -199,6 +200,25 @@ class MolStarProteopediaWrapper { await PluginCommands.State.Update.dispatch(this.plugin, { state, tree }); } } + + snapshot = { + get: () => { + return this.plugin.state.getSnapshot(); + }, + set: (snapshot: PluginState.Snapshot) => { + return this.plugin.state.setSnapshot(snapshot); + }, + download: async (url: string) => { + try { + const data = await this.plugin.runTask(this.plugin.fetch(url)); + const snapshot = JSON.parse(data); + await this.plugin.state.setSnapshot(snapshot); + } catch (e) { + console.log(e); + } + } + + } } (window as any).MolStarProteopediaWrapper = MolStarProteopediaWrapper; \ No newline at end of file diff --git a/src/mol-plugin/context.ts b/src/mol-plugin/context.ts index 43d7ea16a5e6fe6fd62340ee342f598f73e62b5b..0d88181170f4553311e69e0ae2ffb968e4107293 100644 --- a/src/mol-plugin/context.ts +++ b/src/mol-plugin/context.ts @@ -124,6 +124,8 @@ export class PluginContext { * This should be used in all transform related request so that it could be "spoofed" to allow * "static" access to resources. */ + fetch(url: string, type?: 'string', body?: string): Task<string> + fetch(url: string, type?: 'binary', body?: string): Task<Uint8Array> fetch(url: string, type: 'string' | 'binary' = 'string', body?: string): Task<string | Uint8Array> { return ajaxGet({ url, type, body }); // const req = await fetch(url, { referrerPolicy: 'origin-when-cross-origin' }); diff --git a/src/mol-plugin/state/animation/built-in.ts b/src/mol-plugin/state/animation/built-in.ts index 2902a995bbf036a06390224cca243883791c5421..9c85d8df57e786b42370d64c6b24d3b2a934d462 100644 --- a/src/mol-plugin/state/animation/built-in.ts +++ b/src/mol-plugin/state/animation/built-in.ts @@ -15,12 +15,12 @@ export const AnimateModelIndex = PluginStateAnimation.create({ name: 'built-in.animate-model-index', display: { name: 'Animate Model Index' }, params: () => ({ - mode: PD.MappedStatic('once', { - once: PD.Group({ direction: PD.Select('forward', [['forward', 'Forward'], ['backward', 'Backward']]) }, { isFlat: true }), + mode: PD.MappedStatic('palindrome', { palindrome: PD.Group({ }), loop: PD.Group({ }), - }, { options: [['once', 'Once'], ['palindrome', 'Palindrome'], ['loop', 'Loop']] }), - maxFPS: PD.Numeric(3, { min: 0.5, max: 30, step: 0.5 }) + once: PD.Group({ direction: PD.Select('palindrome', [['forward', 'Forward'], ['backward', 'Backward']]) }, { isFlat: true }) + }, { options: [['palindrome', 'Palindrome'], ['loop', 'Loop'], ['once', 'Once']] }), + maxFPS: PD.Numeric(15, { min: 1, max: 30, step: 1 }) }), initialState: () => ({} as { palindromeDirections?: { [id: string]: -1 | 1 | undefined } }), async apply(animState, t, ctx) { diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 622dc32fa44cd123ee3bbc8784bc96654b3bc5d5..7131485bb751aeeee4d9e558c9cfc47013e158cf 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -154,12 +154,12 @@ const StructureAssemblyFromModel = PluginStateTransform.BuiltIn({ if (model.symmetry.assemblies.length === 0) { if (id !== 'deposited') { - plugin.log.warn(`Model '${a.label}' has no assembly, returning deposited structure.`); + plugin.log.warn(`Model '${a.data.label}' has no assembly, returning deposited structure.`); } } else { asm = ModelSymmetry.findAssembly(model, id || ''); if (!asm) { - plugin.log.warn(`Model '${a.label}' has no assembly called '${id}', returning deposited structure.`); + plugin.log.warn(`Model '${a.data.label}' has no assembly called '${id}', returning deposited structure.`); } } diff --git a/src/mol-plugin/ui/plugin.tsx b/src/mol-plugin/ui/plugin.tsx index 1a2b0615822f95389d9175161478dd34bce634d0..3d0e774ce039ac0117a4a6a6143fcd0b98a76fc1 100644 --- a/src/mol-plugin/ui/plugin.tsx +++ b/src/mol-plugin/ui/plugin.tsx @@ -53,15 +53,15 @@ class Layout extends PluginUIComponent { render() { const layout = this.plugin.layout.state; - const spec = this.plugin.spec.layout && this.plugin.spec.layout.controls; + const controls = (this.plugin.spec.layout && this.plugin.spec.layout.controls) || { }; return <div className='msp-plugin'> <div className={`msp-plugin-content ${layout.isExpanded ? 'msp-layout-expanded' : 'msp-layout-standard msp-layout-standard-outside'}`}> <div className={layout.showControls ? 'msp-layout-hide-top' : 'msp-layout-hide-top msp-layout-hide-right msp-layout-hide-bottom msp-layout-hide-left'}> {this.region('main', ViewportWrapper)} - {layout.showControls && spec && spec.left !== 'none' && this.region('left', (spec && spec.left) || State)} - {layout.showControls && spec && spec.right !== 'none' && this.region('right', (spec && spec.right) || ControlsWrapper)} - {layout.showControls && spec && spec.bottom !== 'none' && this.region('bottom', (spec && spec.bottom) || Log)} + {layout.showControls && controls.left !== 'none' && this.region('left', controls.left || State)} + {layout.showControls && controls.right !== 'none' && this.region('right', controls.right || ControlsWrapper)} + {layout.showControls && controls.bottom !== 'none' && this.region('bottom', controls.bottom || Log)} </div> </div> </div>;