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
@@ -1,9 +1,11 @@
1
- Genoverse.Track.Model.Stranded = Genoverse.Track.Model.extend({
1
+ import Model from '../Model';
2
+
3
+ export default Model.extend({
2
4
  init: function (reset) {
3
5
  this.base(reset);
4
6
 
5
7
  if (!reset) {
6
- var otherTrack = this.prop('forwardTrack');
8
+ const otherTrack = this.prop('forwardTrack');
7
9
 
8
10
  if (otherTrack) {
9
11
  this.featuresByChr = otherTrack.prop('featuresByChr');
@@ -13,16 +15,17 @@ Genoverse.Track.Model.Stranded = Genoverse.Track.Model.extend({
13
15
  }
14
16
  },
15
17
 
16
- parseURL: function () {
18
+ parseURL: function (...args) {
17
19
  if (!this.urlParams.strand) {
18
20
  this.urlParams.strand = this.prop('featureStrand');
19
21
  }
20
22
 
21
- return this.base.apply(this, arguments);
23
+ return this.base(...args);
22
24
  },
23
25
 
24
- findFeatures: function () {
25
- var strand = this.track.featureStrand;
26
- return $.grep(this.base.apply(this, arguments), function (feature) { return feature.strand === strand; });
27
- }
26
+ findFeatures: function (...args) {
27
+ const strand = this.track.featureStrand;
28
+
29
+ return this.base(...args).filter(feature => feature.strand === strand);
30
+ },
28
31
  });
@@ -0,0 +1,73 @@
1
+ import Model from '../Transcript';
2
+
3
+ // Ensembl REST API Transcript model
4
+ export default Model.extend({
5
+ url : '//rest.ensembl.org/overlap/region/human/__CHR__:__START__-__END__?feature=transcript;feature=exon;feature=cds;content-type=application/json',
6
+ dataRequestLimit : 5000000, // As per e! REST API restrictions
7
+
8
+ setDefaults: function (...args) {
9
+ this.geneIds = {};
10
+ this.seenGenes = 0;
11
+
12
+ this.base(...args);
13
+ },
14
+
15
+ // The url above responds in json format, data is an array
16
+ // See rest.ensembl.org/documentation/info/overlap_region for more details
17
+ parseData: function (data, chr) {
18
+ const featuresById = this.featuresById;
19
+ const ids = [];
20
+
21
+ data.filter(d => d.feature_type === 'transcript').forEach(
22
+ (feature, i) => {
23
+ if (!featuresById[feature.id]) {
24
+ this.geneIds[feature.Parent] = this.geneIds[feature.Parent] || ++this.seenGenes;
25
+
26
+ feature.chr = feature.chr || chr;
27
+ feature.label = parseInt(feature.strand, 10) === 1 ? `${feature.external_name || feature.id} >` : `< ${feature.external_name || feature.id}`;
28
+ feature.sort = (this.geneIds[feature.Parent] * 1e10) + (feature.logic_name.indexOf('ensembl_havana') === 0 ? 0 : 2e9) + (feature.biotype === 'protein_coding' ? 0 : 1e9) + feature.start + i;
29
+ feature.cdsStart = Infinity;
30
+ feature.cdsEnd = -Infinity;
31
+ feature.exons = {};
32
+ feature.subFeatures = [];
33
+
34
+ this.insertFeature(feature);
35
+ }
36
+
37
+ ids.push(feature.id);
38
+ }
39
+ );
40
+
41
+ data.filter(d => d.feature_type === 'cds' && featuresById[d.Parent]).forEach(
42
+ (cds) => {
43
+ featuresById[cds.Parent].cdsStart = Math.min(featuresById[cds.Parent].cdsStart, cds.start);
44
+ featuresById[cds.Parent].cdsEnd = Math.max(featuresById[cds.Parent].cdsEnd, cds.end);
45
+ }
46
+ );
47
+
48
+ data.filter(d => d.feature_type === 'exon' && featuresById[d.Parent] && !featuresById[d.Parent].exons[d.id]).forEach(
49
+ (exon) => {
50
+ if (exon.end < featuresById[exon.Parent].cdsStart || exon.start > featuresById[exon.Parent].cdsEnd) {
51
+ featuresById[exon.Parent].subFeatures.push({ utr: true, ...exon });
52
+ } else {
53
+ if (exon.start < featuresById[exon.Parent].cdsStart) {
54
+ featuresById[exon.Parent].subFeatures.push({ utr: true, ...exon, end: featuresById[exon.Parent].cdsStart });
55
+ }
56
+
57
+ featuresById[exon.Parent].subFeatures.push({
58
+ ...exon,
59
+ start : Math.max(exon.start, featuresById[exon.Parent].cdsStart),
60
+ end : Math.min(exon.end, featuresById[exon.Parent].cdsEnd),
61
+ strand : featuresById[exon.Parent].strand,
62
+ });
63
+
64
+ if (exon.end > featuresById[exon.Parent].cdsEnd) {
65
+ featuresById[exon.Parent].subFeatures.push({ utr: true, ...exon, start: featuresById[exon.Parent].cdsEnd });
66
+ }
67
+ }
68
+ }
69
+ );
70
+
71
+ ids.forEach(id => featuresById[id].subFeatures.sort((a, b) => a.start - b.start));
72
+ },
73
+ });
@@ -1,5 +1,7 @@
1
+ import Model from '../Model';
2
+
1
3
  // Abstract Transcript model
2
4
  // see sub-models for more specific examples
3
- Genoverse.Track.Model.Transcript = Genoverse.Track.Model.extend({
5
+ export default Model.extend({
4
6
 
5
7
  });
@@ -1,4 +1,8 @@
1
- Genoverse.Track.Model = Base.extend({
1
+ import Base from 'basejs';
2
+ import RTree from 'rtree';
3
+ import wrapFunctions from '../lib/wrap-functions';
4
+
5
+ export default Base.extend({
2
6
  dataType : 'json',
3
7
  allData : false,
4
8
  dataBuffer : undefined, // e.g. { start: 0, end: 0 } - basepairs to extend data region for, when getting data from the origin
@@ -11,8 +15,15 @@ Genoverse.Track.Model = Base.extend({
11
15
  showServerErrors : false, // if true, error messages return from the server by getData requests will be shown on the track
12
16
 
13
17
  constructor: function (properties) {
14
- $.extend(this, properties);
15
- Genoverse.wrapFunctions(this);
18
+ Object.entries(properties).forEach(
19
+ ([ key, val ]) => {
20
+ if (typeof val !== 'undefined') {
21
+ this[key] = val;
22
+ }
23
+ }
24
+ );
25
+
26
+ wrapFunctions(this, 'Model');
16
27
  this.init();
17
28
  },
18
29
 
@@ -20,9 +31,7 @@ Genoverse.Track.Model = Base.extend({
20
31
  this.setDefaults(reset);
21
32
 
22
33
  if (reset) {
23
- for (var i in this.featuresById) {
24
- delete this.featuresById[i].position;
25
- }
34
+ Object.values(this.featuresById).forEach((feature) => { delete feature.position; });
26
35
  }
27
36
 
28
37
  if (!reset || this.data) {
@@ -52,7 +61,7 @@ Genoverse.Track.Model = Base.extend({
52
61
  },
53
62
 
54
63
  setChrProps: function () {
55
- var chr = this.browser.chr;
64
+ const chr = this.browser.chr;
56
65
 
57
66
  this.dataRangesByChr = this.dataRangesByChr || {};
58
67
  this.featuresByChr = this.featuresByChr || {};
@@ -78,26 +87,28 @@ Genoverse.Track.Model = Base.extend({
78
87
  },
79
88
 
80
89
  getData: function (chr, start, end, done) {
90
+ const jQuery = this.browser.jQuery;
91
+
81
92
  start = Math.max(1, start);
82
93
  end = Math.min(this.browser.getChromosomeSize(chr), end);
83
94
 
84
- var deferred = $.Deferred();
95
+ const deferred = jQuery.Deferred();
85
96
 
86
97
  if (typeof this.data !== 'undefined') {
87
- this.receiveData(typeof this.data.sort === 'function' ? this.data.sort(function (a, b) { return a.start - b.start; }) : this.data, chr, start, end);
88
- return deferred.resolveWith(this);
98
+ this.receiveData(typeof this.data.sort === 'function' ? this.data.sort((a, b) => a.start - b.start) : this.data, chr, start, end);
99
+
100
+ return deferred.resolve();
89
101
  }
90
102
 
91
- var model = this;
92
- var bins = [];
93
- var length = end - start + 1;
103
+ const bins = [];
104
+ const length = end - start + 1;
94
105
 
95
106
  if (!this.url) {
96
- return deferred.resolveWith(this);
107
+ return deferred.resolve();
97
108
  }
98
109
 
99
110
  if (this.dataRequestLimit && length > this.dataRequestLimit) {
100
- var i = Math.ceil(length / this.dataRequestLimit);
111
+ let i = Math.ceil(length / this.dataRequestLimit);
101
112
 
102
113
  while (i--) {
103
114
  bins.push([ start, i ? start += this.dataRequestLimit - 1 : end ]);
@@ -107,39 +118,45 @@ Genoverse.Track.Model = Base.extend({
107
118
  bins.push([ start, end ]);
108
119
  }
109
120
 
110
- $.when.apply($, $.map(bins, function (bin) {
111
- var request = $.ajax({
112
- url : model.parseURL(chr, bin[0], bin[1]),
113
- data : model.urlParams,
114
- dataType : model.dataType,
115
- context : model,
116
- xhrFields : model.xhrFields,
117
- success : function (data) {
118
- this.receiveData(data, chr, bin[0], bin[1]);
119
- },
120
- error: function (xhr, statusText) {
121
- this.track.controller.showError(
122
- this.showServerErrors && (xhr.responseJSON || {}).message
123
- ? xhr.responseJSON.message
124
- : statusText + ' while getting the data, see console for more details',
125
- arguments
121
+ jQuery.when(
122
+ ...bins.map(
123
+ (bin) => {
124
+ const request = jQuery.ajax({
125
+ url : this.parseURL(chr, bin[0], bin[1]),
126
+ data : this.urlParams,
127
+ dataType : this.dataType,
128
+ xhrFields : this.xhrFields,
129
+ }).then(
130
+ (data) => {
131
+ this.receiveData(data, chr, bin[0], bin[1]);
132
+ }
133
+ ).catch(
134
+ (xhr, statusText, ...args) => {
135
+ this.track.controller.showError(
136
+ this.showServerErrors && xhr.responseJSON?.message
137
+ ? xhr.responseJSON.message
138
+ : `${statusText} while getting the data, see console for more details`,
139
+ [ xhr, statusText, ...args ]
140
+ );
141
+ }
142
+ ).always(
143
+ () => {
144
+ this.dataLoading = this.dataLoading.filter(loading => request !== loading);
145
+ }
126
146
  );
127
- },
128
- complete: function (xhr) {
129
- this.dataLoading = $.grep(this.dataLoading, function (t) { return xhr !== t; });
130
- }
131
- });
132
147
 
133
- request.coords = [ chr, bin[0], bin[1] ]; // store actual chr, start and end on the request, in case they are needed
148
+ request.coords = [ chr, bin[0], bin[1] ]; // store actual chr, start and end on the request, in case they are needed
134
149
 
135
- if (typeof done === 'function') {
136
- request.done(done);
137
- }
150
+ if (typeof done === 'function') {
151
+ request.done(done);
152
+ }
138
153
 
139
- model.dataLoading.push(request);
154
+ this.dataLoading.push(request);
140
155
 
141
- return request;
142
- })).done(function () { deferred.resolveWith(model); });
156
+ return request;
157
+ }
158
+ )
159
+ ).done(deferred.resolve);
143
160
 
144
161
  return deferred;
145
162
  },
@@ -177,17 +194,15 @@ Genoverse.Track.Model = Base.extend({
177
194
  * and call this.insertFeature(feature)
178
195
  */
179
196
  parseData: function (data, chr, start) { // end is also passed in, but not used in this case
180
- var feature;
181
-
182
197
  // Example of parseData function when data is an array of hashes like { start: ..., end: ... }
183
- for (var i = 0; i < data.length; i++) {
184
- feature = data[i];
198
+ data.forEach(
199
+ (feature, i) => {
200
+ feature.chr = feature.chr || chr;
201
+ feature.sort = start + i;
185
202
 
186
- feature.chr = feature.chr || chr;
187
- feature.sort = start + i;
188
-
189
- this.insertFeature(feature);
190
- }
203
+ this.insertFeature(feature);
204
+ }
205
+ );
191
206
  },
192
207
 
193
208
  updateData: function (data) {
@@ -208,20 +223,22 @@ Genoverse.Track.Model = Base.extend({
208
223
  start = Math.max(1, start);
209
224
  end = Math.min(this.browser.getChromosomeSize(chr), end);
210
225
 
211
- var ranges = this.dataRanges(chr).search({ x: start, w: end - start + 1, y: 0, h: 1 }).sort(function (a, b) { return a[0] - b[0]; });
226
+ const ranges = this.dataRanges(chr).search({ x: start, w: end - start + 1, y: 0, h: 1 }).sort((a, b) => a[0] - b[0]);
212
227
 
213
228
  if (!ranges.length) {
214
229
  return false;
215
230
  }
216
231
 
217
- var s = ranges.length === 1 ? ranges[0][0] : 9e99;
218
- var e = ranges.length === 1 ? ranges[0][1] : -9e99;
232
+ let s = ranges.length === 1 ? ranges[0][0] : 9e99;
233
+ let e = ranges.length === 1 ? ranges[0][1] : -9e99;
234
+
235
+ for (let i = 0; i < ranges.length - 1; i++) {
236
+ const [ s0, s1 ] = ranges[i];
237
+ const [ e0, e1 ] = ranges[i + 1];
219
238
 
220
- for (var i = 0; i < ranges.length - 1; i++) {
221
- // s0 <= s1 && ((e0 >= e1) || (e0 + 1 >= s1))
222
- if (ranges[i][0] <= ranges[i + 1][0] && ((ranges[i][1] >= ranges[i + 1][1]) || (ranges[i][1] + 1 >= ranges[i + 1][0]))) {
223
- s = Math.min(s, ranges[i][0]);
224
- e = Math.max(e, ranges[i][1], ranges[i + 1][1]);
239
+ if (s0 <= s1 && ((e0 >= e1) || (e0 + 1 >= s1))) {
240
+ s = Math.min(s, s0);
241
+ e = Math.max(e, e0, e1);
225
242
  } else {
226
243
  return false;
227
244
  }
@@ -237,67 +254,82 @@ Genoverse.Track.Model = Base.extend({
237
254
 
238
255
  // Make sure we have a unique ID, this method is not efficient, so better supply your own id
239
256
  if (!feature.id) {
240
- feature.id = feature.ID || this.hashCode(JSON.stringify($.extend({}, feature, { sort: '' }))); // sort is dependant on the browser's region, so will change on zoom
257
+ feature.id = feature.ID || this.hashCode(JSON.stringify({ ...feature, sort: '' })); // sort is dependant on the browser's region, so will change on zoom
241
258
  }
242
259
 
243
- var features = this.features(feature.chr);
260
+ const features = this.features(feature.chr);
244
261
 
245
262
  if (features && !this.featuresById[feature.id]) {
246
263
  if (feature.subFeatures) {
247
- feature.subFeatures.sort(function (a, b) { return a.start - b.start; });
248
-
249
- for (var i = 0; i < feature.subFeatures.length; i++) {
250
- feature.subFeatures[i].start = Math.min(Math.max(feature.subFeatures[i].start, feature.start), feature.end);
251
- feature.subFeatures[i].end = Math.max(Math.min(feature.subFeatures[i].end, feature.end), feature.start);
252
- }
264
+ feature.subFeatures.sort(
265
+ (a, b) => a.start - b.start
266
+ ).forEach(
267
+ (subFeature) => {
268
+ subFeature.start = Math.min(Math.max(subFeature.start, feature.start), feature.end);
269
+ subFeature.end = Math.max(Math.min(subFeature.end, feature.end), feature.start);
270
+ }
271
+ );
253
272
 
254
273
  // Add "fake" sub-features at the start and end of the feature - this will allow joins to be drawn when there are no sub-features in the current region.
255
274
  feature.subFeatures.unshift({ start: feature.start, end: feature.start, fake: true });
256
- feature.subFeatures.push({ start: feature.end, end: feature.end, fake: true });
275
+ feature.subFeatures.push({ start: feature.end, end: feature.end, fake: true });
257
276
  }
258
277
 
259
278
  features.insert({ x: feature.start, y: 0, w: feature.end - feature.start + 1, h: 1 }, feature);
279
+
260
280
  this.featuresById[feature.id] = feature;
261
281
  }
262
282
  },
263
283
 
264
284
  findFeatures: function (chr, start, end) {
265
- var features = this.features(chr).search({ x: start - this.dataBuffer.start, y: 0, w: end - start + this.dataBuffer.start + this.dataBuffer.end + 1, h: 1 });
266
- var filters = this.prop('featureFilters') || [];
267
-
268
- for (var i = 0; i < filters.length; i++) {
269
- features = $.grep(features, $.proxy(filters[i], this));
270
- }
285
+ let features = this.features(chr).search({
286
+ x : start - this.dataBuffer.start,
287
+ y : 0,
288
+ w : end - start + this.dataBuffer.start + this.dataBuffer.end + 1,
289
+ h : 1,
290
+ });
291
+
292
+ (this.prop('featureFilters') || []).forEach(
293
+ (filter) => {
294
+ features = features.filter(feature => filter.call(this, feature));
295
+ }
296
+ );
271
297
 
272
298
  return this.sortFeatures(features);
273
299
  },
274
300
 
275
301
  sortFeatures: function (features) {
276
- return features.sort(function (a, b) { return a.sort - b.sort; });
302
+ return features.sort((a, b) => a.sort - b.sort);
277
303
  },
278
304
 
279
- abort: function () {
280
- for (var i = 0; i < this.dataLoading.length; i++) {
281
- this.dataLoading[i].abort();
305
+ hashCode: function (string) {
306
+ let hash = 0;
307
+
308
+ if (string.length) {
309
+ for (let i = 0; i < string.length; i++) {
310
+ const c = string.charCodeAt(i);
311
+
312
+ hash = ((hash << 5) - hash) + c;
313
+ hash &= hash; // Convert to 32bit integer
314
+ }
282
315
  }
283
316
 
284
- this.dataLoading = [];
317
+ return String(hash);
285
318
  },
286
319
 
287
- hashCode: function (string) {
288
- var hash = 0;
289
- var c;
320
+ abort: function () {
321
+ this.dataLoading.forEach(loading => loading.abort());
290
322
 
291
- if (!string.length) {
292
- return hash;
293
- }
323
+ this.dataLoading = [];
324
+ },
294
325
 
295
- for (var i = 0; i < string.length; i++) {
296
- c = string.charCodeAt(i);
297
- hash = ((hash << 5) - hash) + c;
298
- hash &= hash; // Convert to 32bit integer
299
- }
326
+ destroy: function () {
327
+ this.abort();
300
328
 
301
- return '' + hash;
302
- }
329
+ // Force garbage collection
330
+ delete this.data;
331
+ delete this.dataRangesByChr;
332
+ delete this.featuresByChr;
333
+ delete this.featuresById;
334
+ },
303
335
  });
@@ -1,6 +1,8 @@
1
- Genoverse.Track.View.Gene.Ensembl = Genoverse.Track.View.Gene.extend({
1
+ import View from '../Gene';
2
+
3
+ export default View.extend({
2
4
  setFeatureColor: function (feature) {
3
- var processedTranscript = {
5
+ const processedTranscript = {
4
6
  'sense_intronic' : 1,
5
7
  'sense_overlapping' : 1,
6
8
  'processed_transcript' : 1,
@@ -12,7 +14,7 @@ Genoverse.Track.View.Gene.Ensembl = Genoverse.Track.View.Gene.extend({
12
14
  'non_coding' : 1,
13
15
  'ambiguous_orf' : 1,
14
16
  'disrupted_domain' : 1,
15
- '3prime_overlapping_ncrna' : 1
17
+ '3prime_overlapping_ncrna' : 1,
16
18
  };
17
19
 
18
20
  feature.color = '#000000';
@@ -42,5 +44,5 @@ Genoverse.Track.View.Gene.Ensembl = Genoverse.Track.View.Gene.extend({
42
44
  }
43
45
 
44
46
  feature.labelColor = feature.labelColor || feature.color;
45
- }
47
+ },
46
48
  });
@@ -0,0 +1,8 @@
1
+ import View from '../View';
2
+
3
+ export default View.extend({
4
+ featureHeight : 5,
5
+ labels : true,
6
+ repeatLabels : true,
7
+ bump : true,
8
+ });
@@ -1,14 +1,15 @@
1
- Genoverse.Track.View.Sequence = Genoverse.Track.View.extend({
1
+ import View from '../View';
2
+
3
+ export default View.extend({
2
4
  featureMargin : { top: 0, right: 0, bottom: 0, left: 0 },
3
5
  colors : { 'default': '#CCCCCC', A: '#73E973', T: '#DE4C61', G: '#FFFF77', C: '#688EC0' },
4
6
  labelColors : { 'default': '#000000', T: '#FFFFFF', C: '#FFFFFF' },
5
7
  labels : 'overlay',
6
8
 
7
- setDefaults: function () {
8
- this.base.apply(this, arguments);
9
+ setDefaults: function (...args) {
10
+ this.base(...args);
9
11
 
10
- var lowerCase = this.prop('lowerCase');
11
- var key;
12
+ const lowerCase = this.prop('lowerCase');
12
13
 
13
14
  this.labelYOffset = typeof this.labelYOffset === 'number' ? this.labelYOffset : (this.featureHeight + 1) / 2;
14
15
  this.widestLabel = typeof this.widestLabel === 'string' ? this.widestLabel : lowerCase ? 'g' : 'G';
@@ -17,13 +18,11 @@ Genoverse.Track.View.Sequence = Genoverse.Track.View.extend({
17
18
  this.labelWidth[this.widestLabel] = Math.ceil(this.context.measureText(this.widestLabel).width) + 1;
18
19
 
19
20
  if (lowerCase) {
20
- for (key in this.colors) {
21
- this.colors[key.toLowerCase()] = this.colors[key];
22
- }
23
-
24
- for (key in this.labelColors) {
25
- this.labelColors[key.toLowerCase()] = this.labelColors[key];
26
- }
21
+ [ this.colors, this.labelColors ].forEach(
22
+ colorObject => Object.entries(colorObject).forEach(([ letter, color ]) => {
23
+ colorObject[letter.toLowerCase()] = color;
24
+ })
25
+ );
27
26
  }
28
27
  },
29
28
 
@@ -31,25 +30,22 @@ Genoverse.Track.View.Sequence = Genoverse.Track.View.extend({
31
30
  featureContext.textBaseline = 'middle';
32
31
  featureContext.textAlign = 'center';
33
32
 
34
- var width = Math.max(scale, this.minScaledWidth);
33
+ const width = Math.max(scale, this.minScaledWidth);
35
34
 
36
- for (var i = 0; i < features.length; i++) {
37
- this.drawSequence(features[i], featureContext, scale, width);
38
- }
35
+ features.forEach(feature => this.drawSequence(feature, featureContext, scale, width));
39
36
  },
40
37
 
41
38
  drawSequence: function (feature, context, scale, width) {
42
- var drawLabels = this.labelWidth[this.widestLabel] < width - 1;
43
- var start, bp;
39
+ const drawLabels = this.labelWidth[this.widestLabel] < width - 1;
44
40
 
45
- for (var i = 0; i < feature.sequence.length; i++) {
46
- start = feature.position[scale].X + i * scale;
41
+ for (let i = 0; i < feature.sequence.length; i++) {
42
+ const start = feature.position[scale].X + i * scale;
47
43
 
48
44
  if (start < -scale || start > context.canvas.width) {
49
45
  continue;
50
46
  }
51
47
 
52
- bp = feature.sequence.charAt(i);
48
+ const bp = feature.sequence.charAt(i);
53
49
 
54
50
  context.fillStyle = this.colors[bp] || this.colors.default;
55
51
  context.fillRect(start, feature.position[scale].Y, width, this.featureHeight);
@@ -59,5 +55,5 @@ Genoverse.Track.View.Sequence = Genoverse.Track.View.extend({
59
55
  context.fillText(bp, start + (width / 2), feature.position[scale].Y + this.labelYOffset);
60
56
  }
61
57
  }
62
- }
58
+ },
63
59
  });