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,388 @@
1
+ import '../../css/controlPanel.css';
2
+ import karyotype from './karyotype';
3
+
4
+ const plugin = function (pluginConf) {
5
+ const jQuery = this.jQuery;
6
+
7
+ this.controls = [
8
+ // Scroll left/right
9
+ {
10
+ name : 'Scroll left and right by pressing and holding these buttons',
11
+ buttons : [{
12
+ name : 'Scroll left',
13
+ icon : '<i class="fas fa-chevron-left"></i>',
14
+ class : 'gv-scroll-left',
15
+ }, {
16
+ name : 'Scroll right',
17
+ icon : '<i class="fas fa-chevron-right"></i>',
18
+ class : 'gv-scroll-right',
19
+ }],
20
+ init: function (browser) {
21
+ const el = jQuery(this);
22
+
23
+ el.find('.gv-scroll-left, .gv-scroll-right').on({
24
+ mousedown : () => { browser.startDragScroll(); },
25
+ mouseup : () => { browser.stopDragScroll(); },
26
+ });
27
+
28
+ el.find('.gv-scroll-left').mousehold(50, () => { browser.move(browser.scrollDelta); });
29
+ el.find('.gv-scroll-right').mousehold(50, () => { browser.move(-browser.scrollDelta); });
30
+ },
31
+ },
32
+
33
+ // Zoom in/out
34
+ {
35
+ name : 'Zoom-in and zoom-out',
36
+ buttons : [{
37
+ name : 'Zoom in',
38
+ icon : '<i class="fas fa-search-plus"></i>',
39
+ class : 'gv-zoom-in',
40
+ action : (browser) => { browser.zoomIn(); },
41
+ }, {
42
+ name : 'Zoom out',
43
+ icon : '<i class="fas fa-search-minus"></i>',
44
+ class : 'gv-zoom-out',
45
+ action : (browser) => { browser.zoomOut(); },
46
+ }],
47
+ },
48
+
49
+ // Toogle drag action
50
+ {
51
+ name : 'Toggle your mouse drag action between scroll left/right and select region',
52
+ buttons : [{
53
+ name : 'Mouse drag action to scroll the browser left or right',
54
+ icon : '<i class="fas fa-arrows-alt-h"></i>',
55
+ class : 'gv-drag-scroll',
56
+ action : function (browser) {
57
+ browser.setDragAction('scroll');
58
+ jQuery(this).addClass('gv-active').siblings().removeClass('gv-active');
59
+ },
60
+ }, {
61
+ name : 'Mouse drag action to select a region',
62
+ icon : '<i></i>',
63
+ class : 'gv-drag-select',
64
+ action : function (browser) {
65
+ browser.setDragAction('select');
66
+ jQuery(this).addClass('gv-active').siblings().removeClass('gv-active');
67
+ },
68
+ }],
69
+ init: function (browser) {
70
+ jQuery(this).find(`.gv-drag-${browser.dragAction}`).addClass('gv-active').siblings().removeClass('gv-active');
71
+ },
72
+ },
73
+
74
+ // Toogle wheel action
75
+ {
76
+ name : 'Toggle your mouse wheel action between zoom in/out and default page scroll',
77
+ buttons : [{
78
+ name : 'Mouse wheel action to scroll the page up and down',
79
+ icon : '<i class="fas fa-arrows-alt-v"></i>',
80
+ class : 'gv-wheel-off',
81
+ action : function (browser) {
82
+ browser.setWheelAction('off');
83
+ jQuery(this).addClass('gv-active').siblings().removeClass('gv-active');
84
+ },
85
+ }, {
86
+ name : 'Mouse wheel to zoom in and out',
87
+ icon : '&#177;',
88
+ class : 'gv-wheel-zoom',
89
+ action : function (browser) {
90
+ browser.setWheelAction('zoom');
91
+ jQuery(this).addClass('gv-active').siblings().removeClass('gv-active');
92
+ },
93
+ }],
94
+ init: function (browser) {
95
+ jQuery(this).find(`.gv-wheel-${browser.wheelAction}`).addClass('gv-active').siblings().removeClass('gv-active');
96
+ },
97
+ },
98
+ ];
99
+
100
+ if (this.saveable) {
101
+ this.controls.push({
102
+ icon : '<i class="fas fa-undo"></i>',
103
+ name : 'Reset tracks and configuration',
104
+ action : (browser) => { browser.resetConfig(); },
105
+ });
106
+ }
107
+
108
+ this.on({
109
+ beforeInit: function () {
110
+ const browser = this;
111
+
112
+ this.tracksLibrary = (this.tracksLibrary || this.tracks).map(
113
+ track => this.normaliseTrackDefinition(track)
114
+ ).filter(
115
+ track => track.prototype.name
116
+ );
117
+
118
+ const panel = jQuery(`
119
+ <table cellspacing=0 cellpadding=0 class="gv">
120
+ <tr>
121
+ <td class="gv-panel gv-panel-left"></td>
122
+ <td class="gv-canvas-container"></td>
123
+ <td class="gv-panel gv-panel-right"></td>
124
+ </tr>
125
+ </table>
126
+ `).appendTo(this.container).find('.gv-panel-right');
127
+
128
+ this.controlPanel = panel;
129
+ this.superContainer = this.container;
130
+ this.container = jQuery('.gv-canvas-container', this.container);
131
+
132
+ browser.controls.forEach(
133
+ (control) => {
134
+ const buttonSet = jQuery('<div class="gv-button-set">').attr('title', control.name).appendTo(browser.superContainer.find('.gv-panel-right'));
135
+ const buttons = control.buttons || [ control ];
136
+
137
+ buttons.forEach(
138
+ (button) => {
139
+ const el = jQuery(`<button>${button.icon}</button>`).addClass(button.class).attr('title', button.name).appendTo(buttonSet);
140
+
141
+ if (button.action) {
142
+ el.on('click', () => {
143
+ button.action.call(el[0], browser);
144
+ });
145
+ }
146
+
147
+ if (button.init && button !== control) {
148
+ button.init.call(el[0], browser);
149
+ }
150
+ }
151
+ );
152
+
153
+ if (control.init) {
154
+ control.init.call(buttonSet, browser);
155
+ }
156
+ }
157
+ );
158
+
159
+ this.superContainer.width(this.width);
160
+
161
+ // ESC key to toggle crosshair select to drag mode and close menus
162
+ jQuery(document).on('keydown', (e) => {
163
+ if (e.keyCode === 27) {
164
+ if (panel.find('button.gv-drag-select').hasClass('gv-active')) {
165
+ panel.find('button.gv-drag-scroll').trigger('click');
166
+ }
167
+
168
+ jQuery('.gv-menu .gv-close').trigger('click');
169
+ }
170
+ });
171
+ },
172
+
173
+ afterInit: function () {
174
+ const browser = this;
175
+ const tracksButton = jQuery('<button class="gv-tracks-library-button" title="Tracks menu"><i class="fas fa-bars"></i> Tracks</button>').on('click', function () {
176
+ const button = this;
177
+
178
+ const getTrackTags = (track, tags) => (
179
+ track.constructor?.ancestor?.prototype
180
+ ? getTrackTags(track.constructor.ancestor.prototype, tags.concat(track.constructor.ancestor.prototype.tags || []))
181
+ : tags
182
+ );
183
+
184
+ if (jQuery(this).hasClass('gv-active')) {
185
+ jQuery('.gv-menu.gv-tracks-menu .gv-close').trigger('click');
186
+ jQuery(this).removeClass('gv-active');
187
+ } else {
188
+ let menu = jQuery(this).data('menu');
189
+
190
+ if (menu) {
191
+ menu.show();
192
+ } else {
193
+ menu = browser.makeMenu({
194
+ 'Currently enabled tracks:' : 'Available tracks:',
195
+ '<div class="gv-current-tracks"></div>' : '<input placeholder="Search"><div class="gv-available-tracks"></div>',
196
+ }).addClass('gv-tracks-menu');
197
+
198
+ jQuery('input[placeholder=Search]', menu).on('keyup', function () {
199
+ const str = this.value.toLowerCase();
200
+
201
+ jQuery('.gv-tracks-library-item', menu).each(function () {
202
+ const track = jQuery(this).data('track');
203
+
204
+ let match = false;
205
+
206
+ if (track.name && track.name.toLowerCase().indexOf(str) >= 0) {
207
+ match = true;
208
+ } else {
209
+ const tags = getTrackTags(track, []).concat(track.tags || []);
210
+
211
+ if (tags.some(tag => tag.toLowerCase().indexOf(str) >= 0)) {
212
+ match = true;
213
+ }
214
+ }
215
+
216
+ jQuery(this)[match ? 'removeClass' : 'addClass']('gv-hide');
217
+ });
218
+
219
+ jQuery('.gv-tracks-library-category', menu).each(function () {
220
+ const visibleTracks = jQuery(this).children('.gv-tracks-library-item:not(.gv-hide)');
221
+
222
+ jQuery(this)[visibleTracks.length ? 'removeClass' : 'addClass']('gv-hide');
223
+ });
224
+ });
225
+
226
+ jQuery('.gv-close', menu).on('click', () => {
227
+ jQuery(button).removeClass('gv-active');
228
+ });
229
+
230
+ const availableTracks = jQuery('.gv-available-tracks', menu);
231
+ const currentTracks = jQuery('.gv-current-tracks', menu).before('<div class="gv-current-tracks-instructions">Drag and drop to reorder</div>').data({
232
+ reload : function () { jQuery(this).empty().data('listTracks')(); },
233
+ listTracks : function () {
234
+ browser.tracks.filter(
235
+ track => track.name && !(track.removable === false && track.unsortable) && !track.parentTrack && !track.lockToTrack
236
+ ).forEach(
237
+ (track) => {
238
+ const el = jQuery('<div class="gv-tracks-menu-track">')
239
+ .append(`<span class="gv-tracks-menu-track-name" title="${track.name}">${track.defaultName}</span>`)
240
+ .appendTo(currentTracks)
241
+ .data('track', track)
242
+ .addClass(track.unsortable ? 'gv-unsortable' : '');
243
+
244
+ if (track.removable === false) {
245
+ el.prepend('<i class="gv-remove-track gv-menu-button fas fa-circle">');
246
+ } else {
247
+ el.prepend(jQuery('<i class="gv-remove-track gv-menu-button fas fa-times-circle">').on('click', () => { track.remove(); }));
248
+ }
249
+
250
+ const trackNameEl = el.find('.gv-tracks-menu-track-name').tipsy({ gravity: 'w', trigger: 'manual' }).on('mouseenter', function () {
251
+ const tip = jQuery(this).tipsy('show').data('tipsy').$tip;
252
+
253
+ if (tip) {
254
+ tip.css('zIndex', 1002);
255
+ }
256
+ }).on('mouseleave', function () {
257
+ jQuery(this).tipsy('hide');
258
+ });
259
+
260
+ if (track.name === track.defaultName) {
261
+ trackNameEl.tipsy('disable');
262
+ }
263
+ }
264
+ );
265
+ },
266
+ }).sortable({
267
+ items : 'div:not(.gv-unsortable)',
268
+ cursor : 'move',
269
+ axis : 'y',
270
+ handle : 'span',
271
+ update : browser.updateTrackOrder.bind(browser),
272
+ start : function () {
273
+ currentTracks.find('.gv-tracks-menu-track-name').each(function () { jQuery(this).tipsy('hide').tipsy('disable'); });
274
+ },
275
+ stop: function () {
276
+ currentTracks.find('.gv-tracks-menu-track-name').each(function () { jQuery(this).tipsy('enable'); });
277
+ },
278
+ });
279
+
280
+ currentTracks.data('listTracks')();
281
+
282
+ if (browser.saveable) {
283
+ jQuery('<div class="gv-tracks-menu-reset gv-menu-button"><i class="fas fa-undo"></i> Reset tracks and configuration</div>').insertAfter(currentTracks).on('click', (e) => {
284
+ e.preventDefault();
285
+ browser.resetConfig();
286
+ });
287
+ }
288
+
289
+ if (browser.tracksLibrary?.length) {
290
+ const tracksLibraryCategories = browser.tracksLibrary.filter(track => track.prototype.name && track.prototype.removable !== false).reduce(
291
+ (acc, track) => {
292
+ const categoryName = track.prototype.category || '';
293
+
294
+ acc[categoryName] = acc[categoryName] || [];
295
+ acc[categoryName].push([ track.prototype.name.toLowerCase(), track ]);
296
+
297
+ return acc;
298
+ },
299
+ {}
300
+ );
301
+
302
+ const tracksLibraryCategoryOrder = (pluginConf?.tracksLibraryCategoryOrder || []).reduce(
303
+ (acc, categoryName, i) => Object.assign(acc, { [categoryName]: i + 1 }),
304
+ {}
305
+ );
306
+
307
+ Object.keys(tracksLibraryCategories).sort((a, b) => (Boolean(b) - Boolean(a)) || (tracksLibraryCategoryOrder[a] - tracksLibraryCategoryOrder[b]) || a.localeCompare(b)).forEach(
308
+ (categoryName, i, allCategoryNames) => {
309
+ const parentEl = (
310
+ allCategoryNames.length > 1
311
+ ? jQuery('<div class="gv-tracks-library-category">').append(
312
+ jQuery('<div class="gv-tracks-library-category-header">').html(categoryName || 'Other')
313
+ ).appendTo(availableTracks)
314
+ : availableTracks
315
+ );
316
+
317
+ tracksLibraryCategories[categoryName].sort((a, b) => a[0].localeCompare(b[0])).forEach(
318
+ (row) => {
319
+ const track = row[1];
320
+
321
+ jQuery('<div class="gv-tracks-library-item">').append(
322
+ jQuery('<i class="gv-add-track gv-menu-button fas fa-plus-circle">').on('click', () => {
323
+ browser.trackIds = browser.trackIds || {};
324
+ browser.trackIds[track.prototype.id] = browser.trackIds[track.prototype.id] || 1;
325
+
326
+ browser.addTrack(track.extend({ id: `${track.prototype.id}${browser.tracksById[track.prototype.id] ? browser.trackIds[track.prototype.id]++ : ''}` }));
327
+ })
328
+ ).append(`<span>${track.prototype.name}</span>`).appendTo(parentEl).data('track', track.prototype);
329
+ }
330
+ );
331
+ }
332
+ );
333
+ }
334
+
335
+ menu.css({ left: '50%', marginLeft: menu.width() / -2 });
336
+
337
+ jQuery(this).data('menu', menu);
338
+ }
339
+
340
+ jQuery(this).addClass('gv-active');
341
+ }
342
+ });
343
+
344
+ this.labelContainer.prepend(
345
+ jQuery('<li class="gv-unsortable">').append(
346
+ jQuery('<div class="gv-button-set" title="Tracks menu">').append(tracksButton)
347
+ )
348
+ );
349
+ },
350
+
351
+ afterAddDomElements: function () {
352
+ this.wrapper.after('<div class="gv-powered-by">Powered by <a target="_blank" href="https://wtsi-web.github.io/Genoverse/">Genoverse</a></div>');
353
+ this.superContainer.find('.gv-panel-left').append(this.labelContainer);
354
+ },
355
+
356
+ 'afterAddTracks afterRemoveTracks': function () {
357
+ const currentTracks = this.superContainer.find('.gv-tracks-menu .gv-current-tracks');
358
+
359
+ if (currentTracks.length) {
360
+ currentTracks.data('reload').call(currentTracks);
361
+ }
362
+ },
363
+ });
364
+
365
+ this.on({
366
+ afterSetName: function (name) {
367
+ const track = this.track;
368
+
369
+ if (track?.browser) {
370
+ const menu = track.browser.superContainer.find('.gv-tracks-library-button').data('menu');
371
+
372
+ if (menu) {
373
+ menu.find('.gv-tracks-menu-track').filter(function () {
374
+ return jQuery(this).data('track') === track;
375
+ }).children('.gv-tracks-menu-track-name').attr('title', name).each(function () {
376
+ if (name === track.defaultName) {
377
+ jQuery(this).tipsy('hide').tipsy('disable');
378
+ } else {
379
+ jQuery(this).tipsy('enable');
380
+ }
381
+ });
382
+ }
383
+ }
384
+ },
385
+ }, 'tracks');
386
+ };
387
+
388
+ export default { controlPanel: plugin, requires: karyotype };
@@ -0,0 +1,81 @@
1
+ import '../../css/fileDrop.css';
2
+
3
+ const plugin = function () {
4
+ const jQuery = this.jQuery;
5
+
6
+ this.on('afterInit', function () {
7
+ const browser = this;
8
+ const wrapper = this.wrapper;
9
+
10
+ jQuery(window).on('dragenter', (e) => {
11
+ const dataTransfer = e.originalEvent.dataTransfer;
12
+
13
+ if (dataTransfer?.types && (
14
+ dataTransfer.types[0] === 'Files' || dataTransfer.types[1] === 'Files' || dataTransfer.types[2] === 'Files'
15
+ ) && !jQuery('.gv-file-drop-total-overlay').length) {
16
+ const fileDropDiv = jQuery('<div class="gv-file-drop">').appendTo(wrapper);
17
+ const totalDropOverlay = jQuery('<div class="gv-file-drop-total-overlay">').prependTo('body');
18
+
19
+ const dragleave = () => {
20
+ fileDropDiv.remove();
21
+ totalDropOverlay.remove();
22
+ };
23
+
24
+ totalDropOverlay.on('dragenter', (ev) => { ev.preventDefault(); ev.stopPropagation(); });
25
+ totalDropOverlay.on('dragover', (ev) => { ev.preventDefault(); ev.stopPropagation(); });
26
+ totalDropOverlay.on('dragleave', dragleave);
27
+ totalDropOverlay.on('drop', (ev) => {
28
+ dragleave();
29
+ ev.preventDefault();
30
+ ev.stopPropagation();
31
+
32
+ // Sort in order to ensure that .bam files are before their .bam.bai files
33
+ const files = Object.values(ev.originalEvent.dataTransfer.files).sort((a, b) => a.name.localeCompare(b.name));
34
+ const trackImporters = [];
35
+
36
+ for (let i = 0; i < files.length; i++) {
37
+ const file = files[i];
38
+ const parts = file.name.split('.').reverse();
39
+ const gz = parts[0] === 'gz';
40
+ const ext = parts[gz ? 1 : 0];
41
+
42
+ let indexFile;
43
+
44
+ if (files[i + 1] && new RegExp(`^${file.name}\\.\\w+$`).test(files[i + 1].name)) {
45
+ indexFile = files[++i];
46
+ }
47
+
48
+ trackImporters.push({
49
+ file : file,
50
+ indexFile : indexFile,
51
+ gz : gz,
52
+ trackType : ext.toUpperCase(),
53
+ });
54
+ }
55
+
56
+ trackImporters.forEach(
57
+ (importer) => {
58
+ import(`../Track/library/File/${importer.trackType}`).then(
59
+ (imported) => {
60
+ const track = imported.default.extend({
61
+ name : importer.file.name,
62
+ info : `Local file "${importer.file.name}", size: ${importer.file.size} bytes`,
63
+ isLocal : true,
64
+ dataFile : importer.file,
65
+ indexFile : importer.indexFile,
66
+ gz : importer.gz,
67
+ });
68
+
69
+ browser.addTrack(track, browser.tracks.length - 1);
70
+ },
71
+ () => {}
72
+ );
73
+ }
74
+ );
75
+ });
76
+ }
77
+ });
78
+ });
79
+ };
80
+
81
+ export default { fileDrop: plugin };
@@ -0,0 +1,13 @@
1
+ import './controlPanel';
2
+
3
+ const plugin = function () {
4
+ this.controls.push({
5
+ icon : '<i class="fas fa-map-marker-alt"></i>',
6
+ 'class' : 'gv-button-large',
7
+ name : `Reset focus to ${this.focusRegion && this.focusRegion.name ? this.focusRegion.name : `${this.chr}:${this.start}-${this.end}`}`,
8
+ action : (browser) => { browser.moveTo(browser.focusRegion.chr, browser.focusRegion.start, browser.focusRegion.end, true); },
9
+ init : (browser) => { browser.focusRegion = browser.focusRegion || { chr: browser.chr, start: browser.start, end: browser.end }; },
10
+ });
11
+ };
12
+
13
+ export default { focusRegion: plugin };
@@ -1,10 +1,14 @@
1
- Genoverse.Plugins.fullscreen = function () {
2
- var genoverse = this;
3
- var supported = true;
4
- var eventName = 'fullscreenchange'; // All the browsers have different names
5
- var elemName = 'fullscreenElement'; // ... even the capitalisation varies!
6
- var requestName = 'requestFullscreen';
7
- var cancelName = 'exitFullscreen';
1
+ import '../../css/fullscreen.css';
2
+ import controlPanel from './controlPanel';
3
+
4
+ const plugin = function () {
5
+ const genoverse = this;
6
+
7
+ let supported = true;
8
+ let eventName = 'fullscreenchange'; // All the browsers have different names
9
+ let elemName = 'fullscreenElement'; // ... even the capitalisation varies!
10
+ let requestName = 'requestFullscreen';
11
+ let cancelName = 'exitFullscreen';
8
12
 
9
13
  if (document.onmsfullscreenchange || document.onmsfullscreenchange === null) {
10
14
  // We need the IE11 version of this to work; IE9-10 have the actions but not the events.
@@ -33,14 +37,14 @@ Genoverse.Plugins.fullscreen = function () {
33
37
  cancelName : cancelName,
34
38
  requestName : requestName,
35
39
 
36
- enterEvent: function (browser) {
40
+ enterEvent: (browser) => {
37
41
  browser.preFullscreenWidth = browser.superContainer.width();
38
42
  browser.superContainer.addClass('gv-fullscreen');
39
43
  browser.setWidth(window.innerWidth);
40
44
  browser.controlPanel.find('.gv-fullscreen-button .fas').removeClass('fa-expand-arrows-alt').addClass('fa-compress-arrows-alt');
41
45
  },
42
46
 
43
- exitEvent: function (browser) {
47
+ exitEvent: (browser) => {
44
48
  if (browser.superContainer.hasClass('gv-fullscreen')) {
45
49
  browser.superContainer.removeClass('gv-fullscreen');
46
50
  browser.setWidth(browser.preFullscreenWidth);
@@ -48,12 +52,12 @@ Genoverse.Plugins.fullscreen = function () {
48
52
  }
49
53
  },
50
54
 
51
- eventListener: function () {
55
+ eventListener: () => {
52
56
  if (!genoverse.superContainer.is(document[genoverse.fullscreenVars.elemName])) {
53
57
  genoverse.fullscreenVars.exitEvent(genoverse);
54
58
  document.removeEventListener(genoverse.fullscreenVars.eventName, genoverse.fullscreenVars.eventListener);
55
59
  }
56
- }
60
+ },
57
61
  };
58
62
 
59
63
  if (supported) {
@@ -61,7 +65,7 @@ Genoverse.Plugins.fullscreen = function () {
61
65
  icon : '<i class="fas fa-expand-arrows-alt"></i>',
62
66
  class : 'gv-fullscreen-button',
63
67
  name : 'Toggle fullscreen view',
64
- action : function (browser) {
68
+ action : (browser) => {
65
69
  if (browser.superContainer.hasClass('gv-fullscreen')) {
66
70
  document[browser.fullscreenVars.cancelName]();
67
71
  } else {
@@ -69,9 +73,9 @@ Genoverse.Plugins.fullscreen = function () {
69
73
  browser.superContainer[0][browser.fullscreenVars.requestName]();
70
74
  browser.fullscreenVars.enterEvent(browser);
71
75
  }
72
- }
76
+ },
73
77
  });
74
78
  }
75
79
  };
76
80
 
77
- Genoverse.Plugins.fullscreen.requires = 'controlPanel';
81
+ export default { fullscreen: plugin, requires: controlPanel };