Browse Source

added file load button

Alexander Rose 7 years ago
parent
commit
40124be6a9

+ 35 - 13
src/apps/render-test/components/file-input.tsx

@@ -7,7 +7,7 @@
 import * as React from 'react'
 import { WithStyles } from 'material-ui/styles';
 import TextField from 'material-ui/TextField';
-// import FileUpload from '@material-ui/icons/FileUpload';
+import Button from 'material-ui/Button';
 
 import State from '../state'
 import Observer from './observer';
@@ -24,17 +24,39 @@ export default class FileInput extends Observer<{ state: State } & WithStyles, {
     render() {
         const { classes, state } = this.props;
 
-        return <TextField
-            label='PDB ID'
-            className={classes.textField}
-            disabled={this.state.loading}
-            margin='normal'
-            onChange={(event) => {
-                state.pdbId = event.target.value
-            }}
-            onKeyPress={(event) => {
-                if (event.key === 'Enter') state.loadPdbId()
-            }}
-        />
+        return <div>
+            <TextField
+                label='PDB ID'
+                className={classes.textField}
+                disabled={this.state.loading}
+                margin='normal'
+                onChange={(event) => {
+                    state.pdbId = event.target.value
+                }}
+                onKeyPress={(event) => {
+                    if (event.key === 'Enter') state.loadPdbId()
+                }}
+            />
+            <input
+                accept='*.cif'
+                className={classes.input}
+                id='button-file'
+                type='file'
+                onChange={(event) => {
+                    if (event.target.files) {
+                        state.loadFile(event.target.files[0])
+                    }
+                }}
+            />
+            <label htmlFor='button-file'>
+                <Button
+                    variant='raised'
+                    component='span'
+                    className={classes.button}
+                >
+                    Open CIF
+                </Button>
+            </label>
+        </div>
     }
 }

+ 22 - 9
src/apps/render-test/state.ts

@@ -17,10 +17,10 @@ import Spacefill, { SpacefillProps } from 'mol-geo/representation/structure/spac
 import Point, { PointProps } from 'mol-geo/representation/structure/point'
 
 import { Run } from 'mol-task'
-import { Symmetry } from 'mol-model/structure'
+import { Symmetry, Structure } from 'mol-model/structure'
 
 // import mcubes from './utils/mcubes'
-import { getStructuresFromPdbId, log } from './utils'
+import { getStructuresFromPdbId, getStructuresFromFile, log } from './utils'
 import { StructureRepresentation } from 'mol-geo/representation/structure';
 // import Cylinder from 'mol-geo/primitive/cylinder';
 
@@ -77,15 +77,11 @@ export default class State {
         this.viewer.animate()
     }
 
-    async loadPdbId () {
-        const { viewer, pdbId, loading } = this
+    async initStructure (structure: Structure) {
+        const { viewer, loading } = this
         viewer.clear()
 
-        if (pdbId.length !== 4) return
-        loading.next(true)
-
-        const structures = await getStructuresFromPdbId(pdbId)
-        const struct = await Run(Symmetry.buildAssembly(structures[0], '1'), log, 100)
+        const struct = await Run(Symmetry.buildAssembly(structure, '1'), log, 100)
 
         this.pointRepr = StructureRepresentation(Point)
         await Run(this.pointRepr.create(struct, this.getPointProps()), log, 100)
@@ -102,6 +98,23 @@ export default class State {
         loading.next(false)
     }
 
+    async loadFile (file: File) {
+        this.viewer.clear()
+        this.loading.next(true)
+
+        const structures = await getStructuresFromFile(file)
+        this.initStructure(structures[0])
+    }
+
+    async loadPdbId () {
+        this.viewer.clear()
+        if (this.pdbId.length !== 4) return
+        this.loading.next(true)
+
+        const structures = await getStructuresFromPdbId(this.pdbId)
+        this.initStructure(structures[0])
+    }
+
     async update () {
         if (!this.spacefillRepr) return
         await Run(this.spacefillRepr.update(this.getSpacefillProps()), log, 100)

+ 6 - 0
src/apps/render-test/ui.tsx

@@ -52,6 +52,12 @@ const styles: StyleRulesCallback = (theme: Theme) => ({
         marginRight: theme.spacing.unit,
         width: 200,
     },
+    button: {
+        margin: theme.spacing.unit,
+    },
+    input: {
+        display: 'none',
+    },
 } as any);
 
 const decorate = withStyles(styles);

+ 17 - 0
src/apps/render-test/utils/index.ts

@@ -24,4 +24,21 @@ export async function getStructuresFromPdbId(pdbid: string) {
     const data = await fetch(`https://files.rcsb.org/download/${pdbid}.cif`)
     const parsed = await parseCif(await data.text())
     return Structure.ofData({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) })
+}
+
+const readFileAsText = (file: File) => {
+    const fileReader = new FileReader()
+    return new Promise<string>((resolve, reject) => {
+        fileReader.onerror = () => {
+            fileReader.abort()
+            reject(new DOMException('Error parsing input file.'))
+        }
+        fileReader.onload = () => resolve(fileReader.result)
+        fileReader.readAsText(file)
+    })
+}
+
+export async function getStructuresFromFile(file: File) {
+    const parsed = await parseCif(await readFileAsText(file))
+    return Structure.ofData({ kind: 'mmCIF', data: CIF.schema.mmCIF(parsed.result.blocks[0]) })
 }