diff --git a/src/apps/render-test/components/assemblies.tsx b/src/apps/render-test/components/assemblies.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ab0bae997994a229b33d5ac3419e72e484f218f9 --- /dev/null +++ b/src/apps/render-test/components/assemblies.tsx @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import * as React from 'react' +import { WithStyles } from 'material-ui/styles'; +import { MenuItem } from 'material-ui/Menu'; +import { InputLabel } from 'material-ui/Input'; +import { FormControl } from 'material-ui/Form'; +import Select from 'material-ui/Select'; + +import State from '../state' +import Observer from './observer'; +import { Assembly } from 'mol-model/structure/model/properties/symmetry'; + +interface AssemblyState { + loading: boolean + assemblies: ReadonlyArray<Assembly> + value: string +} + +export default class Assemblies extends Observer<{ state: State } & WithStyles, AssemblyState> { + state: AssemblyState = { loading: false, assemblies: [], value: '' } + + componentDidMount() { + this.subscribe(this.props.state.loading, value => { + this.setState({ loading: value }); + }); + this.subscribe(this.props.state.model, value => { + this.setState({ assemblies: value ? value.symmetry.assemblies : [] }); + }); + this.subscribe(this.props.state.assembly, value => { + this.setState({ value }); + }); + } + + handleValueChange = (event: React.ChangeEvent<any>) => { + this.props.state.assembly.next(event.target.value) + } + + render() { + const { classes } = this.props; + + const items = this.state.assemblies.map((value, idx) => { + return <MenuItem key={idx} value={value.id}>{value.details}</MenuItem> + }) + + return <FormControl className={classes.formControl}> + <InputLabel htmlFor='assembly-value'>Assembly</InputLabel> + <Select + className={classes.selectField} + value={this.state.value} + onChange={this.handleValueChange} + inputProps={{ + name: 'value', + id: 'assembly-value', + }} + > + {items} + </Select> + </FormControl> + } +} \ No newline at end of file diff --git a/src/apps/render-test/components/color-theme.tsx b/src/apps/render-test/components/color-theme.tsx index 9f80a040225e12616fae4ca26f8ff61253de1678..701247c5db1bc0e2c0ed79caa486f711b2dc99ac 100644 --- a/src/apps/render-test/components/color-theme.tsx +++ b/src/apps/render-test/components/color-theme.tsx @@ -22,7 +22,7 @@ interface ColorThemeState { } export default class ColorTheme extends Observer<{ state: State } & WithStyles, ColorThemeState> { - state = { loading: false, name: 'element-symbol' as _ColorTheme, value: 0xFF0000 } + state: ColorThemeState = { loading: false, name: 'element-symbol' as _ColorTheme, value: 0xFF0000 } componentDidMount() { this.subscribe(this.props.state.loading, value => { diff --git a/src/apps/render-test/components/detail.tsx b/src/apps/render-test/components/detail.tsx index 65c5eb8e55732b4a54ff1a5e86d2399687935ccc..a53c64f826c6b77a33af5aeb258d90e00d53ab7c 100644 --- a/src/apps/render-test/components/detail.tsx +++ b/src/apps/render-test/components/detail.tsx @@ -20,7 +20,7 @@ interface DetailState { } export default class Detail extends Observer<{ state: State } & WithStyles, DetailState> { - state = { loading: false, value: 2 } + state: DetailState = { loading: false, value: 2 } componentDidMount() { this.subscribe(this.props.state.loading, value => { diff --git a/src/apps/render-test/components/visibility.tsx b/src/apps/render-test/components/visibility.tsx index 86f9e44227e7749d352a9ca9580ae99165c75e50..a93a9b123ba729f5488cfb159339f731cfc921c0 100644 --- a/src/apps/render-test/components/visibility.tsx +++ b/src/apps/render-test/components/visibility.tsx @@ -19,7 +19,7 @@ interface VisibilityState { } export default class Visibility extends Observer<{ state: State } & WithStyles, VisibilityState> { - state = { loading: false, spacefill: true, point: true } + state: VisibilityState = { loading: false, spacefill: true, point: true } componentDidMount() { this.subscribe(this.props.state.loading, value => { diff --git a/src/apps/render-test/state.ts b/src/apps/render-test/state.ts index 1682f2ed840c6543a2cf094dc2a737509d339d4e..74f6cd447869012965e2f13686421b9d660da27c 100644 --- a/src/apps/render-test/state.ts +++ b/src/apps/render-test/state.ts @@ -38,12 +38,14 @@ export type ColorTheme = keyof typeof ColorTheme export default class State { viewer: Viewer pdbId = '4cup' + model = new BehaviorSubject<Model | undefined>(undefined) initialized = new BehaviorSubject<boolean>(false) loading = new BehaviorSubject<boolean>(false) colorTheme = new BehaviorSubject<ColorTheme>('element-symbol') colorValue = new BehaviorSubject<Color>(0xFF4411) detail = new BehaviorSubject<number>(0) + assembly = new BehaviorSubject<string>('') pointVisibility = new BehaviorSubject<boolean>(true) spacefillVisibility = new BehaviorSubject<boolean>(true) @@ -55,6 +57,7 @@ export default class State { this.colorTheme.subscribe(() => this.update()) this.colorValue.subscribe(() => this.update()) this.detail.subscribe(() => this.update()) + this.assembly.subscribe(() => this.initStructure()) this.pointVisibility.subscribe(() => this.updateVisibility()) this.spacefillVisibility.subscribe(() => this.updateVisibility()) @@ -87,17 +90,28 @@ export default class State { this.viewer.animate() } - async initStructure (model: Model) { - const { viewer, loading } = this - viewer.clear() - + async getStructure () { + const model = this.model.getValue() + if (!model) return + const assembly = this.assembly.getValue() let structure: Structure const assemblies = model.symmetry.assemblies if (assemblies.length) { - structure = await Run(Symmetry.buildAssembly(Structure.ofModel(model), '1'), log, 100) + structure = await Run(Symmetry.buildAssembly(Structure.ofModel(model), assembly || '1'), log, 100) } else { structure = Structure.ofModel(model) } + return structure + } + + async initStructure () { + const { viewer, model } = this + if (!viewer || !model) return + + viewer.clear() + + const structure = await this.getStructure() + if (!structure) return this.pointRepr = StructureRepresentation(Point) await Run(this.pointRepr.create(structure, this.getPointProps()), log, 100) @@ -110,25 +124,25 @@ export default class State { this.updateVisibility() viewer.requestDraw() console.log(viewer.stats) + } - loading.next(false) + setModel(model: Model) { + this.model.next(model) + this.initStructure() + this.loading.next(false) } async loadFile (file: File) { this.viewer.clear() this.loading.next(true) - - const structures = await getModelFromFile(file) - this.initStructure(structures[0]) + this.setModel((await getModelFromFile(file))[0]) } async loadPdbId () { this.viewer.clear() if (this.pdbId.length !== 4) return this.loading.next(true) - - const structures = await getModelFromPdbId(this.pdbId) - this.initStructure(structures[0]) + this.setModel((await getModelFromPdbId(this.pdbId))[0]) } async update () { diff --git a/src/apps/render-test/ui.tsx b/src/apps/render-test/ui.tsx index 948a49d2f0d1133b5c48c0ab90bde9bc9a2ada71..2ae6b9fb9119ede88d9b85153527170fae851125 100644 --- a/src/apps/render-test/ui.tsx +++ b/src/apps/render-test/ui.tsx @@ -18,6 +18,7 @@ import FileInput from './components/file-input' import ColorTheme from './components/color-theme' import Detail from './components/detail' import Visibility from './components/visibility' +import Assemblies from './components/assemblies' const styles: StyleRulesCallback = (theme: Theme) => ({ @@ -83,6 +84,7 @@ class UI extends React.Component<{ state: State } & WithStyles, { }> { <FileInput state={state} classes={classes}></FileInput> <form className={classes.root} autoComplete='off'> <div> + <Assemblies state={state} classes={classes}></Assemblies> <ColorTheme state={state} classes={classes}></ColorTheme> <Detail state={state} classes={classes}></Detail> <Visibility state={state} classes={classes}></Visibility>