genoverse 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/.eslintrc.js +197 -0
  2. package/.github/workflows/test.yml +24 -0
  3. package/LICENSE.TXT +24 -0
  4. package/README.md +11 -0
  5. package/css/controlPanel.css +200 -0
  6. package/css/fileDrop.css +22 -0
  7. package/css/font-awesome.css +3 -0
  8. package/css/fullscreen.css +19 -0
  9. package/css/genoverse.css +466 -0
  10. package/css/karyotype.css +85 -0
  11. package/css/resizer.css +36 -0
  12. package/css/tooltips.css +26 -0
  13. package/css/trackControls.css +111 -0
  14. package/expanded.html +120 -0
  15. package/fontawesome/css/fontawesome.min.css +5 -0
  16. package/fontawesome/css/regular.min.css +5 -0
  17. package/fontawesome/css/solid.min.css +5 -0
  18. package/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  19. package/fontawesome/webfonts/fa-brands-400.woff +0 -0
  20. package/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  21. package/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  22. package/fontawesome/webfonts/fa-regular-400.woff +0 -0
  23. package/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  24. package/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  25. package/fontawesome/webfonts/fa-solid-900.woff +0 -0
  26. package/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  27. package/help.pdf +0 -0
  28. package/i/sort_handle.png +0 -0
  29. package/index.html +68 -0
  30. package/index.js +83 -0
  31. package/jest.config.js +4 -0
  32. package/js/Genoverse.js +1681 -0
  33. package/js/Track/Controller/Sequence.js +17 -0
  34. package/js/Track/Controller/Stranded.js +73 -0
  35. package/js/Track/Controller.js +620 -0
  36. package/js/Track/Model/File/BAM.js +44 -0
  37. package/js/Track/Model/File/BED.js +116 -0
  38. package/js/Track/Model/File/GFF.js +40 -0
  39. package/js/Track/Model/File/VCF.js +101 -0
  40. package/js/Track/Model/File/WIG.js +67 -0
  41. package/js/Track/Model/File.js +36 -0
  42. package/js/Track/Model/Gene/Ensembl.js +22 -0
  43. package/js/Track/Model/Gene.js +5 -0
  44. package/js/Track/Model/Sequence/Ensembl.js +4 -0
  45. package/js/Track/Model/Sequence/Fasta.js +60 -0
  46. package/js/Track/Model/Sequence.js +50 -0
  47. package/js/Track/Model/SequenceVariation.js +41 -0
  48. package/js/Track/Model/Stranded.js +28 -0
  49. package/js/Track/Model/Transcript/Ensembl.js +67 -0
  50. package/js/Track/Model/Transcript.js +5 -0
  51. package/js/Track/Model.js +303 -0
  52. package/js/Track/View/Gene/Ensembl.js +46 -0
  53. package/js/Track/View/Gene.js +6 -0
  54. package/js/Track/View/Sequence/Variation.js +115 -0
  55. package/js/Track/View/Sequence.js +63 -0
  56. package/js/Track/View/Transcript/Ensembl.js +12 -0
  57. package/js/Track/View/Transcript.js +28 -0
  58. package/js/Track/View.js +566 -0
  59. package/js/Track/library/Chromosome.js +145 -0
  60. package/js/Track/library/File/BAM.js +30 -0
  61. package/js/Track/library/File/BED.js +24 -0
  62. package/js/Track/library/File/BIGBED.js +47 -0
  63. package/js/Track/library/File/BIGWIG.js +52 -0
  64. package/js/Track/library/File/GFF.js +9 -0
  65. package/js/Track/library/File/VCF.js +71 -0
  66. package/js/Track/library/File/WIG.js +5 -0
  67. package/js/Track/library/File.js +10 -0
  68. package/js/Track/library/Gene.js +37 -0
  69. package/js/Track/library/Graph/Bar.js +235 -0
  70. package/js/Track/library/Graph/Line.js +296 -0
  71. package/js/Track/library/Graph.js +355 -0
  72. package/js/Track/library/HighlightRegion.js +292 -0
  73. package/js/Track/library/Legend.js +224 -0
  74. package/js/Track/library/Scalebar.js +227 -0
  75. package/js/Track/library/Scaleline.js +91 -0
  76. package/js/Track/library/Static.js +78 -0
  77. package/js/Track/library/dbSNP.js +142 -0
  78. package/js/Track.js +632 -0
  79. package/js/genomes/grch37.js +990 -0
  80. package/js/genomes/grch38.js +990 -0
  81. package/js/genoverse.min.js +2 -0
  82. package/js/genoverse.min.js.map +1 -0
  83. package/js/lib/BWReader.js +578 -0
  84. package/js/lib/Base.js +145 -0
  85. package/js/lib/VCFReader.js +286 -0
  86. package/js/lib/dalliance/js/bam.js +494 -0
  87. package/js/lib/dalliance/js/bin.js +185 -0
  88. package/js/lib/dalliance/js/das.js +749 -0
  89. package/js/lib/dalliance/js/utils.js +370 -0
  90. package/js/lib/dalliance-lib.js +3594 -0
  91. package/js/lib/dalliance-lib.min.js +68 -0
  92. package/js/lib/jDataView.js +2 -0
  93. package/js/lib/jParser.js +192 -0
  94. package/js/lib/jquery-ui.js +8 -0
  95. package/js/lib/jquery.js +2 -0
  96. package/js/lib/jquery.mousehold.js +53 -0
  97. package/js/lib/jquery.mousewheel.js +84 -0
  98. package/js/lib/jquery.tipsy.js +258 -0
  99. package/js/lib/rtree.js +1 -0
  100. package/js/plugins/controlPanel.js +395 -0
  101. package/js/plugins/fileDrop.js +62 -0
  102. package/js/plugins/focusRegion.js +12 -0
  103. package/js/plugins/fullscreen.js +77 -0
  104. package/js/plugins/karyotype.js +210 -0
  105. package/js/plugins/resizer.js +45 -0
  106. package/js/plugins/tooltips.js +94 -0
  107. package/js/plugins/trackControls.js +143 -0
  108. package/package.json +43 -0
  109. package/test/View/__snapshots__/render-bar-graph.test.js.snap +111 -0
  110. package/test/View/__snapshots__/render-blocks.test.js.snap +105 -0
  111. package/test/View/__snapshots__/render-chromosome.test.js.snap +5 -0
  112. package/test/View/__snapshots__/render-highlights.test.js.snap +73 -0
  113. package/test/View/__snapshots__/render-insert-variants.test.js.snap +9 -0
  114. package/test/View/__snapshots__/render-labels.test.js.snap +241 -0
  115. package/test/View/__snapshots__/render-legends.test.js.snap +13 -0
  116. package/test/View/__snapshots__/render-line-graph.test.js.snap +349 -0
  117. package/test/View/__snapshots__/render-scalebar.test.js.snap +49 -0
  118. package/test/View/__snapshots__/render-scaleline.test.js.snap +31 -0
  119. package/test/View/__snapshots__/render-sequence.test.js.snap +23 -0
  120. package/test/View/__snapshots__/render-stranded.test.js.snap +5 -0
  121. package/test/View/__snapshots__/render-transcripts.test.js.snap +193 -0
  122. package/test/View/render-bar-graph.test.js +87 -0
  123. package/test/View/render-blocks.test.js +171 -0
  124. package/test/View/render-chromosome.test.js +40 -0
  125. package/test/View/render-highlights.test.js +67 -0
  126. package/test/View/render-insert-variants.test.js +11 -0
  127. package/test/View/render-labels.test.js +266 -0
  128. package/test/View/render-legends.test.js +31 -0
  129. package/test/View/render-line-graph.test.js +169 -0
  130. package/test/View/render-scalebar.test.js +36 -0
  131. package/test/View/render-scaleline.test.js +28 -0
  132. package/test/View/render-sequence.test.js +49 -0
  133. package/test/View/render-stranded.test.js +10 -0
  134. package/test/View/render-transcripts.test.js +165 -0
  135. package/test/create-and-destroy.test.js +63 -0
  136. package/test/track-ordering.test.js +514 -0
  137. package/test/track_config/__snapshots__/config-settings.test.js.snap +23 -0
  138. package/test/track_config/config-settings.test.js +321 -0
  139. package/test/track_config/zoom-level-settings.test.js +98 -0
  140. package/test/utils.js +80 -0
  141. package/utils/createGenome.js +52 -0
  142. package/utils/devServer.js +36 -0
  143. package/utils/expandedTemplate.html +46 -0
  144. package/utils/git-hooks/post-commit +9 -0
  145. package/utils/git-hooks/pre-commit +7 -0
  146. package/utils/git-hooks/setup +6 -0
  147. package/utils/makeExpanded.js +19 -0
  148. package/webpack.config.js +39 -0
@@ -0,0 +1,30 @@
1
+ Genoverse.Track.File.BAM = Genoverse.Track.File.extend({
2
+ name : 'BAM',
3
+ indexExt : '.bai',
4
+ threshold : 100000,
5
+ largeFile : true,
6
+ model : Genoverse.Track.Model.File.BAM,
7
+ view : Genoverse.Track.View.Sequence.extend({
8
+ bump : true,
9
+ autoHeight : true
10
+ }),
11
+
12
+ click: function () {
13
+ var menu = this.base.apply(this, arguments);
14
+
15
+ if (menu) {
16
+ menu.addClass('gv-wrap-values');
17
+ }
18
+
19
+ return menu;
20
+ },
21
+
22
+ populateMenu: function (feature) {
23
+ var f = $.extend({ title: feature.readName }, feature);
24
+
25
+ delete f.sequence;
26
+ delete f.id;
27
+
28
+ return this.base(f);
29
+ }
30
+ });
@@ -0,0 +1,24 @@
1
+ Genoverse.Track.File.BED = Genoverse.Track.File.extend({
2
+ name : 'BED',
3
+ model : Genoverse.Track.Model.File.BED,
4
+ bump : true,
5
+ featureHeight : 10,
6
+ thickHeight : 10,
7
+ thinHeight : 7,
8
+ subFeatureJoinStyle : 'curve',
9
+
10
+ populateMenu: function (feature) {
11
+ var fields = [ false, false, false, 'name', 'score', 'strand', 'thickStart', 'thickEnd', 'itemRgb', 'blockCount', 'blockSizes', 'blockStarts' ]; // First three fields are chr, start, end which are covered by Location
12
+
13
+ return feature.originalFeature.reduce(function (menu, val, i) {
14
+ if (fields[i]) {
15
+ menu[fields[i]] = val;
16
+ }
17
+
18
+ return menu;
19
+ }, {
20
+ title : '<a target="_blank" href="https://genome.ucsc.edu/FAQ/FAQformat.html#format1">BED feature details</a>',
21
+ Location : feature.chr + ':' + feature.start + '-' + feature.end
22
+ });
23
+ }
24
+ });
@@ -0,0 +1,47 @@
1
+ Genoverse.Track.File.BIGBED = Genoverse.Track.File.BED.extend({
2
+ name : 'bigbed',
3
+ model : Genoverse.Track.Model.File.BED.extend({
4
+ getData: function (chr, start, end) {
5
+ var model = this;
6
+ var deferred = $.Deferred();
7
+
8
+ if (!this.bigbedFile) {
9
+ this.bigbedFile = this.bigbedFile || (this.url ? new dallianceLib.URLFetchable(this.url) : new dallianceLib.BlobFetchable(this.track.dataFile));
10
+ }
11
+
12
+ var d = $.Deferred().done(function () {
13
+ model.bwReader.getValues(chr, start, end, function (features, error) {
14
+ if (!error) {
15
+ features.sort(function (a, b) { return a.start - b.start; });
16
+
17
+ if (features.length) {
18
+ model.receiveData(features, chr, features[0].start, features[features.length - 1].end);
19
+ } else {
20
+ model.receiveData(features, chr, start, end);
21
+ }
22
+ }
23
+
24
+ deferred.resolveWith(model);
25
+ });
26
+ });
27
+
28
+ if (this.bwReader) {
29
+ d.resolve();
30
+ } else {
31
+ new BWReader(this.bigbedFile, function (bwReader) {
32
+ if (bwReader) {
33
+ model.bwReader = bwReader;
34
+ d.resolve();
35
+ } else {
36
+ model.receiveData([], chr, start, end);
37
+ return deferred.resolveWith(model);
38
+ }
39
+ });
40
+ }
41
+
42
+ return deferred;
43
+ }
44
+ })
45
+ });
46
+
47
+ Genoverse.Track.File.BB = Genoverse.Track.File.BIGBED;
@@ -0,0 +1,52 @@
1
+ Genoverse.Track.File.BIGWIG = Genoverse.Track.Graph.Bar.extend({
2
+ name : 'bigwig',
3
+ height : 100,
4
+
5
+ setDefaults: function () {
6
+ this.bwReader = null; // Not part of model since it needs to be shared between bar and line graphs
7
+ this.base.apply(this, arguments);
8
+ },
9
+
10
+ getData: function (chr, start, end) {
11
+ var model = this;
12
+ var deferred = $.Deferred();
13
+
14
+ if (!this.bigwigFile) {
15
+ this.bigwigFile = this.bigwigFile || (this.url ? new dallianceLib.URLFetchable(this.url) : new dallianceLib.BlobFetchable(this.track.dataFile));
16
+ }
17
+
18
+ var d = $.Deferred().done(function () {
19
+ model.prop('bwReader').getValues(chr, start, end, function (features, error) {
20
+ if (!error) {
21
+ features.sort(function (a, b) { return a.start - b.start; });
22
+
23
+ if (features.length) {
24
+ model.receiveData(features, chr, features[0].start, features[features.length - 1].end);
25
+ } else {
26
+ model.receiveData(features, chr, start, end);
27
+ }
28
+ }
29
+
30
+ deferred.resolveWith(model);
31
+ });
32
+ });
33
+
34
+ if (this.prop('bwReader')) {
35
+ d.resolve();
36
+ } else {
37
+ new BWReader(this.bigwigFile, function (bwReader) {
38
+ if (bwReader) {
39
+ model.prop('bwReader', bwReader);
40
+ d.resolve();
41
+ } else {
42
+ model.receiveData([], chr, start, end);
43
+ return deferred.resolveWith(model);
44
+ }
45
+ });
46
+ }
47
+
48
+ return deferred;
49
+ }
50
+ });
51
+
52
+ Genoverse.Track.File.BW = Genoverse.Track.File.BIGWIG;
@@ -0,0 +1,9 @@
1
+ Genoverse.Track.File.GFF = Genoverse.Track.File.extend({
2
+ name : 'GFF',
3
+ model : Genoverse.Track.Model.File.GFF,
4
+ bump : true,
5
+ height : 100,
6
+ featureHeight : 5
7
+ });
8
+
9
+ Genoverse.Track.File.GTF = Genoverse.Track.File.GFF;
@@ -0,0 +1,71 @@
1
+ Genoverse.Track.File.VCF = Genoverse.Track.File.extend({
2
+ name : 'VCF',
3
+ indexExt : '.tbi',
4
+ model : Genoverse.Track.Model.File.VCF,
5
+ autoHeight : false,
6
+ maxQual : undefined, // Set this to the maximum value of the QUAL field in the file in order to color features by QUAL. Only required for large (tabix indexed) files - small ones can calculate this value automatically
7
+
8
+ afterSetMVC: function () {
9
+ if (this.prop('gz')) {
10
+ this.prop('threshold', 1e5);
11
+ }
12
+ },
13
+
14
+ populateMenu: function (feature) {
15
+ return {
16
+ title : '<a target="_blank" href="https://www.internationalgenome.org/wiki/Analysis/vcf4.0">VCF feature details</a>',
17
+ CHROM : feature.originalFeature[0],
18
+ POS : feature.originalFeature[1],
19
+ ID : feature.originalFeature[2],
20
+ REF : feature.originalFeature[3],
21
+ ALT : feature.originalFeature[4],
22
+ QUAL : feature.originalFeature[5],
23
+ FILTER : feature.originalFeature[6],
24
+ INFO : feature.originalFeature[7].split(';').join('<br />')
25
+ };
26
+ },
27
+
28
+ 1: {
29
+ view: Genoverse.Track.View.Sequence.extend({
30
+ bump : true,
31
+ labels : false,
32
+ featureMargin : { top: 0, right: 0, bottom: 0, left: 0 },
33
+
34
+ draw: function (features, featureContext, labelContext, scale) {
35
+ this.base.apply(this, arguments);
36
+ this.highlightRef(features, featureContext, scale);
37
+ },
38
+
39
+ highlightRef: function (features, context, scale) {
40
+ context.strokeStyle = 'black';
41
+
42
+ for (var i = 0; i < features.length; i++) {
43
+ if (features[i].allele === 'REF') {
44
+ context.strokeRect(features[i].position[scale].X, features[i].position[scale].Y, features[i].position[scale].width, features[i].position[scale].height);
45
+ }
46
+ }
47
+ }
48
+ })
49
+ },
50
+
51
+ 1000: {
52
+ view: Genoverse.Track.View.extend({
53
+ bump : false,
54
+ labels : false,
55
+
56
+ drawFeature: function (feature) {
57
+ var maxQual = this.prop('maxQual');
58
+
59
+ if (maxQual && !feature.color) {
60
+ var heat = Math.min(255, Math.floor((255 * (feature.originalFeature[5] || 0)) / maxQual)) - 127;
61
+ var red = heat > 0 ? 255 : 127 + heat;
62
+ var green = heat < 0 ? 255 : 127 - heat;
63
+
64
+ feature.color = 'rgb(' + red + ',' + green + ',0)';
65
+ }
66
+
67
+ this.base.apply(this, arguments);
68
+ }
69
+ })
70
+ }
71
+ });
@@ -0,0 +1,5 @@
1
+ Genoverse.Track.File.WIG = Genoverse.Track.Graph.Bar.extend({
2
+ model : Genoverse.Track.Model.File.WIG,
3
+ name : 'wig',
4
+ height : 100
5
+ });
@@ -0,0 +1,10 @@
1
+ Genoverse.Track.File = Genoverse.Track.extend({
2
+ setInterface: function () {
3
+ this.base();
4
+
5
+ this._interface.isLocal = 'model';
6
+ this._interface.dataFile = 'model';
7
+ this._interface.indexFile = 'model';
8
+ this._interface.largeFile = 'model';
9
+ }
10
+ });
@@ -0,0 +1,37 @@
1
+ Genoverse.Track.Gene = Genoverse.Track.extend({
2
+ id : 'genes',
3
+ name : 'Genes',
4
+ height : 200,
5
+ legend : true,
6
+
7
+ populateMenu: function (feature) {
8
+ var url = 'https://www.ensembl.org/Homo_sapiens/' + (feature.feature_type === 'transcript' ? 'Transcript' : 'Gene') + '/Summary?' + (feature.feature_type === 'transcript' ? 't' : 'g') + '=' + feature.id;
9
+ var menu = {
10
+ title : '<a target="_blank" href="' + url + '">' + (feature.external_name ? feature.external_name + ' (' + feature.id + ')' : feature.id) + '</a>',
11
+ Location : feature.chr + ':' + feature.start + '-' + feature.end,
12
+ Source : feature.source,
13
+ Biotype : feature.biotype
14
+ };
15
+
16
+ if (feature.feature_type === 'transcript') {
17
+ menu.Gene = '<a target="_blank" href="https://www.ensembl.org/Homo_sapiens/Gene/Summary?g=' + feature.Parent + '">' + feature.Parent + '</a>';
18
+ }
19
+
20
+ return menu;
21
+ },
22
+
23
+ // Different settings for different zoom level
24
+ 2000000: { // This one applies when > 2M base-pairs per screen
25
+ labels: false
26
+ },
27
+ 100000: { // more than 100K but less then 2M
28
+ labels : true,
29
+ model : Genoverse.Track.Model.Gene.Ensembl,
30
+ view : Genoverse.Track.View.Gene.Ensembl
31
+ },
32
+ 1: { // > 1 base-pair, but less then 100K
33
+ labels : true,
34
+ model : Genoverse.Track.Model.Transcript.Ensembl,
35
+ view : Genoverse.Track.View.Transcript.Ensembl
36
+ }
37
+ });
@@ -0,0 +1,235 @@
1
+ Genoverse.Track.Controller.Graph.Bar = {
2
+ getClickedFeatures: function (x, y) {
3
+ var yZero = this.prop('marginTop') - (this.prop('range')[0] * this.track.getYScale());
4
+ var scale = this.scale;
5
+ var tolerance = scale > 1 ? 0 : 1;
6
+
7
+ // Bars with negative values are stored in featurePositions with h < 0.
8
+ // While this works to a certain degree (fillRect allows negative height, drawing upwards from y), it makes them hard to search for in the RTree - to find such a feature you need to search with y = -h and h = y - h + 1
9
+ // It is therefore easier to search featuresByChr (i.e. the genomic positions) for a feature overlapping the x of the click, and then filter those results for y position manually.
10
+ var features = this.prop('featuresByChr')[this.browser.chr].search({
11
+ x : (x - (tolerance / 2)) / scale,
12
+ y : 0,
13
+ w : (1 + tolerance) / scale,
14
+ h : 1
15
+ });
16
+
17
+ if (features.length) {
18
+ if (
19
+ (y < yZero && features.filter(function (f) { return f.position[scale].bounds.y + f.position[scale].bounds.h <= y && f.position[scale].bounds.y >= y; }).length === 0) ||
20
+ (y >= yZero && this.featurePositions.search({ x: x, y: y, w: 1, h: 1 }).length === 0)
21
+ ) {
22
+ features = [];
23
+ }
24
+ }
25
+
26
+ return features.length ? [ this.model.sortFeatures(features) ] : [];
27
+ },
28
+
29
+ populateMenu: function (features) {
30
+ if (!features.length) {
31
+ return [];
32
+ }
33
+
34
+ var start = features[0].start;
35
+ var end = features[features.length - 1].end;
36
+ var avg = features[0].start !== features[features.length - 1].start;
37
+ var menu = { title: features[0].chr + ':' + (start === end ? start : start + '-' + end) };
38
+ var values, i;
39
+
40
+ function getValues(_features) {
41
+ var vals = _features.map(function (f) { return f.height; }).sort(function (a, b) { return a - b; });
42
+
43
+ return {
44
+ avg : vals.reduce(function (n, v) { return n + v; }, 0) / vals.length,
45
+ min : vals[0],
46
+ max : vals[vals.length - 1]
47
+ };
48
+ }
49
+
50
+ if (avg) {
51
+ if (features.length === 1) {
52
+ values = getValues(features);
53
+
54
+ menu['Average value'] = values.avg;
55
+ menu['Min value'] = values.min;
56
+ menu['Max value'] = values.max;
57
+ } else {
58
+ menu = [ menu ];
59
+
60
+ var datasets = this.prop('datasets');
61
+ var featuresByDataset;
62
+
63
+ if (datasets.length) {
64
+ featuresByDataset = datasets.reduce(function (hash, d) { hash[d.name] = []; return hash; }, {});
65
+
66
+ for (i = 0; i < features.length; i++) {
67
+ featuresByDataset[features[i].dataset].push(features[i]);
68
+ }
69
+ } else {
70
+ datasets = [{ name: '' }];
71
+ featuresByDataset = { '': features };
72
+ }
73
+
74
+ for (i = 0; i < datasets.length; i++) {
75
+ values = getValues(featuresByDataset[datasets[i].name]);
76
+
77
+ menu.push($.extend({
78
+ Average : values.avg,
79
+ Min : values.min,
80
+ Max : values.max
81
+ }, datasets[i].name ? { title: datasets[i].name } : {}));
82
+ }
83
+ }
84
+ } else if (features.length === 1) {
85
+ menu.Value = features[0].height;
86
+ } else {
87
+ for (i = 0; i < features.length; i++) {
88
+ menu[features[i].dataset] = features[i].height;
89
+ }
90
+ }
91
+
92
+ return menu;
93
+ }
94
+ };
95
+
96
+ Genoverse.Track.Model.Graph.Bar = Genoverse.Track.Model.Graph.extend({
97
+ insertFeature: function (feature) {
98
+ var datasets = this.prop('datasets');
99
+
100
+ if (datasets.length) {
101
+ feature.legend = feature.dataset;
102
+ feature.color = (datasets.filter(function (s) { return s.name === feature.dataset; })[0] || { color: this.color }).color;
103
+ }
104
+
105
+ feature.id = feature.id || [ feature.chr, feature.start, feature.end, feature.dataset || '' ].join(':');
106
+
107
+ return this.base.apply(this, arguments);
108
+ }
109
+ });
110
+
111
+ Genoverse.Track.View.Graph.Bar = Genoverse.Track.View.Graph.extend({
112
+ scaleFeatures: function (features, scale) {
113
+ var yScale = this.track.getYScale();
114
+ var zeroY = this.prop('marginTop') - this.prop('range')[0] * yScale;
115
+
116
+ features = this.base(features, scale);
117
+
118
+ for (var i = 0; i < features.length; i++) {
119
+ features[i].position[scale].height = features[i].height * yScale;
120
+ features[i].position[scale].y = zeroY;
121
+ }
122
+
123
+ return features;
124
+ },
125
+
126
+ draw: function (features, featureContext, labelContext, scale) {
127
+ var datasets = this.featureDataSets(features);
128
+ var marginBottom = this.prop('margin');
129
+ var binSize = scale < 1 ? Math.ceil(1 / scale) : 0;
130
+ var conf, set, setFeatures, j, binnedFeatures, binStart, bin, f;
131
+
132
+ var defaults = {
133
+ color : this.color,
134
+ globalAlpha : this.prop('globalAlpha')
135
+ };
136
+
137
+ for (var i = 0; i < datasets.list.length; i++) {
138
+ conf = $.extend({}, defaults, datasets.list[i]);
139
+ set = datasets.list[i].name;
140
+ setFeatures = $.extend(true, [], datasets.features[set] || []);
141
+
142
+ if (!setFeatures.length) {
143
+ continue;
144
+ }
145
+
146
+ if (binSize) {
147
+ binnedFeatures = [];
148
+ j = 0;
149
+
150
+ while (j < setFeatures.length) {
151
+ binStart = setFeatures[j].start;
152
+ bin = [];
153
+
154
+ while (setFeatures[j] && setFeatures[j].start - binStart < binSize) {
155
+ bin.push(setFeatures[j++]);
156
+ }
157
+
158
+ f = $.extend(true, {}, bin[0], {
159
+ height : bin.reduce(function (a, b) { return a + b.height; }, 0) / bin.length,
160
+ end : bin[bin.length - 1].end
161
+ });
162
+
163
+ [ 'H', 'W', 'height', 'width' ].forEach(function (attr) { // eslint-disable-line no-loop-func
164
+ f.position[scale][attr] = bin.reduce(function (a, b) { return a + b.position[scale][attr]; }, 0) / bin.length;
165
+ });
166
+
167
+ binnedFeatures.push(f);
168
+ }
169
+
170
+ setFeatures = binnedFeatures;
171
+ }
172
+
173
+ for (j = 0; j < setFeatures.length; j++) {
174
+ setFeatures[j].color = conf.color;
175
+ }
176
+
177
+ featureContext.globalAlpha = conf.globalAlpha;
178
+
179
+ this.base(setFeatures, featureContext, labelContext, scale);
180
+ }
181
+
182
+ // Don't allow features to be drawn in the margins
183
+ featureContext.clearRect(0, 0, this.width, this.prop('marginTop') - 1);
184
+ featureContext.clearRect(0, this.prop('height') - marginBottom, this.width, marginBottom);
185
+ }
186
+ });
187
+
188
+ Genoverse.Track.Graph.Bar = Genoverse.Track.Graph.extend({
189
+ type : 'Bar',
190
+ model : Genoverse.Track.Model.Graph.Bar,
191
+ view : Genoverse.Track.View.Graph.Bar,
192
+ threshold : 500000,
193
+
194
+ 10000: $.extend( // Switch to line graph at 10000bp region
195
+ Object.keys(Genoverse.Track.Graph.Line.prototype).reduce(function (hash, key) {
196
+ if (Genoverse.Track.Graph.Line.prototype.hasOwnProperty(key) && !Base.prototype[key]) {
197
+ hash[key] = Genoverse.Track.Graph.Line.prototype[key];
198
+ }
199
+
200
+ return hash;
201
+ }, {}), {
202
+ fill : true,
203
+ model : Genoverse.Track.Model.Graph.Line.extend({
204
+ parseData: function (data, chr, start, end) {
205
+ var coords = [];
206
+ var j;
207
+
208
+ for (var i = 0; i < data.length; i++) {
209
+ for (j = data[i].start; j < data[i].end; j++) {
210
+ coords.push([ j, data[i].height ]);
211
+ }
212
+ }
213
+
214
+ return this.base([{ chr: chr, start: start, end: end, coords: coords }], chr, start, end);
215
+ }
216
+ })
217
+ }
218
+ ),
219
+ 50000: $.extend( // Switch to sparser line graph at 50000bp region
220
+ Object.keys(Genoverse.Track.Graph.Line.prototype).reduce(function (hash, key) {
221
+ if (Genoverse.Track.Graph.Line.prototype.hasOwnProperty(key) && !Base.prototype[key]) {
222
+ hash[key] = Genoverse.Track.Graph.Line.prototype[key];
223
+ }
224
+
225
+ return hash;
226
+ }, {}), {
227
+ fill : true,
228
+ model : Genoverse.Track.Model.Graph.Line.extend({
229
+ parseData: function (data, chr, start, end) {
230
+ return this.base([{ chr: chr, start: start, end: end, coords: data.map(function (d) { return [ d.start, d.height ]; }) }], chr, start, end);
231
+ }
232
+ })
233
+ }
234
+ )
235
+ });