@datagrok/helm 2.1.18 → 2.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/tests/sample_HELM-types.csv +5 -0
- package/package.json +10 -7
- package/src/cell-renderer.ts +209 -54
- package/src/helm-monomer-placer.ts +55 -19
- package/src/package.ts +10 -8
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Helm,Protein,RNA,DNA
|
|
2
|
+
PEPTIDE1{I.H.A.N.T.Thr_PO3H2.Aca.D-Tyr_Et}$$$$,IHANTK,ACGU,ACGT
|
|
3
|
+
RNA1{r(A)p.r(C)p.r(G)p.r(U)p}$$$$,KHAQTRT,CGUG,CGGT
|
|
4
|
+
RNA1{d(A)p.d(C)p.d(G)p.d(U)p}$$$$,IHANTKT,CCGU,ACCT
|
|
5
|
+
RNA1{d(A)p.d(C)p.d(G)p.d(U)p}|PEPTIDE1{I.H.A.N.T.Thr_PO3H2}$$$$,PQRHLF,UAAA,CTAA
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/helm",
|
|
3
3
|
"friendlyName": "Helm",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.21",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Oleksandra Serhiienko",
|
|
7
7
|
"email": "oserhiienko@datagrok.ai"
|
|
@@ -15,15 +15,16 @@
|
|
|
15
15
|
"helm/JSDraw/Pistoia.HELM-uncompressed.js"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@datagrok-libraries/bio": "^5.
|
|
18
|
+
"@datagrok-libraries/bio": "^5.39.6",
|
|
19
19
|
"@datagrok-libraries/utils": "^4.0.17",
|
|
20
20
|
"cash-dom": "^8.1.1",
|
|
21
21
|
"datagrok-api": "^1.10.2",
|
|
22
22
|
"dayjs": "^1.10.6",
|
|
23
|
-
"rxjs": "^6.5.5"
|
|
23
|
+
"rxjs": "^6.5.5",
|
|
24
|
+
"wu": "latest"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
|
-
"@
|
|
27
|
+
"@types/wu": "latest",
|
|
27
28
|
"path": "^0.12.7",
|
|
28
29
|
"source-map-loader": "^4.0.1",
|
|
29
30
|
"ts-loader": "^9.2.6",
|
|
@@ -33,10 +34,11 @@
|
|
|
33
34
|
"@typescript-eslint/eslint-plugin": "^5.11.0",
|
|
34
35
|
"@typescript-eslint/parser": "^5.11.0",
|
|
35
36
|
"eslint": "^8.18.0",
|
|
36
|
-
"eslint-config-google": "^0.14.0"
|
|
37
|
+
"eslint-config-google": "^0.14.0",
|
|
38
|
+
"@datagrok/bio": "^2.11.8"
|
|
37
39
|
},
|
|
38
40
|
"scripts": {
|
|
39
|
-
"link-all": "npm link datagrok-api
|
|
41
|
+
"link-all": "npm link datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio",
|
|
40
42
|
"debug-helm": "webpack && grok publish",
|
|
41
43
|
"release-helm": "webpack && grok publish --release",
|
|
42
44
|
"build-helm": "webpack",
|
|
@@ -51,7 +53,8 @@
|
|
|
51
53
|
"lint-fix": "eslint \"./src/**/*.ts\" --fix",
|
|
52
54
|
"test": "grok test",
|
|
53
55
|
"test-dev": "grok test --host dev",
|
|
54
|
-
"test-local": "grok test --host localhost"
|
|
56
|
+
"test-local": "grok test --host localhost",
|
|
57
|
+
"build-all": "npm --prefix ./../../js-api run build && npm --prefix ./../../libraries/utils run build && npm --prefix ./../../libraries/bio run build && npm run build"
|
|
55
58
|
},
|
|
56
59
|
"canEdit": [
|
|
57
60
|
"Developers"
|
package/src/cell-renderer.ts
CHANGED
|
@@ -8,7 +8,10 @@ import {printLeftOrCentered} from '@datagrok-libraries/bio/src/utils/cell-render
|
|
|
8
8
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
9
9
|
|
|
10
10
|
import {findMonomers, parseHelm} from './utils';
|
|
11
|
-
import {HelmMonomerPlacer} from './helm-monomer-placer';
|
|
11
|
+
import {IEditor, HelmMonomerPlacer, IEditorMolAtom, ISeqMonomer} from './helm-monomer-placer';
|
|
12
|
+
import {IMonomerLib} from '@datagrok-libraries/bio/src/types/index';
|
|
13
|
+
|
|
14
|
+
// import {_package} from './package'; // NullError: method not found: '_package' on null
|
|
12
15
|
|
|
13
16
|
const enum tempTAGS {
|
|
14
17
|
helmSumMaxLengthWords = 'helm-sum-maxLengthWords',
|
|
@@ -22,7 +25,154 @@ const helmGapStartRe = /\{(\*\.)+/g;
|
|
|
22
25
|
const helmGapIntRe = /\.(\*\.)+/g;
|
|
23
26
|
const helmGapEndRe = /(\.\*)+\}/g;
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
function getSeqMonomerFromHelm(
|
|
29
|
+
helmPrefix: string, symbol: string, monomerLib: IMonomerLib
|
|
30
|
+
): ISeqMonomer {
|
|
31
|
+
let resSeqMonomer: ISeqMonomer | undefined = undefined;
|
|
32
|
+
for (const polymerType of monomerLib.getPolymerTypes()) {
|
|
33
|
+
if (helmPrefix.startsWith(polymerType))
|
|
34
|
+
resSeqMonomer = {symbol: symbol, polymerType: polymerType};
|
|
35
|
+
}
|
|
36
|
+
if (!resSeqMonomer)
|
|
37
|
+
resSeqMonomer = {symbol: symbol};
|
|
38
|
+
return resSeqMonomer;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function getSeqMonomerFromHelmAtom(atom: IEditorMolAtom): ISeqMonomer {
|
|
42
|
+
let polymerType: string | undefined = undefined;
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
switch (atom.bio.type) {
|
|
45
|
+
case 'HELM_BASE':
|
|
46
|
+
case 'HELM_SUGAR': // r - ribose, d - deoxyribose
|
|
47
|
+
case 'HELM_LINKER': // p - phosphate
|
|
48
|
+
polymerType = 'RNA';
|
|
49
|
+
break;
|
|
50
|
+
case 'HELM_AA':
|
|
51
|
+
polymerType = 'PEPTIDE';
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
polymerType = 'PEPTIDE';
|
|
55
|
+
}
|
|
56
|
+
return {symbol: atom.elem, polymerType: polymerType};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getHoveredMonomerFromEditor(
|
|
60
|
+
argsX: number, argsY: number, gridCell: DG.GridCell, editor: IEditor
|
|
61
|
+
): ISeqMonomer | null {
|
|
62
|
+
let hoveredSeqMonomer: ISeqMonomer | null = null;
|
|
63
|
+
|
|
64
|
+
/** @return {[number, number]} [atom, distance] */
|
|
65
|
+
function getNearest(excluded: (number | undefined)[]): [number | undefined, number | undefined] {
|
|
66
|
+
let atom: number | undefined = undefined;
|
|
67
|
+
let distance: number | undefined = undefined;
|
|
68
|
+
for (let atomI = 0; atomI < editor.m.atoms.length; ++atomI) {
|
|
69
|
+
if (!excluded.includes(atomI)) {
|
|
70
|
+
const aX: number = editor.m.atoms[atomI].p.x;
|
|
71
|
+
const aY: number = editor.m.atoms[atomI].p.y;
|
|
72
|
+
const distanceToAtomI: number = Math.sqrt((argsX - aX) ** 2 + (argsY - aY) ** 2);
|
|
73
|
+
if (distance === undefined || distance > distanceToAtomI) {
|
|
74
|
+
atom = atomI;
|
|
75
|
+
distance = distanceToAtomI;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return [atom, distance];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const [firstAtomI, firstDistance] = getNearest([]);
|
|
83
|
+
const [secondAtomI, secondDistance] = getNearest([firstAtomI]);
|
|
84
|
+
|
|
85
|
+
// for (let atomI = 0; atomI < editor.m.atoms.length; ++atomI) {
|
|
86
|
+
// const aX: number = editor.m.atoms[atomI].p.x;
|
|
87
|
+
// const aY: number = editor.m.atoms[atomI].p.y;
|
|
88
|
+
// const distanceToAtomI: number = Math.sqrt((argsX - aX) ** 2 + (argsY - aY) ** 2);
|
|
89
|
+
// if (firstDistance === undefined || firstDistance > distanceToAtomI) {
|
|
90
|
+
// secondAtomI = firstAtomI;
|
|
91
|
+
// firstAtomI = atomI;
|
|
92
|
+
//
|
|
93
|
+
// secondDistance = firstDistance;
|
|
94
|
+
// firstDistance = distanceToAtomI;
|
|
95
|
+
// }
|
|
96
|
+
// }
|
|
97
|
+
|
|
98
|
+
if (firstAtomI !== undefined && firstDistance !== undefined) {
|
|
99
|
+
const firstAtom = editor.m.atoms[firstAtomI];
|
|
100
|
+
const firstSeqMonomer = getSeqMonomerFromHelmAtom(firstAtom);
|
|
101
|
+
if (secondAtomI !== undefined && secondDistance !== undefined) {
|
|
102
|
+
if (firstDistance < secondDistance * 0.45)
|
|
103
|
+
hoveredSeqMonomer = firstSeqMonomer;
|
|
104
|
+
} else {
|
|
105
|
+
if (firstDistance < 0.35 * gridCell.bounds.height)
|
|
106
|
+
hoveredSeqMonomer = firstSeqMonomer;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return hoveredSeqMonomer;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function getHoveredMonomerFallback(
|
|
113
|
+
argsX: number, _argsY: number, gridCell: DG.GridCell, helmPlacer: HelmMonomerPlacer
|
|
114
|
+
): ISeqMonomer | null {
|
|
115
|
+
let hoveredSeqMonomer: ISeqMonomer | null = null;
|
|
116
|
+
const [allParts, lengths, sumLengths] = helmPlacer.getCellAllPartsLengths(gridCell.tableRowIndex!);
|
|
117
|
+
const maxIndex = Object.values(lengths).length - 1;
|
|
118
|
+
let left = 0;
|
|
119
|
+
let right = maxIndex;
|
|
120
|
+
let found = false;
|
|
121
|
+
let iterCount: number = 0;
|
|
122
|
+
|
|
123
|
+
let mid = 0;
|
|
124
|
+
if (argsX > sumLengths[0]) {
|
|
125
|
+
while (!found && iterCount < sumLengths.length) {
|
|
126
|
+
mid = Math.floor((right + left) / 2);
|
|
127
|
+
if (argsX >= sumLengths[mid] && argsX <= sumLengths[mid + 1]) {
|
|
128
|
+
left = mid;
|
|
129
|
+
found = true;
|
|
130
|
+
} else if (argsX < sumLengths[mid])
|
|
131
|
+
right = mid - 1;
|
|
132
|
+
else if (argsX > sumLengths[mid + 1])
|
|
133
|
+
left = mid + 1;
|
|
134
|
+
|
|
135
|
+
if (left == right)
|
|
136
|
+
found = true;
|
|
137
|
+
|
|
138
|
+
iterCount++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
left = (argsX >= sumLengths[left]) ? left : left - 1; // correct left to between sumLengths
|
|
142
|
+
if (left >= 0)
|
|
143
|
+
hoveredSeqMonomer = getSeqMonomerFromHelm(allParts[0], allParts[left], helmPlacer.monomerLib);
|
|
144
|
+
return hoveredSeqMonomer;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// patch window.dojox.gfx.svg.Text.prototype.getTextWidth hangs
|
|
148
|
+
/** get the text width in pixels */
|
|
149
|
+
// @ts-ignore
|
|
150
|
+
window.dojox.gfx.svg.Text.prototype.getTextWidth = function() {
|
|
151
|
+
const rawNode = this.rawNode;
|
|
152
|
+
const oldParent = rawNode.parentNode;
|
|
153
|
+
const _measurementNode = rawNode.cloneNode(true);
|
|
154
|
+
_measurementNode.style.visibility = 'hidden';
|
|
155
|
+
|
|
156
|
+
// solution to the "orphan issue" in FF
|
|
157
|
+
let _width = 0;
|
|
158
|
+
const _text = _measurementNode.firstChild.nodeValue;
|
|
159
|
+
oldParent.appendChild(_measurementNode);
|
|
160
|
+
|
|
161
|
+
// solution to the "orphan issue" in Opera
|
|
162
|
+
// (nodeValue == "" hangs firefox)
|
|
163
|
+
if (_text != '') {
|
|
164
|
+
let watchdogCounter = 100;
|
|
165
|
+
while (!_width && --watchdogCounter > 0) { // <-- hangs
|
|
166
|
+
//Yang: work around svgweb bug 417 -- http://code.google.com/p/svgweb/issues/detail?id=417
|
|
167
|
+
if (_measurementNode.getBBox)
|
|
168
|
+
_width = parseInt(_measurementNode.getBBox().width);
|
|
169
|
+
else
|
|
170
|
+
_width = 68;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
oldParent.removeChild(_measurementNode);
|
|
174
|
+
return _width;
|
|
175
|
+
};
|
|
26
176
|
|
|
27
177
|
/** Helm cell renderer in case of no missed monomer draws with JSDraw2.Editor (webeditor),
|
|
28
178
|
* in case of missed monomers presented, draws linear sequences aligned in width per monomer.
|
|
@@ -43,68 +193,69 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
43
193
|
try { tableCol = gridCell.tableColumn; } catch { }
|
|
44
194
|
if (!tableCol) return;
|
|
45
195
|
|
|
46
|
-
const helmPlacer = HelmMonomerPlacer.getOrCreate(tableCol);
|
|
47
|
-
const [allParts, lengths, sumLengths] = helmPlacer.getCellAllPartsLengths(gridCell.tableRowIndex!);
|
|
48
|
-
|
|
49
|
-
const maxIndex = Object.values(lengths).length - 1;
|
|
50
196
|
const argsX = e.offsetX - gridCell.bounds.x;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (argsX >= sumLengths[mid] && argsX <= sumLengths[mid + 1]) {
|
|
61
|
-
left = mid;
|
|
62
|
-
found = true;
|
|
63
|
-
} else if (argsX < sumLengths[mid])
|
|
64
|
-
right = mid - 1;
|
|
65
|
-
else if (argsX > sumLengths[mid + 1])
|
|
66
|
-
left = mid + 1;
|
|
67
|
-
|
|
68
|
-
if (left == right)
|
|
69
|
-
found = true;
|
|
70
|
-
|
|
71
|
-
iterCount++;
|
|
72
|
-
}
|
|
197
|
+
const argsY = e.offsetY - gridCell.bounds.y;
|
|
198
|
+
|
|
199
|
+
const helmPlacer = HelmMonomerPlacer.getOrCreate(tableCol);
|
|
200
|
+
const editor: IEditor | null = helmPlacer.getEditor(gridCell.tableRowIndex!);
|
|
201
|
+
const seqMonomer: ISeqMonomer | null = editor ? getHoveredMonomerFromEditor(argsX, argsY, gridCell, editor) :
|
|
202
|
+
getHoveredMonomerFallback(argsX, argsY, gridCell, helmPlacer);
|
|
203
|
+
if (!seqMonomer) {
|
|
204
|
+
ui.tooltip.hide();
|
|
205
|
+
return;
|
|
73
206
|
}
|
|
74
|
-
left = (argsX >= sumLengths[left]) ? left : left - 1; // correct left to between sumLengths
|
|
75
207
|
|
|
76
208
|
const seq: string = !gridCell.cell.value ? '' : gridCell.cell.value
|
|
77
209
|
.replaceAll(helmGapStartRe, '{').replaceAll(helmGapIntRe, '.').replaceAll(helmGapEndRe, '}')
|
|
78
210
|
.replace('{*}', '{}');
|
|
79
211
|
const monomerList = parseHelm(seq);
|
|
80
|
-
const monomers = new Set<string>(monomerList);
|
|
81
212
|
const missedMonomers = findMonomers(monomerList);
|
|
82
213
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
tooltipMessage[partI] = ui.divV(elList);
|
|
214
|
+
if (missedMonomers.has(seqMonomer.symbol)) {
|
|
215
|
+
ui.tooltip.show(ui.divV([
|
|
216
|
+
ui.divText(`Monomer ${seqMonomer.symbol} not found.`),
|
|
217
|
+
ui.divText('Open the Context Panel, then expand Manage Libraries'),
|
|
218
|
+
]), e.x + 16, e.y + 16);
|
|
219
|
+
} else {
|
|
220
|
+
const monomer = helmPlacer.getMonomer(seqMonomer);
|
|
221
|
+
if (monomer) {
|
|
222
|
+
const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
223
|
+
const monomerSvg = grok.chem.svgMol(monomer.smiles, undefined, undefined, options);
|
|
224
|
+
ui.tooltip.show(ui.divV([
|
|
225
|
+
ui.divText(seqMonomer.symbol),
|
|
226
|
+
monomerSvg,
|
|
227
|
+
]), e.x + 16, e.y + 16);
|
|
99
228
|
}
|
|
100
229
|
}
|
|
101
230
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
231
|
+
// const tooltipMessage: HTMLElement[] = [];
|
|
232
|
+
// for (const [part, partI] of wu.enumerate(allParts)) {
|
|
233
|
+
// if (missedMonomers.has(part)) {
|
|
234
|
+
// tooltipMessage[partI] = ui.divV([
|
|
235
|
+
// ui.divText(`Monomer ${allParts[partI]} not found.`),
|
|
236
|
+
// ui.divText('Open the Context Panel, then expand Manage Libraries')
|
|
237
|
+
// ]);
|
|
238
|
+
// } else if (monomers.has(part)) {
|
|
239
|
+
// const elList = [ui.div(part)];
|
|
240
|
+
// const monomer = helmPlacer.getMonomer(part);
|
|
241
|
+
// if (monomer) {
|
|
242
|
+
// const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
|
|
243
|
+
// const monomerSvg = grok.chem.svgMol(monomer.smiles, undefined, undefined, options);
|
|
244
|
+
// elList.push(monomerSvg);
|
|
245
|
+
// }
|
|
246
|
+
// tooltipMessage[partI] = ui.divV(elList);
|
|
247
|
+
// }
|
|
248
|
+
// }
|
|
249
|
+
//
|
|
250
|
+
// (((tooltipMessage[left]?.childNodes.length ?? 0) > 0)) ?
|
|
251
|
+
// ui.tooltip.show(tooltipMessage[left], e.x + 16, e.y + 16) :
|
|
252
|
+
// ui.tooltip.hide();
|
|
105
253
|
} catch (err: any) {
|
|
106
254
|
const errMsg: string = errorToConsole(err);
|
|
107
255
|
console.error('Helm: HelmCellRenderer.onMouseMove() error:\n' + errMsg);
|
|
256
|
+
} finally {
|
|
257
|
+
e.preventDefault();
|
|
258
|
+
e.stopPropagation();
|
|
108
259
|
}
|
|
109
260
|
}
|
|
110
261
|
|
|
@@ -132,13 +283,17 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
132
283
|
const helmPlacer = HelmMonomerPlacer.getOrCreate(tableCol);
|
|
133
284
|
|
|
134
285
|
if (missedMonomers.size == 0) {
|
|
135
|
-
|
|
136
|
-
const host = ui.div([],
|
|
286
|
+
// Recreate host to avoid hanging in window.dojox.gfx.svg.Text.prototype.getTextWidth
|
|
287
|
+
const host = gridCell.element = ui.div([],
|
|
288
|
+
{style: {width: `${w - 2}px`, height: `${h - 2}px`, margin: `${1}px`, backgroundColor: '#FFE0E0'}});
|
|
137
289
|
host.setAttribute('dataformat', 'helm');
|
|
138
290
|
host.setAttribute('data', seq /* gaps skipped */);
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
291
|
+
|
|
292
|
+
// Recreate editor to avoid hanging in window.dojox.gfx.svg.Text.prototype.getTextWidth
|
|
293
|
+
const editor = new JSDraw2.Editor(host, {width: w, height: h, skin: 'w8', viewonly: true}) as IEditor;
|
|
294
|
+
helmPlacer.setEditor(gridCell.tableRowIndex!, editor);
|
|
295
|
+
|
|
296
|
+
helmPlacer.skipCell(gridCell.tableRowIndex!);
|
|
142
297
|
return;
|
|
143
298
|
}
|
|
144
299
|
|
|
@@ -13,11 +13,39 @@ export const enum Temps {
|
|
|
13
13
|
helmMonomerPlacer = 'bio-helmMonomerPlacer',
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
export interface IEditor {
|
|
17
|
+
get m(): IEditorMol;
|
|
18
|
+
|
|
19
|
+
redraw(): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface IEditorMol {
|
|
23
|
+
get atoms(): IEditorMolAtom[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface IEditorMolAtom {
|
|
27
|
+
get p(): IEditorPoint;
|
|
28
|
+
|
|
29
|
+
get elem(): string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface IEditorPoint {
|
|
33
|
+
get x(): number;
|
|
34
|
+
|
|
35
|
+
get y(): number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ISeqMonomer {
|
|
39
|
+
symbol: string,
|
|
40
|
+
polymerType?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
16
43
|
export class HelmMonomerPlacer {
|
|
17
|
-
private _allPartsList: (string[] | null)[]
|
|
18
|
-
private _lengthsList: (number[] | null)
|
|
44
|
+
private readonly _allPartsList: (string[] | null)[];
|
|
45
|
+
private readonly _lengthsList: (number[] | null)[];
|
|
46
|
+
private readonly _editorList: (IEditor | null)[];
|
|
19
47
|
|
|
20
|
-
|
|
48
|
+
public readonly monomerLib: IMonomerLib;
|
|
21
49
|
|
|
22
50
|
public monomerCharWidth: number = 7;
|
|
23
51
|
public leftPadding: number = 5;
|
|
@@ -26,25 +54,20 @@ export class HelmMonomerPlacer {
|
|
|
26
54
|
this.col.dataFrame.onDataChanged.subscribe();
|
|
27
55
|
this.monomerLib = getMonomerLib();
|
|
28
56
|
this.monomerLib.onChanged.subscribe(this.monomerLibOnChanged.bind(this));
|
|
57
|
+
|
|
58
|
+
this._allPartsList = new Array<string[] | null>(this.col.length).fill(null);
|
|
59
|
+
this._lengthsList = new Array<number[] | null>(this.col.length).fill(null);
|
|
60
|
+
this._editorList = new Array<IEditor | null>(this.col.length).fill(null);
|
|
29
61
|
}
|
|
30
62
|
|
|
63
|
+
/** Skips cell for the fallback rendering */
|
|
31
64
|
public skipCell(rowIdx: number): void {
|
|
32
|
-
if (this._allPartsList === null)
|
|
33
|
-
this._allPartsList = new Array<string[] | null>(this.col.length).fill(null);
|
|
34
|
-
if (this._lengthsList === null)
|
|
35
|
-
this._lengthsList = new Array<number[] | null>(this.col.length).fill(null);
|
|
36
|
-
|
|
37
65
|
this._allPartsList[rowIdx] = [];
|
|
38
66
|
this._lengthsList[rowIdx] = [];
|
|
39
67
|
}
|
|
40
68
|
|
|
41
69
|
/** @param rowIdx Row index of the table {@link DG.DataFrame}, HelmMonomerPlacer is {@link DG.Column} based */
|
|
42
70
|
public getCellAllPartsLengths(rowIdx: number): [string[], number[], number[]] {
|
|
43
|
-
if (this._allPartsList === null)
|
|
44
|
-
this._allPartsList = new Array<string[] | null>(this.col.length).fill(null);
|
|
45
|
-
if (this._lengthsList === null)
|
|
46
|
-
this._lengthsList = new Array<number[] | null>(this.col.length).fill(null);
|
|
47
|
-
|
|
48
71
|
const [allParts, lengths] = this.getCellMonomerLengthsForSeq(rowIdx);
|
|
49
72
|
|
|
50
73
|
const sumLengths: number[] = new Array<number>(lengths.length + 1);
|
|
@@ -77,11 +100,15 @@ export class HelmMonomerPlacer {
|
|
|
77
100
|
return seq ? getParts(monomerList, seq) : [];
|
|
78
101
|
}
|
|
79
102
|
|
|
80
|
-
getMonomer(
|
|
103
|
+
getMonomer(monomer: ISeqMonomer): Monomer | null {
|
|
81
104
|
let res: Monomer | null = null;
|
|
82
|
-
|
|
83
|
-
res = this.monomerLib.getMonomer(polymerType,
|
|
84
|
-
|
|
105
|
+
if (monomer.polymerType)
|
|
106
|
+
res = this.monomerLib.getMonomer(monomer.polymerType, monomer.symbol);
|
|
107
|
+
else {
|
|
108
|
+
for (const polymerType of this.monomerLib.getPolymerTypes()) {
|
|
109
|
+
res = this.monomerLib.getMonomer(polymerType, monomer.symbol);
|
|
110
|
+
if (res) break;
|
|
111
|
+
}
|
|
85
112
|
}
|
|
86
113
|
return res;
|
|
87
114
|
}
|
|
@@ -89,8 +116,9 @@ export class HelmMonomerPlacer {
|
|
|
89
116
|
// -- Handle events --
|
|
90
117
|
|
|
91
118
|
private monomerLibOnChanged(_value: any): void {
|
|
92
|
-
this._lengthsList
|
|
93
|
-
this._allPartsList
|
|
119
|
+
this._lengthsList.fill(null);
|
|
120
|
+
this._allPartsList.fill(null);
|
|
121
|
+
this._editorList.fill(null);
|
|
94
122
|
// TODO: Invalidate all grids of this.col.dataFrame
|
|
95
123
|
}
|
|
96
124
|
|
|
@@ -98,4 +126,12 @@ export class HelmMonomerPlacer {
|
|
|
98
126
|
if (!(Temps.helmMonomerPlacer in col.temp)) col.temp[Temps.helmMonomerPlacer] = new HelmMonomerPlacer(col);
|
|
99
127
|
return col.temp[Temps.helmMonomerPlacer];
|
|
100
128
|
}
|
|
129
|
+
|
|
130
|
+
public setEditor(tableRowIndex: number, editor: IEditor) {
|
|
131
|
+
this._editorList![tableRowIndex] = editor;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public getEditor(tableRowIndex: number): IEditor | null {
|
|
135
|
+
return this._editorList![tableRowIndex];
|
|
136
|
+
}
|
|
101
137
|
}
|
package/src/package.ts
CHANGED
|
@@ -3,17 +3,19 @@ import * as grok from 'datagrok-api/grok';
|
|
|
3
3
|
import * as ui from 'datagrok-api/ui';
|
|
4
4
|
import * as DG from 'datagrok-api/dg';
|
|
5
5
|
|
|
6
|
-
import {WebEditorMonomer, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './constants';
|
|
7
|
-
import {HelmWebEditor} from './helm-web-editor';
|
|
8
|
-
import {HelmCellRenderer} from './cell-renderer';
|
|
9
|
-
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
10
|
-
import {GapSymbols, UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
11
|
-
import {findMonomers, parseHelm} from './utils';
|
|
12
6
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
13
7
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
8
|
+
import {GapSymbols, UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
9
|
+
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
10
|
+
|
|
11
|
+
import {findMonomers, parseHelm} from './utils';
|
|
12
|
+
import {HelmWebEditor} from './helm-web-editor';
|
|
13
|
+
import {HelmCellRenderer} from './cell-renderer';
|
|
14
14
|
|
|
15
15
|
let monomerLib: IMonomerLib | null = null;
|
|
16
16
|
|
|
17
|
+
import {WebEditorMonomer, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './constants';
|
|
18
|
+
|
|
17
19
|
export const _package = new DG.Package();
|
|
18
20
|
|
|
19
21
|
//tags: init
|
|
@@ -110,7 +112,7 @@ function rewriteLibraries() {
|
|
|
110
112
|
//name: helmCellRenderer
|
|
111
113
|
//tags: cellRenderer
|
|
112
114
|
//meta.cellType: helm
|
|
113
|
-
//meta.columnTags: units=helm
|
|
115
|
+
//meta.columnTags: quality=Macromolecule, units=helm
|
|
114
116
|
//output: grid_cell_renderer result
|
|
115
117
|
export function helmCellRenderer(): HelmCellRenderer {
|
|
116
118
|
return new HelmCellRenderer();
|
|
@@ -281,7 +283,7 @@ export function getMolfiles(col: DG.Column): DG.Column {
|
|
|
281
283
|
}
|
|
282
284
|
|
|
283
285
|
//name: helmWebEditor
|
|
284
|
-
//output: object
|
|
286
|
+
//output: object result
|
|
285
287
|
export function helmWebEditor(): HelmWebEditor {
|
|
286
288
|
return new HelmWebEditor();
|
|
287
289
|
}
|