Browse Source

mol-plugin-state: DataBuilder

David Sehnal 5 years ago
parent
commit
a5185b456c

+ 15 - 10
src/mol-plugin-state/actions/structure.ts

@@ -235,16 +235,16 @@ const DownloadStructure = StateAction.build({
     const createRepr = !params.source.params.structure.noRepresentation;
 
     if (downloadParams.length > 0 && asTrajectory) {
-        const traj = createSingleTrajectoryModel(downloadParams, state.build());
-        const struct = createStructure(traj, supportProps, src.params.structure.type);
+        const traj = await createSingleTrajectoryModel(plugin, state, downloadParams);
+        const struct = createStructure(state.build().to(traj), supportProps, src.params.structure.type);
         await state.updateTree(struct, { revertIfAborted: true }).runInContext(ctx);
         if (createRepr) {
             await plugin.structureRepresentation.manager.apply(struct.ref, plugin.structureRepresentation.manager.defaultProvider);
         }
     } else {
         for (const download of downloadParams) {
-            const data = state.build().toRoot().apply(StateTransforms.Data.Download, download, { state: { isGhost: true } });
-            const traj = createModelTree(data, format);
+            const data = await plugin.builders.data.download(download, { state: { isGhost: true } });
+            const traj = createModelTree(state.build().to(data), format);
 
             const struct = createStructure(traj, supportProps, src.params.structure.type);
             await state.updateTree(struct, { revertIfAborted: true }).runInContext(ctx);
@@ -264,16 +264,21 @@ function getDownloadParams(src: string, url: (id: string) => string, label: (id:
     return ret;
 }
 
-function createSingleTrajectoryModel(sources: StateTransformer.Params<Download>[], b: StateBuilder.Root) {
-    return b.toRoot()
-        .apply(StateTransforms.Data.DownloadBlob, {
-            sources: sources.map((src, i) => ({ id: '' + i, url: src.url, isBinary: src.isBinary })),
-            maxConcurrency: 6
-        }, { state: { isGhost: true } }).apply(StateTransforms.Data.ParseBlob, {
+async function createSingleTrajectoryModel(plugin: PluginContext, state: State, sources: StateTransformer.Params<Download>[]) {
+    const data = await plugin.builders.data.downloadBlob({
+        sources: sources.map((src, i) => ({ id: '' + i, url: src.url, isBinary: src.isBinary })),
+        maxConcurrency: 6
+    }, { state: { isGhost: true } });
+
+    const trajectory = state.build().to(data)
+        .apply(StateTransforms.Data.ParseBlob, {
             formats: sources.map((_, i) => ({ id: '' + i, format: 'cif' as 'cif' }))
         }, { state: { isGhost: true } })
         .apply(StateTransforms.Model.TrajectoryFromBlob)
         .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 });
+
+    await plugin.runTask(state.updateTree(trajectory, { revertIfAborted: true }));
+    return trajectory.selector;
 }
 
 export function createModelTree(b: StateBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>, format: StructureFormat = 'cif') {

+ 44 - 0
src/mol-plugin-state/builder/data.ts

@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { StateTransformer, StateTransform } from '../../mol-state';
+import { PluginContext } from '../../mol-plugin/context';
+import { Download, ReadFile, DownloadBlob, RawData } from '../transforms/data';
+import { getFileInfo } from '../../mol-util/file-info';
+
+export class DataBuilder {
+    private get dataState() {
+        return this.plugin.state.dataState;
+    }
+
+    async rawData(params: StateTransformer.Params<RawData>, options?: Partial<StateTransform.Options>) {
+        const data = this.dataState.build().toRoot().apply(RawData, params, options);
+        await this.plugin.runTask(this.dataState.updateTree(data));
+        return data.selector;
+    }
+
+    async download(params: StateTransformer.Params<Download>, options?: Partial<StateTransform.Options>) {
+        const data = this.dataState.build().toRoot().apply(Download, params, options);
+        await this.plugin.runTask(this.dataState.updateTree(data));
+        return data.selector;
+    }
+
+    async downloadBlob(params: StateTransformer.Params<DownloadBlob>, options?: Partial<StateTransform.Options>) {        
+        const data = this.dataState.build().toRoot().apply(DownloadBlob, params, options);
+        await this.plugin.runTask(this.dataState.updateTree(data));
+        return data.selector;
+    }
+
+    async readFile(params: StateTransformer.Params<ReadFile>, options?: Partial<StateTransform.Options>) {
+        const data = this.dataState.build().toRoot().apply(ReadFile, params, options);
+        const fileInfo = getFileInfo(params.file);
+        await this.plugin.runTask(this.dataState.updateTree(data));
+        return { data: data.selector, fileInfo };
+    }
+
+    constructor(public plugin: PluginContext) {
+    }
+}

+ 33 - 0
src/mol-plugin-state/transforms/data.ts

@@ -17,6 +17,7 @@ import * as CCP4 from '../../mol-io/reader/ccp4/parser'
 import * as DSN6 from '../../mol-io/reader/dsn6/parser'
 import * as PLY from '../../mol-io/reader/ply/parser'
 import { parsePsf } from '../../mol-io/reader/psf/parser';
+import { isTypedArray } from '../../mol-data/db/column-helpers';
 
 export { Download }
 type Download = typeof Download
@@ -95,6 +96,38 @@ const DownloadBlob = PluginStateTransform.BuiltIn({
     // }
 });
 
+export { RawData }
+type RawData = typeof RawData
+const RawData = PluginStateTransform.BuiltIn({
+    name: 'raw-data',
+    display: { name: 'Raw Data', description: 'Raw data supplied by value.' },
+    from: [SO.Root],
+    to: [SO.Data.String, SO.Data.Binary],
+    params: {
+        data: PD.Value<string | number[]>('', { isHidden: true }),
+        label: PD.Optional(PD.Text(''))
+    }
+})({
+    apply({ params: p }) {
+        return Task.create('Raw Data', async () => {
+            if (typeof p.data !== 'string' && isTypedArray(p.data)) {
+                throw new Error('Supplied binary data must be a plain array.');
+            }
+            return typeof p.data === 'string'
+                ? new SO.Data.String(p.data as string, { label: p.label ? p.label : 'String' })
+                : new SO.Data.Binary(new Uint8Array(p.data), { label: p.label ? p.label : 'Binary' });
+        });
+    },
+    update({ oldParams, newParams, b }) {
+        if (oldParams.data !== newParams.data) return StateTransformer.UpdateResult.Recreate;
+        if (oldParams.label !== newParams.label) {
+            b.label = newParams.label || b.label;
+            return StateTransformer.UpdateResult.Updated;
+        }
+        return StateTransformer.UpdateResult.Unchanged;
+    }
+});
+
 export { ReadFile }
 type ReadFile = typeof ReadFile
 const ReadFile = PluginStateTransform.BuiltIn({

+ 5 - 0
src/mol-plugin/context.ts

@@ -46,6 +46,7 @@ import { ViewportScreenshotHelper } from './util/viewport-screenshot';
 import { StructureRepresentationManager } from '../mol-plugin-state/representation/structure';
 import { CustomProperty } from '../mol-model-props/common/custom-property';
 import { PluginConfigManager } from './config';
+import { DataBuilder } from '../mol-plugin-state/builder/data';
 
 export class PluginContext {
     private disposed = false;
@@ -124,6 +125,10 @@ export class PluginContext {
         registry: new DataFormatRegistry()
     } as const
 
+    readonly builders = {
+        data: new DataBuilder(this)
+    };
+
     readonly customModelProperties = new CustomProperty.Registry<Model>();
     readonly customStructureProperties = new CustomProperty.Registry<Structure>();
     readonly customParamEditors = new Map<string, StateTransformParameters.Class>();