@datagrok/helm 2.1.16 → 2.1.18
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 -2
- package/CHANGELOG.md +23 -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 +2 -2
- package/src/cell-renderer.ts +12 -7
- package/src/helm-monomer-placer.ts +30 -7
- package/src/package.ts +24 -13
- package/src/utils.ts +1 -2
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.18",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Oleksandra Serhiienko",
|
|
7
7
|
"email": "oserhiienko@datagrok.ai"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"helm/JSDraw/Pistoia.HELM-uncompressed.js"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@datagrok-libraries/bio": "^5.
|
|
18
|
+
"@datagrok-libraries/bio": "^5.38.0",
|
|
19
19
|
"@datagrok-libraries/utils": "^4.0.17",
|
|
20
20
|
"cash-dom": "^8.1.1",
|
|
21
21
|
"datagrok-api": "^1.10.2",
|
package/src/cell-renderer.ts
CHANGED
|
@@ -60,11 +60,11 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
60
60
|
if (argsX >= sumLengths[mid] && argsX <= sumLengths[mid + 1]) {
|
|
61
61
|
left = mid;
|
|
62
62
|
found = true;
|
|
63
|
-
} else if (argsX < sumLengths[mid])
|
|
63
|
+
} else if (argsX < sumLengths[mid])
|
|
64
64
|
right = mid - 1;
|
|
65
|
-
|
|
65
|
+
else if (argsX > sumLengths[mid + 1])
|
|
66
66
|
left = mid + 1;
|
|
67
|
-
|
|
67
|
+
|
|
68
68
|
if (left == right)
|
|
69
69
|
found = true;
|
|
70
70
|
|
|
@@ -73,7 +73,9 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
73
73
|
}
|
|
74
74
|
left = (argsX >= sumLengths[left]) ? left : left - 1; // correct left to between sumLengths
|
|
75
75
|
|
|
76
|
-
const seq: string = gridCell.cell.value
|
|
76
|
+
const seq: string = !gridCell.cell.value ? '' : gridCell.cell.value
|
|
77
|
+
.replaceAll(helmGapStartRe, '{').replaceAll(helmGapIntRe, '.').replaceAll(helmGapEndRe, '}')
|
|
78
|
+
.replace('{*}', '{}');
|
|
77
79
|
const monomerList = parseHelm(seq);
|
|
78
80
|
const monomers = new Set<string>(monomerList);
|
|
79
81
|
const missedMonomers = findMonomers(monomerList);
|
|
@@ -121,15 +123,19 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
121
123
|
const monomerColor: string = '#404040';
|
|
122
124
|
const frameColor: string = '#C0C0C0';
|
|
123
125
|
|
|
124
|
-
const seq = gridCell.cell.value
|
|
126
|
+
const seq: string = !gridCell.cell.value ? '' : gridCell.cell.value
|
|
127
|
+
.replaceAll(helmGapStartRe, '{').replaceAll(helmGapIntRe, '.').replaceAll(helmGapEndRe, '}')
|
|
128
|
+
.replace('{*}', '{}');
|
|
125
129
|
const monomerList = parseHelm(seq);
|
|
126
130
|
const monomers: Set<string> = new Set<string>(monomerList);
|
|
127
131
|
const missedMonomers: Set<string> = findMonomers(monomerList);
|
|
132
|
+
const helmPlacer = HelmMonomerPlacer.getOrCreate(tableCol);
|
|
128
133
|
|
|
129
134
|
if (missedMonomers.size == 0) {
|
|
135
|
+
helmPlacer.skipCell(gridCell.tableRowIndex!);
|
|
130
136
|
const host = ui.div([], {style: {width: `${w}px`, height: `${h}px`}});
|
|
131
137
|
host.setAttribute('dataformat', 'helm');
|
|
132
|
-
host.setAttribute('data',
|
|
138
|
+
host.setAttribute('data', seq /* gaps skipped */);
|
|
133
139
|
gridCell.element = host;
|
|
134
140
|
//@ts-ignore
|
|
135
141
|
const canvas = new JSDraw2.Editor(host, {width: w, height: h, skin: 'w8', viewonly: true});
|
|
@@ -152,7 +158,6 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
|
|
|
152
158
|
g.transform(1, 0, 0, 1, x, y);
|
|
153
159
|
g.font = '12px monospace';
|
|
154
160
|
g.textBaseline = 'top';
|
|
155
|
-
const helmPlacer = HelmMonomerPlacer.getOrCreate(tableCol);
|
|
156
161
|
const [allParts, lengths, sumLengths] = helmPlacer.getCellAllPartsLengths(gridCell.tableRowIndex!);
|
|
157
162
|
|
|
158
163
|
for (let i = 0; i < allParts.length; ++i) {
|
|
@@ -25,13 +25,23 @@ export class HelmMonomerPlacer {
|
|
|
25
25
|
constructor(public readonly col: DG.Column<string>) {
|
|
26
26
|
this.col.dataFrame.onDataChanged.subscribe();
|
|
27
27
|
this.monomerLib = getMonomerLib();
|
|
28
|
+
this.monomerLib.onChanged.subscribe(this.monomerLibOnChanged.bind(this));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
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
|
+
this._allPartsList[rowIdx] = [];
|
|
38
|
+
this._lengthsList[rowIdx] = [];
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
/** @param rowIdx Row index of the table {@link DG.DataFrame}, HelmMonomerPlacer is {@link DG.Column} based */
|
|
31
42
|
public getCellAllPartsLengths(rowIdx: number): [string[], number[], number[]] {
|
|
32
43
|
if (this._allPartsList === null)
|
|
33
44
|
this._allPartsList = new Array<string[] | null>(this.col.length).fill(null);
|
|
34
|
-
|
|
35
45
|
if (this._lengthsList === null)
|
|
36
46
|
this._lengthsList = new Array<number[] | null>(this.col.length).fill(null);
|
|
37
47
|
|
|
@@ -45,12 +55,17 @@ export class HelmMonomerPlacer {
|
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
private getCellMonomerLengthsForSeq(rowIdx: number): [string[], number[]] {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
let allParts: string[] | null = this._allPartsList![rowIdx];
|
|
59
|
+
if (allParts === null)
|
|
60
|
+
allParts = this._allPartsList![rowIdx] = this.getAllParts(rowIdx);
|
|
61
|
+
|
|
62
|
+
let lengths: number[] | null = this._lengthsList![rowIdx];
|
|
63
|
+
if (lengths === null) {
|
|
64
|
+
lengths = this._lengthsList![rowIdx] = new Array<number>(allParts.length);
|
|
65
|
+
for (const [part, partI] of wu.enumerate(allParts)) {
|
|
66
|
+
const partWidth: number = part.length * this.monomerCharWidth;
|
|
67
|
+
lengths[partI] = partWidth;
|
|
68
|
+
}
|
|
54
69
|
}
|
|
55
70
|
|
|
56
71
|
return [allParts, lengths];
|
|
@@ -71,6 +86,14 @@ export class HelmMonomerPlacer {
|
|
|
71
86
|
return res;
|
|
72
87
|
}
|
|
73
88
|
|
|
89
|
+
// -- Handle events --
|
|
90
|
+
|
|
91
|
+
private monomerLibOnChanged(_value: any): void {
|
|
92
|
+
this._lengthsList = null;
|
|
93
|
+
this._allPartsList = null;
|
|
94
|
+
// TODO: Invalidate all grids of this.col.dataFrame
|
|
95
|
+
}
|
|
96
|
+
|
|
74
97
|
public static getOrCreate(col: DG.Column<string>): HelmMonomerPlacer {
|
|
75
98
|
if (!(Temps.helmMonomerPlacer in col.temp)) col.temp[Temps.helmMonomerPlacer] = new HelmMonomerPlacer(col);
|
|
76
99
|
return col.temp[Temps.helmMonomerPlacer];
|
package/src/package.ts
CHANGED
|
@@ -7,16 +7,20 @@ import {WebEditorMonomer, RGROUP_CAP_GROUP_NAME, RGROUP_LABEL, SMILES} from './c
|
|
|
7
7
|
import {HelmWebEditor} from './helm-web-editor';
|
|
8
8
|
import {HelmCellRenderer} from './cell-renderer';
|
|
9
9
|
import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
|
|
10
|
-
import {
|
|
10
|
+
import {GapSymbols, UnitsHandler} from '@datagrok-libraries/bio/src/utils/units-handler';
|
|
11
11
|
import {findMonomers, parseHelm} from './utils';
|
|
12
12
|
import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
|
|
13
13
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
14
14
|
|
|
15
|
-
export const _package = new DG.Package();
|
|
16
15
|
let monomerLib: IMonomerLib | null = null;
|
|
17
16
|
|
|
17
|
+
export const _package = new DG.Package();
|
|
18
|
+
|
|
18
19
|
//tags: init
|
|
19
20
|
export async function initHelm(): Promise<void> {
|
|
21
|
+
//@ts-ignore
|
|
22
|
+
org.helm.webeditor.kCaseSensitive = true; // GROK-13880
|
|
23
|
+
|
|
20
24
|
return Promise.all([
|
|
21
25
|
new Promise((resolve, reject) => {
|
|
22
26
|
// @ts-ignore
|
|
@@ -58,6 +62,7 @@ export function getMonomerLib(): IMonomerLib {
|
|
|
58
62
|
return monomerLib!;
|
|
59
63
|
}
|
|
60
64
|
|
|
65
|
+
/** Fills org.helm.webeditor.Monomers dictionary for WebEditor */
|
|
61
66
|
function rewriteLibraries() {
|
|
62
67
|
// @ts-ignore
|
|
63
68
|
org.helm.webeditor.Monomers.clear();
|
|
@@ -87,9 +92,8 @@ function rewriteLibraries() {
|
|
|
87
92
|
} else if (monomer[SMILES] != null) {
|
|
88
93
|
webEditorMonomer.rs = Object.keys(getRS(monomer[SMILES].toString())).length;
|
|
89
94
|
webEditorMonomer.at = getRS(monomer[SMILES].toString());
|
|
90
|
-
} else
|
|
95
|
+
} else
|
|
91
96
|
isBroken = true;
|
|
92
|
-
}
|
|
93
97
|
|
|
94
98
|
if (!isBroken) {
|
|
95
99
|
// @ts-ignore
|
|
@@ -116,8 +120,13 @@ function checkMonomersAndOpenWebEditor(cell?: DG.Cell, value?: string, units?: s
|
|
|
116
120
|
const cellValue: string = !!cell && units === undefined ? cell.value : value;
|
|
117
121
|
const monomerList: string[] = parseHelm(cellValue);
|
|
118
122
|
const monomers = findMonomers(monomerList);
|
|
119
|
-
if (monomers.size
|
|
120
|
-
|
|
123
|
+
if (monomers.size === 0)
|
|
124
|
+
webEditor(cell, value, units);
|
|
125
|
+
else if (monomers.size === 1 && monomers.has(GapSymbols[NOTATION.HELM]))
|
|
126
|
+
grok.shell.warning(`WebEditor doesn't support Helm with gaps '${GapSymbols[NOTATION.HELM]}'.`);
|
|
127
|
+
else {
|
|
128
|
+
grok.shell.warning(
|
|
129
|
+
`Monomers ${Array.from(monomers).map((m) => `'${m}'`).join(', ')} are absent! <br/>` +
|
|
121
130
|
`Please, upload the monomer library! <br/>` +
|
|
122
131
|
`<a href="https://datagrok.ai/help/domains/bio/macromolecules" target="_blank">Learn more</a>`);
|
|
123
132
|
}
|
|
@@ -138,12 +147,13 @@ export function editMoleculeCell(cell: DG.GridCell): void {
|
|
|
138
147
|
export function openEditor(mol: string): void {
|
|
139
148
|
const df = grok.shell.tv.grid.dataFrame;
|
|
140
149
|
const col = df.columns.bySemType('Macromolecule')!;
|
|
150
|
+
const colUh = UnitsHandler.getOrCreate(col);
|
|
141
151
|
const colUnits = col.getTag(DG.TAGS.UNITS);
|
|
142
152
|
if (colUnits === NOTATION.HELM)
|
|
143
153
|
checkMonomersAndOpenWebEditor(df.currentCell, undefined, undefined);
|
|
144
|
-
const
|
|
145
|
-
const
|
|
146
|
-
checkMonomersAndOpenWebEditor(df.currentCell,
|
|
154
|
+
const convert = colUh.getConverter(NOTATION.HELM);
|
|
155
|
+
const helmMol = convert(mol);
|
|
156
|
+
checkMonomersAndOpenWebEditor(df.currentCell, helmMol, col.getTag(DG.TAGS.UNITS));
|
|
147
157
|
}
|
|
148
158
|
|
|
149
159
|
//name: Properties
|
|
@@ -175,7 +185,8 @@ export async function propertiesPanel(helmString: string) {
|
|
|
175
185
|
function webEditor(cell?: DG.Cell, value?: string, units?: string) {
|
|
176
186
|
const view = ui.div();
|
|
177
187
|
const df = grok.shell.tv.grid.dataFrame;
|
|
178
|
-
const
|
|
188
|
+
const col = df.columns.bySemType('Macromolecule')!;
|
|
189
|
+
const uh = UnitsHandler.getOrCreate(col);
|
|
179
190
|
// @ts-ignore
|
|
180
191
|
org.helm.webeditor.MolViewer.molscale = 0.8;
|
|
181
192
|
// @ts-ignore
|
|
@@ -214,10 +225,10 @@ function webEditor(cell?: DG.Cell, value?: string, units?: string) {
|
|
|
214
225
|
const helmValue = app.canvas.getHelm(true).replace(/<\/span>/g, '')
|
|
215
226
|
.replace(/<span style='background:#bbf;'>/g, '');
|
|
216
227
|
if (!!cell) {
|
|
217
|
-
if (units === undefined)
|
|
228
|
+
if (units === undefined)
|
|
218
229
|
cell.value = helmValue;
|
|
219
|
-
|
|
220
|
-
const convertedRes =
|
|
230
|
+
else {
|
|
231
|
+
const convertedRes = uh.convertHelmToFastaSeparator(helmValue, units!);
|
|
221
232
|
cell.value = convertedRes;
|
|
222
233
|
}
|
|
223
234
|
}
|
package/src/utils.ts
CHANGED
|
@@ -94,9 +94,8 @@ export function parseHelm(s: string): string[] {
|
|
|
94
94
|
// return new Set(helmPartList.filter((val) => !monomerNameList.includes(val)));
|
|
95
95
|
// }
|
|
96
96
|
|
|
97
|
-
/** Searches monomers of
|
|
97
|
+
/** Searches monomers of helmString for missed. */
|
|
98
98
|
export function findMonomers(monomerSymbolList: string[]): Set<string> {
|
|
99
|
-
//@ts-ignore
|
|
100
99
|
const types = Object.keys(org.helm.webeditor.monomerTypeList());
|
|
101
100
|
const monomers: any = [];
|
|
102
101
|
const monomerNames: any = [];
|