diff --git a/package.json b/package.json index 531f60c9193d20ca9a1fff0d9c0117874c172c19..ecdd2c6f7f75598a35e945491e0a491b2c30d118 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,6 @@ "test": "jest", "build-viewer": "webpack build/node_modules/apps/viewer/index.js --mode development -o build/viewer/index.js", "watch-viewer": "webpack build/node_modules/apps/viewer/index.js -w --mode development -o build/viewer/index.js", - "build-canvas": "webpack build/node_modules/apps/canvas/index.js --mode development -o build/canvas/index.js", - "watch-canvas": "webpack build/node_modules/apps/canvas/index.js -w --mode development -o build/canvas/index.js", "build-ms-query": "webpack build/node_modules/apps/model-server-query/index.js --mode development -o build/model-server-query/index.js", "watch-ms-query": "webpack build/node_modules/apps/model-server-query/index.js -w --mode development -o build/model-server-query/index.js", "model-server": "node build/node_modules/servers/model/server.js", diff --git a/src/apps/canvas/app.ts b/src/apps/canvas/app.ts deleted file mode 100644 index 2dd92e472497572264c5a63c230c2199aeb5766d..0000000000000000000000000000000000000000 --- a/src/apps/canvas/app.ts +++ /dev/null @@ -1,146 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { Canvas3D } from 'mol-canvas3d/canvas3d'; -import { getCifFromUrl, getModelsFromMmcif, getCifFromFile, getCcp4FromUrl, getVolumeFromCcp4, getCcp4FromFile, getVolumeFromVolcif } from './util'; -import { StructureView } from './structure-view'; -import { BehaviorSubject } from 'rxjs'; -import { CifBlock } from 'mol-io/reader/cif'; -import { VolumeView } from './volume-view'; -import { Ccp4File } from 'mol-io/reader/ccp4/schema'; -import { Progress } from 'mol-task'; -import { ColorTheme } from 'mol-theme/color'; -import { SizeTheme } from 'mol-theme/size'; -import { StructureRepresentationRegistry } from 'mol-repr/structure/registry'; -import { VolumeRepresentationRegistry } from 'mol-repr/volume/registry'; - -export class App { - canvas3d: Canvas3D - container: HTMLDivElement | null = null; - canvas: HTMLCanvasElement | null = null; - structureView: StructureView | null = null; - volumeView: VolumeView | null = null; - - structureLoaded: BehaviorSubject<StructureView | null> = new BehaviorSubject<StructureView | null>(null) - volumeLoaded: BehaviorSubject<VolumeView | null> = new BehaviorSubject<VolumeView | null>(null) - - colorThemeRegistry = new ColorTheme.Registry() - sizeThemeRegistry = new SizeTheme.Registry() - structureRepresentationRegistry = new StructureRepresentationRegistry() - volumeRepresentationRegistry = new VolumeRepresentationRegistry() - - initViewer(_canvas: HTMLCanvasElement, _container: HTMLDivElement) { - this.canvas = _canvas - this.container = _container - - try { - this.canvas3d = Canvas3D.create(this.canvas, this.container) - this.canvas3d.animate() - return true - } catch (e) { - console.error(e) - return false - } - } - - setStatus(msg: string) { - - } - - private taskCount = 0 - taskCountChanged = new BehaviorSubject({ count: 0, info: '' }) - - private changeTaskCount(delta: number, info = '') { - this.taskCount += delta - this.taskCountChanged.next({ count: this.taskCount, info }) - } - - async runTask<T>(promise: Promise<T>, info: string) { - this.changeTaskCount(1, info) - let result: T - try { - result = await promise - } finally { - this.changeTaskCount(-1) - } - return result - } - - log(progress: Progress) { - console.log(Progress.format(progress)) - } - - get reprCtx () { - return { - webgl: this.canvas3d.webgl, - colorThemeRegistry: this.colorThemeRegistry, - sizeThemeRegistry: this.sizeThemeRegistry - } - } - - // - - async loadMmcif(cif: CifBlock, assemblyId?: string) { - const models = await this.runTask(getModelsFromMmcif(cif), 'Build models') - this.structureView = await this.runTask(StructureView(this, this.canvas3d, models, { assemblyId }), 'Init structure view') - this.structureLoaded.next(this.structureView) - } - - async loadPdbIdOrMmcifUrl(idOrUrl: string, options?: { assemblyId?: string, binary?: boolean }) { - if (this.structureView) this.structureView.destroy(); - const url = idOrUrl.length <= 4 ? `https://files.rcsb.org/download/${idOrUrl}.cif` : idOrUrl; - const cif = await this.runTask(getCifFromUrl(url, options ? !!options.binary : false), 'Load mmCIF from URL') - this.loadMmcif(cif.blocks[0], options ? options.assemblyId : void 0) - } - - async loadMmcifFile(file: File) { - if (this.structureView) this.structureView.destroy(); - const binary = /\.bcif$/.test(file.name); - const cif = await this.runTask(getCifFromFile(file, binary), 'Load mmCIF from file') - this.loadMmcif(cif.blocks[0]) - } - - // - - async loadCcp4(ccp4: Ccp4File) { - const volume = await this.runTask(getVolumeFromCcp4(ccp4), 'Get Volume') - this.volumeView = await this.runTask(VolumeView(this, this.canvas3d, volume), 'Init volume view') - this.volumeLoaded.next(this.volumeView) - } - - async loadCcp4File(file: File) { - if (this.volumeView) this.volumeView.destroy(); - const ccp4 = await this.runTask(getCcp4FromFile(file), 'Load CCP4 from file') - this.loadCcp4(ccp4) - } - - async loadCcp4Url(url: string) { - if (this.volumeView) this.volumeView.destroy(); - const ccp4 = await this.runTask(getCcp4FromUrl(url), 'Load CCP4 from URL') - this.loadCcp4(ccp4) - } - - // - - async loadVolcif(cif: CifBlock) { - const volume = await this.runTask(getVolumeFromVolcif(cif), 'Get Volume') - this.volumeView = await this.runTask(VolumeView(this, this.canvas3d, volume), 'Init volume view') - this.volumeLoaded.next(this.volumeView) - } - - async loadVolcifFile(file: File) { - if (this.volumeView) this.volumeView.destroy(); - const binary = /\.bcif$/.test(file.name); - const cif = await this.runTask(getCifFromFile(file, binary), 'Load volCif from file') - this.loadVolcif(cif.blocks[1]) - } - - async loadVolcifUrl(url: string, binary?: boolean) { - if (this.volumeView) this.volumeView.destroy(); - const cif = await this.runTask(getCifFromUrl(url, binary), 'Load volCif from URL') - this.loadVolcif(cif.blocks[1]) - } -} \ No newline at end of file diff --git a/src/apps/canvas/assembly-symmetry.ts b/src/apps/canvas/assembly-symmetry.ts deleted file mode 100644 index e43357c196bd3f16120d60250bd10f502ce5f4e0..0000000000000000000000000000000000000000 --- a/src/apps/canvas/assembly-symmetry.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { AssemblySymmetry } from 'mol-model-props/rcsb/symmetry'; -import { Table } from 'mol-data/db'; -import { Color, ColorScale } from 'mol-util/color'; -import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; -import { Tensor } from 'mol-math/linear-algebra'; -import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere'; -import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder'; -import { Shape } from 'mol-model/shape'; -import { ColorTheme } from 'mol-theme/color'; -import { Location } from 'mol-model/location'; -import { StructureElement, Unit, StructureProperties } from 'mol-model/structure'; - -export function getAxesShape(symmetryId: number, assemblySymmetry: AssemblySymmetry) { - const s = assemblySymmetry.db.rcsb_assembly_symmetry - const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId) - if (!symmetry) return - - const axes = assemblySymmetry.getAxes(symmetryId) - if (!axes._rowCount) return - - const vectorSpace = AssemblySymmetry.Schema.rcsb_assembly_symmetry_axis.start.space; - - const colors: Color[] = [] - const labels: string[] = [] - - const radius = 0.4 - const cylinderProps = { radiusTop: radius, radiusBottom: radius } - const meshBuilder = MeshBuilder.create(256, 128) - - for (let i = 0, il = axes._rowCount; i < il; ++i) { - const start = Tensor.toVec3(vectorSpace, axes.start.value(i)) - const end = Tensor.toVec3(vectorSpace, axes.end.value(i)) - meshBuilder.setGroup(i) - addSphere(meshBuilder, start, radius, 2) - addSphere(meshBuilder, end, radius, 2) - addCylinder(meshBuilder, start, end, 1, cylinderProps) - colors.push(Color(0xCCEE11)) - labels.push(`Axis ${i + 1} for ${symmetry.kind} ${symmetry.type.toLowerCase()} symmetry`) - } - const mesh = meshBuilder.getMesh() - const shape = Shape.create('Axes', mesh, colors, labels) - return shape -} - -function getAsymId(unit: Unit): StructureElement.Property<string> { - switch (unit.kind) { - case Unit.Kind.Atomic: - return StructureProperties.chain.label_asym_id - case Unit.Kind.Spheres: - case Unit.Kind.Gaussians: - return StructureProperties.coarse.asym_id - } -} - -function clusterMemberKey (asym_id: string, oper_list_ids: string[]) { - return `${asym_id}-${oper_list_ids.join('x')}` -} - -export function getClusterColorTheme(symmetryId: number, assemblySymmetry: AssemblySymmetry): ColorTheme { - const DefaultColor = Color(0xCCCCCC) - const s = assemblySymmetry.db.rcsb_assembly_symmetry - const symmetry = Table.pickRow(s, i => s.id.value(i) === symmetryId) - if (!symmetry) return { granularity: 'uniform', color: () => DefaultColor, props: {} } - - const clusters = assemblySymmetry.getClusters(symmetryId) - if (!clusters._rowCount) return { granularity: 'uniform', color: () => DefaultColor, props: {} } - - const clusterByMember = new Map<string, number>() - for (let i = 0, il = clusters._rowCount; i < il; ++i) { - const clusterMembers = assemblySymmetry.getClusterMembers(clusters.id.value(i)) - for (let j = 0, jl = clusterMembers._rowCount; j < jl; ++j) { - const asym_id = clusterMembers.asym_id.value(j) - const oper_list_ids = clusterMembers.pdbx_struct_oper_list_ids.value(j) - clusterByMember.set(clusterMemberKey(asym_id, oper_list_ids), i) - } - } - const scale = ColorScale.create({ domain: [ 0, clusters._rowCount - 1 ] }) - - return { - granularity: 'instance', - color: (location: Location): Color => { - if (StructureElement.isLocation(location)) { - const asym_id = getAsymId(location.unit) - const ns = location.unit.conformation.operator.name.split('-') - const oper_list_ids = ns.length === 2 ? ns[1].split('x') : [] - const cluster = clusterByMember.get(clusterMemberKey(asym_id(location), oper_list_ids)) - return cluster !== undefined ? scale.color(cluster) : DefaultColor - } - return DefaultColor - }, - props: {} - } -} \ No newline at end of file diff --git a/src/apps/canvas/component/app.tsx b/src/apps/canvas/component/app.tsx deleted file mode 100644 index 5d5c388507d29024e39d6c2a2fdd098f792c316a..0000000000000000000000000000000000000000 --- a/src/apps/canvas/component/app.tsx +++ /dev/null @@ -1,130 +0,0 @@ -/** - * 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 { StructureView } from '../structure-view'; -import { App } from '../app'; -import { Viewport } from './viewport'; -import { StructureViewComponent } from './structure-view'; -import { Examples } from '../examples'; -import { VolumeViewComponent } from './volume-view'; -import { VolumeView } from '../volume-view'; - -export interface AppProps { - app: App -} - -export interface AppState { - structureView: StructureView | null, - volumeView: VolumeView | null, - mmcifBinary: boolean, - volcifBinary: boolean -} - -export class AppComponent extends React.Component<AppProps, AppState> { - state = { - structureView: this.props.app.structureView, - volumeView: this.props.app.volumeView, - mmcifBinary: false, - volcifBinary: true - } - - componentDidMount() { - this.props.app.structureLoaded.subscribe((structureView) => { - this.setState({ structureView: this.props.app.structureView }) - }) - this.props.app.volumeLoaded.subscribe((volumeView) => { - this.setState({ volumeView: this.props.app.volumeView }) - }) - } - - render() { - const { structureView, volumeView } = this.state - - return <div style={{width: '100%', height: '100%'}}> - <div style={{left: '0px', right: '350px', height: '100%', position: 'absolute'}}> - <Viewport app={this.props.app} /> - </div> - - <div style={{width: '330px', paddingLeft: '10px', paddingRight: '10px', right: '0px', height: '100%', position: 'absolute', overflow: 'auto'}}> - <div style={{marginTop: '10px'}}> - <span>Load PDB ID or URL</span> - <input type='checkbox' checked={this.state.mmcifBinary} onChange={e => this.setState({ mmcifBinary: e.target.checked })} /> Binary<br /> - <input - style={{ width: '100%' }} - type='text' - onKeyDown={e => { - if (e.keyCode === 13) { - const value = e.currentTarget.value.trim() - if (value) { - this.props.app.loadPdbIdOrMmcifUrl(value, { binary: this.state.mmcifBinary }) - } - } - }} - /> - </div> - <div> - <span>Load CIF file </span> - <input - accept='*.cif' - type='file' - onChange={e => { - if (e.target.files) this.props.app.loadMmcifFile(e.target.files[0]) - }} - /> - </div> - <div> - <span>Load CCP4/MRC file </span> - <input - accept='*.ccp4,*.mrc, *.map' - type='file' - onChange={e => { - if (e.target.files) this.props.app.loadCcp4File(e.target.files[0]) - }} - /> - </div> - <div style={{marginTop: '10px'}}> - <span>Load DensityServer URL</span> - <input type='checkbox' checked={this.state.volcifBinary} onChange={e => this.setState({ volcifBinary: e.target.checked })} /> Binary<br /> - <input - style={{ width: '100%' }} - type='text' - onKeyDown={e => { - if (e.keyCode === 13) { - const value = e.currentTarget.value.trim() - if (value) { - this.props.app.loadVolcifUrl(value, this.state.volcifBinary) - } - } - }} - /> - </div> - <div> - <span>Load example </span> - <select - style={{width: '200px'}} - onChange={e => { - this.props.app.loadPdbIdOrMmcifUrl(e.target.value) - }} - > - <option value=''></option> - {Examples.map(({label, id, description}, i) => { - return <option key={i} value={id}>{`${label ? label : id} - ${description}`}</option> - })} - </select> - </div> - <hr/> - <div style={{marginBottom: '10px'}}> - {structureView ? <StructureViewComponent structureView={structureView} /> : ''} - </div> - <hr/> - <div style={{marginBottom: '10px'}}> - {volumeView ? <VolumeViewComponent volumeView={volumeView} /> : ''} - </div> - </div> - </div>; - } -} \ No newline at end of file diff --git a/src/apps/canvas/component/representation.tsx b/src/apps/canvas/component/representation.tsx deleted file mode 100644 index 7d395d5e9828882b9c26aa699339ef6a6acdac0d..0000000000000000000000000000000000000000 --- a/src/apps/canvas/component/representation.tsx +++ /dev/null @@ -1,68 +0,0 @@ -/** - * 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 { Canvas3D } from 'mol-canvas3d/canvas3d'; -import { App } from '../app'; -import { ParamDefinition as PD } from 'mol-util/param-definition'; -import { Representation } from 'mol-repr/representation'; -import { ParametersComponent } from 'mol-app/component/parameters'; - -export interface RepresentationComponentProps<P extends PD.Params> { - app: App - canvas3d: Canvas3D - repr: Representation<P> -} - -export interface RepresentationComponentState { - label: string - reprParams: PD.Params - reprProps: Readonly<{}> -} - -export class RepresentationComponent<P extends PD.Params> extends React.Component<RepresentationComponentProps<P>, RepresentationComponentState> { - - private stateFromRepr(repr: Representation<P>) { - return { - label: repr.label, - reprParams: repr.params, - reprProps: repr.props - } - } - - componentWillMount() { - this.setState(this.stateFromRepr(this.props.repr)) - } - - async onChange(k: string, v: any) { - await this.props.app.runTask(this.props.repr.createOrUpdate(this.props.app.reprCtx, { [k]: v }).run( - progress => this.props.app.log(progress) - ), 'Representation Update') - this.setState(this.stateFromRepr(this.props.repr)) - } - - render() { - const { label, reprParams, reprProps } = this.state - // let colorTheme: ColorTheme | undefined = undefined - // if ('colorTheme' in reprProps) { - // colorTheme = ColorTheme(getColorThemeProps(reprProps)) - // } - - return <div> - <div> - <h4>{label}</h4> - </div> - <div> - <ParametersComponent - params={reprParams} - values={reprProps} - onChange={(k, v) => this.onChange(k as string, v)} - /> - </div> - {/* { colorTheme !== undefined ? <ColorThemeComponent colorTheme={colorTheme} /> : '' } */} - </div>; - } -} \ No newline at end of file diff --git a/src/apps/canvas/component/structure-view.tsx b/src/apps/canvas/component/structure-view.tsx deleted file mode 100644 index 6cd0828674ea1d63321f71e07b944c023bfa8614..0000000000000000000000000000000000000000 --- a/src/apps/canvas/component/structure-view.tsx +++ /dev/null @@ -1,190 +0,0 @@ -/** - * 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 { StructureView } from '../structure-view'; -import { RepresentationComponent } from './representation'; -import { Representation } from 'mol-repr/representation'; -import { StructureRepresentation } from 'mol-repr/structure/representation'; - -export interface StructureViewComponentProps { - structureView: StructureView -} - -export interface StructureViewComponentState { - structureView: StructureView - - label: string - modelId: number - modelIds: { id: number, label: string }[] - assemblyId: string - assemblyIds: { id: string, label: string }[] - symmetryFeatureId: number - symmetryFeatureIds: { id: number, label: string }[] - - active: { [k: string]: boolean } - structureRepresentations: { [k: string]: StructureRepresentation<any> } -} - -export class StructureViewComponent extends React.Component<StructureViewComponentProps, StructureViewComponentState> { - state = this.stateFromStructureView(this.props.structureView) - - private stateFromStructureView(sv: StructureView) { - return { - structureView: sv, - - label: sv.label, - structure: sv.structure, - modelId: sv.modelId, - modelIds: sv.getModelIds(), - assemblyId: sv.assemblyId, - assemblyIds: sv.getAssemblyIds(), - symmetryFeatureId: sv.symmetryFeatureId, - symmetryFeatureIds: sv.getSymmetryFeatureIds(), - - active: sv.active, - structureRepresentations: sv.structureRepresentations - } - } - - componentWillMount() { - this.setState(this.stateFromStructureView(this.props.structureView)) - } - - componentDidMount() { - const sv = this.props.structureView - - this.props.structureView.updated.subscribe(() => this.setState({ - symmetryFeatureIds: sv.getSymmetryFeatureIds(), - structureRepresentations: sv.structureRepresentations - })) - } - - componentWillReceiveProps(nextProps: StructureViewComponentProps) { - if (nextProps.structureView !== this.props.structureView) { - this.setState(this.stateFromStructureView(nextProps.structureView)) - - 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.assemblyId !== undefined) await sv.setAssembly(state.assemblyId) - if (state.symmetryFeatureId !== undefined) await sv.setSymmetryFeature(state.symmetryFeatureId) - - this.setState(this.stateFromStructureView(sv)) - } - - render() { - const { structureView, label, modelIds, assemblyIds, symmetryFeatureIds, active, structureRepresentations } = this.state - - const modelIdOptions = modelIds.map(m => { - return <option key={m.id} value={m.id}>{m.label}</option> - }) - const assemblyIdOptions = assemblyIds.map(a => { - return <option key={a.id} value={a.id}>{a.label}</option> - }) - const symmetryFeatureIdOptions = symmetryFeatureIds.map(f => { - return <option key={f.id} value={f.id}>{f.label}</option> - }) - - return <div> - <div> - <h2>{label}</h2> - </div> - <div> - <div> - <span>Model </span> - <select - style={{width: '100px'}} - value={this.state.modelId} - onChange={(e) => { - this.update({ modelId: parseInt(e.target.value) }) - }} - > - {modelIdOptions} - </select> - <span> </span> - <input type='range' - defaultValue={this.state.modelId.toString()} - min={Math.min(...modelIds.map(m => m.id))} - max={Math.max(...modelIds.map(m => m.id))} - step='1' - onInput={(e) => { - this.update({ modelId: parseInt(e.currentTarget.value) }) - }} - > - </input> - </div> - <div> - <span>Assembly </span> - <select - style={{width: '150px'}} - value={this.state.assemblyId} - onChange={(e) => { - this.update({ assemblyId: e.target.value }) - }} - > - {assemblyIdOptions} - </select> - </div> - <div> - <span>Symmetry Feature </span> - <select - style={{width: '150px'}} - value={this.state.symmetryFeatureId} - onChange={(e) => { - this.update({ symmetryFeatureId: parseInt(e.target.value) }) - }} - > - {symmetryFeatureIdOptions} - </select> - </div> - <div> - <h4>Active</h4> - { Object.keys(active).map((k, i) => { - return <div key={i}> - <input - type='checkbox' - checked={active[k]} - onChange={(e) => { - const sv = structureView - if (k === 'symmetryAxes') { - sv.setSymmetryAxes(e.target.checked) - } else if (Object.keys(sv.structureRepresentations).includes(k)) { - sv.setStructureRepresentation(k, e.target.checked) - } - }} - /> {k} - </div> - } ) } - </div> - <div> - <h3>Structure Representations</h3> - { Object.keys(structureRepresentations).map((k, i) => { - if (active[k]) { - return <div key={i}> - <RepresentationComponent - repr={structureRepresentations[k] as Representation<any>} - canvas3d={structureView.canvas3d} - app={structureView.app} - /> - </div> - } else { - return '' - } - } ) } - </div> - </div> - </div>; - } -} \ No newline at end of file diff --git a/src/apps/canvas/component/viewport.tsx b/src/apps/canvas/component/viewport.tsx deleted file mode 100644 index ee235026150b35891dc4599336cc60f37e534931..0000000000000000000000000000000000000000 --- a/src/apps/canvas/component/viewport.tsx +++ /dev/null @@ -1,187 +0,0 @@ -/** - * 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 { App } from '../app'; -import { MarkerAction } from 'mol-geo/geometry/marker-data'; -import { EmptyLoci, Loci, areLociEqual } from 'mol-model/loci'; -import { labelFirst } from 'mol-theme/label'; -import { ButtonsType } from 'mol-util/input/input-observer'; -import { throttleTime } from 'rxjs/operators' -import { Camera } from 'mol-canvas3d/camera'; -import { ColorParamComponent } from 'mol-app/component/parameter/color'; -import { Color } from 'mol-util/color'; -import { ParamDefinition as PD } from 'mol-util/param-definition' - -interface ViewportProps { - app: App -} - -interface ViewportState { - noWebGl: boolean - pickingInfo: string - taskInfo: string - cameraMode: Camera.Mode - backgroundColor: Color -} - -const BackgroundColorParam = PD.Color(Color(0x000000), { label: 'Background Color' }) - -export class Viewport extends React.Component<ViewportProps, ViewportState> { - private container: HTMLDivElement | null = null; - private canvas: HTMLCanvasElement | null = null; - - state: ViewportState = { - noWebGl: false, - pickingInfo: '', - taskInfo: '', - cameraMode: 'perspective', - backgroundColor: Color(0x000000) - }; - - handleResize() { - this.props.app.canvas3d.handleResize() - } - - componentDidMount() { - if (!this.canvas || !this.container || !this.props.app.initViewer(this.canvas, this.container)) { - this.setState({ noWebGl: true }); - } - this.handleResize() - - this.setState({ - cameraMode: this.props.app.canvas3d.props.cameraMode, - backgroundColor: this.props.app.canvas3d.props.backgroundColor - }) - - const canvas3d = this.props.app.canvas3d - - canvas3d.input.resize.subscribe(() => this.handleResize()) - - let prevHighlightLoci: Loci = EmptyLoci - // TODO can the 'only ever have one extra element in the queue' functionality be done with rxjs? - let highlightQueueLength = 0 - canvas3d.input.move.pipe(throttleTime(50)).subscribe(async ({x, y, inside, buttons}) => { - if (!inside || buttons || highlightQueueLength > 2) return - ++highlightQueueLength - const p = await canvas3d.identify(x, y) - --highlightQueueLength - if (p) { - const { loci } = canvas3d.getLoci(p) - - if (!areLociEqual(loci, prevHighlightLoci)) { - canvas3d.mark(prevHighlightLoci, MarkerAction.RemoveHighlight) - canvas3d.mark(loci, MarkerAction.Highlight) - prevHighlightLoci = loci - - const label = labelFirst(loci) - const pickingInfo = `${label}` - this.setState({ pickingInfo }) - } - } - }) - - canvas3d.input.click.subscribe(async ({x, y, buttons}) => { - if (buttons !== ButtonsType.Flag.Primary) return - const p = await canvas3d.identify(x, y) - if (p) { - const { loci } = canvas3d.getLoci(p) - canvas3d.mark(loci, MarkerAction.Toggle) - } - }) - - this.props.app.taskCountChanged.subscribe(({ count, info }) => { - this.setState({ taskInfo: count > 0 ? info : '' }) - }) - } - - componentWillUnmount() { - if (super.componentWillUnmount) super.componentWillUnmount(); - // TODO viewer cleanup - } - - renderMissing() { - return <div> - <div> - <p><b>WebGL does not seem to be available.</b></p> - <p>This can be caused by an outdated browser, graphics card driver issue, or bad weather. Sometimes, just restarting the browser helps.</p> - <p>For a list of supported browsers, refer to <a href='http://caniuse.com/#feat=webgl' target='_blank'>http://caniuse.com/#feat=webgl</a>.</p> - </div> - </div> - } - - render() { - if (this.state.noWebGl) return this.renderMissing(); - - return <div style={{ backgroundColor: 'rgb(0, 0, 0)', width: '100%', height: '100%'}}> - <div ref={elm => this.container = elm} style={{width: '100%', height: '100%'}}> - <canvas ref={elm => this.canvas = elm}></canvas> - </div> - <div - style={{ - position: 'absolute', - top: 10, - left: 10, - padding: 10, - color: 'lightgrey', - background: 'rgba(0, 0, 0, 0.2)' - }} - > - {this.state.pickingInfo} - </div> - <div - style={{ - position: 'absolute', - bottom: 10, - right: 10, - padding: 10, - color: 'lightgrey', - background: 'rgba(0, 0, 0, 0.2)' - }} - > - <div> - <span>Camera Mode </span> - <select - value={this.state.cameraMode} - style={{width: '150'}} - onChange={e => { - const p = { cameraMode: e.target.value as Camera.Mode } - this.props.app.canvas3d.setProps(p) - this.setState(p) - }} - > - <option value='perspective'>Perspective</option> - <option value='orthographic'>Orthographic</option> - </select> - </div> - <ColorParamComponent - label={BackgroundColorParam.label || ''} - param={BackgroundColorParam} - value={this.state.backgroundColor} - onChange={value => { - const p = { backgroundColor: value } - this.props.app.canvas3d.setProps(p) - this.setState(p) - }} - /> - </div> - { this.state.taskInfo ? - <div - style={{ - position: 'absolute', - top: 10, - right: 10, - padding: 10, - color: 'lightgrey', - background: 'rgba(0, 0, 0, 0.2)' - }} - > - {this.state.taskInfo} - </div> - : '' } - </div>; - } -} \ No newline at end of file diff --git a/src/apps/canvas/component/volume-view.tsx b/src/apps/canvas/component/volume-view.tsx deleted file mode 100644 index 6a9f309612f8ac006a8aff94e8f7d403e197c9f6..0000000000000000000000000000000000000000 --- a/src/apps/canvas/component/volume-view.tsx +++ /dev/null @@ -1,105 +0,0 @@ -/** - * 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 { RepresentationComponent } from './representation'; -import { Representation } from 'mol-repr/representation'; -import { VolumeView } from '../volume-view'; -import { VolumeRepresentation } from 'mol-repr/volume/representation'; - -export interface VolumeViewComponentProps { - volumeView: VolumeView -} - -export interface VolumeViewComponentState { - volumeView: VolumeView - label: string - active: { [k: string]: boolean } - volumeRepresentations: { [k: string]: VolumeRepresentation<any> } -} - -export class VolumeViewComponent extends React.Component<VolumeViewComponentProps, VolumeViewComponentState> { - state = this.stateFromVolumeView(this.props.volumeView) - - private stateFromVolumeView(vv: VolumeView) { - return { - volumeView: vv, - label: vv.label, - volume: vv.volume, - active: vv.active, - volumeRepresentations: vv.volumeRepresentations - } - } - - componentWillMount() { - this.setState(this.stateFromVolumeView(this.props.volumeView)) - } - - componentDidMount() { - const vv = this.props.volumeView - - this.props.volumeView.updated.subscribe(() => this.setState({ - volumeRepresentations: vv.volumeRepresentations - })) - } - - componentWillReceiveProps(nextProps: VolumeViewComponentProps) { - if (nextProps.volumeView !== this.props.volumeView) { - this.setState(this.stateFromVolumeView(nextProps.volumeView)) - - nextProps.volumeView.updated.subscribe(() => this.setState({ - volumeRepresentations: nextProps.volumeView.volumeRepresentations - })) - } - } - - // async update(state: Partial<VolumeViewComponentState>) { - // const vv = this.state.volumeView - // this.setState(this.stateFromVolumeView(vv)) - // } - - render() { - const { volumeView, label, active, volumeRepresentations } = this.state - - return <div> - <div> - <h2>{label}</h2> - </div> - <div> - <div> - <h4>Active</h4> - { Object.keys(active).map((k, i) => { - return <div key={i}> - <input - type='checkbox' - checked={active[k]} - onChange={(e) => { - volumeView.setVolumeRepresentation(k, e.target.checked) - }} - /> {k} - </div> - } ) } - </div> - <div> - <h3>Volume Representations</h3> - { Object.keys(volumeRepresentations).map((k, i) => { - if (active[k]) { - return <div key={i}> - <RepresentationComponent - repr={volumeRepresentations[k] as Representation<any>} - canvas3d={volumeView.viewer} - app={volumeView.app} - /> - </div> - } else { - return '' - } - } ) } - </div> - </div> - </div>; - } -} \ No newline at end of file diff --git a/src/apps/canvas/examples.ts b/src/apps/canvas/examples.ts deleted file mode 100644 index d998f9b6bc254817cb08592a6833307a7e7f7fe2..0000000000000000000000000000000000000000 --- a/src/apps/canvas/examples.ts +++ /dev/null @@ -1,183 +0,0 @@ - - -export interface Example { - label?: string - id: string - description: string -} - -export const Examples: Example[] = [ - { - id: '1jj2', - description: 'ribosome' - }, - { - id: '1grm', - description: 'helix-like sheets' - }, - { - id: '4umt', - description: 'ligand has bond with order 3' - }, - { - id: '1crn', - description: 'small' - }, - { - id: '1hrv', - description: 'viral assembly' - }, - { - id: '1rb8', - description: 'virus' - }, - { - id: '1blu', - description: 'metal coordination' - }, - { - id: '3pqr', - description: 'inter unit bonds, two polymer chains, ligands, water, carbohydrates linked to protein' - }, - { - id: '4v5a', - description: 'ribosome' - }, - { - id: '6h7w', - description: 'retromer assembled on membrane' - }, - { - id: '3j3q', - description: '...' - }, - { - id: '5gob', - description: 'D-aminoacids' - }, - { - id: '2np2', - description: 'dna' - }, - { - id: '1d66', - description: 'dna' - }, - { - id: '9dna', - description: 'A form dna' - }, - { - id: '1bna', - description: 'B form dna' - }, - { - id: '199d', - description: 'C form dna' - }, - { - id: '4lb6', - description: 'Z form dna' - }, - { - id: '1egk', - description: '4-way dna-rna junction' - }, - { - id: '1y26', - description: 'rna' - }, - { - id: '1xv6', - description: 'rna, modified nucleotides' - }, - { - id: '3bbm', - description: 'rna with linker' - }, - { - id: '1euq', - description: 't-rna' - }, - { - id: '2e2i', - description: 'rna, dna, protein' - }, - { - id: '1gfl', - description: 'GFP, flourophore has carbonyl oxygen removed' - }, - { - id: '1sfi', - description: 'contains cyclic peptid' - }, - { - id: '3sn6', - description: 'discontinuous chains' - }, - { - id: '2zex', - description: 'contains carbohydrate polymer' - }, - { - id: '3sgj', - description: 'contains carbohydrate polymer' - }, - { - id: '3ina', - description: 'contains GlcN and IdoA' - }, - { - id: '1umz', - description: 'contains Xyl (Xyloglucan)' - }, - { - id: '1mfb', - description: 'contains Abe' - }, - { - id: '2gdu', - description: 'contains sucrose' - }, - { - id: '2fnc', - description: 'contains maltotriose' - }, - { - id: '4zs9', - description: 'contains raffinose' - }, - { - id: '2yft', - description: 'contains kestose' - }, - { - id: '2b5t', - description: 'contains large carbohydrate polymer' - }, - { - id: '1b5f', - description: 'contains carbohydrate with alternate locations' - }, - { - id: '5u0q', - description: 'mixed dna/rna in same polymer' - }, - { - id: '1xj9', - description: 'PNA (peptide nucleic acid)' - }, - { - id: '5eme', - description: 'PNA (peptide nucleic acid) and RNA' - }, - { - id: '2X3T', - description: 'temp' - }, - { - label: 'ModelServer/1cbs/full', - id: 'http://localhost:1337/ModelServer/query?%7B%22id%22%3A%221cbs%22%2C%22name%22%3A%22full%22%7D', - description: '1cbs from model server' - } -] \ No newline at end of file diff --git a/src/apps/canvas/index.html b/src/apps/canvas/index.html deleted file mode 100644 index bc9f73aa6dfcb30b9a82e79ed5fa3ce5cdf07e24..0000000000000000000000000000000000000000 --- a/src/apps/canvas/index.html +++ /dev/null @@ -1,33 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> - <title>Mol* Canvas</title> - <style> - * { - margin: 0; - padding: 0; - } - html, body { - width: 100%; - height: 100%; - overflow: hidden; - } - hr { - margin: 10px; - } - h1, h2, h3, h4, h5 { - margin-top: 5px; - margin-bottom: 3px; - } - button { - padding: 2px; - } - </style> - </head> - <body> - <div id="app" style="width: 100%; height: 100%"></div> - <script type="text/javascript" src="./index.js"></script> - </body> -</html> \ No newline at end of file diff --git a/src/apps/canvas/index.ts b/src/apps/canvas/index.ts deleted file mode 100644 index 16c12a7201d64423e7d4f3040319728c2dc17a96..0000000000000000000000000000000000000000 --- a/src/apps/canvas/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * 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 * as ReactDOM from 'react-dom' - -import './index.html' - -import { App } from './app'; -import { AppComponent } from './component/app'; -import { urlQueryParameter } from 'mol-util/url-query'; - -const elm = document.getElementById('app') as HTMLElement -if (!elm) throw new Error('Can not find element with id "app".') - -const app = new App() -ReactDOM.render(React.createElement(AppComponent, { app }), elm); - -const assemblyId = urlQueryParameter('assembly') -const pdbId = urlQueryParameter('pdb') -if (pdbId) app.loadPdbIdOrMmcifUrl(pdbId, { assemblyId }) - -// app.loadPdbIdOrMmcifUrl('http://localhost:8091/ngl/data/1crn.cif') - -// app.loadPdbIdOrMmcifUrl('3pqr') -// app.loadCcp4Url('http://localhost:8091/ngl/data/3pqr-mode0.ccp4') - -app.loadPdbIdOrMmcifUrl('1lee') -app.loadCcp4Url('http://localhost:8091/ngl/data/1lee.ccp4') - -// app.loadPdbIdOrMmcifUrl('6DRV') -// app.loadCcp4Url('http://localhost:8091/ngl/data/betaGal.mrc') - -// app.loadPdbIdOrMmcifUrl('3pqr') -// app.loadVolcifUrl('https://webchem.ncbr.muni.cz/DensityServer/x-ray/3pqr/cell?space=fractional', true) - -// app.loadPdbIdOrMmcifUrl('5ire') -// app.loadVolcifUrl('https://webchem.ncbr.muni.cz/DensityServer/em/emd-8116/cell?space=cartesian&detail=6', true) - -// app.loadPdbIdOrMmcifUrl('5gag') -// app.loadVolcifUrl('https://webchem.ncbr.muni.cz/DensityServer/em/emd-8003/cell?detail=3', true) - -// app.loadPdbIdOrMmcifUrl('http://localhost:8091/test/pdb-dev/carb/1B5F-carb.cif') -// app.loadPdbIdOrMmcifUrl('http://localhost:8091/test/pdb-dev/carb/2HYV-carb.cif') -// app.loadPdbIdOrMmcifUrl('http://localhost:8091/test/pdb-dev/carb/2WMG-carb.cif') -// app.loadPdbIdOrMmcifUrl('http://localhost:8091/test/pdb-dev/carb/5KDS-carb.cif') \ No newline at end of file diff --git a/src/apps/canvas/structure-view.ts b/src/apps/canvas/structure-view.ts deleted file mode 100644 index 3d2c20fc46ff4b7106ec7069e48389550b44a002..0000000000000000000000000000000000000000 --- a/src/apps/canvas/structure-view.ts +++ /dev/null @@ -1,369 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { Model, Structure } from 'mol-model/structure'; -import { getStructureFromModel } from './util'; -import { AssemblySymmetry } from 'mol-model-props/rcsb/symmetry'; -import { getAxesShape } from './assembly-symmetry'; -import { Canvas3D } from 'mol-canvas3d/canvas3d'; -// import { MeshBuilder } from 'mol-geo/mesh/mesh-builder'; -// import { addSphere } from 'mol-geo/mesh/builder/sphere'; -// import { Shape } from 'mol-model/shape'; -// import { Color } from 'mol-util/color'; -// import { computeUnitBoundary } from 'mol-model/structure/structure/util/boundary'; -// import { addBoundingBox } from 'mol-geo/mesh/builder/bounding-box'; -import { BehaviorSubject } from 'rxjs'; -import { App } from './app'; -import { StructureRepresentation } from 'mol-repr/structure/representation'; -import { ShapeRepresentation, ShapeParams } from 'mol-repr/shape/representation'; - -export interface StructureView { - readonly app: App - readonly canvas3d: Canvas3D - - readonly label: string - readonly models: ReadonlyArray<Model> - readonly structure: Structure | undefined - readonly assemblySymmetry: AssemblySymmetry | undefined - - readonly active: { [k: string]: boolean } - readonly structureRepresentations: { [k: string]: StructureRepresentation<any> } - readonly updated: BehaviorSubject<null> - readonly symmetryAxes: ShapeRepresentation<ShapeParams> - - setSymmetryAxes(value: boolean): void - setStructureRepresentation(name: string, value: boolean): void - - readonly modelId: number - readonly assemblyId: string - readonly symmetryFeatureId: number - - setModel(modelId: number): Promise<void> - getModelIds(): { id: number, label: string }[] - setAssembly(assemblyId: string): Promise<void> - getAssemblyIds(): { id: string, label: string }[] - setSymmetryFeature(symmetryFeatureId: number): Promise<void> - getSymmetryFeatureIds(): { id: number, label: string }[] - - destroy: () => void -} - -interface StructureViewProps { - assemblyId?: string - symmetryFeatureId?: number -} - -export async function StructureView(app: App, canvas3d: Canvas3D, models: ReadonlyArray<Model>, props: StructureViewProps = {}): Promise<StructureView> { - const active: { [k: string]: boolean } = { - 'cartoon': true, - 'ball-and-stick': true, - // point: false, - // surface: false, - // carbohydrate: false, - // spacefill: false, - // distanceRestraint: false, - // symmetryAxes: true, - // polymerSphere: false, - } - - const structureRepresentations: { [k: string]: StructureRepresentation<any> } = {} - - const symmetryAxes = ShapeRepresentation() - const polymerSphere = ShapeRepresentation() - - const updated: BehaviorSubject<null> = new BehaviorSubject<null>(null) - - let label: string - let model: Model | undefined - let assemblySymmetry: AssemblySymmetry | undefined - let structure: Structure | undefined - - let modelId: number - let assemblyId: string - let symmetryFeatureId: number - - async function setSymmetryAxes(value: boolean) { - if (!value) { - assemblySymmetry = undefined - } else { - await app.runTask(AssemblySymmetry.attachFromCifOrAPI(models[modelId]), 'Load symmetry annotation') - assemblySymmetry = AssemblySymmetry.get(models[modelId]) - } - active.symmetryAxes = value - await setSymmetryFeature() - } - - async function setStructureRepresentation(k: string, value: boolean) { - active[k] = value - await createStructureRepr() - } - - async function setModel(newModelId: number, newAssemblyId?: string, newSymmetryFeatureId?: number) { - console.log('setModel', newModelId) - modelId = newModelId - model = models[modelId] - if (active.symmetryAxes) { - await AssemblySymmetry.attachFromCifOrAPI(model) - assemblySymmetry = AssemblySymmetry.get(model) - } - await setAssembly(newAssemblyId, newSymmetryFeatureId) - } - - function getModelIds() { - const modelIds: { id: number, label: string }[] = [] - models.forEach((m, i) => { - modelIds.push({ id: i, label: `${i}: ${m.label} #${m.modelNum}` }) - }) - return modelIds - } - - async function setAssembly(newAssemblyId?: string, newSymmetryFeatureId?: number) { - console.log('setAssembly', newAssemblyId) - if (newAssemblyId !== undefined) { - assemblyId = newAssemblyId - } else if (model && model.symmetry.assemblies.length) { - assemblyId = model.symmetry.assemblies[0].id - } else if (model) { - assemblyId = 'deposited' - } else { - assemblyId = '-1' - } - await getStructure() - await setSymmetryFeature(newSymmetryFeatureId) - } - - function getAssemblyIds() { - const assemblyIds: { id: string, label: string }[] = [ - { id: 'deposited', label: 'deposited' } - ] - if (model) model.symmetry.assemblies.forEach(a => { - assemblyIds.push({ id: a.id, label: `${a.id}: ${a.details}` }) - }) - return assemblyIds - } - - async function setSymmetryFeature(newSymmetryFeatureId?: number) { - console.log('setSymmetryFeature', newSymmetryFeatureId) - if (newSymmetryFeatureId !== undefined) { - symmetryFeatureId = newSymmetryFeatureId - } else if (assemblySymmetry) { - const s = assemblySymmetry.getSymmetries(assemblyId) - if (s._rowCount) { - symmetryFeatureId = s.id.value(0) - } else { - symmetryFeatureId = -1 - } - } else { - symmetryFeatureId = -1 - } - await createSymmetryRepr() - } - - function getSymmetryFeatureIds() { - const symmetryFeatureIds: { id: number, label: string }[] = [] - if (assemblySymmetry) { - const symmetries = assemblySymmetry.getSymmetries(assemblyId) - for (let i = 0, il = symmetries._rowCount; i < il; ++i) { - const id = symmetries.id.value(i) - const kind = symmetries.kind.value(i) - const type = symmetries.type.value(i) - const stoichiometry = symmetries.stoichiometry.value(i) - const label = `${id}: ${kind} ${type} ${stoichiometry}` - symmetryFeatureIds.push({ id, label }) - } - } - return symmetryFeatureIds - } - - async function getStructure() { - if (model) structure = await app.runTask(getStructureFromModel(model, assemblyId), 'Build structure') - if (model && structure) { - label = `${model.label} - Assembly ${assemblyId}` - } else { - label = '' - } - await createStructureRepr() - } - - async function createStructureRepr() { - if (structure) { - console.log('createStructureRepr') - for (const k in active) { - if (active[k]) { - let repr: StructureRepresentation - if (structureRepresentations[k]) { - repr = structureRepresentations[k] - } else { - const provider = app.structureRepresentationRegistry.get(k) - repr = provider.factory(provider.getParams) - structureRepresentations[k] = repr - canvas3d.add(repr) - } - await app.runTask(repr.createOrUpdate(app.reprCtx, {}, structure).run( - progress => app.log(progress) - ), 'Create/update representation') - } else { - if (structureRepresentations[k]) { - canvas3d.remove(structureRepresentations[k]) - structureRepresentations[k].destroy() - delete structureRepresentations[k] - } - } - } - - canvas3d.camera.setState({ target: structure.boundary.sphere.center }) - - // const mb = MeshBuilder.create() - // mb.setGroup(0) - // addSphere(mb, structure.boundary.sphere.center, structure.boundary.sphere.radius, 3) - // addBoundingBox(mb, structure.boundary.box, 1, 2, 8) - // for (let i = 0, il = structure.units.length; i < il; ++i) { - // mb.setGroup(1) - // const u = structure.units[i] - // const ci = u.model.atomicHierarchy.chainAtomSegments.index[u.elements[0]] - // const ek = u.model.atomicHierarchy.getEntityKey(ci) - // if (u.model.entities.data.type.value(ek) === 'water') continue - // const boundary = computeUnitBoundary(u) - // addSphere(mb, boundary.sphere.center, boundary.sphere.radius, 3) - // addBoundingBox(mb, boundary.box, 0.5, 2, 8) - // } - // const shape = Shape.create('boundary', mb.getMesh(), [Color(0xCC6633), Color(0x3366CC)], ['sphere boundary']) - // await polymerSphere.createOrUpdate({ - // alpha: 0.5, - // doubleSided: false, - // depthMask: false, - // useFog: false // TODO fog not working properly - // }, shape).run() - } else { - for (const k in structureRepresentations) structureRepresentations[k].destroy() - polymerSphere.destroy() - } - - canvas3d.add(polymerSphere) - - updated.next(null) - canvas3d.requestDraw(true) - console.log('stats', canvas3d.stats) - } - - async function createSymmetryRepr() { - if (assemblySymmetry) { - const symmetries = assemblySymmetry.getSymmetries(assemblyId) - if (symmetries._rowCount) { - const axesShape = getAxesShape(symmetryFeatureId, assemblySymmetry) - if (axesShape) { - // const colorTheme = getClusterColorTheme(symmetryFeatureId, assemblySymmetry) - // await structureRepresentations['cartoon'].createOrUpdate({ - // colorTheme: 'custom', - // colorFunction: colorTheme.color, - // colorGranularity: colorTheme.granularity, - // }).run() - await symmetryAxes.createOrUpdate(app.reprCtx, {}, axesShape).run() - canvas3d.add(symmetryAxes) - } else { - canvas3d.remove(symmetryAxes) - } - } else { - canvas3d.remove(symmetryAxes) - } - } else { - canvas3d.remove(symmetryAxes) - } - updated.next(null) - canvas3d.requestDraw(true) - } - - await setModel(0, props.assemblyId, props.symmetryFeatureId) - - return { - app, - canvas3d, - - get label() { return label }, - models, - get structure() { return structure }, - get assemblySymmetry() { return assemblySymmetry }, - - active, - structureRepresentations, - updated, - symmetryAxes, - - setSymmetryAxes, - setStructureRepresentation, - - get modelId() { return modelId }, - get assemblyId() { return assemblyId }, - get symmetryFeatureId() { return symmetryFeatureId }, - - setModel, - getModelIds, - setAssembly, - getAssemblyIds, - setSymmetryFeature, - getSymmetryFeatureIds, - - destroy: () => { - for (const k in structureRepresentations) { - canvas3d.remove(structureRepresentations[k]) - structureRepresentations[k].destroy() - } - canvas3d.remove(polymerSphere) - canvas3d.remove(symmetryAxes) - canvas3d.requestDraw(true) - - polymerSphere.destroy() - symmetryAxes.destroy() - } - } -} - -// // create new structure via query -// const q1 = Q.generators.atoms({ -// residueTest: qtx => SP.residue.label_seq_id(qtx.element) < 7 -// }); -// const newStructure = StructureSelection.unionStructure(await StructureQuery.run(q1, structure)); - -// // ball+stick for new structure -// const newBallStickRepr = BallAndStickRepresentation() -// await newBallStickRepr.create(newStructure, { -// colorTheme: { name: 'element-symbol' }, -// sizeTheme: { name: 'uniform', value: 0.1 }, -// useFog: false // TODO fog not working properly -// }).run() -// viewer.add(newBallStickRepr) - -// // create a mesh -// const meshBuilder = MeshBuilder.create(256, 128) -// const colors: Color[] = [] -// const labels: string[] = [] -// // red sphere -// meshBuilder.setGroup(0) -// colors[0] = Color(0xFF2233) -// labels[0] = 'red sphere' -// addSphere(meshBuilder, Vec3.create(0, 0, 0), 4, 2) -// // green cube -// meshBuilder.setGroup(1) -// colors[1] = Color(0x2233FF) -// labels[1] = 'blue cube' -// const t = Mat4.identity() -// Mat4.fromTranslation(t, Vec3.create(10, 0, 0)) -// Mat4.scale(t, t, Vec3.create(3, 3, 3)) -// meshBuilder.add(t, Box()) -// const mesh = meshBuilder.getMesh() -// const mesh = getObjFromUrl('mesh.obj') - -// // create shape from mesh -// const shape = Shape.create('myShape', mesh, colors, labels) - -// // add representation from shape -// const customRepr = ShapeRepresentation() -// await customRepr.create(shape, { -// colorTheme: { name: 'shape-group' }, -// // colorTheme: { name: 'uniform', value: Color(0xFFCC22) }, -// useFog: false // TODO fog not working properly -// }).run() -// viewer.add(customRepr) \ No newline at end of file diff --git a/src/apps/canvas/util.ts b/src/apps/canvas/util.ts deleted file mode 100644 index e9b7dfdf2b61830f00422f6ffd1ae9d3a3404d52..0000000000000000000000000000000000000000 --- a/src/apps/canvas/util.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { readUrl, readFile, readUrlAsBuffer, readFileAsBuffer } from 'mol-util/read'; -import CIF, { CifBlock } from 'mol-io/reader/cif' -import { Model, Format, StructureSymmetry, Structure } from 'mol-model/structure'; -import CCP4 from 'mol-io/reader/ccp4/parser' -import { FileHandle } from 'mol-io/common/file-handle'; -import { Ccp4File } from 'mol-io/reader/ccp4/schema'; -import { volumeFromCcp4 } from 'mol-model/volume/formats/ccp4'; -import { parseDensityServerData } from 'mol-model/volume'; -// import { parse as parseObj } from 'mol-io/reader/obj/parser' - -// export async function getObjFromUrl(url: string) { -// const data = await readUrlAs(url, false) as string -// const comp = parseObj(data) -// const parsed = await comp.run() -// if (parsed.isError) throw parsed -// return parsed.result -// } - -export async function getCifFromData(data: string | Uint8Array) { - const comp = CIF.parse(data) - const parsed = await comp.run() - if (parsed.isError) throw parsed - return parsed.result -} - -export async function getCifFromUrl(url: string, binary = false) { - return getCifFromData(await readUrl(url, binary)) -} - -export async function getCifFromFile(file: File, binary = false) { - return getCifFromData(await readFile(file, binary)) -} - -export async function getModelsFromMmcif(cif: CifBlock) { - return await Model.create(Format.mmCIF(cif)).run() -} - -export async function getStructureFromModel(model: Model, assembly: string) { - const assemblies = model.symmetry.assemblies - if (assembly === 'deposited') { - return Structure.ofModel(model) - } else if (assemblies.find(a => a.id === assembly)) { - return await StructureSymmetry.buildAssembly(Structure.ofModel(model), assembly).run() - } -} - -// - -export async function getCcp4FromUrl(url: string) { - return getCcp4FromData(await readUrlAsBuffer(url)) -} - -export async function getCcp4FromFile(file: File) { - return getCcp4FromData(await readFileAsBuffer(file)) -} - -export async function getCcp4FromData(data: Uint8Array) { - const file = FileHandle.fromBuffer(data) - const parsed = await CCP4(file).run() - if (parsed.isError) throw parsed - return parsed.result -} - -export async function getVolumeFromCcp4(ccp4: Ccp4File) { - return await volumeFromCcp4(ccp4).run() -} - -// - -export async function getVolumeFromVolcif(cif: CifBlock) { - return await parseDensityServerData(CIF.schema.densityServer(cif)).run() -} \ No newline at end of file diff --git a/src/apps/canvas/volume-view.ts b/src/apps/canvas/volume-view.ts deleted file mode 100644 index a0f39495f80aef32f9ad84833791aca5d5605344..0000000000000000000000000000000000000000 --- a/src/apps/canvas/volume-view.ts +++ /dev/null @@ -1,97 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { Canvas3D } from 'mol-canvas3d/canvas3d'; -import { BehaviorSubject } from 'rxjs'; -import { App } from './app'; -import { VolumeData } from 'mol-model/volume'; -import { VolumeRepresentation } from 'mol-repr/volume/representation'; -import { IsosurfaceRepresentation } from 'mol-repr/volume/isosurface-mesh'; -import { DirectVolumeRepresentation } from 'mol-repr/volume/direct-volume'; - -export interface VolumeView { - readonly app: App - readonly viewer: Canvas3D - - readonly label: string - readonly volume: VolumeData - - readonly active: { [k: string]: boolean } - readonly volumeRepresentations: { [k: string]: VolumeRepresentation<any> } - readonly updated: BehaviorSubject<null> - - setVolumeRepresentation(name: string, value: boolean): void - destroy: () => void -} - -interface VolumeViewProps { - -} - -export async function VolumeView(app: App, viewer: Canvas3D, volume: VolumeData, props: VolumeViewProps = {}): Promise<VolumeView> { - const active: { [k: string]: boolean } = { - isosurface: true, - directVolume: false, - } - - const volumeRepresentations: { [k: string]: VolumeRepresentation<any> } = { - isosurface: IsosurfaceRepresentation(), - directVolume: DirectVolumeRepresentation(), - } - - const updated: BehaviorSubject<null> = new BehaviorSubject<null>(null) - - let label: string = 'Volume' - - async function setVolumeRepresentation(k: string, value: boolean) { - active[k] = value - await createVolumeRepr() - } - - async function createVolumeRepr() { - for (const k in volumeRepresentations) { - if (active[k]) { - await app.runTask(volumeRepresentations[k].createOrUpdate(app.reprCtx, {}, volume).run( - progress => app.log(progress) - ), 'Create/update representation') - viewer.add(volumeRepresentations[k]) - } else { - viewer.remove(volumeRepresentations[k]) - } - } - - // const center = Vec3.clone(volume.cell.size) - // Vec3.scale(center, center, 0.5) - // viewer.center(center) - - updated.next(null) - viewer.requestDraw(true) - console.log('stats', viewer.stats) - } - - await createVolumeRepr() - - return { - app, - viewer, - - get label() { return label }, - volume, - - active, - volumeRepresentations, - setVolumeRepresentation, - updated, - - destroy: () => { - for (const k in volumeRepresentations) { - viewer.remove(volumeRepresentations[k]) - volumeRepresentations[k].destroy() - } - viewer.requestDraw(true) - } - } -} \ No newline at end of file