-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathstate.ts
141 lines (113 loc) · 5.96 KB
/
state.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
* Copyright (c) 2017 MolQL contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <[email protected]>
*/
import LiteMol from 'litemol'
import Expression from '../mini-lisp/expression'
import { Model } from '../reference-implementation/structure/data'
import AtomSelection from '../reference-implementation/molql/data/atom-selection'
import parseCIF from '../reference-implementation/structure/parser'
import compile, { Compiled } from '../reference-implementation/molql/compiler'
import Context from '../reference-implementation/molql/runtime/context'
import Result from './result'
import Language, { Example } from './languages/language'
import Languages from './languages'
import Rx = LiteMol.Core.Rx
import Transformer = LiteMol.Bootstrap.Entity.Transformer
export interface StructureData {
data: string,
model: Model
}
export type Query =
| { kind: 'ok', sourceLanguage: string, text: string, expression: Expression, compiled: Compiled<AtomSelection> }
| { kind: 'error', message: string }
class State {
queryString = new Rx.BehaviorSubject<string>('');
plugin: LiteMol.Plugin.Controller;
query = new Rx.BehaviorSubject<Query>({ kind: 'error', message: 'Enter query' });
compileTarget = new Rx.BehaviorSubject<'lisp' | 'json'>('lisp');
currentLanguage = new Rx.BehaviorSubject<{ language: Language, example: Example | undefined }>({ language: Languages[0], example: Languages[0].examples[0] });
pdbId = '1tqn';
structureData: StructureData | undefined = void 0;
loadState = new Rx.BehaviorSubject<'none' | 'downloading' | 'loaded'>('none');
currentSymbol = new Rx.BehaviorSubject<string>('');
editorActive = new Rx.BehaviorSubject<boolean>(false);
queryResult = new Rx.BehaviorSubject<Result>(Result.empty);
async loadStructure() {
try {
this.loadState.onNext('downloading');
this.plugin.clear();
this.plugin.clear();
this.queryResult.onNext(Result.empty);
const plugin = this.plugin;
let url = `https://models.rcsb.org/v1/${this.pdbId.toLowerCase()}/full?encoding=cif©_all_categories=false&download=false`;
const data = await LiteMol.Bootstrap.Utils.ajaxGetString(url).run(plugin.context);
const t = plugin.createTransform();
t.add(plugin.context.tree.root, Transformer.Data.FromData, { data })
.then(Transformer.Data.ParseCif, {})
.then(Transformer.Molecule.CreateFromMmCif, { blockIndex: 0 }, {})
.then(Transformer.Molecule.CreateModel, { modelIndex: 0 }, { ref: 'model' })
.then(Transformer.Molecule.CreateMacromoleculeVisual, { het: true, polymer: true, water: true, groupRef: 'cartoons' })
await plugin.applyTransform(t);
const model = parseCIF(data).models[0];
this.structureData = { data, model };
this.loadState.onNext('loaded');
} catch (e) {
console.error(e);
this.loadState.onNext('none');
}
}
execute() {
try {
const query = this.query.getValue();
if (query.kind !== 'ok') return;
this.plugin.command(LiteMol.Bootstrap.Command.Tree.RemoveNode, 'selection');
this.plugin.command(LiteMol.Bootstrap.Command.Tree.RemoveNode, 'cartoons');
this.queryResult.onNext(Result.empty);
const model = this.structureData!.model;
const ctx = Context.ofModel(model);
const selection = query.compiled(ctx);
const lang = this.currentLanguage.getValue().language;
const result = Result(model, selection, lang.mergeSelection);
this.queryResult.onNext(result);
const queryP = this.plugin;
const tQ = queryP.createTransform();
if (!this.plugin.selectEntities('background').length) {
const backgroundStyle: LiteMol.Bootstrap.Visualization.Molecule.Style<LiteMol.Bootstrap.Visualization.Molecule.BallsAndSticksParams> = {
type: 'BallsAndSticks',
taskType: 'Silent',
params: { useVDW: false, atomRadius: 0.10, bondRadius: 0.05, detail: 'Automatic' },
theme: { template: LiteMol.Bootstrap.Visualization.Molecule.Default.UniformThemeTemplate, colors: LiteMol.Bootstrap.Visualization.Molecule.Default.UniformThemeTemplate.colors!.set('Uniform', { r: 0.2, g: 0.2, b: 0.2 }), transparency: { alpha: 0.1 } },
isNotSelectable: true
}
tQ.add('model', Transformer.Molecule.CreateVisual, { style: backgroundStyle }, { ref: 'background' });
}
tQ.add('model', Transformer.Molecule.CreateSelectionFromQuery, { query: LiteMol.Core.Structure.Query.atomsFromIndices(result.allIndices) }, { ref: 'selection' })
.then(Transformer.Molecule.CreateVisual, { style: LiteMol.Bootstrap.Visualization.Molecule.Default.ForType.get('BallsAndSticks') }, {});
queryP.applyTransform(tQ);
} catch (e) {
console.error(e);
this.queryResult.onNext(Result.error(e.message));
}
}
private parseQuery(text: string) {
if (!text) {
this.query.onNext({ kind: 'error', message: 'Enter query' });
return;
}
try {
const transpiler = this.currentLanguage.getValue().language.transpiler;
const expression = transpiler(text);
const compiled = compile(expression, 'query');
this.query.onNext({ kind: 'ok', sourceLanguage: 'json', text, expression, compiled });
} catch (e) {
this.query.onNext({ kind: 'error', message: '' + e });
}
}
constructor() {
this.queryString.distinctUntilChanged().debounce(100).subscribe(s => this.parseQuery(s));
this.currentLanguage.subscribe(l => this.queryString.onNext(l.example ? l.example.value : ''));
}
}
export default State