@datagrok/sequence-translator 1.2.7 → 1.3.0

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 (107) hide show
  1. package/.eslintrc.json +5 -5
  2. package/CHANGELOG.md +14 -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 +22 -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 +487 -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 +94 -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 +79 -0
  38. package/src/apps/pattern/view/components/bulk-convert/table-controls.ts +38 -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 +200 -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 +77 -0
  52. package/src/apps/pattern/view/svg-utils/legend-block.ts +92 -0
  53. package/src/apps/pattern/view/svg-utils/strands-block.ts +335 -0
  54. package/src/apps/pattern/view/svg-utils/svg-block-base.ts +37 -0
  55. package/src/apps/pattern/view/svg-utils/svg-display-manager.ts +44 -0
  56. package/src/apps/pattern/view/svg-utils/svg-element-factory.ts +94 -0
  57. package/src/apps/pattern/view/svg-utils/svg-renderer.ts +51 -0
  58. package/src/apps/pattern/view/svg-utils/text-dimensions-calculator.ts +29 -0
  59. package/src/apps/pattern/view/svg-utils/title-block.ts +53 -0
  60. package/src/apps/pattern/view/svg-utils/utils.ts +37 -0
  61. package/src/apps/pattern/view/types.ts +14 -0
  62. package/src/apps/pattern/view/ui.ts +61 -0
  63. package/src/{model/structure-app → apps/structure/model}/mol-transformations.ts +3 -3
  64. package/src/{model/structure-app → apps/structure/model}/monomer-code-parser.ts +9 -10
  65. package/src/{model/structure-app → apps/structure/model}/oligo-structure.ts +4 -4
  66. package/src/{model/structure-app → apps/structure/model}/sequence-to-molfile.ts +2 -2
  67. package/src/{view/apps/oligo-structure.ts → apps/structure/view/ui.ts} +31 -17
  68. package/src/{model/translator-app → apps/translator/model}/conversion-utils.ts +25 -7
  69. package/src/{model/translator-app → apps/translator/model}/format-converter.ts +7 -12
  70. package/src/{view/const/oligo-translator.ts → apps/translator/view/const.ts} +1 -1
  71. package/src/{view/apps/oligo-translator.ts → apps/translator/view/ui.ts} +88 -42
  72. package/src/demo/demo-st-ui.ts +12 -32
  73. package/src/package.ts +91 -55
  74. package/src/plugins/mermade.ts +9 -9
  75. package/src/polytool/const.ts +28 -0
  76. package/src/polytool/csv-to-json-monomer-lib-converter.ts +40 -0
  77. package/src/polytool/cyclized.ts +56 -0
  78. package/src/polytool/monomer-lib-handler.ts +115 -0
  79. package/src/polytool/pt-conversion.ts +307 -0
  80. package/src/polytool/pt-dialog.ts +115 -0
  81. package/src/polytool/pt-enumeration.ts +127 -0
  82. package/src/polytool/pt-rules.ts +73 -0
  83. package/src/polytool/utils.ts +27 -0
  84. package/src/tests/const.ts +5 -5
  85. package/src/tests/formats-support.ts +6 -6
  86. package/src/tests/formats-to-helm.ts +5 -5
  87. package/src/tests/helm-to-nucleotides.ts +5 -10
  88. package/tsconfig.json +3 -9
  89. package/webpack.config.js +3 -0
  90. package/files/axolabs-style.json +0 -97
  91. package/src/model/data-loading-utils/json-loader.ts +0 -38
  92. package/src/model/pattern-app/const.ts +0 -33
  93. package/src/model/pattern-app/draw-svg.ts +0 -193
  94. package/src/model/pattern-app/helpers.ts +0 -96
  95. package/src/model/pattern-app/oligo-pattern.ts +0 -111
  96. package/src/view/app-ui.ts +0 -193
  97. package/src/view/apps/oligo-pattern.ts +0 -759
  98. /package/src/{model → apps/common/model}/helpers.ts +0 -0
  99. /package/src/{model → apps/common/model}/monomer-lib/const.ts +0 -0
  100. /package/src/{view/utils → apps/common/view/components}/app-info-dialog.ts +0 -0
  101. /package/src/{view/utils → apps/common/view/components}/colored-input/input-painters.ts +0 -0
  102. /package/src/{view/style/colored-text-input.css → apps/common/view/components/colored-input/style.css} +0 -0
  103. /package/src/{view/utils → apps/common/view/components}/router.ts +0 -0
  104. /package/src/{model/structure-app → apps/structure/model}/const.ts +0 -0
  105. /package/src/{view/style/structure-app.css → apps/structure/view/style.css} +0 -0
  106. /package/src/{model/translator-app → apps/translator/model}/const.ts +0 -0
  107. /package/src/{view/style/translator-app.css → apps/translator/view/style.css} +0 -0
@@ -4,11 +4,11 @@ import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import {before, category, expect, test} from '@datagrok-libraries/utils/src/test';
7
- import {DEFAULT_FORMATS} from '../model/const';
8
- import {getJsonData} from '../model/data-loading-utils/json-loader';
7
+ import {DEFAULT_FORMATS} from '../apps/common/model/const';
8
+ import {loadJsonData} from '../apps/common/model/data-loader/json-loader';
9
9
  import {formatsToHelm} from './const';
10
- import {SequenceValidator} from '../model/parsing-validation/sequence-validator';
11
- import {getTranslatedSequences} from '../model/translator-app/conversion-utils';
10
+ import {SequenceValidator} from '../apps/common/model/parsing-validation/sequence-validator';
11
+ import {getTranslatedSequences} from '../apps/translator/model/conversion-utils';
12
12
  import {_package} from '../package';
13
13
 
14
14
  function getTranslationObject(sequence: string, format: string): {[format: string]: string} {
@@ -19,11 +19,11 @@ function getTranslationObject(sequence: string, format: string): {[format: strin
19
19
  const inputs = {
20
20
  [DEFAULT_FORMATS.AXOLABS]: 'Afcgacsu',
21
21
  [DEFAULT_FORMATS.HELM]: 'RNA1{[fR](A)p.[25r](C)p.[25r](G)p.[25r](A)p.[25r](C)[sp].[25r](U)}$$$$'
22
- }
22
+ };
23
23
 
24
24
  category('Formats support', () => {
25
25
  before(async () => {
26
- await getJsonData();
26
+ await loadJsonData();
27
27
  await _package.initMonomerLib();
28
28
  });
29
29
 
@@ -4,9 +4,9 @@ import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import {before, category, expect, test} from '@datagrok-libraries/utils/src/test';
7
- import {DEFAULT_FORMATS} from '../model/const';
8
- import {FormatConverter} from '../model/translator-app/format-converter';
9
- import {getJsonData} from '../model/data-loading-utils/json-loader';
7
+ import {DEFAULT_FORMATS} from '../apps/common/model/const';
8
+ import {FormatConverter} from '../apps/translator/model/format-converter';
9
+ import {loadJsonData} from '../apps/common/model/data-loader/json-loader';
10
10
  import {formatsToHelm} from './const';
11
11
  import {_package} from '../package';
12
12
 
@@ -20,7 +20,7 @@ function getFromat(helm: string, format: string): string {
20
20
 
21
21
  category('Formats to HELM', () => {
22
22
  before(async () => {
23
- await getJsonData();
23
+ await loadJsonData();
24
24
  await _package.initMonomerLib();
25
25
  });
26
26
 
@@ -37,7 +37,7 @@ category('Formats to HELM', () => {
37
37
 
38
38
  category('HELM to Formats', () => {
39
39
  before(async () => {
40
- await getJsonData();
40
+ await loadJsonData();
41
41
  await _package.initMonomerLib();
42
42
  });
43
43
 
@@ -1,18 +1,13 @@
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
1
  import {before, category, expect, test} from '@datagrok-libraries/utils/src/test';
7
- import {getNucleotidesSequence} from '../model/translator-app/conversion-utils';
8
- import {getJsonData} from '../model/data-loading-utils/json-loader';
2
+ import {getNucleotidesSequence} from '../apps/translator/model/conversion-utils';
3
+ import {loadJsonData} from '../apps/common/model/data-loader/json-loader';
9
4
  import {helmToNucleotides} from './const';
10
5
  import {_package} from '../package';
11
- import {MonomerLibWrapper} from '../model/monomer-lib/lib-wrapper';
6
+ import {MonomerLibWrapper} from '../apps/common/model/monomer-lib/lib-wrapper';
12
7
 
13
8
  category('HELM to Nucleotides', () => {
14
9
  before(async () => {
15
- await getJsonData();
10
+ await loadJsonData();
16
11
  await _package.initMonomerLib();
17
12
  });
18
13
 
@@ -22,5 +17,5 @@ category('HELM to Nucleotides', () => {
22
17
  const result = getNucleotidesSequence(helm, MonomerLibWrapper.getInstance());
23
18
  expect(result, expected);
24
19
  });
25
- })
20
+ });
26
21
  });
package/tsconfig.json CHANGED
@@ -4,15 +4,9 @@
4
4
 
5
5
  /* Basic Options */
6
6
  // "incremental": true, /* Enable incremental compilation */
7
- "target": "es2022",
8
- /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
9
- "module": "es2022",
10
- /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
11
- "lib": [
12
- "ES2022",
13
- "dom"
14
- ],
15
- /* Specify library files to be included in the compilation. */
7
+ "target": "es2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
8
+ "module": "es2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
9
+ "lib": ["ES2022", "ES2022.String", "dom"], /* Specify library files to be included in the compilation. */
16
10
  // "allowJs": true, /* Allow javascript files to be compiled. */
17
11
  // "checkJs": true, /* Report errors in .js files. */
18
12
  // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
package/webpack.config.js CHANGED
@@ -2,6 +2,9 @@ const path = require('path');
2
2
  const packageName = path.parse(require('./package.json').name).name.toLowerCase().replace(/-/g, '');
3
3
 
4
4
  module.exports = {
5
+ cache: {
6
+ type: 'filesystem',
7
+ },
5
8
  mode: 'development',
6
9
  entry: {
7
10
  package: ['./src/package.ts'],
@@ -1,97 +0,0 @@
1
- {
2
- "RNA": {
3
- "fullName": "RNA nucleotides",
4
- "symbols": ["A", "C", "G", "U"],
5
- "color": "rgb(255,230,153)"
6
- },
7
- "DNA": {
8
- "fullName": "DNA nucleotides",
9
- "symbols": ["dA", "dC", "dG", "dT"],
10
- "color": "rgb(66, 120, 245)"
11
- },
12
- "2'-Fluoro": {
13
- "fullName": "2'-Fluoro nucleotides",
14
- "symbols": ["Af", "Cf", "Gf", "Uf"],
15
- "color": "rgb(95, 212, 245)"
16
- },
17
- "2'-O-Methyl": {
18
- "fullName": "2'-O-Methyl nucleotides",
19
- "symbols": ["a", "c", "g", "u"],
20
- "color": "rgb(150, 95, 245)"
21
- },
22
- "2'-O-MOE": {
23
- "fullName": "2'-O-MOE nucleotides (including 5-Methyl C)",
24
- "symbols": ["Am", "Cm", "Gm", "Tm"],
25
- "color": "rgb(129, 199, 130)"
26
- },
27
- "GNA": {
28
- "fullName": "Glycol nucleic acid",
29
- "symbols": ["(GNA-A)", "(GNA-C)", "(GNA-G)", "(GNA-T)"],
30
- "color": "rgb(199, 169, 129)"
31
- },
32
- "LNA": {
33
- "fullName": "Locked nucleic acid (including 5-Methyl C)",
34
- "symbols": ["Ab", "Cb", "Gb", "Tb"],
35
- "color": "rgb(250, 185, 182)"
36
- },
37
- "UNA": {
38
- "fullName": "Unlocked nucleotides",
39
- "symbols": ["Ao", "Co", "Go", "Uo"],
40
- "color": "rgb(237, 104, 184)"
41
- },
42
- "A": {
43
- "fullName": "Adenosine",
44
- "symbols": ["a"],
45
- "color": "rgb(255,230,153)"
46
- },
47
- "C": {
48
- "fullName": "Cytidine",
49
- "symbols": ["c"],
50
- "color": "rgb(255,230,153)"
51
- },
52
- "G": {
53
- "fullName": "Guanosine",
54
- "symbols": ["g"],
55
- "color": "rgb(255,230,153)"
56
- },
57
- "U": {
58
- "fullName": "Uridine",
59
- "symbols": ["u"],
60
- "color": "rgb(255,230,153)"
61
- },
62
- "X-New": {
63
- "fullName": "",
64
- "symbols": ["X"],
65
- "color": "rgb(196, 91, 252)"
66
- },
67
- "Y-New": {
68
- "fullName": "",
69
- "symbols": ["Y"],
70
- "color": "rgb(150, 177, 255)"
71
- },
72
- "Z-New": {
73
- "fullName": "",
74
- "symbols": ["Z"],
75
- "color": "rgb(11, 222, 71)"
76
- },
77
- "invAb": {
78
- "fullName": "Inverted abasic capped",
79
- "symbols": ["(invAb)"],
80
- "color": "rgb(243, 153, 247)"
81
- },
82
- "5'-vinylps": {
83
- "fullName": "5'-vinylphosphonate-2'-OMe-uridine",
84
- "symbols": ["(vinu)"],
85
- "color": "rgb(99, 3, 40)"
86
- },
87
- "invAb(o)": {
88
- "fullName": "Inverted abasic capped (overhang)",
89
- "symbols": ["(invAb)"],
90
- "color": "rgb(240, 224, 108)"
91
- },
92
- "2'-OMe-U(o)": {
93
- "fullName": "Nucleotide Uridine with 2'O-Methyl protection (overhang)",
94
- "symbols": ["mU"],
95
- "color": "rgb(190, 237, 123)"
96
- }
97
- }
@@ -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
- };