genoverse 3.2.0 → 4.0.1

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 (217) hide show
  1. package/.eslintrc.js +93 -162
  2. package/.github/workflows/test.yml +9 -10
  3. package/.github/workflows/update-gh-pages.yml +33 -0
  4. package/LICENSE.TXT +2 -2
  5. package/README.md +174 -3
  6. package/{i → assets}/sort_handle.png +0 -0
  7. package/babel.config.js +19 -0
  8. package/dist/129.css +334 -0
  9. package/dist/129.css.map +1 -0
  10. package/dist/129.genoverse.js +2 -0
  11. package/dist/129.genoverse.js.map +1 -0
  12. package/dist/15d98c18221c8bcb2334.ttf +0 -0
  13. package/dist/166.css +2 -0
  14. package/dist/166.genoverse.js +1 -0
  15. package/dist/216.css +20 -0
  16. package/dist/216.css.map +1 -0
  17. package/dist/232.css +114 -0
  18. package/dist/232.css.map +1 -0
  19. package/dist/232.genoverse.js +2 -0
  20. package/dist/232.genoverse.js.map +1 -0
  21. package/dist/2e659e443f3e98569e9f.png +0 -0
  22. package/dist/394.css +114 -0
  23. package/dist/394.css.map +1 -0
  24. package/dist/394.genoverse.js +2 -0
  25. package/dist/394.genoverse.js.map +1 -0
  26. package/dist/469.css +24 -0
  27. package/dist/469.css.map +1 -0
  28. package/dist/469.genoverse.js +2 -0
  29. package/dist/469.genoverse.js.map +1 -0
  30. package/dist/4896d4b04430cc3dfb06.woff2 +0 -0
  31. package/dist/530.css +39 -0
  32. package/dist/530.css.map +1 -0
  33. package/dist/530.genoverse.js +2 -0
  34. package/dist/530.genoverse.js.map +1 -0
  35. package/dist/547.css +469 -0
  36. package/dist/547.css.map +1 -0
  37. package/dist/547.genoverse.js +1 -0
  38. package/dist/729.css +315 -0
  39. package/dist/729.css.map +1 -0
  40. package/dist/79da213423ac0def2058.ttf +0 -0
  41. package/dist/804.genoverse.js +2 -0
  42. package/dist/804.genoverse.js.map +1 -0
  43. package/dist/842.genoverse.js +2 -0
  44. package/dist/842.genoverse.js.map +1 -0
  45. package/dist/893.genoverse.js +2 -0
  46. package/dist/893.genoverse.js.map +1 -0
  47. package/dist/949.css +315 -0
  48. package/dist/949.css.map +1 -0
  49. package/dist/949.genoverse.js +2 -0
  50. package/dist/949.genoverse.js.map +1 -0
  51. package/dist/952.css +315 -0
  52. package/dist/952.css.map +1 -0
  53. package/dist/952.genoverse.js +2 -0
  54. package/dist/952.genoverse.js.map +1 -0
  55. package/dist/d79c2ec96ab9ff1161a2.woff2 +0 -0
  56. package/dist/genoverse.js +2 -0
  57. package/dist/genoverse.js.map +1 -0
  58. package/index.html +13 -14
  59. package/jest.config.js +5 -0
  60. package/jest.setup.js +13 -0
  61. package/package.json +29 -12
  62. package/{css → src/css}/controlPanel.css +0 -0
  63. package/{css → src/css}/fileDrop.css +0 -0
  64. package/src/css/fontawesome.css +3 -0
  65. package/{css → src/css}/fullscreen.css +0 -0
  66. package/{css → src/css}/genoverse.css +1 -1
  67. package/{css → src/css}/karyotype.css +2 -0
  68. package/{css → src/css}/resizer.css +0 -0
  69. package/{css → src/css}/tooltips.css +0 -0
  70. package/{css → src/css}/trackControls.css +0 -0
  71. package/src/js/Genoverse.js +1747 -0
  72. package/{js → src/js}/Track/Controller/Sequence.js +6 -4
  73. package/src/js/Track/Controller/Stranded.js +83 -0
  74. package/{js → src/js}/Track/Controller.js +201 -160
  75. package/src/js/Track/Model/File/BAM.js +47 -0
  76. package/src/js/Track/Model/File/BED.js +122 -0
  77. package/src/js/Track/Model/File/GFF.js +42 -0
  78. package/src/js/Track/Model/File/VCF.js +109 -0
  79. package/src/js/Track/Model/File/WIG.js +82 -0
  80. package/src/js/Track/Model/File.js +36 -0
  81. package/src/js/Track/Model/Gene/Ensembl.js +24 -0
  82. package/{js → src/js}/Track/Model/Gene.js +3 -1
  83. package/src/js/Track/Model/Sequence/Ensembl.js +6 -0
  84. package/{js → src/js}/Track/Model/Sequence/Fasta.js +24 -17
  85. package/{js → src/js}/Track/Model/Sequence.js +10 -7
  86. package/{js → src/js}/Track/Model/SequenceVariation.js +17 -11
  87. package/{js → src/js}/Track/Model/Stranded.js +11 -8
  88. package/src/js/Track/Model/Transcript/Ensembl.js +73 -0
  89. package/{js → src/js}/Track/Model/Transcript.js +3 -1
  90. package/{js → src/js}/Track/Model.js +125 -93
  91. package/{js → src/js}/Track/View/Gene/Ensembl.js +6 -4
  92. package/src/js/Track/View/Gene.js +8 -0
  93. package/{js → src/js}/Track/View/Sequence.js +18 -22
  94. package/src/js/Track/View/SequenceVariation.js +117 -0
  95. package/src/js/Track/View/Transcript/Ensembl.js +17 -0
  96. package/src/js/Track/View/Transcript.js +32 -0
  97. package/{js → src/js}/Track/View.js +200 -159
  98. package/{js → src/js}/Track/library/Chromosome.js +18 -13
  99. package/src/js/Track/library/File/BAM.js +34 -0
  100. package/src/js/Track/library/File/BED.js +27 -0
  101. package/src/js/Track/library/File/BIGBED.js +51 -0
  102. package/src/js/Track/library/File/BIGWIG.js +54 -0
  103. package/src/js/Track/library/File/GFF.js +10 -0
  104. package/{js → src/js}/Track/library/File/VCF.js +29 -22
  105. package/src/js/Track/library/File/WIG.js +8 -0
  106. package/{js → src/js}/Track/library/File.js +4 -2
  107. package/src/js/Track/library/Gene.js +44 -0
  108. package/src/js/Track/library/Graph/Bar.js +263 -0
  109. package/src/js/Track/library/Graph/Line.js +335 -0
  110. package/{js → src/js}/Track/library/Graph.js +137 -114
  111. package/{js → src/js}/Track/library/HighlightRegion.js +118 -93
  112. package/src/js/Track/library/Legend.js +258 -0
  113. package/{js → src/js}/Track/library/Scalebar.js +69 -49
  114. package/{js → src/js}/Track/library/Scaleline.js +29 -27
  115. package/src/js/Track/library/Static.js +82 -0
  116. package/{js → src/js}/Track/library/dbSNP.js +47 -50
  117. package/src/js/Track.js +651 -0
  118. package/{js → src/js}/genomes/grch37.js +52 -52
  119. package/{js → src/js}/genomes/grch38.js +52 -52
  120. package/src/js/lib/BWReader.js +562 -0
  121. package/src/js/lib/VCFReader.js +296 -0
  122. package/src/js/lib/dalliance/bam.js +517 -0
  123. package/src/js/lib/dalliance/bin.js +317 -0
  124. package/src/js/lib/dalliance/jszlib-inflate.js +2159 -0
  125. package/src/js/lib/dalliance/lh3utils.js +105 -0
  126. package/src/js/lib/dalliance/sha1.js +334 -0
  127. package/src/js/lib/import-tracks.js +42 -0
  128. package/{js/lib → src/js/lib/jquery-plugins}/jquery.mousehold.js +0 -0
  129. package/{js/lib → src/js/lib/jquery-plugins}/jquery.mousewheel.js +0 -0
  130. package/{js/lib → src/js/lib/jquery-plugins}/jquery.tipsy.js +0 -0
  131. package/src/js/lib/jquery.js +26 -0
  132. package/src/js/lib/polyfills.js +11 -0
  133. package/src/js/lib/wrap-functions.js +88 -0
  134. package/src/js/plugins/controlPanel.js +388 -0
  135. package/src/js/plugins/fileDrop.js +81 -0
  136. package/src/js/plugins/focusRegion.js +13 -0
  137. package/{js → src/js}/plugins/fullscreen.js +18 -14
  138. package/{js → src/js}/plugins/karyotype.js +51 -45
  139. package/src/js/plugins/resizer.js +52 -0
  140. package/{js → src/js}/plugins/tooltips.js +31 -29
  141. package/src/js/plugins/trackControls.js +159 -0
  142. package/test/View/render-legends.test.js +1 -1
  143. package/test/change-width.test.js +71 -0
  144. package/test/create-and-destroy.test.js +2 -2
  145. package/test/track-ordering.test.js +3 -2
  146. package/test/track_config/config-settings.test.js +1 -1
  147. package/test/utils.js +4 -2
  148. package/webpack.config.js +103 -34
  149. package/css/font-awesome.css +0 -3
  150. package/expanded.html +0 -120
  151. package/fontawesome/css/fontawesome.min.css +0 -5
  152. package/fontawesome/css/regular.min.css +0 -5
  153. package/fontawesome/css/solid.min.css +0 -5
  154. package/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  155. package/fontawesome/webfonts/fa-brands-400.woff +0 -0
  156. package/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  157. package/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  158. package/fontawesome/webfonts/fa-regular-400.woff +0 -0
  159. package/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  160. package/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  161. package/fontawesome/webfonts/fa-solid-900.woff +0 -0
  162. package/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  163. package/help.pdf +0 -0
  164. package/index.js +0 -83
  165. package/js/Genoverse.js +0 -1681
  166. package/js/Track/Controller/Stranded.js +0 -73
  167. package/js/Track/Model/File/BAM.js +0 -44
  168. package/js/Track/Model/File/BED.js +0 -116
  169. package/js/Track/Model/File/GFF.js +0 -40
  170. package/js/Track/Model/File/VCF.js +0 -101
  171. package/js/Track/Model/File/WIG.js +0 -67
  172. package/js/Track/Model/File.js +0 -36
  173. package/js/Track/Model/Gene/Ensembl.js +0 -22
  174. package/js/Track/Model/Sequence/Ensembl.js +0 -4
  175. package/js/Track/Model/Transcript/Ensembl.js +0 -67
  176. package/js/Track/View/Gene.js +0 -6
  177. package/js/Track/View/Sequence/Variation.js +0 -115
  178. package/js/Track/View/Transcript/Ensembl.js +0 -12
  179. package/js/Track/View/Transcript.js +0 -28
  180. package/js/Track/library/File/BAM.js +0 -30
  181. package/js/Track/library/File/BED.js +0 -24
  182. package/js/Track/library/File/BIGBED.js +0 -47
  183. package/js/Track/library/File/BIGWIG.js +0 -52
  184. package/js/Track/library/File/GFF.js +0 -9
  185. package/js/Track/library/File/WIG.js +0 -5
  186. package/js/Track/library/Gene.js +0 -37
  187. package/js/Track/library/Graph/Bar.js +0 -235
  188. package/js/Track/library/Graph/Line.js +0 -296
  189. package/js/Track/library/Legend.js +0 -224
  190. package/js/Track/library/Static.js +0 -78
  191. package/js/Track.js +0 -632
  192. package/js/genoverse.min.js +0 -2
  193. package/js/genoverse.min.js.map +0 -1
  194. package/js/lib/BWReader.js +0 -578
  195. package/js/lib/Base.js +0 -145
  196. package/js/lib/VCFReader.js +0 -286
  197. package/js/lib/dalliance/js/bam.js +0 -494
  198. package/js/lib/dalliance/js/bin.js +0 -185
  199. package/js/lib/dalliance/js/das.js +0 -749
  200. package/js/lib/dalliance/js/utils.js +0 -370
  201. package/js/lib/dalliance-lib.js +0 -3594
  202. package/js/lib/dalliance-lib.min.js +0 -68
  203. package/js/lib/jDataView.js +0 -2
  204. package/js/lib/jParser.js +0 -192
  205. package/js/lib/jquery-ui.js +0 -8
  206. package/js/lib/jquery.js +0 -2
  207. package/js/lib/rtree.js +0 -1
  208. package/js/plugins/controlPanel.js +0 -395
  209. package/js/plugins/fileDrop.js +0 -62
  210. package/js/plugins/focusRegion.js +0 -12
  211. package/js/plugins/resizer.js +0 -45
  212. package/js/plugins/trackControls.js +0 -143
  213. package/utils/expandedTemplate.html +0 -46
  214. package/utils/git-hooks/post-commit +0 -9
  215. package/utils/git-hooks/pre-commit +0 -7
  216. package/utils/git-hooks/setup +0 -6
  217. package/utils/makeExpanded.js +0 -19
@@ -0,0 +1,47 @@
1
+ import makeBam from '../../../lib/dalliance/bam';
2
+ import { URLFetchable, BlobFetchable } from '../../../lib/dalliance/bin';
3
+ import Model from '../File';
4
+
5
+ export default Model.extend({
6
+ getData: function (chr, start, end) {
7
+ const deferred = this.browser.jQuery.Deferred();
8
+
9
+ if (!this.bamFile) {
10
+ if (this.url) {
11
+ this.bamFile = new URLFetchable(this.url);
12
+ this.baiFile = new URLFetchable(this.url + this.prop('indexExt'));
13
+ } else if (this.dataFile && this.indexFile) {
14
+ this.bamFile = new BlobFetchable(this.dataFile);
15
+ this.baiFile = new BlobFetchable(this.indexFile);
16
+ } else {
17
+ return deferred.reject(new Error('BAM files must be accompanied by a .bai index file'));
18
+ }
19
+ }
20
+
21
+ makeBam(this.bamFile, this.baiFile, null, (bam, makeBamError) => {
22
+ if (makeBamError) {
23
+ console.error(makeBamError); // eslint-disable-line no-console
24
+ } else {
25
+ bam.fetch(chr, start, end, (features, fetchBamError) => {
26
+ if (fetchBamError) {
27
+ console.error(fetchBamError); // eslint-disable-line no-console
28
+ } else {
29
+ this.receiveData(features, chr, start, end);
30
+ deferred.resolve();
31
+ }
32
+ });
33
+ }
34
+ });
35
+
36
+ return deferred;
37
+ },
38
+
39
+ insertFeature: function (feature) {
40
+ feature.id = `${feature.chr}:${feature.readName}:${feature.pos}`;
41
+ feature.start = feature.pos + 1;
42
+ feature.end = feature.start + feature.seq.length;
43
+ feature.sequence = feature.seq;
44
+
45
+ return this.base(feature);
46
+ },
47
+ });
@@ -0,0 +1,122 @@
1
+ import Model from '../File';
2
+
3
+ export default Model.extend({
4
+ parseData: function (data, chr) {
5
+ const lines = typeof data === 'string' ? data.split('\n') : data;
6
+ const thinHeight = this.prop('thinHeight');
7
+ const thickHeight = this.prop('thickHeight');
8
+
9
+ function filterNumber(n) {
10
+ return !isNaN(n);
11
+ }
12
+
13
+ lines.forEach(
14
+ (line) => {
15
+ const fields = line.split('\t').filter(f => f);
16
+
17
+ if (fields.length < 3 || fields[0] === 'track' || fields[0] === 'browser') {
18
+ return;
19
+ }
20
+
21
+ const len = fields.length;
22
+
23
+ if (fields[0] === String(chr) || fields[0].toLowerCase() === `chr${chr}` || fields[0].match(`[^1-9]${chr}$`)) {
24
+ const feature = {
25
+ chr : chr,
26
+ start : parseInt(fields[1], 10) + 1,
27
+ end : parseInt(fields[2], 10),
28
+ name : fields[3],
29
+ color : '#000000',
30
+ originalFeature : fields,
31
+ };
32
+
33
+ if (len > 3) { feature.score = parseFloat(fields[4], 10); }
34
+ if (len > 5) { feature.strand = fields[5]; }
35
+
36
+ if (len > 7) {
37
+ feature.thickStart = parseInt(fields[6], 10) + 1;
38
+ feature.thickEnd = parseInt(fields[7], 10);
39
+ feature.drawThick = fields[6] !== fields[7];
40
+ }
41
+
42
+ if (fields[8]) {
43
+ feature.color = `rgb(${fields[8]})`;
44
+ } else {
45
+ feature.color = this.scoreColor(isNaN(feature.score) ? 1000 : feature.score);
46
+ }
47
+
48
+ if (len === 12) { // subfeatures present
49
+ feature.blockCount = parseInt(fields[9], 10);
50
+
51
+ const subfeatures = [];
52
+ const blockSizes = fields[10].split(',').filter(filterNumber);
53
+ const blockStarts = fields[11].split(',').filter(filterNumber);
54
+
55
+ blockSizes.forEach(
56
+ (blockSize, i) => {
57
+ const subfeature = {
58
+ start : feature.start + parseInt(blockStarts[i], 10),
59
+ height : thinHeight, // if subfeature lies entirely left / right to [ thickStart, thickEnd ]
60
+ };
61
+
62
+ subfeature.end = subfeature.start + parseInt(blockSize, 10) - 1;
63
+
64
+ if (feature.drawThick && subfeature.start <= feature.thickEnd && subfeature.end >= feature.thickStart) {
65
+ // some kind of an overlap for sure
66
+ if (subfeature.start >= feature.thickStart && subfeature.end <= feature.thickEnd) {
67
+ // subfeature within thickBlock, draw thick
68
+ subfeature.height = thickHeight;
69
+ subfeatures.push(subfeature);
70
+ } else if (subfeature.start < feature.thickStart && subfeature.end <= feature.thickEnd) {
71
+ // left overlap, split subfeature into 2 - thin | thick
72
+ const thinFeature = { ...subfeature, end: feature.thickStart };
73
+ const thickFeature = { ...subfeature, start: feature.thickStart, height: thickHeight };
74
+
75
+ subfeatures.push(...[ thinFeature, thickFeature ]);
76
+ } else if (subfeature.start >= feature.thickStart && subfeature.end > feature.thickEnd) {
77
+ // right overlap, split subfeature into 2 - thick | thin
78
+ const thinFeature = { ...subfeature, start: feature.thickEnd };
79
+ const thickFeature = { ...subfeature, end: feature.thickEnd, height: thickHeight };
80
+
81
+ subfeatures.push(...[ thickFeature, thinFeature ]);
82
+ } else {
83
+ // thickBlock lies within subfeature, split into 3 - thin | thick | thin
84
+ // the least possible case but lets be prepared for the outliers
85
+ const thinFeature1 = { ...subfeature, end: feature.thickStart };
86
+ const thinFeature2 = { ...subfeature, start: feature.thickEnd };
87
+ const thickFeature = { start: feature.thickStart, end: feature.thickEnd, height: thickHeight };
88
+
89
+ subfeatures.push(...[ thinFeature1, thickFeature, thinFeature2 ]);
90
+ }
91
+ } else {
92
+ // no thick block
93
+ subfeatures.push(subfeature);
94
+ }
95
+ }
96
+ );
97
+
98
+ if (subfeatures.length) {
99
+ feature.subFeatures = subfeatures;
100
+ }
101
+ }
102
+
103
+ this.insertFeature(feature);
104
+ }
105
+ }
106
+ );
107
+ },
108
+
109
+ // As per https://genome.ucsc.edu/FAQ/FAQformat.html#format1 specification
110
+ scoreColor: function (score) {
111
+ if (score <= 166) { return 'rgb(219,219,219)'; }
112
+ if (score <= 277) { return 'rgb(186,186,186)'; }
113
+ if (score <= 388) { return 'rgb(154,154,154)'; }
114
+ if (score <= 499) { return 'rgb(122,122,122)'; }
115
+ if (score <= 611) { return 'rgb(94,94,94)'; }
116
+ if (score <= 722) { return 'rgb(67,67,67)'; }
117
+ if (score <= 833) { return 'rgb(42,42,42)'; }
118
+ if (score <= 944) { return 'rgb(21,21,21)'; }
119
+
120
+ return '#000000';
121
+ },
122
+ });
@@ -0,0 +1,42 @@
1
+ import Model from '../File';
2
+
3
+ export default Model.extend({
4
+ parseData: function (text, chr) {
5
+ const lines = text.split('\n');
6
+
7
+ lines.forEach(
8
+ (line) => {
9
+ if (!line.length || line.indexOf('#') === 0) {
10
+ return;
11
+ }
12
+
13
+ const fields = line.split('\t');
14
+
15
+ if (fields.length < 5) {
16
+ return;
17
+ }
18
+
19
+ const seqId = fields[0].toLowerCase();
20
+
21
+ if (
22
+ seqId === String(chr) ||
23
+ seqId === `chr${chr}` ||
24
+ seqId.match(`[^1-9]${chr}$`) ||
25
+ seqId.match(`^${chr}\\b`)
26
+ ) {
27
+ this.insertFeature({
28
+ id : fields.slice(0, 5).join('|'),
29
+ chr : chr,
30
+ start : parseInt(fields[3], 10),
31
+ end : parseInt(fields[4], 10),
32
+ source : fields[1],
33
+ type : fields[2],
34
+ score : fields[5],
35
+ strand : fields[6] === '-' ? -1 : 1,
36
+ label : `${fields[1]} ${fields[2]} ${fields[3]}-${fields[4]}`,
37
+ });
38
+ }
39
+ }
40
+ );
41
+ },
42
+ });
@@ -0,0 +1,109 @@
1
+ import VCFReader from '../../../lib/VCFReader';
2
+ import { URLFetchable, BlobFetchable } from '../../../lib/dalliance/bin';
3
+ import Model from '../File';
4
+
5
+ export default Model.extend({
6
+ getData: function (chr, start, end, done) {
7
+ if (!this.prop('gz')) {
8
+ return this.base(chr, start, end, done);
9
+ }
10
+
11
+ const deferred = this.browser.jQuery.Deferred();
12
+
13
+ if (!this.vcfFile) {
14
+ if (this.url) {
15
+ this.vcfFile = new URLFetchable(this.url);
16
+ this.tbiFile = new URLFetchable(this.url + this.prop('indexExt'));
17
+ } else if (this.dataFile && this.indexFile) {
18
+ this.vcfFile = new BlobFetchable(this.dataFile);
19
+ this.tbiFile = new BlobFetchable(this.indexFile);
20
+ } else {
21
+ return deferred.reject(new Error('GZipped VCF files must be accompanied by a .tbi index file'));
22
+ }
23
+ }
24
+
25
+ this.makeVCF(this.vcfFile, this.tbiFile).then((vcf) => {
26
+ this.cachedVCF = vcf;
27
+
28
+ vcf.getRecords(chr, start, end, (records) => {
29
+ this.receiveData(records, chr, start, end);
30
+ deferred.resolve();
31
+ });
32
+ });
33
+
34
+ return deferred;
35
+ },
36
+
37
+ makeVCF: function (vcfFile, tbiFile) {
38
+ const deferred = this.browser.jQuery.Deferred();
39
+
40
+ if (this.cachedVCF) {
41
+ deferred.resolve(this.cachedVCF);
42
+ } else {
43
+ const vcf = new VCFReader(vcfFile, tbiFile);
44
+
45
+ vcf.readTabix((tabix) => {
46
+ vcf.tabix = tabix;
47
+ deferred.resolve(vcf);
48
+ });
49
+ }
50
+
51
+ return deferred;
52
+ },
53
+
54
+ parseData: function (text, chr) {
55
+ const lines = text.split('\n');
56
+
57
+ let maxQual = this.allData ? this.prop('maxQual') || 0 : false;
58
+
59
+ lines.forEach(
60
+ (line) => {
61
+ if (!line.length || line.indexOf('#') === 0) {
62
+ return;
63
+ }
64
+
65
+ const fields = line.split('\t');
66
+
67
+ if (fields.length < 5) {
68
+ return;
69
+ }
70
+
71
+ if (fields[0] === String(chr) || fields[0] === `chr${chr}`) {
72
+ const id = fields.slice(0, 3).join('|');
73
+ const start = parseInt(fields[1], 10);
74
+ const alleles = fields[4].split(',');
75
+
76
+ alleles.unshift(fields[3]);
77
+
78
+ alleles.forEach(
79
+ (allele, i) => {
80
+ const end = start + allele.length - 1;
81
+
82
+ this.insertFeature({
83
+ id : `${id}|${allele}`,
84
+ sort : i,
85
+ chr : chr,
86
+ start : start,
87
+ end : end,
88
+ width : end - start,
89
+ allele : i === 0 ? 'REF' : 'ALT',
90
+ sequence : allele,
91
+ label : allele,
92
+ labelColor : '#FFFFFF',
93
+ originalFeature : fields,
94
+ });
95
+ }
96
+ );
97
+
98
+ if (maxQual !== false) {
99
+ maxQual = Math.max(maxQual, fields[5]);
100
+ }
101
+ }
102
+ }
103
+ );
104
+
105
+ if (maxQual) {
106
+ this.prop('maxQual', maxQual);
107
+ }
108
+ },
109
+ });
@@ -0,0 +1,82 @@
1
+ import { Model as BarGraphModel } from '../../library/Graph/Bar';
2
+ import Model from '../File';
3
+
4
+ export default BarGraphModel.extend({
5
+ dataType: 'text',
6
+
7
+ getData: function (...args) {
8
+ if (!this.url) {
9
+ this.isLocal = true;
10
+ this.dataFile = this.track.dataFile;
11
+
12
+ return Model.prototype.getData(...args);
13
+ }
14
+
15
+ return this.base(...args);
16
+ },
17
+
18
+ parseData: function (text, chr, s, e) {
19
+ const lines = text.split('\n');
20
+ const features = [];
21
+
22
+ let firstFeatureLine;
23
+
24
+ while (lines.length) {
25
+ firstFeatureLine = lines.shift();
26
+
27
+ if (!firstFeatureLine) {
28
+ break;
29
+ }
30
+
31
+ if (firstFeatureLine.indexOf('#') !== -1 || firstFeatureLine.indexOf('browser') !== -1 || firstFeatureLine.indexOf('track') !== -1) {
32
+ continue;
33
+ } else {
34
+ break;
35
+ }
36
+ }
37
+
38
+ if (firstFeatureLine) {
39
+ const fields = firstFeatureLine.split(/\s+/);
40
+ const chrom = parseInt(fields[1].split('=')[1].replace('chr', ''), 10);
41
+
42
+ if (fields[0] === 'fixedStep') {
43
+ const step = parseInt(fields[3].split('=')[1], 10);
44
+ const span = fields[4] ? parseInt(fields[4].split('=')[1], 10) : 1;
45
+
46
+ let start = parseInt(fields[2].split('=')[1], 10);
47
+
48
+ lines.forEach(
49
+ (line) => {
50
+ features.push({
51
+ chr : chrom,
52
+ start : start,
53
+ end : start + span,
54
+ height : parseFloat(line),
55
+ });
56
+
57
+ start += step;
58
+ }
59
+ );
60
+ } else if (fields[0] === 'variableStep') {
61
+ const span = fields[2] ? parseInt(fields[2].split('=')[1], 10) : 1;
62
+
63
+ lines.forEach(
64
+ (line) => {
65
+ const lineFields = line.split(/\s+/);
66
+ const feature = {
67
+ chr : chrom,
68
+ start : parseInt(lineFields[0], 10),
69
+ height : parseFloat(lineFields[1]),
70
+ };
71
+
72
+ feature.end = feature.start + span;
73
+
74
+ features.push(feature);
75
+ }
76
+ );
77
+ }
78
+ }
79
+
80
+ return this.base.call(this, features, chr, s, e);
81
+ },
82
+ });
@@ -0,0 +1,36 @@
1
+ import Model from '../Model';
2
+
3
+ export default Model.extend({
4
+ dataType: 'text',
5
+
6
+ init: function (...args) {
7
+ if (this.isLocal) {
8
+ this.url = false;
9
+ }
10
+
11
+ if (!(this.largeFile || this.indexFile)) {
12
+ this.allData = true;
13
+ }
14
+
15
+ this.base(...args);
16
+ },
17
+
18
+ getData: function (chr, ...args) {
19
+ if (this.isLocal && this.dataFile) {
20
+ const reader = new FileReader();
21
+ const deferred = this.browser.jQuery.Deferred();
22
+
23
+ reader.onload = (e) => {
24
+ deferred.done(() => {
25
+ this.receiveData(e.target.result, chr, 1, this.browser.getChromosomeSize(chr));
26
+ }).resolve();
27
+ };
28
+
29
+ reader.readAsText(this.dataFile);
30
+
31
+ return deferred;
32
+ }
33
+
34
+ return this.base(chr, ...args);
35
+ },
36
+ });
@@ -0,0 +1,24 @@
1
+ import Model from '../Gene';
2
+
3
+ // Ensembl REST API Gene model
4
+ export default Model.extend({
5
+ url : '//rest.ensembl.org/overlap/region/human/__CHR__:__START__-__END__?feature=gene;content-type=application/json',
6
+ dataRequestLimit : 5000000, // As per e! REST API restrictions
7
+
8
+ // The url above responds in json format, data is an array
9
+ // We assume that parents always preceed children in data array, gene -> transcript -> exon
10
+ // See rest.ensembl.org/documentation/info/feature_region for more details
11
+ parseData: function (data, chr) {
12
+ data.forEach(
13
+ (feature) => {
14
+ if (feature.feature_type === 'gene' && !this.featuresById[feature.id]) {
15
+ feature.chr = feature.chr || chr;
16
+ feature.label = parseInt(feature.strand, 10) === 1 ? `${feature.external_name || feature.id} >` : `< ${feature.external_name || feature.id}`;
17
+ feature.transcripts = [];
18
+
19
+ this.insertFeature(feature);
20
+ }
21
+ }
22
+ );
23
+ },
24
+ });
@@ -1,5 +1,7 @@
1
+ import Model from '../Model';
2
+
1
3
  // Abstract Gene model
2
4
  // see sub-models for more specific examples
3
- Genoverse.Track.Model.Gene = Genoverse.Track.Model.extend({
5
+ export default Model.extend({
4
6
 
5
7
  });
@@ -0,0 +1,6 @@
1
+ import Model from '../Sequence';
2
+
3
+ export default Model.extend({
4
+ url : '//rest.ensembl.org/sequence/region/human/__CHR__:__START__-__END__?content-type=text/plain', // Example url
5
+ dataRequestLimit : 10000000, // As per e! REST API restrictions
6
+ });
@@ -1,4 +1,6 @@
1
- Genoverse.Track.Model.Sequence.Fasta = Genoverse.Track.Model.Sequence.extend({
1
+ import Model from '../Sequence';
2
+
3
+ export default Model.extend({
2
4
  url: 'https://wtsi-web.github.io/Genoverse/data/Homo_sapiens.GRCh37.72.dna.chromosome.1.fa', // Example url
3
5
 
4
6
  // Following settings could be left undefined and will be detected automatically via .getStartByte()
@@ -8,25 +10,31 @@ Genoverse.Track.Model.Sequence.Fasta = Genoverse.Track.Model.Sequence.extend({
8
10
  // TODO: Check if URL provided
9
11
 
10
12
  getData: function (chr, start, end) {
11
- var deferred = $.Deferred();
13
+ const jQuery = this.browser.jQuery;
14
+ const deferred = jQuery.Deferred();
12
15
 
13
- $.when(this.getStartByte()).done(function () {
16
+ jQuery.when(this.getStartByte()).done(() => {
14
17
  start = start - (start % this.chunkSize) + 1;
15
18
  end = end + this.chunkSize - (end % this.chunkSize);
16
19
 
17
- var startByte = start - 1 + Math.floor((start - 1) / this.lineLength) + this.startByte;
18
- var endByte = end - 1 + Math.floor((end - 1) / this.lineLength) + this.startByte;
20
+ const startByte = start - 1 + Math.floor((start - 1) / this.lineLength) + this.startByte;
21
+ const endByte = end - 1 + Math.floor((end - 1) / this.lineLength) + this.startByte;
19
22
 
20
- $.ajax({
23
+ jQuery.ajax({
21
24
  url : this.parseURL(),
22
25
  dataType : this.dataType,
23
- context : this,
24
- headers : { Range: 'bytes=' + startByte + '-' + endByte },
26
+ headers : { Range: `bytes=${startByte}-${endByte}` },
25
27
  xhrFields : this.xhrFields,
26
- success : function (data) { this.receiveData(data, chr, start, end); },
27
- error : this.track.controller.showError
28
- }).done(function () { deferred.resolveWith(this); }).fail(function () { deferred.rejectWith(this); });
29
- }).fail(function () { deferred.rejectWith(this); });
28
+ success : (data) => { this.receiveData(data, chr, start, end); },
29
+ error : this.track.controller.showError,
30
+ }).done(() => {
31
+ deferred.resolve();
32
+ }).fail(() => {
33
+ deferred.reject();
34
+ });
35
+ }).fail(() => {
36
+ deferred.reject();
37
+ });
30
38
 
31
39
  return deferred;
32
40
  },
@@ -37,13 +45,12 @@ Genoverse.Track.Model.Sequence.Fasta = Genoverse.Track.Model.Sequence.extend({
37
45
  }
38
46
 
39
47
  if (this.startByte === undefined || this.lineLength === undefined) {
40
- this.startByteRequest = $.ajax({
48
+ this.startByteRequest = this.browser.jQuery.ajax({
41
49
  url : this.parseURL(),
42
50
  dataType : 'text',
43
- context : this,
44
51
  headers : { 'Range': 'bytes=0-300' },
45
52
  xhrFields : this.xhrFields,
46
- success : function (data) {
53
+ success : (data) => {
47
54
  if (data.indexOf('>') === 0) {
48
55
  this.startByte = data.indexOf('\n') + 1;
49
56
  } else {
@@ -51,10 +58,10 @@ Genoverse.Track.Model.Sequence.Fasta = Genoverse.Track.Model.Sequence.extend({
51
58
  }
52
59
 
53
60
  this.lineLength = data.indexOf('\n', this.startByte) - this.startByte;
54
- }
61
+ },
55
62
  });
56
63
 
57
64
  return this.startByteRequest;
58
65
  }
59
- }
66
+ },
60
67
  });
@@ -1,14 +1,16 @@
1
+ import Model from '../Model';
2
+
1
3
  // Abstract Sequence model
2
4
  // assumes that the data source responds with raw sequence text
3
5
  // see Fasta model for more specific example
4
- Genoverse.Track.Model.Sequence = Genoverse.Track.Model.extend({
6
+ export default Model.extend({
5
7
  threshold : 100000,
6
8
  chunkSize : 1000,
7
9
  buffer : 0,
8
10
  dataType : 'text',
9
11
 
10
12
  setChrProps: function () {
11
- var chr = this.browser.chr;
13
+ const chr = this.browser.chr;
12
14
 
13
15
  this.base();
14
16
 
@@ -19,6 +21,7 @@ Genoverse.Track.Model.Sequence = Genoverse.Track.Model.extend({
19
21
  getData: function (chr, start, end) {
20
22
  start = start - (start % this.chunkSize) + 1;
21
23
  end = end + this.chunkSize - (end % this.chunkSize);
24
+
22
25
  return this.base(chr, start, end);
23
26
  },
24
27
 
@@ -29,22 +32,22 @@ Genoverse.Track.Model.Sequence = Genoverse.Track.Model.extend({
29
32
  data = data.toLowerCase();
30
33
  }
31
34
 
32
- for (var i = 0; i < data.length; i += this.chunkSize) {
35
+ for (let i = 0; i < data.length; i += this.chunkSize) {
33
36
  if (this.chunksByChr[chr][start + i]) {
34
37
  continue;
35
38
  }
36
39
 
37
- var feature = {
38
- id : chr + ':' + start + ':' + i,
40
+ const feature = {
41
+ id : `${chr}:${start}:${i}`,
39
42
  chr : chr,
40
43
  start : start + i,
41
44
  end : start + i + this.chunkSize - 1,
42
45
  sequence : data.substr(i, this.chunkSize),
43
- sort : start + i
46
+ sort : start + i,
44
47
  };
45
48
 
46
49
  this.chunksByChr[chr][feature.start] = feature;
47
50
  this.insertFeature(feature);
48
51
  }
49
- }
52
+ },
50
53
  });
@@ -1,18 +1,23 @@
1
- Genoverse.Track.Model.SequenceVariation = Genoverse.Track.Model.extend({
2
- seqModel: Genoverse.Track.Model.Sequence.Ensembl,
1
+ import Model from '../Model';
2
+ import SequenceModel from './Sequence/Ensembl';
3
+
4
+ export default Model.extend({
5
+ seqModel: SequenceModel,
3
6
 
4
7
  getSeqModel: function () {
5
- var models = this.prop('models');
8
+ const models = this.prop('models');
9
+
6
10
  models.seq = models.seq || this.track.newMVC(this.seqModel);
11
+
7
12
  return models.seq;
8
13
  },
9
14
 
10
15
  getData: function (chr, start, end) {
11
- var model = this;
12
- var deferred = $.Deferred();
13
- var seqData = this.getSeqModel().checkDataRange(chr, start, end);
16
+ const model = this;
17
+ const deferred = this.browser.jQuery.Deferred();
18
+ const seqData = this.getSeqModel().checkDataRange(chr, start, end);
14
19
 
15
- this.base(chr, start, end).done(function () {
20
+ this.base(chr, start, end).done(() => {
16
21
  if (seqData) {
17
22
  deferred.resolve();
18
23
  } else {
@@ -24,11 +29,12 @@ Genoverse.Track.Model.SequenceVariation = Genoverse.Track.Model.extend({
24
29
  },
25
30
 
26
31
  insertFeature: function (feature) {
27
- return this.base($.extend(feature, {
32
+ return this.base({
33
+ ...feature,
28
34
  end : feature.start + feature.alt_allele.length - 1,
29
35
  length : feature.alt_allele.length,
30
- sequence : feature.alt_allele
31
- }));
36
+ sequence : feature.alt_allele,
37
+ });
32
38
  },
33
39
 
34
40
  checkDataRange: function (chr, start, end) {
@@ -37,5 +43,5 @@ Genoverse.Track.Model.SequenceVariation = Genoverse.Track.Model.extend({
37
43
 
38
44
  findFeatures: function (chr, start, end) {
39
45
  return this.getSeqModel().findFeatures(chr, start, end).concat(this.base(chr, start, end));
40
- }
46
+ },
41
47
  });