Skip to content
Snippets Groups Projects
Commit ca13c576 authored by Alexander Rose's avatar Alexander Rose
Browse files

wip, canvas example

parent 03dbb067
No related branches found
No related tags found
No related merge requests found
...@@ -5,9 +5,10 @@ ...@@ -5,9 +5,10 @@
*/ */
import Viewer from 'mol-view/viewer'; import Viewer from 'mol-view/viewer';
import { getCifFromUrl, getModelsFromMmcif } from './util'; import { getCifFromUrl, getModelsFromMmcif, getCifFromFile } from './util';
import { StructureView } from './structure-view'; import { StructureView } from './structure-view';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { CifBlock } from 'mol-io/reader/cif';
export class App { export class App {
viewer: Viewer viewer: Viewer
...@@ -31,11 +32,21 @@ export class App { ...@@ -31,11 +32,21 @@ export class App {
} }
} }
async loadPdbId(id: string, assemblyId?: string) { async loadCif(cif: CifBlock, assemblyId?: string) {
if (this.structureView) this.structureView.destroy()
const cif = await getCifFromUrl(`https://files.rcsb.org/download/${id}.cif`)
const models = await getModelsFromMmcif(cif) const models = await getModelsFromMmcif(cif)
this.structureView = await StructureView(this.viewer, models, { assemblyId }) this.structureView = await StructureView(this.viewer, models, { assemblyId })
this.pdbIdLoaded.next(this.structureView) this.pdbIdLoaded.next(this.structureView)
} }
async loadPdbId(id: string, assemblyId?: string) {
if (this.structureView) this.structureView.destroy()
const cif = await getCifFromUrl(`https://files.rcsb.org/download/${id}.cif`)
this.loadCif(cif, assemblyId)
}
async loadCifFile(file: File) {
if (this.structureView) this.structureView.destroy()
const cif = await getCifFromFile(file)
this.loadCif(cif)
}
} }
\ No newline at end of file
...@@ -35,9 +35,11 @@ export class AppComponent extends React.Component<AppProps, AppState> { ...@@ -35,9 +35,11 @@ export class AppComponent extends React.Component<AppProps, AppState> {
} }
componentDidMount() { componentDidMount() {
this.props.app.pdbIdLoaded.subscribe(() => this.setState({ this.props.app.pdbIdLoaded.subscribe((structureView) => {
this.setState({
structureView: this.props.app.structureView structureView: this.props.app.structureView
})) })
})
} }
render() { render() {
...@@ -49,8 +51,35 @@ export class AppComponent extends React.Component<AppProps, AppState> { ...@@ -49,8 +51,35 @@ export class AppComponent extends React.Component<AppProps, AppState> {
</div> </div>
<div style={{float: 'right', width: '25%', height: '100%'}}> <div style={{float: 'right', width: '25%', height: '100%'}}>
<div>
<span>Load PDB ID</span>
<input
type='text'
onKeyDown={e => {
if (e.keyCode === 13) {
const value = e.currentTarget.value.trim()
if (value) {
this.props.app.loadPdbId(value)
}
}
}}
/>
</div>
<div>
<span>Load CIF file</span>
<input
accept='*.cif'
type='file'
onChange={e => {
if (e.target.files) this.props.app.loadCifFile(e.target.files[0])
}}
/>
</div>
<hr/>
<div>
{structureView ? <StructureViewComponent structureView={structureView} /> : ''} {structureView ? <StructureViewComponent structureView={structureView} /> : ''}
</div> </div>
</div>
</div>; </div>;
} }
} }
\ No newline at end of file
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
import * as React from 'react' import * as React from 'react'
import { StructureRepresentation, StructureProps } from 'mol-geo/representation/structure'; import { StructureRepresentation, StructureProps } from 'mol-geo/representation/structure';
import Viewer from 'mol-view/viewer'; import Viewer from 'mol-view/viewer';
import { VisualQuality } from 'mol-geo/representation/util'; import { VisualQuality, VisualQualityNames } from 'mol-geo/representation/util';
import { ColorThemeProps, ColorThemeName, ColorThemeNames } from 'mol-view/theme/color';
export interface StructureRepresentationComponentProps { export interface StructureRepresentationComponentProps {
viewer: Viewer viewer: Viewer
...@@ -18,6 +19,7 @@ export interface StructureRepresentationComponentState { ...@@ -18,6 +19,7 @@ export interface StructureRepresentationComponentState {
label: string label: string
visible: boolean visible: boolean
quality: VisualQuality quality: VisualQuality
colorTheme: ColorThemeProps
} }
export class StructureRepresentationComponent extends React.Component<StructureRepresentationComponentProps, StructureRepresentationComponentState> { export class StructureRepresentationComponent extends React.Component<StructureRepresentationComponentProps, StructureRepresentationComponentState> {
...@@ -25,6 +27,7 @@ export class StructureRepresentationComponent extends React.Component<StructureR ...@@ -25,6 +27,7 @@ export class StructureRepresentationComponent extends React.Component<StructureR
label: this.props.representation.label, label: this.props.representation.label,
visible: this.props.representation.props.visible, visible: this.props.representation.props.visible,
quality: this.props.representation.props.quality, quality: this.props.representation.props.quality,
colorTheme: this.props.representation.props.colorTheme,
} }
componentWillMount() { componentWillMount() {
...@@ -35,6 +38,7 @@ export class StructureRepresentationComponent extends React.Component<StructureR ...@@ -35,6 +38,7 @@ export class StructureRepresentationComponent extends React.Component<StructureR
label: repr.label, label: repr.label,
visible: repr.props.visible, visible: repr.props.visible,
quality: repr.props.quality, quality: repr.props.quality,
colorTheme: repr.props.colorTheme,
}) })
} }
...@@ -44,6 +48,7 @@ export class StructureRepresentationComponent extends React.Component<StructureR ...@@ -44,6 +48,7 @@ export class StructureRepresentationComponent extends React.Component<StructureR
if (state.visible !== undefined) props.visible = state.visible if (state.visible !== undefined) props.visible = state.visible
if (state.quality !== undefined) props.quality = state.quality if (state.quality !== undefined) props.quality = state.quality
if (state.colorTheme !== undefined) props.colorTheme = state.colorTheme
await repr.createOrUpdate(props).run() await repr.createOrUpdate(props).run()
this.props.viewer.add(repr) this.props.viewer.add(repr)
...@@ -52,13 +57,14 @@ export class StructureRepresentationComponent extends React.Component<StructureR ...@@ -52,13 +57,14 @@ export class StructureRepresentationComponent extends React.Component<StructureR
const newState = { const newState = {
...this.state, ...this.state,
visible: repr.props.visible, visible: repr.props.visible,
quality: repr.props.quality quality: repr.props.quality,
colorTheme: repr.props.colorTheme,
} }
this.setState(newState) this.setState(newState)
} }
render() { render() {
const { label, visible, quality } = this.state const { label, visible, quality, colorTheme } = this.state
return <div> return <div>
<div> <div>
...@@ -74,12 +80,13 @@ export class StructureRepresentationComponent extends React.Component<StructureR ...@@ -74,12 +80,13 @@ export class StructureRepresentationComponent extends React.Component<StructureR
<div> <div>
<span>Quality</span> <span>Quality</span>
<select value={quality} onChange={(e) => this.update({ quality: e.target.value as VisualQuality }) }> <select value={quality} onChange={(e) => this.update({ quality: e.target.value as VisualQuality }) }>
<option value='auto'>auto</option> {VisualQualityNames.map(name => <option key={name} value={name}>{name}</option>)}
<option value='lowest'>lowest</option> </select>
<option value='low'>low</option> </div>
<option value='medium'>medium</option> <div>
<option value='high'>high</option> <span>Color Theme</span>
<option value='highest'>highest</option> <select value={colorTheme.name} onChange={(e) => this.update({ colorTheme: { name: e.target.value as ColorThemeName } }) }>
{ColorThemeNames.map(name => <option key={name} value={name}>{name}</option>)}
</select> </select>
</div> </div>
</div> </div>
......
...@@ -25,6 +25,8 @@ export interface StructureViewComponentProps { ...@@ -25,6 +25,8 @@ export interface StructureViewComponentProps {
} }
export interface StructureViewComponentState { export interface StructureViewComponentState {
structureView: StructureView
label: string label: string
modelId: number modelId: number
modelIds: { id: number, label: string }[] modelIds: { id: number, label: string }[]
...@@ -38,24 +40,12 @@ export interface StructureViewComponentState { ...@@ -38,24 +40,12 @@ export interface StructureViewComponentState {
} }
export class StructureViewComponent extends React.Component<StructureViewComponentProps, StructureViewComponentState> { export class StructureViewComponent extends React.Component<StructureViewComponentProps, StructureViewComponentState> {
state = { state = this.stateFromStructureView(this.props.structureView)
label: this.props.structureView.label,
modelId: this.props.structureView.modelId,
modelIds: this.props.structureView.getModelIds(),
assemblyId: this.props.structureView.assemblyId,
assemblyIds: this.props.structureView.getAssemblyIds(),
symmetryFeatureId: this.props.structureView.symmetryFeatureId,
symmetryFeatureIds: this.props.structureView.getSymmetryFeatureIds(),
active: this.props.structureView.active,
structureRepresentations: this.props.structureView.structureRepresentations
}
componentWillMount() { private stateFromStructureView(sv: StructureView) {
const sv = this.props.structureView return {
structureView: sv,
this.setState({
...this.state,
label: sv.label, label: sv.label,
modelId: sv.modelId, modelId: sv.modelId,
modelIds: sv.getModelIds(), modelIds: sv.getModelIds(),
...@@ -66,7 +56,11 @@ export class StructureViewComponent extends React.Component<StructureViewCompone ...@@ -66,7 +56,11 @@ export class StructureViewComponent extends React.Component<StructureViewCompone
active: sv.active, active: sv.active,
structureRepresentations: sv.structureRepresentations structureRepresentations: sv.structureRepresentations
}) }
}
componentWillMount() {
this.setState(this.stateFromStructureView(this.props.structureView))
} }
componentDidMount() { componentDidMount() {
...@@ -78,33 +72,29 @@ export class StructureViewComponent extends React.Component<StructureViewCompone ...@@ -78,33 +72,29 @@ export class StructureViewComponent extends React.Component<StructureViewCompone
})) }))
} }
async update(state: Partial<StructureViewComponentState>) { componentWillReceiveProps(nextProps: StructureViewComponentProps) {
const sv = this.props.structureView if (nextProps.structureView !== this.props.structureView) {
this.setState(this.stateFromStructureView(nextProps.structureView))
console.log(state) nextProps.structureView.updated.subscribe(() => this.setState({
symmetryFeatureIds: nextProps.structureView.getSymmetryFeatureIds(),
structureRepresentations: nextProps.structureView.structureRepresentations
}))
}
}
async update(state: Partial<StructureViewComponentState>) {
const sv = this.state.structureView
if (state.modelId !== undefined) await sv.setModel(state.modelId) if (state.modelId !== undefined) await sv.setModel(state.modelId)
if (state.assemblyId !== undefined) await sv.setAssembly(state.assemblyId) if (state.assemblyId !== undefined) await sv.setAssembly(state.assemblyId)
if (state.symmetryFeatureId !== undefined) await sv.setSymmetryFeature(state.symmetryFeatureId) if (state.symmetryFeatureId !== undefined) await sv.setSymmetryFeature(state.symmetryFeatureId)
const newState = { this.setState(this.stateFromStructureView(sv))
...this.state,
label: sv.label,
modelId: sv.modelId,
modelIds: sv.getModelIds(),
assemblyId: sv.assemblyId,
assemblyIds: sv.getAssemblyIds(),
symmetryFeatureId: sv.symmetryFeatureId,
symmetryFeatureIds: sv.getSymmetryFeatureIds(),
active: sv.active,
structureRepresentations: sv.structureRepresentations
}
this.setState(newState)
} }
render() { render() {
const { label, modelIds, assemblyIds, symmetryFeatureIds, active, structureRepresentations } = this.state const { structureView, label, modelIds, assemblyIds, symmetryFeatureIds, active, structureRepresentations } = this.state
const modelIdOptions = modelIds.map(m => { const modelIdOptions = modelIds.map(m => {
return <option key={m.id} value={m.id}>{m.label}</option> return <option key={m.id} value={m.id}>{m.label}</option>
...@@ -172,7 +162,7 @@ export class StructureViewComponent extends React.Component<StructureViewCompone ...@@ -172,7 +162,7 @@ export class StructureViewComponent extends React.Component<StructureViewCompone
type='checkbox' type='checkbox'
checked={active[k]} checked={active[k]}
onChange={(e) => { onChange={(e) => {
const sv = this.props.structureView const sv = structureView
if (k === 'symmetryAxes') { if (k === 'symmetryAxes') {
sv.setSymmetryAxes(e.target.checked) sv.setSymmetryAxes(e.target.checked)
} else if (Object.keys(sv.structureRepresentations).includes(k)) { } else if (Object.keys(sv.structureRepresentations).includes(k)) {
...@@ -190,7 +180,7 @@ export class StructureViewComponent extends React.Component<StructureViewCompone ...@@ -190,7 +180,7 @@ export class StructureViewComponent extends React.Component<StructureViewCompone
return <div key={i}> return <div key={i}>
<StructureRepresentationComponent <StructureRepresentationComponent
representation={structureRepresentations[k]} representation={structureRepresentations[k]}
viewer={this.props.structureView.viewer} viewer={structureView.viewer}
/> />
</div> </div>
} else { } else {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
*/ */
import CIF, { CifBlock } from 'mol-io/reader/cif' import CIF, { CifBlock } from 'mol-io/reader/cif'
import { readUrlAs } from 'mol-util/read'; import { readUrlAs, readFileAs } from 'mol-util/read';
import { Model, Format, StructureSymmetry, Structure } from 'mol-model/structure'; import { Model, Format, StructureSymmetry, Structure } from 'mol-model/structure';
// import { parse as parseObj } from 'mol-io/reader/obj/parser' // import { parse as parseObj } from 'mol-io/reader/obj/parser'
...@@ -17,14 +17,21 @@ import { Model, Format, StructureSymmetry, Structure } from 'mol-model/structure ...@@ -17,14 +17,21 @@ import { Model, Format, StructureSymmetry, Structure } from 'mol-model/structure
// return parsed.result // return parsed.result
// } // }
export async function getCifFromUrl(url: string) { export async function getCifFromData(data: string | Uint8Array) {
const data = await readUrlAs(url, false)
const comp = CIF.parse(data) const comp = CIF.parse(data)
const parsed = await comp.run() const parsed = await comp.run()
if (parsed.isError) throw parsed if (parsed.isError) throw parsed
return parsed.result.blocks[0] return parsed.result.blocks[0]
} }
export async function getCifFromUrl(url: string) {
return getCifFromData(await readUrlAs(url, false))
}
export async function getCifFromFile(file: File, binary = false) {
return getCifFromData(await readFileAs(file, binary))
}
export async function getModelsFromMmcif(cif: CifBlock) { export async function getModelsFromMmcif(cif: CifBlock) {
return await Model.create(Format.mmCIF(cif)).run() return await Model.create(Format.mmCIF(cif)).run()
} }
......
...@@ -131,6 +131,7 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu ...@@ -131,6 +131,7 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
} else { } else {
if (group && !areGroupsIdentical(group, currentGroup)) { if (group && !areGroupsIdentical(group, currentGroup)) {
currentGroup = group currentGroup = group
currentProps.colorTheme.structure = currentStructure
} }
await update(ctx, props) await update(ctx, props)
} }
......
...@@ -84,7 +84,17 @@ export function updateRenderableState(state: RenderableState, props: Required<Ba ...@@ -84,7 +84,17 @@ export function updateRenderableState(state: RenderableState, props: Required<Ba
state.depthMask = props.depthMask state.depthMask = props.depthMask
} }
export type VisualQuality = 'custom' | 'auto' | 'highest' | 'high' | 'medium' | 'low' | 'lowest' export const VisualQualityInfo = {
'custom': {},
'auto': {},
'highest': {},
'high': {},
'medium': {},
'low': {},
'lowest': {},
}
export type VisualQuality = keyof typeof VisualQualityInfo
export const VisualQualityNames = Object.keys(VisualQualityInfo)
export interface QualityProps { export interface QualityProps {
quality: VisualQuality quality: VisualQuality
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment