From 7d16daacdfb0e4f0cca04c6784a13c338162595c Mon Sep 17 00:00:00 2001 From: Alexander Rose <alex.rose@rcsb.org> Date: Mon, 20 Aug 2018 16:32:37 -0700 Subject: [PATCH] wip, added canvas app --- package.json | 2 + src/apps/canvas/index.html | 15 +++ src/apps/canvas/index.ts | 122 ++++++++++++++++++ .../structure/representation/cartoon.ts | 3 +- 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/apps/canvas/index.html create mode 100644 src/apps/canvas/index.ts diff --git a/package.json b/package.json index 9caf11605..82df32b2e 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "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", "model-server": "node build/node_modules/servers/model/server.js", "model-server-watch": "nodemon --watch build/node_modules build/node_modules/servers/model/server.js" }, diff --git a/src/apps/canvas/index.html b/src/apps/canvas/index.html new file mode 100644 index 000000000..3aa50333e --- /dev/null +++ b/src/apps/canvas/index.html @@ -0,0 +1,15 @@ +<!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> + </head> + <body> + <div id="container" style="width:800px; height: 600px;"> + <canvas id="canvas"></canvas> + </div> + <span id="info"></span> + <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 new file mode 100644 index 000000000..ed3103de5 --- /dev/null +++ b/src/apps/canvas/index.ts @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import './index.html' + +import Viewer from 'mol-view/viewer'; +import CIF, { CifBlock } from 'mol-io/reader/cif' +import { readUrlAs } from 'mol-util/read' +import { Model, Format, Structure, StructureSymmetry } from 'mol-model/structure'; +import { CartoonRepresentation } from 'mol-geo/representation/structure/representation/cartoon'; +import { BallAndStickRepresentation } from 'mol-geo/representation/structure/representation/ball-and-stick'; +import { EveryLoci } from 'mol-model/loci'; +import { MarkerAction } from 'mol-geo/util/marker-data'; +import { labelFirst } from 'mol-view/label'; +import { Queries as Q, StructureProperties as SP, StructureSelection, StructureQuery } from 'mol-model/structure'; +import { MeshBuilder } from 'mol-geo/shape/mesh-builder'; +import { CustomRepresentation } from 'mol-geo/representation/custom'; +import { Vec3 } from 'mol-math/linear-algebra'; + +const container = document.getElementById('container') +if (!container) throw new Error('Can not find element with id "container".') + +const canvas = document.getElementById('canvas') as HTMLCanvasElement +if (!canvas) throw new Error('Can not find element with id "canvas".') + +const info = document.getElementById('info') as HTMLCanvasElement +if (!info) throw new Error('Can not find element with id "info".') + +const viewer = Viewer.create(canvas, container) +viewer.animate() + +viewer.input.resize.subscribe(() => { + // do whatever appropriate +}) + +viewer.input.move.subscribe(({x, y, inside, buttons}) => { + if (!inside || buttons) return + const p = viewer.identify(x, y) + const loci = viewer.getLoci(p) + + viewer.mark(EveryLoci, MarkerAction.RemoveHighlight) + viewer.mark(loci, MarkerAction.Highlight) + + const label = labelFirst(loci) + info.innerText = `${label}` +}) + +async function getCifFromUrl(url: string) { + const data = await readUrlAs(url, false) + const comp = CIF.parse(data) + const parsed = await comp.run() + if (parsed.isError) throw parsed + return parsed.result.blocks[0] +} + +async function getModelFromMmcif(cif: CifBlock) { + const models = await Model.create(Format.mmCIF(cif)).run() + return models[0] +} + +async function getStructureFromModel(model: Model, assembly = '1') { + const assemblies = model.symmetry.assemblies + if (assemblies.length) { + return await StructureSymmetry.buildAssembly(Structure.ofModel(model), assembly).run() + } else { + return Structure.ofModel(model) + } +} + +async function init() { + const cif = await getCifFromUrl('https://files.rcsb.org/download/1crn.cif') + const model = await getModelFromMmcif(cif) + const structure = await getStructureFromModel(model) + + viewer.center(structure.boundary.sphere.center) + + // cartoon for whole structure + const cartoonRepr = CartoonRepresentation() + await cartoonRepr.create(structure, { + colorTheme: { name: 'chain-id' }, + sizeTheme: { name: 'uniform', value: 0.2 }, + useFog: false // TODO fog not working properly + }).run() + viewer.add(cartoonRepr) + + // 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 ballStickRepr = BallAndStickRepresentation() + await ballStickRepr.create(newStructure, { + colorTheme: { name: 'element-symbol' }, + sizeTheme: { name: 'uniform', value: 0.1 }, + useFog: false // TODO fog not working properly + }).run() + viewer.add(ballStickRepr) + + // create a custom mesh + const meshBuilder = MeshBuilder.create(256, 128) + meshBuilder.setId(0) + meshBuilder.addSphere(Vec3.create(0, 0, 0), 4, 2) + const mesh = meshBuilder.getMesh() + // Mesh.computeNormalsImmediate(mesh) + + // add representation from custom mesh + const customRepr = CustomRepresentation() + await customRepr.create(mesh, { + useFog: false // TODO fog not working properly + }).run() + viewer.add(customRepr) + + // ensure the added representations get rendered, i.e. without mouse input + viewer.requestDraw() +} + +init() \ No newline at end of file diff --git a/src/mol-geo/representation/structure/representation/cartoon.ts b/src/mol-geo/representation/structure/representation/cartoon.ts index 904b43360..bc9b43e09 100644 --- a/src/mol-geo/representation/structure/representation/cartoon.ts +++ b/src/mol-geo/representation/structure/representation/cartoon.ts @@ -33,7 +33,8 @@ export function CartoonRepresentation(): StructureRepresentation<CartoonProps> { return { get renderObjects() { return [ ...traceRepr.renderObjects, ...gapRepr.renderObjects, - ...blockRepr.renderObjects, ...directionRepr.renderObjects ] + ...blockRepr.renderObjects // , ...directionRepr.renderObjects + ] }, get props() { return { ...traceRepr.props, ...gapRepr.props, ...blockRepr.props } -- GitLab