@datagrok/helm 2.1.34 → 2.2.1
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/.eslintrc.json +1 -1
- package/CHANGELOG.md +30 -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/package.json +12 -12
- package/src/cell-renderer.ts +21 -153
- package/src/constants.ts +0 -11
- package/src/helm-helper.ts +9 -10
- package/src/helm-monomer-placer.ts +21 -85
- package/src/helm-web-editor.ts +5 -2
- package/src/package-test.ts +6 -2
- package/src/package-utils.ts +150 -0
- package/src/package.ts +96 -100
- package/src/tests/get-monomer-tests.ts +210 -0
- package/src/tests/helm-service-tests.ts +97 -0
- package/src/tests/helm-tests.ts +1 -0
- package/src/tests/properties-widget-tests.ts +4 -2
- package/src/tests/renderers-tests.ts +97 -22
- package/src/types/dojo.ts +3 -0
- package/src/types/index.ts +0 -0
- package/src/utils/dummy-monomer.ts +184 -0
- package/src/utils/get-hovered.ts +104 -0
- package/src/utils/get-monomer.ts +111 -0
- package/src/utils/helm-grid-cell-renderer.ts +199 -0
- package/src/utils/helm-service.ts +130 -0
- package/src/utils/index.ts +7 -7
- package/webpack.config.js +7 -0
- /package/src/tests/{get-molfiles.ts → get-molfiles-tests.ts} +0 -0
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.2.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Oleksandra Serhiienko",
|
|
7
7
|
"email": "oserhiienko@datagrok.ai"
|
|
@@ -12,33 +12,33 @@
|
|
|
12
12
|
"https://ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js",
|
|
13
13
|
"helm/JSDraw/Scilligence.JSDraw2.Lite.js",
|
|
14
14
|
"helm/JSDraw/Scilligence.JSDraw2.Resources.js",
|
|
15
|
-
"helm/JSDraw/Pistoia.HELM
|
|
15
|
+
"helm/JSDraw/Pistoia.HELM.js"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@datagrok-libraries/bio": "^5.
|
|
18
|
+
"@datagrok-libraries/bio": "^5.41.2",
|
|
19
19
|
"@datagrok-libraries/chem-meta": "^1.2.5",
|
|
20
|
-
"@datagrok-libraries/utils": "^4.2.
|
|
20
|
+
"@datagrok-libraries/utils": "^4.2.2",
|
|
21
21
|
"cash-dom": "^8.1.1",
|
|
22
|
-
"datagrok-api": "^1.17.
|
|
22
|
+
"datagrok-api": "^1.17.4",
|
|
23
23
|
"dayjs": "^1.10.6",
|
|
24
24
|
"rxjs": "^6.5.5",
|
|
25
25
|
"wu": "latest"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
+
"@datagrok/bio": "^2.12.18",
|
|
29
|
+
"@datagrok/chem": "^1.9.2",
|
|
28
30
|
"@types/node": "17.0.45",
|
|
29
31
|
"@types/wu": "latest",
|
|
32
|
+
"@typescript-eslint/eslint-plugin": "^5.11.0",
|
|
33
|
+
"@typescript-eslint/parser": "^5.11.0",
|
|
34
|
+
"eslint": "^8.18.0",
|
|
35
|
+
"eslint-config-google": "^0.14.0",
|
|
30
36
|
"path": "^0.12.7",
|
|
31
37
|
"source-map-loader": "^4.0.1",
|
|
32
38
|
"ts-loader": "^9.2.6",
|
|
33
39
|
"typescript": "^4.8.4",
|
|
34
40
|
"webpack": "^5.76.3",
|
|
35
|
-
"webpack-cli": "^4.9.1"
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "^5.11.0",
|
|
37
|
-
"@typescript-eslint/parser": "^5.11.0",
|
|
38
|
-
"eslint": "^8.18.0",
|
|
39
|
-
"eslint-config-google": "^0.14.0",
|
|
40
|
-
"@datagrok/bio": "^2.12.11",
|
|
41
|
-
"@datagrok/chem": "^1.9.0"
|
|
41
|
+
"webpack-cli": "^4.9.1"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"link-all": "npm link @datagrok-libraries/chem-meta datagrok-api @datagrok-libraries/utils @datagrok-libraries/bio",
|
package/src/cell-renderer.ts
CHANGED
|
@@ -2,16 +2,18 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
+
import * as JSDraw2 from 'JSDraw2';
|
|
5
6
|
import wu from 'wu';
|
|
6
7
|
|
|
7
8
|
import {printLeftOrCentered} from '@datagrok-libraries/bio/src/utils/cell-renderer';
|
|
8
9
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
10
|
+
import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
9
11
|
|
|
10
12
|
import {findMonomers, parseHelm, removeGapsFromHelm} from './utils';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
+
import {HelmMonomerPlacer, ISeqMonomer} from './helm-monomer-placer';
|
|
14
|
+
import {getHoveredMonomerFallback, getHoveredMonomerFromEditorMol} from './utils/get-hovered';
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
import {getMonomerLib} from './package';
|
|
15
17
|
|
|
16
18
|
const enum tempTAGS {
|
|
17
19
|
helmSumMaxLengthWords = 'helm-sum-maxLengthWords',
|
|
@@ -20,145 +22,6 @@ const enum tempTAGS {
|
|
|
20
22
|
helmPlacer = 'bio-helmPlacer',
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
function getSeqMonomerFromHelm(
|
|
24
|
-
helmPrefix: string, symbol: string, monomerLib: IMonomerLib
|
|
25
|
-
): ISeqMonomer {
|
|
26
|
-
let resSeqMonomer: ISeqMonomer | undefined = undefined;
|
|
27
|
-
for (const polymerType of monomerLib.getPolymerTypes()) {
|
|
28
|
-
if (helmPrefix.startsWith(polymerType))
|
|
29
|
-
resSeqMonomer = {symbol: symbol, polymerType: polymerType};
|
|
30
|
-
}
|
|
31
|
-
if (!resSeqMonomer)
|
|
32
|
-
throw new Error(`Monomer not found for symbol = '${symbol}' and helmPrefix = '${helmPrefix}'.`);
|
|
33
|
-
return resSeqMonomer;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function getSeqMonomerFromHelmAtom(atom: IEditorMolAtom): ISeqMonomer {
|
|
37
|
-
let polymerType: string | undefined = undefined;
|
|
38
|
-
// @ts-ignore
|
|
39
|
-
switch (atom.bio.type) {
|
|
40
|
-
case 'HELM_BASE':
|
|
41
|
-
case 'HELM_SUGAR': // r - ribose, d - deoxyribose
|
|
42
|
-
case 'HELM_LINKER': // p - phosphate
|
|
43
|
-
polymerType = 'RNA';
|
|
44
|
-
break;
|
|
45
|
-
case 'HELM_AA':
|
|
46
|
-
polymerType = 'PEPTIDE';
|
|
47
|
-
break;
|
|
48
|
-
default:
|
|
49
|
-
polymerType = 'PEPTIDE';
|
|
50
|
-
}
|
|
51
|
-
return {symbol: atom.elem, polymerType: polymerType};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function getHoveredMonomerFromEditor(
|
|
55
|
-
argsX: number, argsY: number, gridCell: DG.GridCell, editor: IEditor
|
|
56
|
-
): ISeqMonomer | null {
|
|
57
|
-
let hoveredSeqMonomer: ISeqMonomer | null = null;
|
|
58
|
-
|
|
59
|
-
/** @return {[number, number]} [atom, distance] */
|
|
60
|
-
function getNearest(excluded: (number | undefined)[]): [number | undefined, number | undefined] {
|
|
61
|
-
let atom: number | undefined = undefined;
|
|
62
|
-
let distance: number | undefined = undefined;
|
|
63
|
-
for (let atomI = 0; atomI < editor.m.atoms.length; ++atomI) {
|
|
64
|
-
if (!excluded.includes(atomI)) {
|
|
65
|
-
const aX: number = editor.m.atoms[atomI].p.x;
|
|
66
|
-
const aY: number = editor.m.atoms[atomI].p.y;
|
|
67
|
-
const distanceToAtomI: number = Math.sqrt((argsX - aX) ** 2 + (argsY - aY) ** 2);
|
|
68
|
-
if (distance === undefined || distance > distanceToAtomI) {
|
|
69
|
-
atom = atomI;
|
|
70
|
-
distance = distanceToAtomI;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return [atom, distance];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const [firstAtomI, firstDistance] = getNearest([]);
|
|
78
|
-
const [secondAtomI, secondDistance] = getNearest([firstAtomI]);
|
|
79
|
-
|
|
80
|
-
// for (let atomI = 0; atomI < editor.m.atoms.length; ++atomI) {
|
|
81
|
-
// const aX: number = editor.m.atoms[atomI].p.x;
|
|
82
|
-
// const aY: number = editor.m.atoms[atomI].p.y;
|
|
83
|
-
// const distanceToAtomI: number = Math.sqrt((argsX - aX) ** 2 + (argsY - aY) ** 2);
|
|
84
|
-
// if (firstDistance === undefined || firstDistance > distanceToAtomI) {
|
|
85
|
-
// secondAtomI = firstAtomI;
|
|
86
|
-
// firstAtomI = atomI;
|
|
87
|
-
//
|
|
88
|
-
// secondDistance = firstDistance;
|
|
89
|
-
// firstDistance = distanceToAtomI;
|
|
90
|
-
// }
|
|
91
|
-
// }
|
|
92
|
-
|
|
93
|
-
if (firstAtomI !== undefined && firstDistance !== undefined) {
|
|
94
|
-
const firstAtom = editor.m.atoms[firstAtomI];
|
|
95
|
-
const firstSeqMonomer = getSeqMonomerFromHelmAtom(firstAtom);
|
|
96
|
-
if (secondAtomI !== undefined && secondDistance !== undefined) {
|
|
97
|
-
if (firstDistance < secondDistance * 0.45)
|
|
98
|
-
hoveredSeqMonomer = firstSeqMonomer;
|
|
99
|
-
} else {
|
|
100
|
-
if (firstDistance < 0.35 * gridCell.bounds.height)
|
|
101
|
-
hoveredSeqMonomer = firstSeqMonomer;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return hoveredSeqMonomer;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function getHoveredMonomerFallback(
|
|
108
|
-
argsX: number, _argsY: number, gridCell: DG.GridCell, helmPlacer: HelmMonomerPlacer
|
|
109
|
-
): ISeqMonomer | null {
|
|
110
|
-
let hoveredSeqMonomer: ISeqMonomer | null = null;
|
|
111
|
-
const [allParts, lengths, sumLengths] = helmPlacer.getCellAllPartsLengths(gridCell.tableRowIndex!);
|
|
112
|
-
const maxIndex = Object.values(lengths).length - 1;
|
|
113
|
-
let left = 0;
|
|
114
|
-
let right = maxIndex;
|
|
115
|
-
let found = false;
|
|
116
|
-
let iterCount: number = 0;
|
|
117
|
-
|
|
118
|
-
let mid = 0;
|
|
119
|
-
if (argsX > sumLengths[0]) {
|
|
120
|
-
while (!found && iterCount < sumLengths.length) {
|
|
121
|
-
mid = Math.floor((right + left) / 2);
|
|
122
|
-
if (argsX >= sumLengths[mid] && argsX <= sumLengths[mid + 1]) {
|
|
123
|
-
left = mid;
|
|
124
|
-
found = true;
|
|
125
|
-
} else if (argsX < sumLengths[mid])
|
|
126
|
-
right = mid - 1;
|
|
127
|
-
else if (argsX > sumLengths[mid + 1])
|
|
128
|
-
left = mid + 1;
|
|
129
|
-
|
|
130
|
-
if (left == right)
|
|
131
|
-
found = true;
|
|
132
|
-
|
|
133
|
-
iterCount++;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
left = (argsX >= sumLengths[left]) ? left : left - 1; // correct left to between sumLengths
|
|
137
|
-
if (left >= 0)
|
|
138
|
-
hoveredSeqMonomer = getSeqMonomerFromHelm(allParts[0], allParts[left], helmPlacer.monomerLib);
|
|
139
|
-
return hoveredSeqMonomer;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
type RendererGridCellTemp = {
|
|
143
|
-
[Temps.helmMonomerPlacer]: HelmMonomerPlacer;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function getRendererGridCellTemp(gridCell: DG.GridCell
|
|
147
|
-
): [DG.GridColumn | null, DG.Column | null, RendererGridCellTemp] {
|
|
148
|
-
/** Primarily store/get MonomerPlacer at GridColumn, fallback at (Table) Column for scatter plot tooltip */
|
|
149
|
-
let temp: RendererGridCellTemp | null = null;
|
|
150
|
-
|
|
151
|
-
let gridCol: DG.GridColumn | null = null;
|
|
152
|
-
try { gridCol = gridCell.gridColumn; } catch { gridCol = null; }
|
|
153
|
-
temp = gridCol ? gridCol.temp as RendererGridCellTemp : null;
|
|
154
|
-
|
|
155
|
-
const tableCol: DG.Column = gridCell.cell.column;
|
|
156
|
-
if (!temp) temp = tableCol.temp;
|
|
157
|
-
|
|
158
|
-
if (temp === null) throw new Error(`Monomer placer store (GridColumn or Column) not found.`);
|
|
159
|
-
return [gridCol, tableCol, temp];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
25
|
/** Helm cell renderer in case of no missed monomer draws with JSDraw2.Editor (webeditor),
|
|
163
26
|
* in case of missed monomers presented, draws linear sequences aligned in width per monomer.
|
|
164
27
|
*/
|
|
@@ -173,8 +36,9 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
173
36
|
|
|
174
37
|
onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
|
|
175
38
|
try {
|
|
176
|
-
const [_gridCol, tableCol, temp] =
|
|
177
|
-
|
|
39
|
+
const [_gridCol, tableCol, temp] =
|
|
40
|
+
getGridCellRendererBack<string, HelmMonomerPlacer>(gridCell);
|
|
41
|
+
const helmPlacer = temp['rendererBack'];
|
|
178
42
|
/* Can not do anything without tableColumn */
|
|
179
43
|
if (!tableCol) return;
|
|
180
44
|
|
|
@@ -182,11 +46,11 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
182
46
|
const argsX = e.offsetX - gcb.x;
|
|
183
47
|
const argsY = e.offsetY - gcb.y;
|
|
184
48
|
|
|
185
|
-
const
|
|
49
|
+
const editorMol: JSDraw2.IEditorMol | null = helmPlacer.getEditorMol(gridCell.tableRowIndex!);
|
|
186
50
|
let seqMonomer: ISeqMonomer | null;
|
|
187
51
|
let missedMonomers: Set<string> = new Set<string>(); // of .size = 0
|
|
188
|
-
if (
|
|
189
|
-
seqMonomer =
|
|
52
|
+
if (editorMol)
|
|
53
|
+
seqMonomer = getHoveredMonomerFromEditorMol(argsX, argsY, gridCell, editorMol);
|
|
190
54
|
else {
|
|
191
55
|
const seq: string = !gridCell.cell.value ? '' : removeGapsFromHelm(gridCell.cell.value as string);
|
|
192
56
|
const monomerList = parseHelm(seq);
|
|
@@ -209,7 +73,9 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
209
73
|
if (seqMonomer) {
|
|
210
74
|
if (!missedMonomers.has(seqMonomer.symbol)) {
|
|
211
75
|
const tooltipElements: HTMLElement[] = [ui.div(seqMonomer.symbol)];
|
|
212
|
-
const
|
|
76
|
+
const monomerLib = getMonomerLib();
|
|
77
|
+
const monomerDiv = monomerLib ? monomerLib.getTooltip(seqMonomer.polymerType, seqMonomer.symbol) :
|
|
78
|
+
ui.divText('Monomer library is not available.');
|
|
213
79
|
tooltipElements.push(monomerDiv);
|
|
214
80
|
ui.tooltip.show(ui.divV(tooltipElements), e.x + 16, e.y + 16);
|
|
215
81
|
} else {
|
|
@@ -244,11 +110,12 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
244
110
|
) {
|
|
245
111
|
g.save();
|
|
246
112
|
try {
|
|
247
|
-
const [gridCol, tableCol, temp] =
|
|
113
|
+
const [gridCol, tableCol, temp] =
|
|
114
|
+
getGridCellRendererBack<string, HelmMonomerPlacer>(gridCell);
|
|
248
115
|
/* Can not do anything without tableColumn containing temp */
|
|
249
116
|
if (!tableCol) return;
|
|
250
|
-
let helmPlacer = temp[
|
|
251
|
-
if (!helmPlacer) helmPlacer = temp[
|
|
117
|
+
let helmPlacer = temp['rendererBack'];
|
|
118
|
+
if (!helmPlacer) helmPlacer = temp['rendererBack'] = new HelmMonomerPlacer(gridCol, tableCol);
|
|
252
119
|
|
|
253
120
|
const grid = gridCell.gridRow !== -1 ? gridCell.grid : undefined;
|
|
254
121
|
const missedColor = 'red';
|
|
@@ -273,8 +140,9 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
273
140
|
}
|
|
274
141
|
|
|
275
142
|
// Recreate editor to avoid hanging in window.dojox.gfx.svg.Text.prototype.getTextWidth
|
|
276
|
-
const editor = new JSDraw2.Editor(host,
|
|
277
|
-
|
|
143
|
+
const editor = new JSDraw2.Editor(host,
|
|
144
|
+
{width: w, height: h, skin: 'w8', viewonly: true});
|
|
145
|
+
helmPlacer.setEditorMol(gridCell.tableRowIndex!, editor.m);
|
|
278
146
|
|
|
279
147
|
helmPlacer.skipCell(gridCell.tableRowIndex!);
|
|
280
148
|
return;
|
package/src/constants.ts
CHANGED
|
@@ -12,17 +12,6 @@ export const jsonSdfMonomerLibDict = {
|
|
|
12
12
|
'symbol': 'MonomerCode'
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
-
export type WebEditorMonomer = {
|
|
16
|
-
/** symbol */ id: string,
|
|
17
|
-
/** name */ n: string,
|
|
18
|
-
/** natural analog */ na?: string,
|
|
19
|
-
/** polymer type */type: string,
|
|
20
|
-
/** monomer type */ mt: string,
|
|
21
|
-
/** molfile */ m: string,
|
|
22
|
-
/** substituents */ at: { [group: string]: string },
|
|
23
|
-
/** number of substituents */ rs: number
|
|
24
|
-
};
|
|
25
|
-
|
|
26
15
|
export const SMILES = 'smiles';
|
|
27
16
|
export const RGROUPS = 'rgroups';
|
|
28
17
|
export const MONOMER_SYMBOL = 'symbol';
|
package/src/helm-helper.ts
CHANGED
|
@@ -2,8 +2,12 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
+
import * as scil from 'scil';
|
|
6
|
+
import * as org from 'org';
|
|
7
|
+
|
|
5
8
|
import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
6
|
-
import {IHelmWebEditor
|
|
9
|
+
import {IHelmWebEditor} from '@datagrok-libraries/bio/src/helm/types';
|
|
10
|
+
|
|
7
11
|
import {HelmWebEditor} from './helm-web-editor';
|
|
8
12
|
|
|
9
13
|
type HelmHelperWindowType = Window & {
|
|
@@ -16,11 +20,9 @@ export class HelmHelper implements IHelmHelper {
|
|
|
16
20
|
return new HelmWebEditor();
|
|
17
21
|
}
|
|
18
22
|
|
|
19
|
-
createWebEditorApp(host: HTMLDivElement, helm: string): IWebEditorApp {
|
|
20
|
-
// @ts-ignore
|
|
23
|
+
createWebEditorApp(host: HTMLDivElement, helm: string): org.helm.IWebEditorApp {
|
|
21
24
|
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
22
|
-
|
|
23
|
-
const webEditorApp = new scil.helm.App(host, {
|
|
25
|
+
const webEditorApp: org.helm.IWebEditorApp = new org.helm.webeditor.App(host, {
|
|
24
26
|
showabout: false,
|
|
25
27
|
mexfontsize: '90%',
|
|
26
28
|
mexrnapinontab: true,
|
|
@@ -29,16 +31,13 @@ export class HelmHelper implements IHelmHelper {
|
|
|
29
31
|
sequenceviewonly: false,
|
|
30
32
|
mexfavoritefirst: true,
|
|
31
33
|
mexfilter: true
|
|
32
|
-
})
|
|
34
|
+
});
|
|
33
35
|
const sizes = webEditorApp.calculateSizes();
|
|
34
36
|
webEditorApp.canvas.resize(sizes.rightwidth - 100, sizes.topheight - 210);
|
|
35
|
-
let s = {width: sizes.rightwidth - 100 + 'px', height: sizes.bottomheight + 'px'};
|
|
36
|
-
//@ts-ignore
|
|
37
|
+
let s: Partial<CSSStyleDeclaration> = {width: sizes.rightwidth - 100 + 'px', height: sizes.bottomheight + 'px'};
|
|
37
38
|
scil.apply(webEditorApp.sequence.style, s);
|
|
38
|
-
//@ts-ignore
|
|
39
39
|
scil.apply(webEditorApp.notation.style, s);
|
|
40
40
|
s = {width: sizes.rightwidth + 'px', height: (sizes.bottomheight + webEditorApp.toolbarheight) + 'px'};
|
|
41
|
-
//@ts-ignore
|
|
42
41
|
scil.apply(webEditorApp.properties.parent.style, s);
|
|
43
42
|
webEditorApp.structureview.resize(sizes.rightwidth, sizes.bottomheight + webEditorApp.toolbarheight);
|
|
44
43
|
webEditorApp.mex.resize(sizes.topheight - 80);
|
|
@@ -2,94 +2,43 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
+
import * as org from 'org';
|
|
6
|
+
import * as JSDraw2 from 'JSDraw2';
|
|
5
7
|
import wu from 'wu';
|
|
6
|
-
import {Unsubscribable} from 'rxjs';
|
|
7
8
|
|
|
8
9
|
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types/index';
|
|
10
|
+
import {CellRendererBackBase} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
|
|
11
|
+
import {IEditorMol} from '@datagrok-libraries/bio/src/types/helm-web-editor';
|
|
9
12
|
|
|
10
13
|
import {getParts, parseHelm} from './utils';
|
|
11
14
|
|
|
12
15
|
import {_package, getMonomerLib} from './package';
|
|
13
16
|
|
|
14
|
-
export const enum Temps {
|
|
15
|
-
helmMonomerPlacer = 'bio-helmMonomerPlacer',
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface IEditor {
|
|
19
|
-
get m(): IEditorMol;
|
|
20
|
-
|
|
21
|
-
redraw(): void;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface IEditorMol {
|
|
25
|
-
get atoms(): IEditorMolAtom[];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface IEditorMolAtom {
|
|
29
|
-
get p(): IEditorPoint;
|
|
30
|
-
|
|
31
|
-
get elem(): string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface IEditorPoint {
|
|
35
|
-
get x(): number;
|
|
36
|
-
|
|
37
|
-
get y(): number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
17
|
export interface ISeqMonomer {
|
|
41
|
-
polymerType:
|
|
42
|
-
symbol: string
|
|
18
|
+
polymerType: org.helm.PolymerType;
|
|
19
|
+
symbol: string;
|
|
43
20
|
}
|
|
44
21
|
|
|
45
|
-
export class HelmMonomerPlacer {
|
|
46
|
-
private readonly grid: DG.Grid | null;
|
|
47
|
-
public readonly monomerLib: IMonomerLib;
|
|
48
|
-
|
|
22
|
+
export class HelmMonomerPlacer extends CellRendererBackBase<string> {
|
|
49
23
|
private _allPartsList: (string[] | null)[];
|
|
50
24
|
private _lengthsList: (number[] | null)[];
|
|
51
|
-
private
|
|
25
|
+
private _editorMolList: (JSDraw2.IEditorMol | null)[];
|
|
52
26
|
|
|
53
27
|
public monomerCharWidth: number = 7;
|
|
54
28
|
public leftPadding: number = 5;
|
|
55
29
|
public monomerTextSizeMap: { [p: string]: TextMetrics } = {};
|
|
56
30
|
|
|
57
|
-
private subs: Unsubscribable[] = [];
|
|
58
|
-
|
|
59
31
|
public constructor(
|
|
60
|
-
|
|
61
|
-
|
|
32
|
+
gridCol: DG.GridColumn | null,
|
|
33
|
+
tableCol: DG.Column<string>
|
|
62
34
|
) {
|
|
63
|
-
|
|
64
|
-
this.reset();
|
|
65
|
-
if (this.grid) {
|
|
66
|
-
this.subs.push(this.col.dataFrame.onDataChanged.subscribe(() => {
|
|
67
|
-
try {
|
|
68
|
-
this.reset();
|
|
69
|
-
} catch (err: any) {
|
|
70
|
-
console.error(err);
|
|
71
|
-
}
|
|
72
|
-
}));
|
|
73
|
-
this.subs.push(grok.events.onViewRemoved.subscribe((view: DG.View) => {
|
|
74
|
-
try {
|
|
75
|
-
if (this.grid && this.grid.view?.id === view.id) this.destroy();
|
|
76
|
-
} catch (err: any) {
|
|
77
|
-
console.error(err);
|
|
78
|
-
}
|
|
79
|
-
}));
|
|
80
|
-
}
|
|
81
|
-
this.monomerLib = getMonomerLib();
|
|
82
|
-
this.subs.push(this.monomerLib.onChanged.subscribe(this.monomerLibOnChanged.bind(this)));
|
|
35
|
+
super(gridCol, tableCol, _package.logger);
|
|
83
36
|
}
|
|
84
37
|
|
|
85
|
-
|
|
86
|
-
this._allPartsList = new Array<string[] | null>(this.
|
|
87
|
-
this._lengthsList = new Array<number[] | null>(this.
|
|
88
|
-
this.
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
private destroy(): void {
|
|
92
|
-
for (const sub of this.subs) sub.unsubscribe();
|
|
38
|
+
protected override reset(): void {
|
|
39
|
+
this._allPartsList = new Array<string[] | null>(this.tableCol.length).fill(null);
|
|
40
|
+
this._lengthsList = new Array<number[] | null>(this.tableCol.length).fill(null);
|
|
41
|
+
this._editorMolList = new Array<JSDraw2.IEditorMol | null>(this.tableCol.length).fill(null);
|
|
93
42
|
}
|
|
94
43
|
|
|
95
44
|
/** Skips cell for the fallback rendering */
|
|
@@ -112,7 +61,7 @@ export class HelmMonomerPlacer {
|
|
|
112
61
|
private getCellMonomerLengthsForSeq(rowIdx: number): [string[], number[]] {
|
|
113
62
|
let allParts: string[] | null = this._allPartsList![rowIdx];
|
|
114
63
|
if (allParts === null) {
|
|
115
|
-
const seq = this.
|
|
64
|
+
const seq = this.tableCol.get(rowIdx);
|
|
116
65
|
allParts = this._allPartsList![rowIdx] = getAllParts(seq);
|
|
117
66
|
}
|
|
118
67
|
|
|
@@ -128,32 +77,19 @@ export class HelmMonomerPlacer {
|
|
|
128
77
|
return [allParts, lengths];
|
|
129
78
|
}
|
|
130
79
|
|
|
131
|
-
getMonomer(monomer: ISeqMonomer): Monomer | null {
|
|
132
|
-
let res: Monomer | null = null;
|
|
133
|
-
if (monomer.polymerType)
|
|
134
|
-
res = this.monomerLib.getMonomer(monomer.polymerType, monomer.symbol);
|
|
135
|
-
else {
|
|
136
|
-
for (const polymerType of this.monomerLib.getPolymerTypes()) {
|
|
137
|
-
res = this.monomerLib.getMonomer(polymerType, monomer.symbol);
|
|
138
|
-
if (res) break;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return res;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
80
|
// -- Handle events --
|
|
145
81
|
|
|
146
82
|
private monomerLibOnChanged(_value: any): void {
|
|
147
83
|
this.reset();
|
|
148
|
-
|
|
84
|
+
this.invalidateGrid();
|
|
149
85
|
}
|
|
150
86
|
|
|
151
|
-
public
|
|
152
|
-
this.
|
|
87
|
+
public setEditorMol(tableRowIndex: number, editorMol: JSDraw2.IEditorMol) {
|
|
88
|
+
this._editorMolList![tableRowIndex] = editorMol.clone(false);
|
|
153
89
|
}
|
|
154
90
|
|
|
155
|
-
public
|
|
156
|
-
return this.
|
|
91
|
+
public getEditorMol(tableRowIndex: number): JSDraw2.IEditorMol | null {
|
|
92
|
+
return this._editorMolList![tableRowIndex];
|
|
157
93
|
}
|
|
158
94
|
}
|
|
159
95
|
|
package/src/helm-web-editor.ts
CHANGED
|
@@ -2,11 +2,14 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
+
import * as JSDraw2 from 'JSDraw2';
|
|
6
|
+
|
|
5
7
|
import {IHelmWebEditor} from '@datagrok-libraries/bio/src/helm/types';
|
|
6
8
|
|
|
7
9
|
export class HelmWebEditor implements IHelmWebEditor {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
editor: JSDraw2.Editor;
|
|
11
|
+
host: HTMLDivElement;
|
|
12
|
+
|
|
10
13
|
w = 200;
|
|
11
14
|
h = 100;
|
|
12
15
|
|
package/src/package-test.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import * as DG from 'datagrok-api/dg';
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
|
|
4
|
+
import '@datagrok-libraries/bio/src/types/helm';
|
|
4
5
|
import {runTests, tests, TestContext} from '@datagrok-libraries/utils/src/test';
|
|
5
6
|
|
|
6
7
|
import './tests/helm-tests.ts';
|
|
7
8
|
import './tests/findMonomers-tests';
|
|
9
|
+
import './tests/helm-service-tests';
|
|
8
10
|
import './tests/renderers-tests';
|
|
9
|
-
import './tests/get-molfiles';
|
|
11
|
+
import './tests/get-molfiles-tests';
|
|
10
12
|
import './tests/properties-widget-tests';
|
|
11
13
|
import './tests/get-all-parts-tests';
|
|
14
|
+
import './tests/get-monomer-tests';
|
|
12
15
|
|
|
13
16
|
export const _package = new DG.Package();
|
|
14
17
|
export {tests};
|
|
@@ -20,6 +23,7 @@ export {tests};
|
|
|
20
23
|
//input: object testContext {optional: true}
|
|
21
24
|
//output: dataframe result
|
|
22
25
|
export async function test(category: string, test: string, testContext: TestContext): Promise<DG.DataFrame> {
|
|
23
|
-
|
|
26
|
+
// verbose: true - for tests returning dataframe
|
|
27
|
+
const data = await runTests({category, test, testContext, verbose: true});
|
|
24
28
|
return DG.DataFrame.fromObjects(data)!;
|
|
25
29
|
}
|