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,12 +1,22 @@
1
- Genoverse.Track.Controller = Base.extend({
1
+ import Base from 'basejs';
2
+ import wrapFunctions from '../lib/wrap-functions';
3
+
4
+ export default Base.extend({
2
5
  scrollBuffer : 1.2, // Number of widths, if left or right closer to the edges of viewpoint than the buffer, start making more images
3
6
  threshold : Infinity, // Length above which the track is not drawn
4
7
  clickTolerance : 0, // pixels of tolerance added to a click position when finding features for popup menus, when scale < 1
5
8
  messages : undefined,
6
9
 
7
10
  constructor: function (properties) {
8
- $.extend(this, properties);
9
- Genoverse.wrapFunctions(this);
11
+ Object.entries(properties).forEach(
12
+ ([ key, val ]) => {
13
+ if (typeof val !== 'undefined') {
14
+ this[key] = val;
15
+ }
16
+ }
17
+ );
18
+
19
+ wrapFunctions(this, 'Controller');
10
20
  this.init();
11
21
  },
12
22
 
@@ -24,17 +34,17 @@ Genoverse.Track.Controller = Base.extend({
24
34
  this.messages = this.messages || {
25
35
  error : 'ERROR: ',
26
36
  threshold : 'Data for this track is not displayed in regions greater than ',
27
- resize : 'Some features are currently hidden, <a class="gv-resize">resize to see all</a>'
37
+ resize : 'Some features are currently hidden, <a class="gv-resize">resize to see all</a>',
28
38
  };
29
39
  },
30
40
 
31
- reset: function () {
41
+ reset: function (arg) {
32
42
  this.abort();
33
43
  this.setDefaults();
34
44
  this.resetImages();
35
45
  this.browser.closeMenus(this);
36
46
 
37
- if (arguments[0] !== 'resizing') {
47
+ if (arg !== 'resizing') {
38
48
  this.setScale();
39
49
  this.makeFirstImage();
40
50
  }
@@ -46,7 +56,7 @@ Genoverse.Track.Controller = Base.extend({
46
56
  },
47
57
 
48
58
  resetImageRanges: function () {
49
- var browser = this.browser;
59
+ const browser = this.browser;
50
60
 
51
61
  this.left = 0;
52
62
  this.scrollStart = [ 'ss', browser.chr, browser.start, browser.end ].join('-');
@@ -57,11 +67,11 @@ Genoverse.Track.Controller = Base.extend({
57
67
 
58
68
  setName: function (name, configName) {
59
69
  this.track.name = name;
60
- this.labelName = this.labelName || $('<span class="gv-name">').appendTo(this.label);
70
+ this.labelName = this.labelName || this.browser.jQuery('<span class="gv-name">').appendTo(this.label);
61
71
 
62
72
  this.labelName.attr('title', name).html(
63
73
  configName && configName.length
64
- ? configName.map(function (part) { return '<span class="gv-name-part">' + part + '</span>'; })
74
+ ? configName.map(part => `<span class="gv-name-part">${part}</span>`)
65
75
  : name
66
76
  );
67
77
 
@@ -75,28 +85,35 @@ Genoverse.Track.Controller = Base.extend({
75
85
  },
76
86
 
77
87
  addDomElements: function () {
78
- var name = this.track.name || '';
79
-
80
- this.menus = $();
81
- this.container = $('<div class="gv-track-container">').appendTo(this.browser.wrapper);
82
- this.scrollContainer = $('<div class="gv-scroll-container">').appendTo(this.container);
83
- this.imgContainer = $('<div class="gv-image-container">').width(this.width).addClass(this.prop('invert') ? 'gv-invert' : '');
84
- this.messageContainer = $('<div class="gv-message-container"><div class="gv-messages"></div><i class="gv-control gv-collapse fas fa-angle-double-left"></i><i class="gv-control gv-expand fas fa-angle-double-right"></i></div>').appendTo(this.container);
85
- this.label = $('<li>').appendTo(this.browser.labelContainer).height(this.prop('height')).data('track', this.track);
86
- this.context = $('<canvas>')[0].getContext('2d');
88
+ const name = this.track.name || '';
89
+ const jQuery = this.browser.jQuery;
90
+
91
+ this.menus = jQuery();
92
+ this.container = jQuery('<div class="gv-track-container">').appendTo(this.browser.wrapper);
93
+ this.scrollContainer = jQuery('<div class="gv-scroll-container">').appendTo(this.container);
94
+ this.imgContainer = jQuery('<div class="gv-image-container">').width(this.width).addClass(this.prop('invert') ? 'gv-invert' : '');
95
+ this.label = jQuery('<li>').appendTo(this.browser.labelContainer).height(this.prop('height')).data('track', this.track);
96
+ this.context = jQuery('<canvas>')[0].getContext('2d');
97
+ this.messageContainer = jQuery(`
98
+ <div class="gv-message-container">
99
+ <div class="gv-messages"></div>
100
+ <i class="gv-control gv-collapse fas fa-angle-double-left"></i>
101
+ <i class="gv-control gv-expand fas fa-angle-double-right"></i>
102
+ </div>
103
+ `).appendTo(this.container);
87
104
 
88
105
  if (this.prop('border')) {
89
- $('<div class="gv-track-border">').appendTo(this.container);
106
+ jQuery('<div class="gv-track-border">').appendTo(this.container);
90
107
  }
91
108
 
92
109
  if (this.prop('unsortable')) {
93
110
  this.label.addClass('gv-unsortable');
94
111
  } else {
95
- $('<div class="gv-handle">').appendTo(this.label);
112
+ jQuery('<div class="gv-handle">').appendTo(this.label);
96
113
  }
97
114
 
98
115
  if (this.prop('children')) {
99
- this.superContainer = $('<div class="gv-track-container gv-track-super-container">').insertAfter(this.container);
116
+ this.superContainer = jQuery('<div class="gv-track-container gv-track-super-container">').insertAfter(this.container);
100
117
  this.container.appendTo(this.superContainer);
101
118
  } else if (this.prop('parentTrack')) {
102
119
  this.superContainer = this.prop('parentTrack').prop('superContainer');
@@ -113,10 +130,10 @@ Genoverse.Track.Controller = Base.extend({
113
130
  },
114
131
 
115
132
  addUserEventHandlers: function () {
116
- var controller = this;
117
- var browser = this.browser;
133
+ const controller = this;
134
+ const browser = this.browser;
118
135
 
119
- this.container.on('mouseup', '.gv-image-container', function (e) {
136
+ this.container.on('mouseup', '.gv-image-container', (e) => {
120
137
  if ((e.which && e.which !== 1) || (typeof browser.dragStart === 'number' && browser.start !== browser.dragStart) || (browser.dragAction === 'select' && browser.selector.outerWidth(true) > 2)) {
121
138
  return; // Only show menus on left click when not dragging and not selecting
122
139
  }
@@ -124,23 +141,24 @@ Genoverse.Track.Controller = Base.extend({
124
141
  controller.click(e);
125
142
  });
126
143
 
127
- this.messageContainer.children().on('click', function () {
128
- var collapsed = controller.messageContainer.children('.gv-messages').is(':visible') ? ' gv-collapsed' : '';
129
- var code = controller.messageContainer.find('.gv-msg').data('code');
144
+ this.messageContainer.children().on('click', () => {
145
+ const collapsed = controller.messageContainer.children('.gv-messages').is(':visible') ? ' gv-collapsed' : '';
146
+ const code = controller.messageContainer.find('.gv-msg').data('code');
130
147
 
131
- controller.messageContainer.attr('class', 'gv-message-container' + collapsed);
148
+ controller.messageContainer.attr('class', `gv-message-container${collapsed}`);
132
149
  controller.checkHeight();
133
150
 
134
151
  if (code !== 'error') {
135
- document.cookie = [ 'gv_msg', code, controller.prop('id') ].join('_') + '=1; expires=' + (collapsed ? 'Tue, 19 Jan 2038' : 'Thu, 01 Jan 1970') + ' 00:00:00 GMT; path=/';
152
+ document.cookie = `gv_msg_${code}_${controller.prop('id')}=1; expires=${collapsed ? 'Tue, 19 Jan 2038' : 'Thu, 01 Jan 1970'} 00:00:00 GMT; path=/`;
136
153
  }
137
154
  });
138
155
  },
139
156
 
140
157
  click: function (e) {
141
- var target = $(e.target);
142
- var x = e.pageX - this.container.parent().offset().left + this.browser.scaledStart;
143
- var y = e.pageY - target.offset().top;
158
+ const target = this.browser.jQuery(e.target);
159
+ const x = e.pageX - this.container.parent().offset().left + this.browser.scaledStart;
160
+
161
+ let y = e.pageY - target.offset().top;
144
162
 
145
163
  if (this.imgContainer.hasClass('gv-invert')) {
146
164
  y = target.height() - y;
@@ -150,28 +168,30 @@ Genoverse.Track.Controller = Base.extend({
150
168
  },
151
169
 
152
170
  getClickedFeatures: function (x, y, target) {
153
- var bounds = { x: x, y: y, w: 1, h: 1 };
154
- var scale = this.scale;
155
- var tolerance = scale < 1 ? this.clickTolerance : 0;
171
+ const bounds = { x: x, y: y, w: 1, h: 1 };
172
+ const scale = this.scale;
173
+ const tolerance = scale < 1 ? this.clickTolerance : 0;
156
174
 
157
175
  if (tolerance) {
158
176
  bounds.x -= tolerance / 2;
159
177
  bounds.w += tolerance;
160
178
  }
161
179
 
162
- var features = this[target && target.hasClass('gv-labels') ? 'labelPositions' : 'featurePositions'].search(bounds);
180
+ const features = this[target && target.hasClass('gv-labels') ? 'labelPositions' : 'featurePositions'].search(bounds);
163
181
 
164
182
  if (tolerance) {
165
- return features.filter(function (f) {
166
- var featureBounds = f.position[scale].bounds;
167
- var center = featureBounds.x + (featureBounds.w / 2);
168
- var minX = Math.min(featureBounds.x, center - (tolerance / 2));
169
- var maxX = Math.max(featureBounds.x + featureBounds.w, center + (tolerance / 2));
170
-
171
- return x >= minX && x <= maxX;
172
- }).sort(function (a, b) {
173
- return Math.abs(a.position[scale].start - x) - Math.abs(b.position[scale].start - x);
174
- });
183
+ return features.filter(
184
+ (f) => {
185
+ const featureBounds = f.position[scale].bounds;
186
+ const center = featureBounds.x + (featureBounds.w / 2);
187
+ const minX = Math.min(featureBounds.x, center - (tolerance / 2));
188
+ const maxX = Math.max(featureBounds.x + featureBounds.w, center + (tolerance / 2));
189
+
190
+ return x >= minX && x <= maxX;
191
+ }
192
+ ).sort(
193
+ (a, b) => Math.abs(a.position[scale].start - x) - Math.abs(b.position[scale].start - x)
194
+ );
175
195
  }
176
196
 
177
197
  return this.model.sortFeatures(features);
@@ -179,21 +199,23 @@ Genoverse.Track.Controller = Base.extend({
179
199
 
180
200
  // FIXME: messages are now hidden/shown instead of removed/added. This will cause a problem if a new message arrives with the same code as one that already exists.
181
201
  showMessage: function (code, additionalText) {
182
- var messages = this.messageContainer.children('.gv-messages');
202
+ let messages = this.messageContainer.children('.gv-messages');
183
203
 
184
- if (!messages.children('.gv-' + code).show().length) {
185
- var msg = $('<div class="gv-msg gv-' + code + '">' + this.messages[code] + (additionalText || '') + '</div>').data('code', code).prependTo(messages);
204
+ if (!messages.children(`.gv-${code}`).show().length) {
205
+ const msg = this.browser.jQuery(`<div class="gv-msg gv-${code}">${this.messages[code]}${additionalText || ''}</div>`).data('code', code).prependTo(messages);
186
206
 
187
207
  if (code === 'resize') {
188
- msg.children('a.gv-resize').on('click', $.proxy(function () {
189
- this.resize(this.fullVisibleHeight);
190
- }, this));
208
+ const controller = this;
209
+
210
+ msg.children('a.gv-resize').on('click', () => {
211
+ controller.resize(controller.fullVisibleHeight);
212
+ });
191
213
  }
192
214
 
193
- this.messageContainer[document.cookie.match([ 'gv_msg', code, this.prop('id') ].join('_') + '=1') ? 'addClass' : 'removeClass']('gv-collapsed');
215
+ this.messageContainer[document.cookie.match(`${[ 'gv_msg', code, this.prop('id') ].join('_')}=1`) ? 'addClass' : 'removeClass']('gv-collapsed');
194
216
  }
195
217
 
196
- var height = this.messageContainer.show().outerHeight(true);
218
+ const height = this.messageContainer.show().outerHeight(true);
197
219
 
198
220
  if (height > this.prop('height')) {
199
221
  this.resize(height, undefined, false);
@@ -203,10 +225,10 @@ Genoverse.Track.Controller = Base.extend({
203
225
  },
204
226
 
205
227
  hideMessage: function (code) {
206
- var messages = this.messageContainer.find('.gv-msg');
228
+ let messages = this.messageContainer.find('.gv-msg');
207
229
 
208
230
  if (code) {
209
- messages = messages.filter('.gv-' + code).hide();
231
+ messages = messages.filter(`.gv-${code}`).hide();
210
232
 
211
233
  if (messages.length && !messages.siblings().filter(function () { return this.style.display !== 'none'; }).length) {
212
234
  this.messageContainer.hide();
@@ -239,7 +261,7 @@ Genoverse.Track.Controller = Base.extend({
239
261
  return;
240
262
  }
241
263
 
242
- var autoHeight;
264
+ let autoHeight;
243
265
 
244
266
  if (this.browser.length > this.threshold) {
245
267
  autoHeight = this.prop('autoHeight');
@@ -256,22 +278,23 @@ Genoverse.Track.Controller = Base.extend({
256
278
  },
257
279
 
258
280
  visibleFeatureHeight: function () {
259
- var bounds = { x: this.browser.scaledStart, w: this.width, y: 0, h: 9e99 };
260
- var scale = this.scale;
261
- var features = this.featurePositions.search(bounds);
262
- var minHeight = this.prop('hideEmpty') ? 0 : this.minLabelHeight;
263
- var height = Math.max.apply(Math, $.map(features, function (feature) { return feature.position[scale].bottom; }).concat(minHeight));
281
+ const bounds = { x: this.browser.scaledStart, w: this.width, y: 0, h: 9e99 };
282
+ const scale = this.scale;
283
+ const features = this.featurePositions.search(bounds);
284
+ const minHeight = this.prop('hideEmpty') ? 0 : this.minLabelHeight;
285
+
286
+ let height = Math.max(...features.map(feature => feature.position[scale].bottom).concat(minHeight));
264
287
 
265
288
  if (this.prop('labels') === 'separate') {
266
289
  this.labelTop = height;
267
- height += Math.max.apply(Math, $.map(this.labelPositions.search(bounds).concat(this.prop('repeatLabels') ? features : []), function (feature) { return feature.position[scale].label.bottom; }).concat(minHeight));
290
+ height += Math.max(...this.labelPositions.search(bounds).concat(this.prop('repeatLabels') ? features : []).map(feature => feature.position[scale].label.bottom).concat(minHeight));
268
291
  }
269
292
 
270
293
  return height;
271
294
  },
272
295
 
273
296
  autoResize: function () {
274
- var autoHeight = this.prop('autoHeight');
297
+ const autoHeight = this.prop('autoHeight');
275
298
 
276
299
  if (autoHeight || this.prop('labels') === 'separate') {
277
300
  this.resize(autoHeight ? this.fullVisibleHeight : this.prop('height'), this.labelTop, false);
@@ -301,8 +324,8 @@ Genoverse.Track.Controller = Base.extend({
301
324
  return;
302
325
  }
303
326
 
304
- var featureMargin = this.prop('featureMargin');
305
- var height = this.prop('height');
327
+ const featureMargin = this.prop('featureMargin');
328
+ const height = this.prop('height');
306
329
 
307
330
  // Note: fullVisibleHeight - featureMargin.top - featureMargin.bottom is not actually the correct value to test against, but it's the easiest best guess to obtain.
308
331
  // fullVisibleHeight is the maximum bottom position of the track's features in the region, which includes margin at the bottom of each feature and label
@@ -312,14 +335,14 @@ Genoverse.Track.Controller = Base.extend({
312
335
  if (this.fullVisibleHeight - featureMargin.top - featureMargin.bottom > height && !this.prop('disabled')) {
313
336
  this.showMessage('resize');
314
337
 
315
- var controller = this;
316
- var h = this.messageContainer.outerHeight(true);
338
+ const controller = this;
339
+ const h = this.messageContainer.outerHeight(true);
317
340
 
318
341
  if (h > height) {
319
342
  this.resize(h, undefined, saveConfig);
320
343
  }
321
344
 
322
- this.expander = (this.expander || $('<div class="gv-expander gv-static">').width(this.width).appendTo(this.container).on('click', function () {
345
+ this.expander = (this.expander || this.browser.jQuery('<div class="gv-expander gv-static">').width(this.width).appendTo(this.container).on('click', () => {
323
346
  controller.resize(controller.fullVisibleHeight);
324
347
  }))[this.prop('height') === 0 ? 'hide' : 'show']();
325
348
  } else if (this.expander) {
@@ -329,22 +352,24 @@ Genoverse.Track.Controller = Base.extend({
329
352
  },
330
353
 
331
354
  setLabelHeight: function (enforceMinHeight) {
332
- var parent = this.prop('parentTrack');
355
+ const parent = this.prop('parentTrack');
333
356
 
334
357
  if (parent) {
335
- return parent.controller.setLabelHeight();
358
+ parent.controller.setLabelHeight();
359
+
360
+ return;
336
361
  }
337
362
 
338
- var tracks = [ this ].concat(this.prop('childTracks') || []);
339
- var height = tracks.reduce(function (h, track) { return h + (track.prop('disabled') ? 0 : track.prop('height')); }, 0);
363
+ const tracks = [ this ].concat(this.prop('childTracks') || []);
364
+ const height = tracks.reduce((h, track) => h + (track.prop('disabled') ? 0 : track.prop('height')), 0);
340
365
 
341
366
  this.label.height(this.prop('disabled') ? 0 : enforceMinHeight && this.minLabelHeight ? Math.max(height, this.minLabelHeight) : height);
342
367
 
343
368
  if (tracks.length > 1) {
344
- var top = tracks[0].prop('height');
369
+ let top = tracks[0].prop('height');
345
370
 
346
- tracks.slice(1).forEach(function (track) {
347
- var h = track.prop('height');
371
+ tracks.slice(1).forEach((track) => {
372
+ const h = track.prop('height');
348
373
 
349
374
  track.prop('labelName').css('top', top)[h ? 'removeClass' : 'addClass']('gv-hide');
350
375
  top += h;
@@ -353,24 +378,22 @@ Genoverse.Track.Controller = Base.extend({
353
378
  },
354
379
 
355
380
  setWidth: function (width) {
356
- var track = this.track;
381
+ const track = this.track;
357
382
 
358
- $.each([ this, track, track.model, track.view ], function () {
359
- this.width = width;
360
- });
383
+ [ this, track, track.model, track.view ].forEach((obj) => { obj.width = width; });
361
384
 
362
385
  this.imgContainer.add(this.expander).width(width);
363
386
  },
364
387
 
365
388
  setScale: function () {
366
- var controller = this;
389
+ const controller = this;
367
390
 
368
391
  this.scale = this.browser.scale;
369
392
 
370
393
  this.track.setMVC();
371
394
  this.resetImageRanges();
372
395
 
373
- var labels = this.prop('labels');
396
+ const labels = this.prop('labels');
374
397
 
375
398
  if (labels && labels !== 'overlay') {
376
399
  this.model.setLabelBuffer(this.browser.labelBuffer);
@@ -380,7 +403,9 @@ Genoverse.Track.Controller = Base.extend({
380
403
  this.thresholdMessage = this.view.formatLabel(this.threshold);
381
404
  }
382
405
 
383
- $.each(this.view.setScaleSettings(this.scale), function (k, v) { controller[k] = v; });
406
+ Object.entries(this.view.setScaleSettings(this.scale)).forEach(
407
+ ([ key, value ]) => { controller[key] = value; }
408
+ );
384
409
 
385
410
  this.hideMessage();
386
411
  },
@@ -389,10 +414,10 @@ Genoverse.Track.Controller = Base.extend({
389
414
  this.left += delta;
390
415
  this.scrollContainer.css('left', this.left);
391
416
 
392
- var scrollStart = this.scrollStart;
417
+ const scrollStart = this.scrollStart;
393
418
 
394
419
  if (this.imgRange[scrollStart] && this.imgRange[scrollStart].left + this.left > -this.scrollBuffer * this.width) {
395
- var end = this.scrollRange[scrollStart].start - 1;
420
+ const end = this.scrollRange[scrollStart].start - 1;
396
421
 
397
422
  this.makeImage({
398
423
  scale : this.scale,
@@ -400,7 +425,7 @@ Genoverse.Track.Controller = Base.extend({
400
425
  start : end - this.browser.length + 1,
401
426
  end : end,
402
427
  left : this.imgRange[scrollStart].left,
403
- cls : scrollStart
428
+ cls : scrollStart,
404
429
  });
405
430
 
406
431
  (this.imgRange[scrollStart] || {}).left -= this.width;
@@ -408,7 +433,7 @@ Genoverse.Track.Controller = Base.extend({
408
433
  }
409
434
 
410
435
  if (this.imgRange[scrollStart] && this.imgRange[scrollStart].right + this.left < this.scrollBuffer * this.width) {
411
- var start = this.scrollRange[scrollStart].end + 1;
436
+ const start = this.scrollRange[scrollStart].end + 1;
412
437
 
413
438
  this.makeImage({
414
439
  scale : this.scale,
@@ -416,7 +441,7 @@ Genoverse.Track.Controller = Base.extend({
416
441
  start : start,
417
442
  end : start + this.browser.length - 1,
418
443
  left : this.imgRange[scrollStart].right,
419
- cls : scrollStart
444
+ cls : scrollStart,
420
445
  });
421
446
 
422
447
  (this.imgRange[scrollStart] || {}).right += this.width;
@@ -425,8 +450,8 @@ Genoverse.Track.Controller = Base.extend({
425
450
  },
426
451
 
427
452
  moveTo: function (chr, start, end, delta) {
428
- var scrollRange = this.scrollRange[this.scrollStart];
429
- var scrollStart = [ 'ss', chr, start, end ].join('-');
453
+ const scrollRange = this.scrollRange[this.scrollStart];
454
+ const scrollStart = [ 'ss', chr, start, end ].join('-');
430
455
 
431
456
  if (this.scrollRange[scrollStart] || start > scrollRange.end || end < scrollRange.start) {
432
457
  this.resetImageRanges();
@@ -444,23 +469,25 @@ Genoverse.Track.Controller = Base.extend({
444
469
  params.featureHeight = params.featureHeight || 0;
445
470
  params.labelHeight = params.labelHeight || 0;
446
471
 
447
- var deferred;
448
- var controller = this;
449
- var tooLarge = this.browser.length > this.threshold;
450
- var div = this.imgContainer.clone().addClass((params.cls + ' gv-loading').replace('.', '_')).css({ left: params.left, display: params.cls === this.scrollStart ? 'block' : 'none' });
451
- var bgImage = params.background ? $('<img class="gv-bg">').hide().addClass(params.background).data(params).prependTo(div) : false;
452
- var image = $('<img class="gv-data">').hide().data(params).appendTo(div).on('load', function () {
453
- $(this).fadeIn('fast').parent().removeClass('gv-loading');
454
- $(this).siblings('.gv-bg').show();
472
+ const controller = this;
473
+ const jQuery = this.browser.jQuery;
474
+ const tooLarge = this.browser.length > this.threshold;
475
+ const div = this.imgContainer.clone().addClass((`${params.cls} gv-loading`).replace('.', '_')).css({ left: params.left, display: params.cls === this.scrollStart ? 'block' : 'none' });
476
+ const bgImage = params.background ? jQuery('<img class="gv-bg">').hide().addClass(params.background).data(params).prependTo(div) : false;
477
+ const image = this.browser.jQuery('<img class="gv-data">').hide().data(params).appendTo(div).on('load', function () {
478
+ jQuery(this).fadeIn('fast').parent().removeClass('gv-loading');
479
+ jQuery(this).siblings('.gv-bg').show();
455
480
  });
456
481
 
482
+ let deferred;
483
+
457
484
  params.container = div;
458
485
 
459
486
  this.imgContainers.push(div[0]);
460
487
  this.scrollContainer.append(this.imgContainers);
461
488
 
462
489
  if (!tooLarge && !this.model.checkDataRange(params.chr, params.start, params.end)) {
463
- var buffer = this.prop('dataBuffer');
490
+ const buffer = this.prop('dataBuffer');
464
491
 
465
492
  params.start -= buffer.start;
466
493
  params.end += buffer.end;
@@ -468,44 +495,49 @@ Genoverse.Track.Controller = Base.extend({
468
495
  }
469
496
 
470
497
  if (!deferred) {
471
- deferred = $.Deferred();
472
- setTimeout($.proxy(deferred.resolve, this), 1); // This defer makes scrolling A LOT smoother, pushing render call to the end of the exec queue
498
+ deferred = jQuery.Deferred();
499
+ setTimeout(deferred.resolve, 1); // This defer makes scrolling A LOT smoother, pushing render call to the end of the exec queue
473
500
  }
474
501
 
475
502
  this.deferreds.push(deferred);
476
503
 
477
- return deferred.done(function () {
478
- var features = tooLarge ? [] : controller.model.findFeatures(params.chr, params.start, params.end);
479
- controller.render(features, image);
504
+ return deferred.done(
505
+ () => {
506
+ const features = tooLarge ? [] : controller.model.findFeatures(params.chr, params.start, params.end);
507
+
508
+ controller.render(features, image);
480
509
 
481
- if (bgImage) {
482
- controller.renderBackground(features, bgImage);
510
+ if (bgImage) {
511
+ controller.renderBackground(features, bgImage);
512
+ }
483
513
  }
484
- }).fail(function (e) {
485
- controller.showError(e);
486
- });
514
+ ).fail(
515
+ (e) => { controller.showError(e); }
516
+ );
487
517
  },
488
518
 
489
519
  makeFirstImage: function (moveTo) {
490
- var deferred = $.Deferred();
520
+ const jQuery = this.browser.jQuery;
521
+ const deferred = jQuery.Deferred();
491
522
 
492
- if (this.scrollContainer.children().hide().filter('.' + (moveTo || this.scrollStart)).show().length) {
523
+ if (this.scrollContainer.children().hide().filter(`.${moveTo || this.scrollStart}`).show().length) {
493
524
  this.scrollContainer.css('left', 0);
494
525
  this.checkHeight();
495
526
 
496
527
  return deferred.resolve();
497
528
  }
498
529
 
499
- var controller = this;
500
- var chr = this.browser.chr;
501
- var start = this.browser.start;
502
- var end = this.browser.end;
503
- var length = this.browser.length;
504
- var scale = this.scale;
505
- var cls = this.scrollStart;
506
- var images = [{ chr: chr, start: start, end: end, scale: scale, cls: cls, left: 0 }];
507
- var left = 0;
508
- var width = this.width;
530
+ const controller = this;
531
+ const chr = this.browser.chr;
532
+ const start = this.browser.start;
533
+ const end = this.browser.end;
534
+ const length = this.browser.length;
535
+ const scale = this.scale;
536
+ const cls = this.scrollStart;
537
+ const images = [{ chr: chr, start: start, end: end, scale: scale, cls: cls, left: 0 }];
538
+
539
+ let left = 0;
540
+ let width = this.width;
509
541
 
510
542
  if (!this.browser.isStatic) {
511
543
  if (start > 1) {
@@ -520,12 +552,10 @@ Genoverse.Track.Controller = Base.extend({
520
552
  }
521
553
  }
522
554
 
523
- var loading = this.imgContainer.clone().addClass('gv-loading').css({ left: left, width: width }).prependTo(this.scrollContainer.css('left', 0));
555
+ const loading = this.imgContainer.clone().addClass('gv-loading').css({ left: left, width: width }).prependTo(this.scrollContainer.css('left', 0));
524
556
 
525
557
  function makeImages() {
526
- $.when.apply($, images.map(function (image) {
527
- return controller.makeImage(image);
528
- })).done(deferred.resolve);
558
+ jQuery.when(...images.map(image => controller.makeImage(image))).done(deferred.resolve);
529
559
 
530
560
  loading.remove();
531
561
  }
@@ -533,9 +563,9 @@ Genoverse.Track.Controller = Base.extend({
533
563
  if (length > this.threshold || this.model.checkDataRange(chr, start, end)) {
534
564
  makeImages();
535
565
  } else {
536
- var buffer = this.prop('dataBuffer');
566
+ const buffer = this.prop('dataBuffer');
537
567
 
538
- this.model.getData(chr, start - buffer.start - length, end + buffer.end + length).done(makeImages).fail(function (e) {
568
+ this.model.getData(chr, start - buffer.start - length, end + buffer.end + length).done(makeImages).fail((e) => {
539
569
  controller.showError(e);
540
570
  });
541
571
  }
@@ -544,22 +574,31 @@ Genoverse.Track.Controller = Base.extend({
544
574
  },
545
575
 
546
576
  render: function (features, img) {
547
- var params = img.data();
577
+ const params = img.data();
548
578
 
549
579
  // positionFeatures alters params.featureHeight, so this must happen before the canvases are created
550
580
  features = this.view.positionFeatures(this.view.scaleFeatures(features, params.scale), params);
551
581
 
552
- var featureCanvas = $('<canvas>').attr({ width: params.width, height: params.featureHeight || 1 });
553
- var labelCanvas = this.prop('labels') === 'separate' && params.labelHeight ? featureCanvas.clone().attr('height', params.labelHeight) : featureCanvas;
554
- var featureContext = featureCanvas[0].getContext('2d');
555
- var labelContext = labelCanvas[0].getContext('2d');
582
+ const featureCanvas = this.browser.jQuery('<canvas>').attr({ width: params.width, height: params.featureHeight || 1 });
583
+ const labelCanvas = this.prop('labels') === 'separate' && params.labelHeight ? featureCanvas.clone().attr('height', params.labelHeight) : featureCanvas;
584
+
585
+ const featureContext = featureCanvas[0].getContext('2d');
586
+ const labelContext = labelCanvas[0].getContext('2d');
556
587
 
557
588
  featureContext.font = labelContext.font = this.prop('font');
558
589
 
559
590
  switch (this.prop('labels')) {
560
- case false : break;
561
- case 'overlay' : labelContext.textAlign = 'center'; labelContext.textBaseline = 'middle'; break;
562
- default : labelContext.textAlign = 'left'; labelContext.textBaseline = 'top'; break;
591
+ case false: break;
592
+ case 'overlay':
593
+ labelContext.textAlign = 'center';
594
+ labelContext.textBaseline = 'middle';
595
+
596
+ break;
597
+ default:
598
+ labelContext.textAlign = 'left';
599
+ labelContext.textBaseline = 'top';
600
+
601
+ break;
563
602
  }
564
603
 
565
604
  this.view.draw(features, featureContext, labelContext, params.scale);
@@ -571,44 +610,46 @@ Genoverse.Track.Controller = Base.extend({
571
610
  }
572
611
 
573
612
  this.checkHeight();
574
-
575
- featureCanvas = labelCanvas = img = null;
576
613
  },
577
614
 
578
615
  renderBackground: function (features, img, height) {
579
- var canvas = $('<canvas>').attr({ width: this.width, height: height || 1 })[0];
616
+ const canvas = this.browser.jQuery('<canvas>').attr({ width: this.width, height: height || 1 })[0];
617
+
580
618
  this.view.drawBackground(features, canvas.getContext('2d'), img.data());
581
619
  img.attr('src', canvas.toDataURL());
582
- canvas = img = null;
583
620
  },
584
621
 
585
622
  populateMenu: function (feature) {
586
- var f = $.extend(true, {}, feature);
587
- var menu = {
588
- title : f.label ? f.label[0] : f.id,
589
- Location : f.chr + ':' + f.start + '-' + f.end
623
+ const title = feature.label ? feature.label[0] : feature.id;
624
+
625
+ return {
626
+ title : title,
627
+ Location : `${feature.chr}:${feature.start}-${feature.end}`,
628
+ ...Object.entries(feature).reduce(
629
+ (acc, [ key, value ]) => {
630
+ if (typeof value === 'object' || value === title || [ 'chr', 'start', 'end', 'sort' ].includes(key)) {
631
+ return acc;
632
+ }
633
+
634
+ return Object.assign(acc, { [key]: value });
635
+ },
636
+ {}
637
+ ),
590
638
  };
639
+ },
591
640
 
592
- delete f.chr;
593
- delete f.start;
594
- delete f.end;
595
- delete f.sort;
596
-
597
- for (var i in f) {
598
- if (typeof f[i] === 'object' || menu.title === f[i]) {
599
- delete f[i];
600
- }
601
- }
602
-
603
- return $.extend(menu, f);
641
+ insertPropertiesIntoMenu: function (menuProperties, menuEl, contentEl, feature) {
642
+ return this.browser.insertPropertiesIntoMenu(menuProperties, menuEl, contentEl, feature, this.track);
604
643
  },
605
644
 
606
645
  abort: function () {
607
- for (var i = 0; i < this.deferreds.length; i++) {
608
- if (this.deferreds[i].state() === 'pending') {
609
- this.deferreds[i].reject();
646
+ this.deferreds.forEach(
647
+ (deferred) => {
648
+ if (deferred.state() === 'pending') {
649
+ deferred.reject();
650
+ }
610
651
  }
611
- }
652
+ );
612
653
 
613
654
  this.deferreds = [];
614
655
  },
@@ -616,5 +657,5 @@ Genoverse.Track.Controller = Base.extend({
616
657
  destroy: function () {
617
658
  this.abort();
618
659
  this.container.add(this.label).add(this.menus).remove();
619
- }
660
+ },
620
661
  });