@datagrok/sequence-translator 1.2.6 → 1.2.9

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.
Files changed (102) hide show
  1. package/.eslintrc.json +5 -5
  2. package/CHANGELOG.md +12 -0
  3. package/dist/package-test.js +2 -1
  4. package/dist/package-test.js.LICENSE.txt +8 -0
  5. package/dist/package-test.js.map +1 -1
  6. package/dist/package.js +2 -1
  7. package/dist/package.js.LICENSE.txt +8 -0
  8. package/dist/package.js.map +1 -1
  9. package/files/pattern-app-data.json +80 -0
  10. package/package.json +21 -14
  11. package/src/{model → apps/common/model}/const.ts +1 -1
  12. package/src/{model/data-loading-utils → apps/common/model/data-loader}/const.ts +7 -2
  13. package/src/apps/common/model/data-loader/json-loader.ts +48 -0
  14. package/src/{model/data-loading-utils → apps/common/model/data-loader}/types.ts +13 -6
  15. package/src/{model → apps/common/model}/monomer-lib/lib-wrapper.ts +9 -12
  16. package/src/apps/common/model/oligo-toolkit-package.ts +30 -0
  17. package/src/{model → apps/common/model}/parsing-validation/format-detector.ts +5 -5
  18. package/src/{model → apps/common/model}/parsing-validation/format-handler.ts +18 -19
  19. package/src/{model → apps/common/model}/parsing-validation/sequence-validator.ts +1 -1
  20. package/src/apps/common/view/app-ui-base.ts +28 -0
  21. package/src/apps/common/view/combined-app-ui.ts +66 -0
  22. package/src/{view/utils → apps/common/view/components}/colored-input/colored-text-input.ts +1 -1
  23. package/src/{view/utils → apps/common/view/components}/draw-molecule.ts +1 -1
  24. package/src/{view/utils → apps/common/view/components}/molecule-img.ts +3 -3
  25. package/src/{view/const/ui.ts → apps/common/view/const.ts} +4 -4
  26. package/src/apps/common/view/isolated-app-ui.ts +43 -0
  27. package/src/{view/monomer-lib-viewer/viewer.ts → apps/common/view/monomer-lib-viewer.ts} +2 -2
  28. package/src/apps/common/view/utils.ts +29 -0
  29. package/src/apps/pattern/model/const.ts +121 -0
  30. package/src/apps/pattern/model/data-manager.ts +297 -0
  31. package/src/apps/pattern/model/event-bus.ts +470 -0
  32. package/src/apps/pattern/model/router.ts +46 -0
  33. package/src/apps/pattern/model/subscription-manager.ts +21 -0
  34. package/src/apps/pattern/model/translator.ts +68 -0
  35. package/src/apps/pattern/model/types.ts +52 -0
  36. package/src/apps/pattern/model/utils.ts +110 -0
  37. package/src/apps/pattern/view/components/bulk-convert/column-input.ts +69 -0
  38. package/src/apps/pattern/view/components/bulk-convert/table-controls.ts +37 -0
  39. package/src/apps/pattern/view/components/bulk-convert/table-input.ts +95 -0
  40. package/src/apps/pattern/view/components/edit-block-controls.ts +196 -0
  41. package/src/apps/pattern/view/components/left-section.ts +44 -0
  42. package/src/apps/pattern/view/components/load-block-controls.ts +198 -0
  43. package/src/apps/pattern/view/components/numeric-label-visibility-controls.ts +69 -0
  44. package/src/apps/pattern/view/components/right-section.ts +148 -0
  45. package/src/apps/pattern/view/components/strand-editor/dialog.ts +79 -0
  46. package/src/apps/pattern/view/components/strand-editor/header-controls.ts +105 -0
  47. package/src/apps/pattern/view/components/strand-editor/strand-controls.ts +159 -0
  48. package/src/apps/pattern/view/components/terminal-modification-editor.ts +127 -0
  49. package/src/apps/pattern/view/components/translation-examples-block.ts +139 -0
  50. package/src/{view/style/pattern-app.css → apps/pattern/view/style.css} +4 -0
  51. package/src/apps/pattern/view/svg-utils/const.ts +63 -0
  52. package/src/apps/pattern/view/svg-utils/dimensions-calculator.ts +498 -0
  53. package/src/apps/pattern/view/svg-utils/svg-display-manager.ts +45 -0
  54. package/src/apps/pattern/view/svg-utils/svg-element-factory.ts +82 -0
  55. package/src/apps/pattern/view/svg-utils/svg-renderer.ts +396 -0
  56. package/src/apps/pattern/view/svg-utils/utils.ts +37 -0
  57. package/src/apps/pattern/view/types.ts +14 -0
  58. package/src/apps/pattern/view/ui.ts +61 -0
  59. package/src/{model/structure-app → apps/structure/model}/mol-transformations.ts +3 -3
  60. package/src/{model/structure-app → apps/structure/model}/monomer-code-parser.ts +9 -10
  61. package/src/{model/structure-app → apps/structure/model}/oligo-structure.ts +4 -4
  62. package/src/{model/structure-app → apps/structure/model}/sequence-to-molfile.ts +2 -2
  63. package/src/{view/apps/oligo-structure.ts → apps/structure/view/ui.ts} +31 -17
  64. package/src/{model/translator-app → apps/translator/model}/conversion-utils.ts +25 -7
  65. package/src/{model/translator-app → apps/translator/model}/format-converter.ts +7 -12
  66. package/src/{view/const/oligo-translator.ts → apps/translator/view/const.ts} +2 -0
  67. package/src/apps/translator/view/ui.ts +547 -0
  68. package/src/demo/demo-st-ui.ts +12 -32
  69. package/src/package.ts +76 -56
  70. package/src/plugins/mermade.ts +9 -9
  71. package/src/polytool/const.ts +40 -0
  72. package/src/polytool/csv-to-json-monomer-lib-converter.ts +40 -0
  73. package/src/polytool/cyclized.ts +56 -0
  74. package/src/polytool/monomer-lib-handler.ts +115 -0
  75. package/src/polytool/transformation.ts +326 -0
  76. package/src/polytool/ui.ts +59 -0
  77. package/src/polytool/utils.ts +20 -0
  78. package/src/tests/const.ts +5 -5
  79. package/src/tests/formats-support.ts +6 -6
  80. package/src/tests/formats-to-helm.ts +5 -5
  81. package/src/tests/helm-to-nucleotides.ts +5 -5
  82. package/tsconfig.json +4 -10
  83. package/webpack.config.js +3 -0
  84. package/files/axolabs-style.json +0 -97
  85. package/src/model/data-loading-utils/json-loader.ts +0 -38
  86. package/src/model/pattern-app/const.ts +0 -33
  87. package/src/model/pattern-app/draw-svg.ts +0 -193
  88. package/src/model/pattern-app/helpers.ts +0 -96
  89. package/src/model/pattern-app/oligo-pattern.ts +0 -111
  90. package/src/view/app-ui.ts +0 -193
  91. package/src/view/apps/oligo-pattern.ts +0 -759
  92. package/src/view/apps/oligo-translator.ts +0 -184
  93. /package/src/{model → apps/common/model}/helpers.ts +0 -0
  94. /package/src/{model → apps/common/model}/monomer-lib/const.ts +0 -0
  95. /package/src/{view/utils → apps/common/view/components}/app-info-dialog.ts +0 -0
  96. /package/src/{view/utils → apps/common/view/components}/colored-input/input-painters.ts +0 -0
  97. /package/src/{view/style/colored-text-input.css → apps/common/view/components/colored-input/style.css} +0 -0
  98. /package/src/{view/utils → apps/common/view/components}/router.ts +0 -0
  99. /package/src/{model/structure-app → apps/structure/model}/const.ts +0 -0
  100. /package/src/{view/style/structure-app.css → apps/structure/view/style.css} +0 -0
  101. /package/src/{model/translator-app → apps/translator/model}/const.ts +0 -0
  102. /package/src/{view/style/translator-app.css → apps/translator/view/style.css} +0 -0
@@ -1,38 +0,0 @@
1
- /* Do not change these import lines to match external modules in webpack configuration */
2
- import * as grok from 'datagrok-api/grok';
3
- import * as ui from 'datagrok-api/ui';
4
- import * as DG from 'datagrok-api/dg';
5
-
6
- import {APP_PATH, AXOLABS_STYLE_FILENAME, CODES_TO_HELM_DICT_FILENAME, CODES_TO_SYMBOLS_FILENAME, MONOMERS_WITH_PHOSPHATE_LINKERS} from './const';
7
- import {AxolabsStyle, FormatToHELMDict, CodeToSymbol} from './types';
8
-
9
- const fileSource = new DG.FileSource(APP_PATH);
10
-
11
- export let axolabsStyleMap: AxolabsStyle;
12
- export let codesToHelmDictionary: FormatToHELMDict;
13
- export let codesToSymbolsDictionary: CodeToSymbol;
14
- export let monomersWithPhosphateLinkers: {[key: string]: string[]};
15
-
16
- export async function getJsonData(): Promise<void> {
17
- const data = [axolabsStyleMap, codesToHelmDictionary, codesToSymbolsDictionary, monomersWithPhosphateLinkers];
18
-
19
- if (data.every((item) => item !== undefined))
20
- return;
21
-
22
- axolabsStyleMap = await parse(AXOLABS_STYLE_FILENAME);
23
- codesToHelmDictionary = await parse(CODES_TO_HELM_DICT_FILENAME);
24
- codesToSymbolsDictionary = await parse(CODES_TO_SYMBOLS_FILENAME);
25
- monomersWithPhosphateLinkers = await parse(MONOMERS_WITH_PHOSPHATE_LINKERS);
26
- }
27
-
28
- async function parse(path: string): Promise<any> {
29
- let parsedJson: string;
30
- try {
31
- parsedJson = JSON.parse(await fileSource.readAsText(path))
32
- } catch (err: any) {
33
- const errMsg: string = err.hasOwnProperty('message') ? err.message : err.toString();
34
- throw new Error(`Error loading json from ${path}:` + errMsg);
35
- }
36
- return parsedJson;
37
- }
38
-
@@ -1,33 +0,0 @@
1
- export const DEFAULT_PTO: boolean = true;
2
- export const DEFAULT_SEQUENCE_LENGTH: number = 23;
3
- export const MAX_SEQUENCE_LENGTH: number = 35;
4
- export const USER_STORAGE_KEY: string = 'SequenceTranslator';
5
- export const EXAMPLE_MIN_WIDTH: string = '400px';
6
-
7
- export const enum JSON_FIELD {
8
- SS_BASES = 'ssBases',
9
- AS_BASES = 'asBases',
10
- SS_PTO = 'ssPtoLinkages',
11
- AS_PTO = 'asPtoLinkages',
12
- SS_3 = 'ssThreeModification',
13
- SS_5 = 'ssFiveModification',
14
- AS_3 = 'asThreeModification',
15
- AS_5 = 'asFiveModification',
16
- COMMENT = 'comment',
17
- };
18
-
19
- export const SS = 'SS' as const;
20
- export const AS = 'AS' as const;
21
- export const STRANDS = [SS, AS];
22
- export const STRAND_NAME = {
23
- [SS]: 'Sense strand',
24
- [AS]: 'Anti sense',
25
- }
26
-
27
- export const THREE_PRIME = 'THREE_PRIME' as const;
28
- export const FIVE_PRIME = 'FIVE_PRIME' as const;
29
- export const TERMINAL_KEYS = [THREE_PRIME, FIVE_PRIME];
30
- export const TERMINAL = {
31
- [THREE_PRIME]: 3,
32
- [FIVE_PRIME]: 5,
33
- }
@@ -1,193 +0,0 @@
1
- import {NUCLEOTIDES} from '../const';
2
- import {isOverhang, svg, textWidth, countOverhangsOnTheRightEdge, baseColor, textInsideCircle,
3
- fontColorVisibleOnBackground, isOneDigitNumber} from './helpers';
4
-
5
- const BASE_RADIUS = 15;
6
- const BASE_DIAMETER = 2 * BASE_RADIUS;
7
- const shiftToAlignTwoDigitNumberNearCircle = -10;
8
- const shiftToAlignOneDigitNumberNearCircle = -5;
9
- const LEGEND_RADIUS = 6;
10
- const PS_LINKAGE_RADIUS = 5;
11
- const BASE_FONT_SIZE = 17;
12
- const LEGEND_FONT_SIZE = 14;
13
- const PS_LINKAGE_COLOR = 'red';
14
- const FONT_COLOR = 'var(--grey-6)';
15
- const TITLE_FONT_COLOR = 'black';
16
- const MODIFICATIONS_COLOR = 'red';
17
- const SS_LEFT_TEXT = 'SS: 5\'';
18
- const AS_LEFT_TEXT = 'AS: 3\'';
19
- const SS_RIGHT_TEXT = '3\'';
20
- const AS_RIGHT_TEXT = '5\'';
21
-
22
- const WIDTH_OF_LEFT_TEXT = Math.max(
23
- textWidth(SS_LEFT_TEXT, BASE_FONT_SIZE),
24
- textWidth(AS_LEFT_TEXT, BASE_FONT_SIZE),
25
- );
26
-
27
- const WIDTH_OF_RIGHT_TEXT = Math.max(
28
- textWidth(SS_RIGHT_TEXT, BASE_FONT_SIZE),
29
- textWidth(AS_RIGHT_TEXT, BASE_FONT_SIZE),
30
- );
31
-
32
- const X = {
33
- TITLE: BASE_RADIUS, // Math.round(width / 4),
34
- LEFT_TEXTS: 0,
35
- };
36
- const X_OF_LEFT_MODIFICATIONS = X.LEFT_TEXTS + WIDTH_OF_LEFT_TEXT - 5;
37
-
38
- const Y = {
39
- TITLE: BASE_RADIUS,
40
- SS_INDICES: 2 * BASE_RADIUS,
41
- SS_CIRCLES: 3.5 * BASE_RADIUS,
42
- SS_TEXTS: 4 * BASE_RADIUS,
43
- AS_CIRCLES: 6.5 * BASE_RADIUS,
44
- AS_TEXTS: 7 * BASE_RADIUS,
45
- AS_INDICES: 8.5 * BASE_RADIUS,
46
- comment: (asExists: boolean) => (asExists) ? 11 * BASE_RADIUS : 8.5 * BASE_RADIUS,
47
- circlesInLegends: (asExists: boolean) => (asExists) ? 9.5 * BASE_RADIUS : 6 * BASE_RADIUS,
48
- textLegend: (asExists: boolean) => (asExists) ? 10 * BASE_RADIUS - 3 : Y.AS_CIRCLES - 3,
49
- svgHeight: (asExists: boolean) => (asExists) ? 11 * BASE_RADIUS : 9 * BASE_RADIUS,
50
- };
51
-
52
- export function drawAxolabsPattern(
53
- patternName: string, asExists: boolean, ssBases: string[],
54
- asBases: string[], ssPtoStatuses: boolean[], asPtoStatuses: boolean[],
55
- ss3Modification: string, ss5Modification: string,
56
- as3Modification: string, as5Modification: string, comment: string,
57
- enumerateModifications: string[],
58
- ): Element {
59
- function equidistantXForLegend(index: number): number {
60
- return Math.round((index + startFrom) * width / (uniqueBases.length + startFrom) + LEGEND_RADIUS);
61
- }
62
-
63
- function xOfBaseCircles(index: number, rightOverhangs: number): number {
64
- return widthOfRightModification +
65
- (resultingNumberOfNucleotidesInStrands - index + rightOverhangs + 1) * BASE_DIAMETER;
66
- }
67
-
68
- function shiftToAlignNumberNearCircle(bases: string[], generalIndex: number, nucleotideIndex: number): number {
69
- return (isOneDigitNumber(nucleotideIndex) || NUCLEOTIDES.includes(bases[generalIndex])) ?
70
- shiftToAlignOneDigitNumberNearCircle : shiftToAlignTwoDigitNumberNearCircle;
71
- }
72
-
73
- ssBases = ssBases.reverse();
74
- ssPtoStatuses = ssPtoStatuses.reverse();
75
-
76
- const ssRightOverhangs = countOverhangsOnTheRightEdge(ssBases);
77
- const asRightOverhangs = countOverhangsOnTheRightEdge(asBases);
78
-
79
- const resultingNumberOfNucleotidesInStrands = Math.max(
80
- ssBases.length - ssRightOverhangs,
81
- asBases.length - asRightOverhangs,
82
- );
83
-
84
- const widthOfRightOverhangs = Math.max(ssRightOverhangs, asRightOverhangs);
85
- const widthOfBases = BASE_DIAMETER * (resultingNumberOfNucleotidesInStrands + widthOfRightOverhangs);
86
-
87
- const widthOfLeftModification = Math.max(
88
- textWidth(ss3Modification, BASE_FONT_SIZE),
89
- textWidth(as5Modification, BASE_FONT_SIZE),
90
- );
91
-
92
- const widthOfRightModification = Math.max(
93
- textWidth(ss5Modification, BASE_FONT_SIZE),
94
- textWidth(as3Modification, BASE_FONT_SIZE),
95
- );
96
-
97
- const uniqueBases = asExists ?
98
- [...new Set(ssBases.concat(asBases))] :
99
- [...new Set(ssBases)];
100
-
101
- const isPtoExist = asExists ?
102
- ssPtoStatuses.concat(asPtoStatuses).includes(true) :
103
- ssPtoStatuses.includes(true);
104
-
105
- const startFrom = isPtoExist ? 1 : 0;
106
-
107
- const xOfSsRightModifications = ssRightOverhangs * BASE_DIAMETER + xOfBaseCircles(-0.5, 0);
108
- const xOfAsRightModifications = asRightOverhangs * BASE_DIAMETER + xOfBaseCircles(-0.5, 0);
109
-
110
- const xOfRightTexts = Math.max(xOfSsRightModifications, xOfAsRightModifications) + widthOfLeftModification +
111
- BASE_DIAMETER * widthOfRightOverhangs;
112
-
113
- const width = WIDTH_OF_LEFT_TEXT + widthOfLeftModification + widthOfBases + widthOfRightModification +
114
- WIDTH_OF_RIGHT_TEXT + BASE_DIAMETER;
115
- const image = svg.render(width, Y.svgHeight(asExists));
116
-
117
- image.append(
118
- svg.text(SS_LEFT_TEXT, X.LEFT_TEXTS, Y.SS_TEXTS, BASE_FONT_SIZE, FONT_COLOR),
119
- asExists ? svg.text(AS_LEFT_TEXT, X.LEFT_TEXTS, Y.AS_TEXTS, BASE_FONT_SIZE, FONT_COLOR) : '',
120
- svg.text(SS_RIGHT_TEXT, xOfRightTexts, Y.SS_TEXTS, BASE_FONT_SIZE, FONT_COLOR),
121
- asExists ? svg.text(AS_RIGHT_TEXT, xOfRightTexts, Y.AS_TEXTS, BASE_FONT_SIZE, FONT_COLOR) : '',
122
- svg.text(ss5Modification, X_OF_LEFT_MODIFICATIONS, Y.SS_TEXTS, BASE_FONT_SIZE, MODIFICATIONS_COLOR),
123
- asExists ? svg.text(as3Modification, X_OF_LEFT_MODIFICATIONS, Y.AS_TEXTS, BASE_FONT_SIZE, MODIFICATIONS_COLOR) : '',
124
- svg.text(ss3Modification, xOfSsRightModifications, Y.SS_TEXTS, BASE_FONT_SIZE, MODIFICATIONS_COLOR),
125
- asExists ? svg.text(as5Modification, xOfAsRightModifications, Y.AS_TEXTS, BASE_FONT_SIZE, MODIFICATIONS_COLOR) : '',
126
- svg.text(comment, X.LEFT_TEXTS, Y.comment(asExists), LEGEND_FONT_SIZE, FONT_COLOR),
127
- isPtoExist ? svg.star(BASE_RADIUS, Y.circlesInLegends(asExists), PS_LINKAGE_COLOR) : '',
128
- isPtoExist ? svg.text('ps linkage', 2 * BASE_RADIUS - 8, Y.textLegend(asExists), LEGEND_FONT_SIZE, FONT_COLOR) : '',
129
- );
130
-
131
- const numberOfSsNucleotides = ssBases.filter((value) => !isOverhang(value)).length;
132
- let nucleotideCounter = numberOfSsNucleotides;
133
- for (let i = ssBases.length - 1; i > -1; i--) {
134
- const xOfNumbers = xOfBaseCircles(i, ssRightOverhangs) +
135
- shiftToAlignNumberNearCircle(ssBases, ssBases.length - i, numberOfSsNucleotides - nucleotideCounter);
136
- if (!isOverhang(ssBases[i]))
137
- nucleotideCounter--;
138
- const n = (!isOverhang(ssBases[i]) && enumerateModifications.includes(ssBases[i])) ?
139
- String(numberOfSsNucleotides - nucleotideCounter) : '';
140
- image.append(
141
- svg.text(n, xOfNumbers, Y.SS_INDICES, LEGEND_FONT_SIZE, FONT_COLOR),
142
- svg.circle(xOfBaseCircles(i, ssRightOverhangs), Y.SS_CIRCLES, BASE_RADIUS, baseColor(ssBases[i])),
143
- svg.text(textInsideCircle(ssBases, i), xOfNumbers, Y.SS_TEXTS, BASE_FONT_SIZE,
144
- fontColorVisibleOnBackground(ssBases[i])),
145
- ssPtoStatuses[i] ?
146
- svg.star(xOfBaseCircles(i, ssRightOverhangs) + BASE_RADIUS, Y.SS_TEXTS + PS_LINKAGE_RADIUS, PS_LINKAGE_COLOR) :
147
- '',
148
- );
149
- }
150
- image.append(
151
- ssPtoStatuses[ssBases.length] ?
152
- svg.star(xOfBaseCircles(ssBases.length, ssRightOverhangs) +
153
- BASE_RADIUS, Y.SS_TEXTS + PS_LINKAGE_RADIUS, PS_LINKAGE_COLOR) : '',
154
- );
155
-
156
- const numberOfAsNucleotides = asBases.filter((value) => !isOverhang(value)).length;
157
- if (asExists) {
158
- let nucleotideCounter = numberOfAsNucleotides;
159
- for (let i = asBases.length - 1; i > -1; i--) {
160
- if (!isOverhang(asBases[i]))
161
- nucleotideCounter--;
162
- const xOfNumbers = xOfBaseCircles(i, asRightOverhangs) +
163
- shiftToAlignNumberNearCircle(asBases, i, nucleotideCounter + 1);
164
- const n = (!isOverhang(asBases[i]) && enumerateModifications.includes(asBases[i])) ?
165
- String(nucleotideCounter + 1) : '';
166
- image.append(
167
- svg.text(n, xOfNumbers, Y.AS_INDICES, LEGEND_FONT_SIZE, FONT_COLOR),
168
- svg.circle(xOfBaseCircles(i, asRightOverhangs), Y.AS_CIRCLES, BASE_RADIUS, baseColor(asBases[i])),
169
- svg.text(textInsideCircle(asBases, i),
170
- xOfBaseCircles(i, asRightOverhangs) + shiftToAlignNumberNearCircle(asBases, i, nucleotideCounter + 1),
171
- Y.AS_TEXTS, BASE_FONT_SIZE, fontColorVisibleOnBackground(asBases[i])),
172
- asPtoStatuses[i] ? svg.star(xOfBaseCircles(i, asRightOverhangs) +
173
- BASE_RADIUS, Y.AS_TEXTS + PS_LINKAGE_RADIUS, PS_LINKAGE_COLOR) : '',
174
- );
175
- }
176
- image.append(
177
- asPtoStatuses[asBases.length] ?
178
- svg.star(xOfBaseCircles(asBases.length, asRightOverhangs) + BASE_RADIUS, Y.AS_TEXTS + PS_LINKAGE_RADIUS,
179
- PS_LINKAGE_COLOR) : '',
180
- );
181
- }
182
-
183
- const title = `${patternName} for ${numberOfSsNucleotides}${(asExists ? `/${numberOfAsNucleotides}` : '')}mer`;
184
- image.append(svg.text(title, X.TITLE, Y.TITLE, BASE_FONT_SIZE, TITLE_FONT_COLOR));
185
- for (let i = 0; i < uniqueBases.length; i++) {
186
- image.append(
187
- svg.circle(equidistantXForLegend(i), Y.circlesInLegends(asExists), LEGEND_RADIUS, baseColor(uniqueBases[i])),
188
- svg.text(uniqueBases[i], equidistantXForLegend(i) + LEGEND_RADIUS + 4, Y.textLegend(asExists), LEGEND_FONT_SIZE,
189
- FONT_COLOR),
190
- );
191
- }
192
- return image;
193
- }
@@ -1,96 +0,0 @@
1
- import {NUCLEOTIDES} from '../const';
2
- import {axolabsStyleMap} from '../data-loading-utils/json-loader';
3
-
4
- export function isOverhang(modification: string): boolean {
5
- return modification.slice(-3) === '(o)';
6
- }
7
-
8
- export function isOneDigitNumber(n: number): boolean {
9
- return n < 10;
10
- }
11
-
12
- // https://uxdesign.cc/star-rating-make-svg-great-again-d4ce4731347e
13
- export function getPointsToDrawStar(centerX: number, centerY: number): string {
14
- const innerCirclePoints = 5; // a 5 point star
15
- const innerRadius = 15 / innerCirclePoints;
16
- const innerOuterRadiusRatio = 2; // outter circle is x2 the inner
17
- const outerRadius = innerRadius * innerOuterRadiusRatio;
18
- const angle = Math.PI / innerCirclePoints;
19
- const angleOffsetToCenterStar = 60;
20
- const totalNumberOfPoints = innerCirclePoints * 2; // 10 in a 5-points star
21
-
22
- let points = '';
23
- for (let i = 0; i < totalNumberOfPoints; i++) {
24
- const r = (i % 2 === 0) ? outerRadius : innerRadius;
25
- const currentX = centerX + Math.cos(i * angle + angleOffsetToCenterStar) * r;
26
- const currentY = centerY + Math.sin(i * angle + angleOffsetToCenterStar) * r;
27
- points += `${currentX},${currentY} `;
28
- }
29
- return points;
30
- }
31
-
32
- export function countOverhangsOnTheRightEdge(modifications: string[]): number {
33
- let i = 0;
34
- while (i < modifications.length && isOverhang(modifications[i]))
35
- i++;
36
- return (i === modifications.length - 1) ? 0 : i;
37
- }
38
-
39
- export function textWidth(text: string, font: number): number {
40
- const context = document.createElement('canvas').getContext('2d');
41
- // @ts-ignore
42
- context.font = String(font);
43
- // @ts-ignore
44
- return 2 * context.measureText(text).width;
45
- }
46
-
47
- export function textInsideCircle(bases: string[], index: number): string {
48
- return (isOverhang(bases[index]) || !NUCLEOTIDES.includes(bases[index])) ? '' : bases[index];
49
- }
50
-
51
- export function fontColorVisibleOnBackground(base: string): string {
52
- const AXOLABS_MAP = axolabsStyleMap;
53
- const rgbIntList = AXOLABS_MAP[base].color.match(/\d+/g)!.map((e) => Number(e));
54
- return (rgbIntList[0] * 0.299 + rgbIntList[1] * 0.587 + rgbIntList[2] * 0.114) > 186 ? '#33333' : '#ffffff';
55
- }
56
-
57
- export function baseColor(base: string): string {
58
- const AXOLABS_MAP = axolabsStyleMap;
59
- return AXOLABS_MAP[base].color;
60
- }
61
-
62
- export const svg = {
63
- xmlns: 'http://www.w3.org/2000/svg',
64
- render: function(width: number, height: number): Element {
65
- const e = document.createElementNS(this.xmlns, 'svg');
66
- e.setAttribute('id', 'mySvg');
67
- e.setAttribute('width', String(width));
68
- e.setAttribute('height', String(height));
69
- return e;
70
- },
71
- circle: function(x: number, y: number, radius: number, color: string): Element {
72
- const e = document.createElementNS(this.xmlns, 'circle');
73
- e.setAttribute('cx', String(x));
74
- e.setAttribute('cy', String(y));
75
- e.setAttribute('r', String(radius));
76
- e.setAttribute('fill', color);
77
- return e;
78
- },
79
- text: function(text: string, x: number, y: number, fontSize: number, color: string): Element {
80
- const e = document.createElementNS(this.xmlns, 'text');
81
- e.setAttribute('x', String(x));
82
- e.setAttribute('y', String(y));
83
- e.setAttribute('font-size', String(fontSize));
84
- e.setAttribute('font-weight', 'normal');
85
- e.setAttribute('font-family', 'Arial');
86
- e.setAttribute('fill', color);
87
- e.innerHTML = text;
88
- return e;
89
- },
90
- star: function(x: number, y: number, fill: string): Element {
91
- const e = document.createElementNS(this.xmlns, 'polygon');
92
- e.setAttribute('points', getPointsToDrawStar(x, y));
93
- e.setAttribute('fill', fill);
94
- return e;
95
- },
96
- };
@@ -1,111 +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
- // @ts-ignore
5
- import * as svg from 'save-svg-as-png';
6
- import $ from 'cash-dom';
7
-
8
- import {isOverhang} from './helpers';
9
- import {axolabsStyleMap} from '../data-loading-utils/json-loader';
10
-
11
- export function generateExample(sequenceLength: number, sequenceBasis: string): string {
12
- const AXOLABS_MAP = axolabsStyleMap;
13
- const uniqueSymbols = AXOLABS_MAP[sequenceBasis].symbols.join('');
14
- return uniqueSymbols.repeat(Math.floor(sequenceLength / 4)) + uniqueSymbols.slice(0, sequenceLength % 4);
15
- }
16
-
17
- export function findDuplicates(data: Int32Array | Float32Array | Float64Array | Uint32Array): number[] {
18
- return Array.from(new Set(data)).filter((value) => data.indexOf(value) !== data.lastIndexOf(value));
19
- }
20
-
21
- export async function isCurrentUserCreatedThisPattern(patternName: string): Promise<boolean> {
22
- return await grok.dapi.users.current().then((user) => {
23
- const [firstName, lastName] = getUserName(patternName);
24
- return (user.firstName !== firstName || user.lastName !== lastName);
25
- });
26
- }
27
-
28
- export function getShortName(patternName: string): string {
29
- let first = patternName.length + 1;
30
- for (let i = 0; i < patternName.length; i++) {
31
- if (patternName[i] === '(') {
32
- first = i;
33
- break;
34
- }
35
- }
36
- return patternName.slice(0, first - 1);
37
- }
38
-
39
- function getUserName(patternName: string): string[] {
40
- let first = -1;
41
- for (let i = 0; i < patternName.length; i++) {
42
- if (patternName[i] === '(') {
43
- first = i;
44
- break;
45
- }
46
- }
47
- return (first === -1) ? ['', ''] : patternName.slice(first + 9, patternName.length - 1).split(' ').slice(1);
48
- }
49
-
50
- export function translateSequence(
51
- sequence: string,
52
- bases: DG.InputBase[],
53
- ptoLinkages: DG.InputBase[],
54
- startModification: DG.InputBase,
55
- endModification: DG.InputBase,
56
- firstPtoExist: boolean): string {
57
- let i: number = -1;
58
- let mainSequence = sequence.replace(/[AUGC]/g, function(x: string) {
59
- i++;
60
- const AXOLABS_MAP = axolabsStyleMap;
61
-
62
- const baseChoices: string[] = Object.keys(AXOLABS_MAP);
63
- // const defaultBase: string = baseChoices[0];
64
- const indexOfSymbol = AXOLABS_MAP['RNA']['symbols'].indexOf(x);
65
- let symbol = AXOLABS_MAP[bases[i].value]['symbols'][indexOfSymbol];
66
- if (isOverhang(bases[i].value)) {
67
- if (i < sequence.length / 2 && !isOverhang(bases[i + 1].value))
68
- symbol = symbol + x + 'f';
69
- else if (i > sequence.length / 2 && !isOverhang(bases[i - 1].value))
70
- symbol = x + 'f' + symbol;
71
- }
72
- return (ptoLinkages[i].value) ? symbol + 's' : symbol;
73
- });
74
- if (mainSequence.slice(0, 5).split('mU').length === 3)
75
- mainSequence = '(uu)' + mainSequence.slice(4);
76
- if (mainSequence.slice(mainSequence.length - 7).split('mU').length === 3)
77
- mainSequence = mainSequence.slice(0, mainSequence.length - 4) + '(uu)';
78
- return startModification.value + (firstPtoExist ? 's' : '') + mainSequence + endModification.value;
79
- }
80
-
81
- export function addColumnWithIds(tableName: string, columnName: string, patternName: string) {
82
- const nameOfNewColumn = 'ID ' + patternName;
83
- const columns = grok.shell.table(tableName).columns;
84
- if (columns.contains(nameOfNewColumn))
85
- columns.remove(nameOfNewColumn);
86
- const columnWithIds = columns.byName(columnName);
87
- return columns.addNewString(nameOfNewColumn).init((i: number) => {
88
- return (columnWithIds.getString(i) === '') ? '' : columnWithIds.get(i) + '_' + patternName;
89
- });
90
- }
91
-
92
- export function addColumnWithTranslatedSequences(
93
- tableName: string,
94
- columnName: string,
95
- bases: DG.InputBase[],
96
- ptoLinkages: DG.InputBase[],
97
- startModification: DG.InputBase,
98
- endModification: DG.InputBase,
99
- firstPtoExist: boolean) {
100
- const nameOfNewColumn = 'Axolabs ' + columnName;
101
- const columns = grok.shell.table(tableName).columns;
102
- if (columns.contains(nameOfNewColumn))
103
- columns.remove(nameOfNewColumn);
104
- const columnWithInputSequences = columns.byName(columnName);
105
- return columns.addNewString(nameOfNewColumn).init((i: number) => {
106
- return columnWithInputSequences.getString(i) === '' ?
107
- '' :
108
- translateSequence(columnWithInputSequences.getString(i), bases, ptoLinkages, startModification, endModification,
109
- firstPtoExist);
110
- });
111
- }
@@ -1,193 +0,0 @@
1
- /* Do not change these import lines to match external modules in webpack configuration */
2
- import * as grok from 'datagrok-api/grok';
3
- import * as ui from 'datagrok-api/ui';
4
- import * as DG from 'datagrok-api/dg';
5
-
6
- import {TAB, APP} from './const/ui';
7
- import {TranslatorLayoutHandler} from './apps/oligo-translator';
8
- import {StructureLayoutHandler} from './apps/oligo-structure';
9
- import {PatternLayoutHandler} from './apps/oligo-pattern';
10
- import {MonomerLibViewer} from './monomer-lib-viewer/viewer';
11
- import {_package} from '../package';
12
- import {tryCatch} from '../model/helpers';
13
-
14
- type ViewFactories = {[name: string]: () => DG.View};
15
-
16
- export abstract class AppUIBase {
17
- constructor(protected appName: string, protected parentAppName?: string) { }
18
- abstract addView(): Promise<void>;
19
-
20
- async createAppLayout(): Promise<void> {
21
- const pi: DG.TaskBarProgressIndicator = DG.TaskBarProgressIndicator.create(`Loading ${this.appName}...`);
22
-
23
- let currentView = grok.shell.v?.root;
24
- if (currentView)
25
- ui.setUpdateIndicator(currentView, true);
26
-
27
- await tryCatch(async () => {
28
- await this.addView();
29
- }, () => pi.close());
30
-
31
- if (currentView)
32
- ui.setUpdateIndicator(currentView, false);
33
- }
34
- }
35
-
36
- abstract class SimpleAppUIBase extends AppUIBase {
37
- constructor(appName: string) {
38
- super(appName);
39
- this.view = DG.View.create();
40
- this.setupView();
41
- }
42
-
43
- protected view: DG.View;
44
- async addView(): Promise<void> {
45
- await this.initView();
46
- const name = this.parentAppName ? this.parentAppName + '/' + this.appName : this.appName;
47
- this.view.path = `/apps/${_package.name}/${name.replace(/\s/g, '')}/`;
48
- grok.shell.addView(this.view);
49
- }
50
-
51
- protected abstract getHtml(): Promise<HTMLDivElement>;
52
- async initView(): Promise<void> {
53
- const html = await this.getHtml();
54
- this.view.append(html);
55
- }
56
-
57
- protected setupView(): void {
58
- this.view.box = true;
59
- this.view.name = this.appName;
60
-
61
- const windows = grok.shell.windows;
62
- windows.showProperties = false;
63
- windows.showToolbox = false;
64
- windows.showHelp = false;
65
- }
66
-
67
- getView(): DG.View {
68
- return this.view;
69
- }
70
- }
71
-
72
- export class CombinedAppUI extends AppUIBase {
73
- constructor(externalViewFactories: ViewFactories) {
74
- super(APP.COMBINED)
75
- this.externalViewFactories = externalViewFactories;
76
- const factories = this.getViewFactories();
77
- this.multiView = new DG.MultiView({viewFactories: factories});
78
- }
79
-
80
- private multiView: DG.MultiView;
81
- private externalViewFactories?: ViewFactories;
82
-
83
- private getViewFactories(): ViewFactories {
84
- function viewFactory(uiConstructor: new (view: DG.View) => SimpleAppUIBase): () => DG.View {
85
- const view = DG.View.create();
86
- const translateUI = new uiConstructor(view);
87
- // intentonally don't await for the promise
88
- translateUI.initView();
89
- return () => translateUI.getView();
90
- }
91
-
92
- let result: {[key: string]: () => DG.View } = {
93
- [TAB.TRANSLATOR]: viewFactory(OligoTranslatorUI),
94
- [TAB.PATTERN]: viewFactory(OligoPatternUI),
95
- [TAB.STRUCTRE]: viewFactory(OligoStructureUI),
96
- }
97
-
98
- if (this.externalViewFactories)
99
- result = Object.assign({}, result, this.externalViewFactories);
100
-
101
- return result
102
- }
103
-
104
- private getPath(): string {
105
- let name = this.multiView.tabs.currentPane.name;
106
- name = name.charAt(0).toUpperCase() + name.substring(1).toLowerCase();
107
- const path = `/apps/${_package.name}/OligoToolkit/${name}`;
108
- return path;
109
- }
110
-
111
- private setUrl(): void {
112
- this.multiView.path = this.getPath();
113
- }
114
-
115
- async addView(): Promise<void> {
116
- this.multiView.tabs.onTabChanged.subscribe(() => this.setUrl());
117
- this.setUrl();
118
- grok.shell.addView(this.multiView);
119
- }
120
- }
121
-
122
- /** For plugins from external packages */
123
- export class ExternalPluginUI extends SimpleAppUIBase {
124
- constructor(viewName: string, layout: HTMLDivElement) {
125
- super(viewName);
126
- this.layout = layout;
127
- }
128
- private layout: HTMLDivElement;
129
-
130
- protected getHtml(): Promise<HTMLDivElement> {
131
- return Promise.resolve(this.layout);
132
- }
133
- }
134
-
135
- export class AppUIFactory {
136
- private constructor() {}
137
-
138
- static getUI(appName: string): SimpleAppUIBase {
139
- switch (appName) {
140
- case APP.TRANSLATOR:
141
- return new OligoTranslatorUI();
142
- case APP.PATTERN:
143
- return new OligoPatternUI();
144
- case APP.STRUCTRE:
145
- return new OligoStructureUI();
146
- default:
147
- throw new Error(`Unknown app name: ${appName}`);
148
- }
149
- }
150
- }
151
-
152
- class OligoTranslatorUI extends SimpleAppUIBase {
153
- constructor() {
154
- super(APP.TRANSLATOR);
155
-
156
- const viewMonomerLibIcon = ui.iconFA('book', MonomerLibViewer.view, 'View monomer library');
157
- this.topPanel = [
158
- viewMonomerLibIcon,
159
- ];
160
- this.view.setRibbonPanels([this.topPanel]);
161
- this.ui = new TranslatorLayoutHandler();
162
- }
163
-
164
- private readonly topPanel: HTMLElement[];
165
- private readonly ui: TranslatorLayoutHandler;
166
-
167
- protected getHtml(): Promise<HTMLDivElement> {
168
- return this.ui.getHtmlElement();
169
- };
170
- }
171
-
172
- class OligoPatternUI extends SimpleAppUIBase {
173
- constructor() {
174
- super(APP.PATTERN);
175
- this.ui = new PatternLayoutHandler();
176
- }
177
- private readonly ui: PatternLayoutHandler;
178
- protected getHtml(): Promise<HTMLDivElement> {
179
- return Promise.resolve(this.ui.htmlDivElement);
180
- }
181
- }
182
-
183
- class OligoStructureUI extends SimpleAppUIBase {
184
- constructor() {
185
- super(APP.STRUCTRE)
186
- this.ui = new StructureLayoutHandler();
187
- }
188
- private readonly ui: StructureLayoutHandler;
189
-
190
- protected getHtml(): Promise<HTMLDivElement> {
191
- return this.ui.getHtmlDivElement();
192
- }
193
- }