@datagrok/helm 2.1.19 → 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.
@@ -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.19",
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.38.8",
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
- "@datagrok/bio": "^2.1.12",
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 @datagrok-libraries/utils @datagrok-libraries/bio",
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"
@@ -8,7 +8,8 @@ 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 {IEditor, 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';
12
13
 
13
14
  // import {_package} from './package'; // NullError: method not found: '_package' on null
14
15
 
@@ -24,10 +25,41 @@ const helmGapStartRe = /\{(\*\.)+/g;
24
25
  const helmGapIntRe = /\.(\*\.)+/g;
25
26
  const helmGapEndRe = /(\.\*)+\}/g;
26
27
 
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
+
27
59
  function getHoveredMonomerFromEditor(
28
60
  argsX: number, argsY: number, gridCell: DG.GridCell, editor: IEditor
29
- ): string | null {
30
- let hoveredMonomerSymbol: string | null = null;
61
+ ): ISeqMonomer | null {
62
+ let hoveredSeqMonomer: ISeqMonomer | null = null;
31
63
 
32
64
  /** @return {[number, number]} [atom, distance] */
33
65
  function getNearest(excluded: (number | undefined)[]): [number | undefined, number | undefined] {
@@ -64,21 +96,23 @@ function getHoveredMonomerFromEditor(
64
96
  // }
65
97
 
66
98
  if (firstAtomI !== undefined && firstDistance !== undefined) {
99
+ const firstAtom = editor.m.atoms[firstAtomI];
100
+ const firstSeqMonomer = getSeqMonomerFromHelmAtom(firstAtom);
67
101
  if (secondAtomI !== undefined && secondDistance !== undefined) {
68
102
  if (firstDistance < secondDistance * 0.45)
69
- hoveredMonomerSymbol = editor.m.atoms[firstAtomI].elem;
103
+ hoveredSeqMonomer = firstSeqMonomer;
70
104
  } else {
71
105
  if (firstDistance < 0.35 * gridCell.bounds.height)
72
- hoveredMonomerSymbol = editor.m.atoms[firstAtomI].elem;
106
+ hoveredSeqMonomer = firstSeqMonomer;
73
107
  }
74
108
  }
75
- return hoveredMonomerSymbol;
109
+ return hoveredSeqMonomer;
76
110
  }
77
111
 
78
112
  function getHoveredMonomerFallback(
79
113
  argsX: number, _argsY: number, gridCell: DG.GridCell, helmPlacer: HelmMonomerPlacer
80
- ): string | null {
81
- let hoveredMonomerSymbol: string | null = null;
114
+ ): ISeqMonomer | null {
115
+ let hoveredSeqMonomer: ISeqMonomer | null = null;
82
116
  const [allParts, lengths, sumLengths] = helmPlacer.getCellAllPartsLengths(gridCell.tableRowIndex!);
83
117
  const maxIndex = Object.values(lengths).length - 1;
84
118
  let left = 0;
@@ -106,38 +140,39 @@ function getHoveredMonomerFallback(
106
140
  }
107
141
  left = (argsX >= sumLengths[left]) ? left : left - 1; // correct left to between sumLengths
108
142
  if (left >= 0)
109
- hoveredMonomerSymbol = allParts[left];
110
- return hoveredMonomerSymbol;
143
+ hoveredSeqMonomer = getSeqMonomerFromHelm(allParts[0], allParts[left], helmPlacer.monomerLib);
144
+ return hoveredSeqMonomer;
111
145
  }
112
146
 
113
- // window.dojox.gfx.svg.Text.prototype.getTextWidth hangs
114
- // /** get the text width in pixels */
115
- // // @ts-ignore
116
- // window.dojox.gfx.svg.Text.prototype.getTextWidth = function() {
117
- // const rawNode = this.rawNode;
118
- // const oldParent = rawNode.parentNode;
119
- // const _measurementNode = rawNode.cloneNode(true);
120
- // _measurementNode.style.visibility = 'hidden';
121
- //
122
- // // solution to the "orphan issue" in FF
123
- // let _width = 0;
124
- // const _text = _measurementNode.firstChild.nodeValue;
125
- // oldParent.appendChild(_measurementNode);
126
- //
127
- // // solution to the "orphan issue" in Opera
128
- // // (nodeValue == "" hangs firefox)
129
- // if (_text != '') {
130
- // while (!_width) { // <-- hangs
131
- // //Yang: work around svgweb bug 417 -- http://code.google.com/p/svgweb/issues/detail?id=417
132
- // if (_measurementNode.getBBox)
133
- // _width = parseInt(_measurementNode.getBBox().width);
134
- // else
135
- // _width = 68;
136
- // }
137
- // }
138
- // oldParent.removeChild(_measurementNode);
139
- // return _width;
140
- // };
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
+ };
141
176
 
142
177
  /** Helm cell renderer in case of no missed monomer draws with JSDraw2.Editor (webeditor),
143
178
  * in case of missed monomers presented, draws linear sequences aligned in width per monomer.
@@ -163,9 +198,9 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
163
198
 
164
199
  const helmPlacer = HelmMonomerPlacer.getOrCreate(tableCol);
165
200
  const editor: IEditor | null = helmPlacer.getEditor(gridCell.tableRowIndex!);
166
- const hoveredMonomerSymbol = editor ? getHoveredMonomerFromEditor(argsX, argsY, gridCell, editor) :
201
+ const seqMonomer: ISeqMonomer | null = editor ? getHoveredMonomerFromEditor(argsX, argsY, gridCell, editor) :
167
202
  getHoveredMonomerFallback(argsX, argsY, gridCell, helmPlacer);
168
- if (!hoveredMonomerSymbol) {
203
+ if (!seqMonomer) {
169
204
  ui.tooltip.hide();
170
205
  return;
171
206
  }
@@ -176,18 +211,18 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
176
211
  const monomerList = parseHelm(seq);
177
212
  const missedMonomers = findMonomers(monomerList);
178
213
 
179
- if (missedMonomers.has(hoveredMonomerSymbol)) {
214
+ if (missedMonomers.has(seqMonomer.symbol)) {
180
215
  ui.tooltip.show(ui.divV([
181
- ui.divText(`Monomer ${hoveredMonomerSymbol} not found.`),
216
+ ui.divText(`Monomer ${seqMonomer.symbol} not found.`),
182
217
  ui.divText('Open the Context Panel, then expand Manage Libraries'),
183
218
  ]), e.x + 16, e.y + 16);
184
219
  } else {
185
- const monomer = helmPlacer.getMonomer(hoveredMonomerSymbol);
220
+ const monomer = helmPlacer.getMonomer(seqMonomer);
186
221
  if (monomer) {
187
222
  const options = {autoCrop: true, autoCropMargin: 0, suppressChiralText: true};
188
223
  const monomerSvg = grok.chem.svgMol(monomer.smiles, undefined, undefined, options);
189
224
  ui.tooltip.show(ui.divV([
190
- ui.divText(hoveredMonomerSymbol),
225
+ ui.divText(seqMonomer.symbol),
191
226
  monomerSvg,
192
227
  ]), e.x + 16, e.y + 16);
193
228
  }
@@ -218,6 +253,9 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
218
253
  } catch (err: any) {
219
254
  const errMsg: string = errorToConsole(err);
220
255
  console.error('Helm: HelmCellRenderer.onMouseMove() error:\n' + errMsg);
256
+ } finally {
257
+ e.preventDefault();
258
+ e.stopPropagation();
221
259
  }
222
260
  }
223
261
 
@@ -246,7 +284,8 @@ export class HelmCellRenderer extends DG.GridCellRenderer {
246
284
 
247
285
  if (missedMonomers.size == 0) {
248
286
  // Recreate host to avoid hanging in window.dojox.gfx.svg.Text.prototype.getTextWidth
249
- const host = gridCell.element = ui.div([], {style: {width: `${w}px`, height: `${h}px`}});
287
+ const host = gridCell.element = ui.div([],
288
+ {style: {width: `${w - 2}px`, height: `${h - 2}px`, margin: `${1}px`, backgroundColor: '#FFE0E0'}});
250
289
  host.setAttribute('dataformat', 'helm');
251
290
  host.setAttribute('data', seq /* gaps skipped */);
252
291
 
@@ -35,12 +35,17 @@ export interface IEditorPoint {
35
35
  get y(): number;
36
36
  }
37
37
 
38
+ export interface ISeqMonomer {
39
+ symbol: string,
40
+ polymerType?: string
41
+ }
42
+
38
43
  export class HelmMonomerPlacer {
39
- private _allPartsList: (string[] | null)[];
40
- private _lengthsList: (number[] | null)[];
41
- private _editorList: (IEditor | null)[];
44
+ private readonly _allPartsList: (string[] | null)[];
45
+ private readonly _lengthsList: (number[] | null)[];
46
+ private readonly _editorList: (IEditor | null)[];
42
47
 
43
- private monomerLib: IMonomerLib;
48
+ public readonly monomerLib: IMonomerLib;
44
49
 
45
50
  public monomerCharWidth: number = 7;
46
51
  public leftPadding: number = 5;
@@ -95,11 +100,15 @@ export class HelmMonomerPlacer {
95
100
  return seq ? getParts(monomerList, seq) : [];
96
101
  }
97
102
 
98
- getMonomer(monomerSymbol: any): Monomer | null {
103
+ getMonomer(monomer: ISeqMonomer): Monomer | null {
99
104
  let res: Monomer | null = null;
100
- for (const polymerType of this.monomerLib.getPolymerTypes()) {
101
- res = this.monomerLib.getMonomer(polymerType, monomerSymbol);
102
- if (res) break;
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
+ }
103
112
  }
104
113
  return res;
105
114
  }
package/src/package.ts CHANGED
@@ -112,7 +112,7 @@ function rewriteLibraries() {
112
112
  //name: helmCellRenderer
113
113
  //tags: cellRenderer
114
114
  //meta.cellType: helm
115
- //meta.columnTags: units=helm
115
+ //meta.columnTags: quality=Macromolecule, units=helm
116
116
  //output: grid_cell_renderer result
117
117
  export function helmCellRenderer(): HelmCellRenderer {
118
118
  return new HelmCellRenderer();
@@ -283,7 +283,7 @@ export function getMolfiles(col: DG.Column): DG.Column {
283
283
  }
284
284
 
285
285
  //name: helmWebEditor
286
- //output: object
286
+ //output: object result
287
287
  export function helmWebEditor(): HelmWebEditor {
288
288
  return new HelmWebEditor();
289
289
  }