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,292 @@
1
+ Genoverse.Track.HighlightRegion = Genoverse.Track.extend({
2
+ id : 'highlights',
3
+ unsortable : true,
4
+ fixedOrder : true,
5
+ repeatLabels : true,
6
+ resizable : false,
7
+ border : false,
8
+ alwaysReposition : true,
9
+ height : 15,
10
+ featureHeight : 2,
11
+ order : -1,
12
+ orderReverse : 9e99,
13
+ controls : 'off',
14
+ colors : [ '#777777', '#F08080', '#3CB371', '#6495ED', '#FFA500', '#9370DB' ],
15
+ labels : 'separate',
16
+ depth : 1,
17
+ featureMargin : { top: 13, right: 0, bottom: 0, left: 0 },
18
+ margin : 0,
19
+
20
+ constructor: function () {
21
+ this.colorIndex = 0;
22
+ return this.base.apply(this, arguments);
23
+ },
24
+
25
+ addHighlights: function (highlights) {
26
+ for (var i = 0; i < highlights.length; i++) {
27
+ this.model.insertFeature($.extend({ label: (highlights[i].start + '-' + highlights[i].end) }, highlights[i]));
28
+ }
29
+
30
+ this.reset();
31
+ },
32
+
33
+ removeHighlights: function (highlights) {
34
+ var featuresByChr = this.prop('featuresByChr');
35
+ var featuresById = this.prop('featuresById');
36
+ var features, bounds, h;
37
+
38
+ highlights = highlights || $.map(featuresById, function (f) { return f; });
39
+
40
+ for (var i = 0; i < highlights.length; i++) {
41
+ if (highlights[i].removable === false) {
42
+ continue;
43
+ }
44
+
45
+ features = featuresByChr[highlights[i].chr];
46
+ bounds = { x: highlights[i].start, y: 0, w: highlights[i].end - highlights[i].start + 1, h: 1 };
47
+
48
+ // RTree.remove only works if the second argument (the object to be removed) === the object found in the tree.
49
+ // Here, while highlight is effectively the same object as the one in the tree, it has been cloned, so the === check fails.
50
+ // To fix this, search for the feature to remove in the location of highlight.
51
+ h = $.grep(features.search(bounds), function (item) { return item.id === highlights[i].id; }); // eslint-disable-line no-loop-func
52
+
53
+ if (h.length) {
54
+ features.remove(bounds, h[0]);
55
+ }
56
+
57
+ delete featuresById[highlights[i].id];
58
+ }
59
+
60
+ if (this.prop('strand') === 1) {
61
+ this.prop('reverseTrack').removeHighlights(highlights);
62
+ }
63
+
64
+ this.reset();
65
+ },
66
+
67
+ controller: Genoverse.Track.Controller.Stranded.extend({
68
+ setDefaults: function () {
69
+ if (this.prop('strand') === -1) {
70
+ this.prop('labels', false);
71
+ this.prop('border', false);
72
+ this.prop('height', 2);
73
+ this.prop('featureMargin').top = 0;
74
+ }
75
+
76
+ this.base();
77
+ },
78
+
79
+ setName: function (name) {
80
+ if (this.prop('strand') === -1) {
81
+ this.base('');
82
+ this.minLabelHeight = 0;
83
+ this.label.height(0);
84
+ } else {
85
+ this.base(name);
86
+ }
87
+ },
88
+
89
+ makeImage: function (params) {
90
+ if (this.prop('strand') === 1) {
91
+ params.background = 'gv-full-height';
92
+ }
93
+
94
+ var rtn = this.base(params);
95
+ params.container.addClass(params.background);
96
+ return rtn;
97
+ },
98
+
99
+ render: function (features, img) {
100
+ this.base(features, img);
101
+ img.siblings('.gv-labels').css('top', this.prop('featureHeight') - this.prop('featureMargin').top);
102
+ },
103
+
104
+ renderBackground: function (f, img) {
105
+ this.base(f, img);
106
+ img.height(this.browser.wrapper.outerHeight(true));
107
+ },
108
+
109
+ populateMenu: function (features) {
110
+ var menu = [];
111
+ var location, m;
112
+
113
+ if (features.length > 1) {
114
+ menu.push({ title: 'Highlights' });
115
+ }
116
+
117
+ for (var i = 0; i < features.length; i++) {
118
+ location = features[i].start + '-' + features[i].end;
119
+ m = {
120
+ title : features[i].label ? features[i].label[0] : location,
121
+ start : false
122
+ };
123
+
124
+ m[m.title === location ? 'title' : 'Location'] = features[i].chr + ':' + location;
125
+ m['<a class="gv-focus-highlight" href="#" data-chr="' + features[i].chr + '" data-start="' + features[i].start + '" data-end="' + features[i].end + '">Focus here</a>'] = '';
126
+
127
+ if (features[i].removable !== false) {
128
+ m['<a class="gv-remove-highlight" href="#" data-id="' + features[i].id + '">Remove this highlight</a>'] = '';
129
+ m['<a class="gv-remove-highlights" href="#">Remove all highlights</a>'] = '';
130
+ }
131
+
132
+ menu.push(m);
133
+ }
134
+
135
+ return menu;
136
+ },
137
+
138
+ click: function () {
139
+ if (this.prop('strand') !== 1) {
140
+ return;
141
+ }
142
+
143
+ var menuEl = this.base.apply(this, arguments);
144
+
145
+ if (menuEl && !menuEl.data('highlightEvents')) {
146
+ var track = this.track;
147
+
148
+ menuEl.find('.gv-remove-highlight').on('click', function () {
149
+ var id = $(this).data('id');
150
+ track.removeHighlights($.grep(menuEl.data('feature'), function (f) { return f.id === id; }));
151
+ return false;
152
+ });
153
+
154
+ menuEl.find('.gv-remove-highlights').on('click', function () {
155
+ track.removeHighlights();
156
+ return false;
157
+ });
158
+
159
+ menuEl.find('.gv-focus-highlight').on('click', function () {
160
+ var data = $(this).data();
161
+ var length = data.end - data.start + 1;
162
+ var context = Math.max(Math.round(length / 4), 25);
163
+
164
+ track.browser.moveTo(data.chr, data.start - context, data.end + context, true);
165
+
166
+ return false;
167
+ });
168
+
169
+ menuEl.data('highlightEvents', true);
170
+ }
171
+ },
172
+
173
+ getClickedFeatures: function (x, y) {
174
+ var seen = {};
175
+ var scale = this.scale;
176
+ var features = $.grep(
177
+ // feature positions
178
+ this.featurePositions.search({ x: x, y: y, w: 1, h: 1 }).concat(
179
+ // plus label positions where the labels are visible
180
+ $.grep(this.labelPositions.search({ x: x, y: y, w: 1, h: 1 }), function (f) {
181
+ return f.position[scale].label.visible !== false;
182
+ })
183
+ ),
184
+ function (f) {
185
+ // with duplicates removed
186
+ var rtn = !seen[f.id];
187
+ seen[f.id] = true;
188
+ return rtn;
189
+ }
190
+ );
191
+
192
+ return features.length ? [ this.model.sortFeatures(features) ] : false;
193
+ }
194
+ }),
195
+
196
+ model: Genoverse.Track.Model.Stranded.extend({
197
+ url: false,
198
+
199
+ insertFeature: function (feature) {
200
+ feature.id = feature.chr + ':' + feature.start + '-' + feature.end;
201
+ feature.sort = feature.start;
202
+
203
+ if (!feature.color) {
204
+ var colors = this.prop('colors');
205
+ var i = this.prop('colorIndex');
206
+
207
+ feature.color = colors[i++];
208
+
209
+ this.prop('colorIndex', colors[i] ? i : 0);
210
+ }
211
+
212
+ if (!this.featuresById[feature.id]) {
213
+ this.base(feature);
214
+ }
215
+ },
216
+
217
+ findFeatures: function () {
218
+ return Genoverse.Track.Model.prototype.findFeatures.apply(this, arguments);
219
+ }
220
+ }),
221
+
222
+ view: Genoverse.Track.View.extend({
223
+ positionFeatures: function (features, params) {
224
+ var rtn = this.base.apply(this, arguments);
225
+
226
+ // featureMargin.top gets used to define params.featureHeight, which is used to determine canvas height.
227
+ // Since featureMargin.top = 13 on forward strand, the canvas has a 13px space at the bottom, meaning there is a gap before the background starts.
228
+ // Reducing params.featureHeight here fixes that.
229
+ params.featureHeight = Math.max(params.featureHeight - this.featureMargin.top, 0);
230
+
231
+ return rtn;
232
+ },
233
+
234
+ draw: function (features, featureContext, labelContext, scale) {
235
+ if (this.prop('strand') === 1) {
236
+ featureContext.fillStyle = '#FFF';
237
+ featureContext.fillRect(0, 0, featureContext.canvas.width, featureContext.canvas.height);
238
+ }
239
+
240
+ this.base(features, featureContext, labelContext, scale);
241
+ },
242
+
243
+ drawBackground: function (features, context, params) {
244
+ if (this.prop('strand') === -1) {
245
+ return;
246
+ }
247
+
248
+ for (var i = 0; i < features.length; i++) {
249
+ context.fillStyle = features[i].color;
250
+
251
+ this.drawFeature($.extend(true, {}, features[i], {
252
+ x : features[i].position[params.scale].X,
253
+ y : 0,
254
+ width : features[i].position[params.scale].width,
255
+ height : context.canvas.height,
256
+ color : this.shadeColor(context.fillStyle, 0.8),
257
+ border : features[i].color,
258
+ label : false,
259
+ decorations : true
260
+ }), context, false, params.scale);
261
+ }
262
+ },
263
+
264
+ decorateFeature: function (feature, context) {
265
+ var x1 = feature.x + 0.5;
266
+ var x2 = x1 + feature.width;
267
+ var draw = false;
268
+
269
+ context.strokeStyle = feature.border;
270
+ context.lineWidth = 2;
271
+ context.beginPath();
272
+
273
+ if (x1 >= 0 && x1 <= this.width) {
274
+ context.moveTo(x1, feature.y);
275
+ context.lineTo(x1, feature.y + feature.height);
276
+ draw = true;
277
+ }
278
+
279
+ if (x2 >= 0 && x2 <= this.width) {
280
+ context.moveTo(x2, feature.y);
281
+ context.lineTo(x2, feature.y + feature.height);
282
+ draw = true;
283
+ }
284
+
285
+ if (draw) {
286
+ context.stroke();
287
+ }
288
+
289
+ context.lineWidth = 1;
290
+ }
291
+ })
292
+ });
@@ -0,0 +1,224 @@
1
+ Genoverse.Track.Controller.Legend = Genoverse.Track.Controller.Static.extend({
2
+ init: function () {
3
+ this.base();
4
+
5
+ this.container.addClass('gv-track-container-legend');
6
+
7
+ this.browser.legends[this.track.id] = this.track;
8
+
9
+ this.track.setTracks();
10
+ },
11
+
12
+ destroy: function () {
13
+ delete this.browser.legends[this.prop('id')];
14
+ this.base();
15
+ }
16
+ });
17
+
18
+ Genoverse.Track.Model.Legend = Genoverse.Track.Model.Static.extend({
19
+ findFeatures: function () {
20
+ var bounds = { x: this.browser.scaledStart, y: 0, w: this.width };
21
+ var features = {};
22
+
23
+ $.each($.map(this.track.tracks, function (track) {
24
+ var featurePositions = track.prop('featurePositions');
25
+ bounds.h = track.prop('height');
26
+ return featurePositions ? featurePositions.search(bounds).concat(track.prop('labelPositions').search(bounds)) : [];
27
+ }), function () {
28
+ if (Array.isArray(this.legend)) {
29
+ this.legend.forEach(function (legend) { features[legend.label] = legend.color; });
30
+ } else if (this.legend) {
31
+ features[this.legend] = this.legendColor || this.color;
32
+ }
33
+ });
34
+
35
+ return this.sortFeatures($.map(features, function (color, text) { return [[ text, color ]]; }));
36
+ },
37
+
38
+ sortFeatures: function (features) {
39
+ // sort legend alphabetically
40
+ return features.sort(function (a, b) { return a[0].localeCompare(b[0]); });
41
+ }
42
+ });
43
+
44
+ Genoverse.Track.View.Legend = Genoverse.Track.View.Static.extend({
45
+ textColor : '#000000',
46
+ labels : 'overlay',
47
+ featureHeight : 12,
48
+
49
+ positionFeatures: function (f, params) {
50
+ if (params.positioned) {
51
+ return f;
52
+ }
53
+
54
+ var cols = 2;
55
+ var pad = 5;
56
+ var w = 20;
57
+ var x = 0;
58
+ var y = 0;
59
+ var xScale = this.width / cols;
60
+ var yScale = this.fontHeight + pad;
61
+ var features = [];
62
+ var xOffest = params.xOffset || 0;
63
+ var xPos, yPos, labelWidth;
64
+
65
+ for (var i = 0; i < f.length; i++) {
66
+ xPos = (x * xScale) + pad;
67
+ yPos = (y * yScale) + pad;
68
+ labelWidth = this.context.measureText(f[i][0]).width;
69
+
70
+ features.push(
71
+ { x: xPos + xOffest, y: yPos, width: w, height: this.featureHeight, color: f[i][1] },
72
+ { x: xPos + xOffest + pad + w, y: yPos, width: labelWidth + 1, height: this.featureHeight, color: false, labelColor: this.textColor, labelWidth: labelWidth, label: f[i][0] }
73
+ );
74
+
75
+ if (++x === cols) {
76
+ x = 0;
77
+ y++;
78
+ }
79
+ }
80
+
81
+ params.height = this.prop('height', f.length ? ((y + (x ? 1 : 0)) * yScale) + pad : 0);
82
+ params.width = this.width;
83
+ params.positioned = true;
84
+
85
+ return this.base(features, params);
86
+ }
87
+ });
88
+
89
+ Genoverse.Track.Legend = Genoverse.Track.Static.extend({
90
+ unsortable : true,
91
+ lockToTrack : true, // Always put the legend just below the last track that the legend is for
92
+ removable : false,
93
+
94
+ controller : Genoverse.Track.Controller.Legend,
95
+ model : Genoverse.Track.Model.Legend,
96
+ view : Genoverse.Track.View.Legend,
97
+
98
+ setDefaults: function () {
99
+ this.order = typeof this.order !== 'undefined' ? this.order : 9e99;
100
+ this.id = this.id || 'legend';
101
+ this.type = this.type || 'legend';
102
+ this.base();
103
+ },
104
+
105
+ setEvents: function () {
106
+ this.browser.on({
107
+ 'afterAddTracks afterRemoveTracks': function () {
108
+ for (var i in this.legends) {
109
+ this.legends[i].setTracks();
110
+ }
111
+
112
+ this.sortTracks();
113
+ },
114
+ afterRemoveTracks: function (tracks) {
115
+ var i;
116
+
117
+ for (i in tracks) {
118
+ if (tracks[i].legendTrack && tracks[i].legendTrack.tracks.length === 0) {
119
+ tracks[i].legendTrack.remove();
120
+ }
121
+ }
122
+
123
+ for (i in this.legends) {
124
+ this.legends[i].controller.makeImage({});
125
+ }
126
+ },
127
+ afterUpdateTrackOrder: function (e, ui) {
128
+ var track = ui.item.data('track');
129
+ var legendTrack = this.legends[track.id] || track.legendTrack;
130
+
131
+ // If a legend track, or a track with a sortable legend has been reordered, its lockToTrack status is ignored from now on.
132
+ // This allows a legend to initially be locked to a track, but then to be reordered once the browser has been initialized
133
+ if (legendTrack && legendTrack.lockToTrack && legendTrack.unsortable === false) {
134
+ legendTrack.lockToTrack = false;
135
+ }
136
+
137
+ for (var i in this.legends) {
138
+ this.legends[i].updateOrder();
139
+ }
140
+
141
+ this.sortTracks();
142
+ }
143
+ });
144
+
145
+ this.browser.on({
146
+ afterPositionFeatures: function (features, params) {
147
+ var legend = this.prop('legendTrack');
148
+
149
+ if (legend) {
150
+ setTimeout(function () { legend.controller.makeImage(params); }, 1);
151
+ }
152
+ },
153
+ afterResize: function (height, userResize) {
154
+ var legend = this.prop('legendTrack');
155
+
156
+ if (legend && userResize === true) {
157
+ legend.controller.makeImage({});
158
+ }
159
+ },
160
+ afterCheckHeight: function () {
161
+ var legend = this.prop('legendTrack');
162
+
163
+ if (legend) {
164
+ legend.controller.makeImage({});
165
+ }
166
+ },
167
+ afterSetMVC: function () {
168
+ var legend = this.prop('legendTrack');
169
+
170
+ if (legend && legend.tracks.length) {
171
+ legend.disable();
172
+
173
+ if (this.legend !== false) {
174
+ legend.enable();
175
+ }
176
+ }
177
+ }
178
+ }, this);
179
+ },
180
+
181
+ setTracks: function () {
182
+ var legend = this;
183
+ var type = this.type;
184
+
185
+ this.tracks = $.map(this.browser.tracks.filter(function (t) {
186
+ if (t.legendType === type) {
187
+ t.legendTrack = t.legendTrack || legend;
188
+ return true;
189
+ }
190
+
191
+ return false;
192
+ }), function (track) {
193
+ return [ track ].concat(track.prop('childTracks'), track.prop('parentTrack')).filter(function (t) { return t && t !== legend && !t.prop('disabled'); });
194
+ });
195
+
196
+ this.updateOrder();
197
+
198
+ if (typeof this.controller === 'object') {
199
+ this[this.tracks.length ? 'enable' : 'disable']();
200
+ } else {
201
+ this.disabled = !this.tracks.length;
202
+ }
203
+ },
204
+
205
+ updateOrder: function () {
206
+ if (this.lockToTrack) {
207
+ var tracks = this.tracks.filter(function (t) { return !t.prop('parentTrack'); });
208
+
209
+ if (tracks.length) {
210
+ this.order = tracks[tracks.length - 1].order + 0.1;
211
+ }
212
+ }
213
+ },
214
+
215
+ enable: function () {
216
+ this.base();
217
+ this.controller.makeImage({});
218
+ },
219
+
220
+ disable: function () {
221
+ delete this.controller.stringified;
222
+ this.base();
223
+ }
224
+ });