@datagrok/helm 2.4.6 → 2.5.2

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/webpack.config.js CHANGED
@@ -16,6 +16,11 @@ module.exports = {
16
16
  library: {type: 'var', name: `${packageName}_test`},
17
17
  import: './src/package-test.ts',
18
18
  },
19
+ dojo: {
20
+ filename: 'package-dojo.js',
21
+ library: {type: 'var', name: `${packageName}_dojo`},
22
+ import: './helm/dojo/package.ts',
23
+ },
19
24
  },
20
25
  resolve: {
21
26
  fallback: {'url': false},
@@ -29,7 +34,9 @@ module.exports = {
29
34
  devServer: {
30
35
  contentBase: './dist',
31
36
  },
37
+ // amd: {toUrlUndefined: true},
32
38
  module: {
39
+ noParse: /vendor/,
33
40
  rules: [
34
41
  {test: /\.js$/, enforce: 'pre', use: ['source-map-loader'], exclude: [/node_modules/]},
35
42
  {test: /\.ts(x?)$/, use: 'ts-loader', exclude: [/node_modules/]},
@@ -1,162 +0,0 @@
1
- import * as grok from 'datagrok-api/grok';
2
- import * as ui from 'datagrok-api/ui';
3
- import * as DG from 'datagrok-api/dg';
4
-
5
- import wu from 'wu';
6
-
7
- import {HelmMol, ISeqMonomer} from '@datagrok-libraries/bio/src/helm/types';
8
-
9
- import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
10
- import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
11
-
12
- import {findMonomers, parseHelm, removeGapsFromHelm} from './utils';
13
- import {HelmMonomerPlacer} from './helm-monomer-placer';
14
- import {getHoveredMonomerFallback, getHoveredMonomerFromEditorMol, getSeqMonomerFromHelmAtom} from './utils/get-hovered';
15
- import {JSDraw2Module} from './types';
16
-
17
- import {_package} from './package';
18
-
19
- declare const JSDraw2: JSDraw2Module;
20
-
21
- const enum tempTAGS {
22
- helmSumMaxLengthWords = 'helm-sum-maxLengthWords',
23
- helmMaxLengthWords = 'helm-maxLengthWords',
24
-
25
- helmPlacer = 'bio-helmPlacer',
26
- }
27
-
28
- /** Helm cell renderer in case of no missed monomer draws with JSDraw2.Editor (webeditor),
29
- * in case of missed monomers presented, draws linear sequences aligned in width per monomer.
30
- */
31
- export class HelmCellRenderer extends DG.GridCellRenderer {
32
- get name() { return 'helm'; }
33
-
34
- get cellType() { return 'helm'; }
35
-
36
- get defaultWidth(): number | null { return 400; }
37
-
38
- get defaultHeight(): number | null { return 100; }
39
-
40
- onMouseMove(gridCell: DG.GridCell, e: MouseEvent): void {
41
- try {
42
- const [_gridCol, tableCol, temp] =
43
- getGridCellRendererBack<string, HelmMonomerPlacer>(gridCell);
44
- const helmPlacer = temp['rendererBack'];
45
- /* Can not do anything without tableColumn */
46
- if (!tableCol) return;
47
-
48
- /** {@link gridCell}.bounds */ const gcb = gridCell.bounds;
49
- const argsX = e.offsetX - gcb.x;
50
- const argsY = e.offsetY - gcb.y;
51
-
52
- const monomerLib = _package.monomerLib;
53
- const editorMol: HelmMol | null = helmPlacer.getEditorMol(gridCell.tableRowIndex!);
54
- let seqMonomer: ISeqMonomer | null;
55
- let missedMonomers: Set<string> = new Set<string>(); // of .size = 0
56
- if (editorMol) {
57
- const hoveredAtom = getHoveredMonomerFromEditorMol(argsX, argsY, editorMol, gridCell.bounds.height);
58
- seqMonomer = hoveredAtom ? getSeqMonomerFromHelmAtom(hoveredAtom) : null;
59
- } else {
60
- const seq: string = !gridCell.cell.value ? '' : removeGapsFromHelm(gridCell.cell.value as string);
61
- const monomerList = parseHelm(seq);
62
- missedMonomers = findMonomers(monomerList, monomerLib);
63
- const parsedMonomers = new Set<string>(monomerList);
64
- seqMonomer = getHoveredMonomerFallback(argsX, argsY, gridCell, helmPlacer);
65
- if (seqMonomer && !parsedMonomers.has(seqMonomer.symbol)) seqMonomer = null;
66
- if (seqMonomer) {
67
- const textSize = helmPlacer.monomerTextSizeMap[seqMonomer.symbol];
68
- if (textSize) {
69
- const textBaseLine = gcb.height / 2 -
70
- (textSize.fontBoundingBoxAscent + textSize.fontBoundingBoxDescent) / 2 + 1;
71
- const textTop = textBaseLine - textSize.fontBoundingBoxAscent;
72
- const textBottom = textBaseLine + textSize.fontBoundingBoxDescent;
73
- if (argsY < textTop || textBottom < argsY) seqMonomer = null;
74
- }
75
- }
76
- }
77
-
78
- if (seqMonomer) {
79
- if (!missedMonomers.has(seqMonomer.symbol)) {
80
- const tooltipElements: HTMLElement[] = [ui.div(seqMonomer.symbol)];
81
- const monomerDiv = monomerLib ? monomerLib.getTooltip(seqMonomer.polymerType, seqMonomer.symbol) :
82
- ui.divText('Monomer library is not available.');
83
- tooltipElements.push(monomerDiv);
84
- ui.tooltip.show(ui.divV(tooltipElements), e.x + 16, e.y + 16);
85
- } else {
86
- ui.tooltip.show(ui.divV([
87
- ui.divText(`Monomer '${seqMonomer.symbol}' not found.`),
88
- ui.divText('Open the Context Panel, then expand Manage Libraries'),
89
- ]), e.x + 16, e.y + 16);
90
- }
91
- } else if (missedMonomers.size == 0) {
92
- ui.tooltip.hide();
93
- return;
94
- } else { // seqMonomer == null && missedMonomers.size > 0
95
- const mmStrList = wu(missedMonomers.keys()).toArray().sort()
96
- .filter((_, i) => i < 3);
97
- const missedMonomersStr = mmStrList.join(', ') + (missedMonomers.size > 3 ? ', ...' : '');
98
- ui.tooltip.show(ui.divV([ui.divText('Monomers missed in monomer libraries:'),
99
- ui.divText(missedMonomersStr)
100
- ]), e.x + 16, e.y + 16);
101
- }
102
- } catch (err: any) {
103
- const errMsg: string = errorToConsole(err);
104
- console.error('Helm: HelmCellRenderer.onMouseMove() error:\n' + errMsg);
105
- } finally {
106
- e.preventDefault();
107
- e.stopPropagation();
108
- }
109
- }
110
-
111
-
112
- render(g: CanvasRenderingContext2D, x: number, y: number, w: number, h: number,
113
- gridCell: DG.GridCell, cellStyle: DG.GridCellStyle
114
- ) {
115
- g.save();
116
- try {
117
- const [gridCol, tableCol, temp] =
118
- getGridCellRendererBack<string, HelmMonomerPlacer>(gridCell);
119
- /* Can not do anything without tableColumn containing temp */
120
- if (!tableCol) return;
121
- let helmPlacer = temp['rendererBack'];
122
- if (!helmPlacer) helmPlacer = temp['rendererBack'] = new HelmMonomerPlacer(gridCol, tableCol);
123
-
124
- const grid = gridCell.gridRow !== -1 ? gridCell.grid : undefined;
125
- const missedColor = 'red';
126
- const monomerColor: string = '#404040';
127
- const frameColor: string = '#C0C0C0';
128
-
129
- const seq: string = !gridCell.cell.value ? '' : removeGapsFromHelm(gridCell.cell.value);
130
- const monomerList = parseHelm(seq);
131
- const monomers: Set<string> = new Set<string>(monomerList);
132
- const monomerLib = _package.monomerLib;
133
- const missedMonomers: Set<string> = findMonomers(monomerList, monomerLib);
134
-
135
- if (missedMonomers.size == 0) {
136
- // Recreate host to avoid hanging in window.dojox.gfx.svg.Text.prototype.getTextWidth
137
- const host = gridCell.element = ui.div([],
138
- {style: {width: `${w - 2}px`, height: `${h - 2}px`, margin: `${1}px`, backgroundColor: '#FFE0E0'}});
139
- host.setAttribute('dataformat', 'helm');
140
- host.setAttribute('data', seq /* gaps skipped */);
141
- // if grid has neighbour to the left, then shift host to the left
142
- if (host.parentElement && (gridCell.grid?.canvas?.offsetLeft ?? 0) > 0) {
143
- host.parentElement.style.left =
144
- `${(gridCell.grid?.canvas?.offsetLeft ?? 0) + host.parentElement.offsetLeft}px`;
145
- }
146
-
147
- // Recreate editor to avoid hanging in window.dojox.gfx.svg.Text.prototype.getTextWidth
148
- const editor = new JSDraw2.Editor(host,
149
- {width: w, height: h, skin: 'w8', viewonly: true});
150
- helmPlacer.setEditorMol(gridCell.tableRowIndex!, editor.m);
151
-
152
- helmPlacer.skipCell(gridCell.tableRowIndex!);
153
- return;
154
- }
155
-
156
- if (missedMonomers.size > 0)
157
- throw new Error('Unexpected missed monomers');
158
- } finally {
159
- g.restore();
160
- }
161
- }
162
- }
@@ -1,149 +0,0 @@
1
- import * as grok from 'datagrok-api/grok';
2
- import * as ui from 'datagrok-api/ui';
3
- import * as DG from 'datagrok-api/dg';
4
-
5
- import {
6
- HelmType, IWebEditorMonomer, MonomerType, PolymerType, WebEditorRGroups
7
- } from '@datagrok-libraries/bio/src/helm/types';
8
-
9
- import {Monomer} from '@datagrok-libraries/bio/src/types/index';
10
- import {
11
- HELM_REQUIRED_FIELD as REQ, HELM_OPTIONAL_FIELDS as OPT, HELM_RGROUP_FIELDS as RGP,
12
- } from '@datagrok-libraries/bio/src/utils/const';
13
-
14
- export function getRS(smiles: string) {
15
- const newS = smiles.match(/(?<=\[)[^\][]*(?=])/gm);
16
- const res: { [name: string]: string } = {};
17
- let el = '';
18
- let digit;
19
- if (!!newS) {
20
- for (let i = 0; i < newS.length; i++) {
21
- if (newS[i] != null) {
22
- if (/\d/.test(newS[i])) {
23
- digit = newS[i][newS[i].length - 1];
24
- newS[i] = newS[i].replace(/[0-9]/g, '');
25
- for (let j = 0; j < newS[i].length; j++) {
26
- if (newS[i][j] != ':')
27
- el += newS[i][j];
28
- }
29
- res['R' + digit] = el;
30
- el = '';
31
- }
32
- }
33
- }
34
- }
35
- return res;
36
- }
37
-
38
- /* eslint-disable camelcase */
39
- export abstract class DummyWebEditorMonomer implements IWebEditorMonomer {
40
- //@formatter:off
41
- public abstract get backgroundcolor(): string | undefined;
42
- public abstract get linecolor(): string | undefined;
43
- public abstract get textcolor(): string | undefined;
44
- //@formatter:on
45
-
46
- get issmiles(): boolean { return !!this.smiles; }
47
-
48
- /** R-Group index os single digit only is allowed in Pistoia code */
49
- public readonly at: WebEditorRGroups = {
50
- R1: 'H', R2: 'H', R3: 'H', R4: 'H', R5: 'H', R6: 'H', R7: 'H', R8: 'H', R9: 'H'
51
- };
52
-
53
- public get rs(): number { return Object.keys(this.at).length; }
54
-
55
- protected constructor(
56
- public readonly biotype: string,
57
- /** symbol */ public readonly id: string,
58
- /** name */ public readonly n: string | undefined = 'missing',
59
- /** molfile */ public readonly m: string | undefined = undefined,
60
- /* Pistoia.HELM deletes .type and .mt in Monomers.addOneMonomer() */
61
- /** polymer type */ public readonly type: PolymerType | undefined = undefined,
62
- /** monomer type */ public readonly mt: MonomerType | undefined = undefined,
63
- public readonly smiles?: string,
64
- ) {
65
- if (!this.id)
66
- throw new Error('Invalid arg undefined [id].');
67
-
68
- // return new Proxy(this, {
69
- // get: (target: any, prop: string | symbol, _receiver: any) => {
70
- // const logPrefix = `${this.toLog()}.proxy.get( '${String(prop)}' )`;
71
- // switch (prop) {
72
- // case 'id':
73
- // case 'at':
74
- // case 'na':
75
- // case 'nature':
76
- // case 'backgroundcolor':
77
- // case 'linecolor':
78
- // case 'textcolor': {
79
- // // these attributes are known and handled
80
- // return target[prop];
81
- // }
82
- // case 'rs': {
83
- // /* R-Group count (?), 2 is default for monomer "?" */
84
- // throw new Error('Not supported get "rs" attribute.');
85
- // }
86
- // default:
87
- // // Unexpected attribute requested
88
- // _package.logger.warning(`${logPrefix}`);
89
- // return target[prop];
90
- // }
91
- // },
92
- // set: (target, prop, value: any, _receiver: any): boolean => {
93
- // throw new Error(`Not supported set '${String(prop)}' attribute, any.`);
94
- // },
95
- // apply: (target: any, thisArg: any, argArray: any[]): any | undefined => {
96
- // throw new Error(`Not supported call (apply) '${thisArg.toString()}' method, any.`);
97
- // }
98
- // });
99
- }
100
-
101
- private static objCounter: number = -1;
102
- private readonly objId: number = ++DummyWebEditorMonomer.objCounter;
103
-
104
- private readonly className: string = 'DummyWebEditorMonomer';
105
-
106
- protected toLog(): string {
107
- return `Helm: ${this.className}<${this.objId}>`;
108
- }
109
- }
110
-
111
- export class GapWebEditorMonomer extends DummyWebEditorMonomer {
112
- public readonly backgroundcolor: string = '#FFFFFF';
113
- public readonly linecolor: string = '#808080';
114
- public readonly textcolor: string = '#808080';
115
-
116
- constructor(biotype: string, id: string) {
117
- super(biotype, id, 'gap');
118
- }
119
- }
120
-
121
- export class AmbiguousWebEditorMonomer extends DummyWebEditorMonomer {
122
- public readonly backgroundcolor: string = '#808080';
123
- public readonly linecolor: string = '#000000';
124
- public readonly textcolor: string = '#000000';
125
-
126
- constructor(biotype: string, id: string) {
127
- super(biotype, id, 'ambiguous');
128
- }
129
- }
130
-
131
- export class MissingWebEditorMonomer extends DummyWebEditorMonomer {
132
- public readonly backgroundcolor: string = '#FF4444';
133
- public readonly linecolor: string = '#800000';
134
- public readonly textcolor: string = '#FFFFFF';
135
-
136
- constructor(biotype: string, id: string) {
137
- super(biotype, id, 'missing');
138
- }
139
- }
140
-
141
- export class BrokenWebEditorMonomer extends DummyWebEditorMonomer {
142
- public readonly backgroundcolor: string = '#FFFF44';
143
- public readonly linecolor: string = '#800000';
144
- public readonly textcolor: string = '#000000';
145
-
146
- constructor(biotype: string, id: string) {
147
- super(biotype, id, 'broken');
148
- }
149
- }
@@ -1,90 +0,0 @@
1
- import * as grok from 'datagrok-api/grok';
2
- import * as ui from 'datagrok-api/ui';
3
- import * as DG from 'datagrok-api/dg';
4
-
5
- import {
6
- HelmType, IWebEditorMonomer, IMonomerColors, MonomerType, PolymerType, WebEditorRGroups
7
- } from '@datagrok-libraries/bio/src/helm/types';
8
- import {Monomer} from '@datagrok-libraries/bio/src/types';
9
- import {
10
- HELM_OPTIONAL_FIELDS as OPT, HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP
11
- } from '@datagrok-libraries/bio/src/utils/const';
12
- import {BrokenWebEditorMonomer, getRS, MissingWebEditorMonomer} from './get-monomer-dummy';
13
-
14
- function getMonomerColors(monomer: Monomer): IMonomerColors | null {
15
- const currentMonomerSchema = 'default';
16
- let monomerSchema: string = currentMonomerSchema;
17
- if (!monomer.meta || !monomer.meta.colors) return null;
18
-
19
- const monomerColors: { [colorSchemaName: string]: any } = monomer.meta.colors;
20
-
21
- if (!(currentMonomerSchema in monomerColors)) monomerSchema = 'default';
22
-
23
- const res = monomerColors[monomerSchema];
24
-
25
- return !res ? null : {
26
- textcolor: res.text ?? res.textColor,
27
- linecolor: res.line ?? res.lineColor,
28
- backgroundcolor: res.background ?? res.backgroundColor
29
- } as IMonomerColors;
30
- }
31
-
32
- export class LibraryWebEditorMonomer implements IWebEditorMonomer {
33
- public get rs(): number { return Object.keys(this.at).length; }
34
-
35
- public get issmiles(): boolean { return !!this.smiles; }
36
-
37
- public linecolor?: string;
38
- public backgroundcolor?: string;
39
- public textcolor?: string;
40
-
41
- /* eslint-disable max-params */
42
- protected constructor(
43
- public readonly id: string,
44
- public readonly m: string,
45
- public readonly n: string,
46
- public readonly na: string | undefined,
47
- public readonly type: PolymerType,
48
- public readonly mt: MonomerType,
49
- public readonly at: WebEditorRGroups,
50
- public readonly smiles?: string,
51
- ) /* eslint-enable max-params */ {}
52
-
53
- static fromMonomer(biotype: HelmType, monomer: Monomer): IWebEditorMonomer {
54
- let at: WebEditorRGroups = {};
55
- const symbol = monomer[REQ.SYMBOL];
56
- const smiles = monomer[REQ.SMILES];
57
- if (monomer.rgroups.length > 0) {
58
- monomer.rgroups.forEach((it) => {
59
- at[it[RGP.LABEL]] = it[RGP.CAP_GROUP_NAME];
60
- });
61
- } else if (smiles) {
62
- // Generate R-Groups from SMILES
63
- at = getRS(smiles);
64
- } else if (!monomer.lib) {
65
- // missing
66
- return new MissingWebEditorMonomer(biotype, symbol);
67
- } else {
68
- // broken
69
- return new BrokenWebEditorMonomer(biotype, symbol);
70
- }
71
-
72
- const res = new LibraryWebEditorMonomer(
73
- monomer[REQ.SYMBOL],
74
- monomer[REQ.MOLFILE],
75
- monomer[REQ.NAME],
76
- monomer[OPT.NATURAL_ANALOG],
77
- monomer[REQ.POLYMER_TYPE],
78
- monomer[REQ.MONOMER_TYPE],
79
- at);
80
-
81
- const colors = getMonomerColors(monomer);
82
- if (colors) {
83
- res.textcolor = colors?.textcolor;
84
- res.linecolor = colors?.linecolor;
85
- res.backgroundcolor = colors?.backgroundcolor;
86
- }
87
-
88
- return res;
89
- }
90
- }