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.
- package/.eslintrc.js +93 -162
- package/.github/workflows/test.yml +9 -10
- package/.github/workflows/update-gh-pages.yml +33 -0
- package/LICENSE.TXT +2 -2
- package/README.md +174 -3
- package/{i → assets}/sort_handle.png +0 -0
- package/babel.config.js +19 -0
- package/dist/129.css +334 -0
- package/dist/129.css.map +1 -0
- package/dist/129.genoverse.js +2 -0
- package/dist/129.genoverse.js.map +1 -0
- package/dist/15d98c18221c8bcb2334.ttf +0 -0
- package/dist/166.css +2 -0
- package/dist/166.genoverse.js +1 -0
- package/dist/216.css +20 -0
- package/dist/216.css.map +1 -0
- package/dist/232.css +114 -0
- package/dist/232.css.map +1 -0
- package/dist/232.genoverse.js +2 -0
- package/dist/232.genoverse.js.map +1 -0
- package/dist/2e659e443f3e98569e9f.png +0 -0
- package/dist/394.css +114 -0
- package/dist/394.css.map +1 -0
- package/dist/394.genoverse.js +2 -0
- package/dist/394.genoverse.js.map +1 -0
- package/dist/469.css +24 -0
- package/dist/469.css.map +1 -0
- package/dist/469.genoverse.js +2 -0
- package/dist/469.genoverse.js.map +1 -0
- package/dist/4896d4b04430cc3dfb06.woff2 +0 -0
- package/dist/530.css +39 -0
- package/dist/530.css.map +1 -0
- package/dist/530.genoverse.js +2 -0
- package/dist/530.genoverse.js.map +1 -0
- package/dist/547.css +469 -0
- package/dist/547.css.map +1 -0
- package/dist/547.genoverse.js +1 -0
- package/dist/729.css +315 -0
- package/dist/729.css.map +1 -0
- package/dist/79da213423ac0def2058.ttf +0 -0
- package/dist/804.genoverse.js +2 -0
- package/dist/804.genoverse.js.map +1 -0
- package/dist/842.genoverse.js +2 -0
- package/dist/842.genoverse.js.map +1 -0
- package/dist/893.genoverse.js +2 -0
- package/dist/893.genoverse.js.map +1 -0
- package/dist/949.css +315 -0
- package/dist/949.css.map +1 -0
- package/dist/949.genoverse.js +2 -0
- package/dist/949.genoverse.js.map +1 -0
- package/dist/952.css +315 -0
- package/dist/952.css.map +1 -0
- package/dist/952.genoverse.js +2 -0
- package/dist/952.genoverse.js.map +1 -0
- package/dist/d79c2ec96ab9ff1161a2.woff2 +0 -0
- package/dist/genoverse.js +2 -0
- package/dist/genoverse.js.map +1 -0
- package/index.html +13 -14
- package/jest.config.js +5 -0
- package/jest.setup.js +13 -0
- package/package.json +29 -12
- package/{css → src/css}/controlPanel.css +0 -0
- package/{css → src/css}/fileDrop.css +0 -0
- package/src/css/fontawesome.css +3 -0
- package/{css → src/css}/fullscreen.css +0 -0
- package/{css → src/css}/genoverse.css +1 -1
- package/{css → src/css}/karyotype.css +2 -0
- package/{css → src/css}/resizer.css +0 -0
- package/{css → src/css}/tooltips.css +0 -0
- package/{css → src/css}/trackControls.css +0 -0
- package/src/js/Genoverse.js +1747 -0
- package/{js → src/js}/Track/Controller/Sequence.js +6 -4
- package/src/js/Track/Controller/Stranded.js +83 -0
- package/{js → src/js}/Track/Controller.js +201 -160
- package/src/js/Track/Model/File/BAM.js +47 -0
- package/src/js/Track/Model/File/BED.js +122 -0
- package/src/js/Track/Model/File/GFF.js +42 -0
- package/src/js/Track/Model/File/VCF.js +109 -0
- package/src/js/Track/Model/File/WIG.js +82 -0
- package/src/js/Track/Model/File.js +36 -0
- package/src/js/Track/Model/Gene/Ensembl.js +24 -0
- package/{js → src/js}/Track/Model/Gene.js +3 -1
- package/src/js/Track/Model/Sequence/Ensembl.js +6 -0
- package/{js → src/js}/Track/Model/Sequence/Fasta.js +24 -17
- package/{js → src/js}/Track/Model/Sequence.js +10 -7
- package/{js → src/js}/Track/Model/SequenceVariation.js +17 -11
- package/{js → src/js}/Track/Model/Stranded.js +11 -8
- package/src/js/Track/Model/Transcript/Ensembl.js +73 -0
- package/{js → src/js}/Track/Model/Transcript.js +3 -1
- package/{js → src/js}/Track/Model.js +125 -93
- package/{js → src/js}/Track/View/Gene/Ensembl.js +6 -4
- package/src/js/Track/View/Gene.js +8 -0
- package/{js → src/js}/Track/View/Sequence.js +18 -22
- package/src/js/Track/View/SequenceVariation.js +117 -0
- package/src/js/Track/View/Transcript/Ensembl.js +17 -0
- package/src/js/Track/View/Transcript.js +32 -0
- package/{js → src/js}/Track/View.js +200 -159
- package/{js → src/js}/Track/library/Chromosome.js +18 -13
- package/src/js/Track/library/File/BAM.js +34 -0
- package/src/js/Track/library/File/BED.js +27 -0
- package/src/js/Track/library/File/BIGBED.js +51 -0
- package/src/js/Track/library/File/BIGWIG.js +54 -0
- package/src/js/Track/library/File/GFF.js +10 -0
- package/{js → src/js}/Track/library/File/VCF.js +29 -22
- package/src/js/Track/library/File/WIG.js +8 -0
- package/{js → src/js}/Track/library/File.js +4 -2
- package/src/js/Track/library/Gene.js +44 -0
- package/src/js/Track/library/Graph/Bar.js +263 -0
- package/src/js/Track/library/Graph/Line.js +335 -0
- package/{js → src/js}/Track/library/Graph.js +137 -114
- package/{js → src/js}/Track/library/HighlightRegion.js +118 -93
- package/src/js/Track/library/Legend.js +258 -0
- package/{js → src/js}/Track/library/Scalebar.js +69 -49
- package/{js → src/js}/Track/library/Scaleline.js +29 -27
- package/src/js/Track/library/Static.js +82 -0
- package/{js → src/js}/Track/library/dbSNP.js +47 -50
- package/src/js/Track.js +651 -0
- package/{js → src/js}/genomes/grch37.js +52 -52
- package/{js → src/js}/genomes/grch38.js +52 -52
- package/src/js/lib/BWReader.js +562 -0
- package/src/js/lib/VCFReader.js +296 -0
- package/src/js/lib/dalliance/bam.js +517 -0
- package/src/js/lib/dalliance/bin.js +317 -0
- package/src/js/lib/dalliance/jszlib-inflate.js +2159 -0
- package/src/js/lib/dalliance/lh3utils.js +105 -0
- package/src/js/lib/dalliance/sha1.js +334 -0
- package/src/js/lib/import-tracks.js +42 -0
- package/{js/lib → src/js/lib/jquery-plugins}/jquery.mousehold.js +0 -0
- package/{js/lib → src/js/lib/jquery-plugins}/jquery.mousewheel.js +0 -0
- package/{js/lib → src/js/lib/jquery-plugins}/jquery.tipsy.js +0 -0
- package/src/js/lib/jquery.js +26 -0
- package/src/js/lib/polyfills.js +11 -0
- package/src/js/lib/wrap-functions.js +88 -0
- package/src/js/plugins/controlPanel.js +388 -0
- package/src/js/plugins/fileDrop.js +81 -0
- package/src/js/plugins/focusRegion.js +13 -0
- package/{js → src/js}/plugins/fullscreen.js +18 -14
- package/{js → src/js}/plugins/karyotype.js +51 -45
- package/src/js/plugins/resizer.js +52 -0
- package/{js → src/js}/plugins/tooltips.js +31 -29
- package/src/js/plugins/trackControls.js +159 -0
- package/test/View/render-legends.test.js +1 -1
- package/test/change-width.test.js +71 -0
- package/test/create-and-destroy.test.js +2 -2
- package/test/track-ordering.test.js +3 -2
- package/test/track_config/config-settings.test.js +1 -1
- package/test/utils.js +4 -2
- package/webpack.config.js +103 -34
- package/css/font-awesome.css +0 -3
- package/expanded.html +0 -120
- package/fontawesome/css/fontawesome.min.css +0 -5
- package/fontawesome/css/regular.min.css +0 -5
- package/fontawesome/css/solid.min.css +0 -5
- package/fontawesome/webfonts/fa-brands-400.ttf +0 -0
- package/fontawesome/webfonts/fa-brands-400.woff +0 -0
- package/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
- package/fontawesome/webfonts/fa-regular-400.ttf +0 -0
- package/fontawesome/webfonts/fa-regular-400.woff +0 -0
- package/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
- package/fontawesome/webfonts/fa-solid-900.ttf +0 -0
- package/fontawesome/webfonts/fa-solid-900.woff +0 -0
- package/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
- package/help.pdf +0 -0
- package/index.js +0 -83
- package/js/Genoverse.js +0 -1681
- package/js/Track/Controller/Stranded.js +0 -73
- package/js/Track/Model/File/BAM.js +0 -44
- package/js/Track/Model/File/BED.js +0 -116
- package/js/Track/Model/File/GFF.js +0 -40
- package/js/Track/Model/File/VCF.js +0 -101
- package/js/Track/Model/File/WIG.js +0 -67
- package/js/Track/Model/File.js +0 -36
- package/js/Track/Model/Gene/Ensembl.js +0 -22
- package/js/Track/Model/Sequence/Ensembl.js +0 -4
- package/js/Track/Model/Transcript/Ensembl.js +0 -67
- package/js/Track/View/Gene.js +0 -6
- package/js/Track/View/Sequence/Variation.js +0 -115
- package/js/Track/View/Transcript/Ensembl.js +0 -12
- package/js/Track/View/Transcript.js +0 -28
- package/js/Track/library/File/BAM.js +0 -30
- package/js/Track/library/File/BED.js +0 -24
- package/js/Track/library/File/BIGBED.js +0 -47
- package/js/Track/library/File/BIGWIG.js +0 -52
- package/js/Track/library/File/GFF.js +0 -9
- package/js/Track/library/File/WIG.js +0 -5
- package/js/Track/library/Gene.js +0 -37
- package/js/Track/library/Graph/Bar.js +0 -235
- package/js/Track/library/Graph/Line.js +0 -296
- package/js/Track/library/Legend.js +0 -224
- package/js/Track/library/Static.js +0 -78
- package/js/Track.js +0 -632
- package/js/genoverse.min.js +0 -2
- package/js/genoverse.min.js.map +0 -1
- package/js/lib/BWReader.js +0 -578
- package/js/lib/Base.js +0 -145
- package/js/lib/VCFReader.js +0 -286
- package/js/lib/dalliance/js/bam.js +0 -494
- package/js/lib/dalliance/js/bin.js +0 -185
- package/js/lib/dalliance/js/das.js +0 -749
- package/js/lib/dalliance/js/utils.js +0 -370
- package/js/lib/dalliance-lib.js +0 -3594
- package/js/lib/dalliance-lib.min.js +0 -68
- package/js/lib/jDataView.js +0 -2
- package/js/lib/jParser.js +0 -192
- package/js/lib/jquery-ui.js +0 -8
- package/js/lib/jquery.js +0 -2
- package/js/lib/rtree.js +0 -1
- package/js/plugins/controlPanel.js +0 -395
- package/js/plugins/fileDrop.js +0 -62
- package/js/plugins/focusRegion.js +0 -12
- package/js/plugins/resizer.js +0 -45
- package/js/plugins/trackControls.js +0 -143
- package/utils/expandedTemplate.html +0 -46
- package/utils/git-hooks/post-commit +0 -9
- package/utils/git-hooks/pre-commit +0 -7
- package/utils/git-hooks/setup +0 -6
- package/utils/makeExpanded.js +0 -19
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import Base from 'basejs';
|
|
2
|
+
import RTree from 'rtree';
|
|
3
|
+
import wrapFunctions from '../lib/wrap-functions';
|
|
4
|
+
|
|
5
|
+
export default Base.extend({
|
|
2
6
|
fontHeight : 10,
|
|
3
7
|
fontFamily : 'sans-serif',
|
|
4
8
|
fontWeight : 'normal',
|
|
@@ -19,8 +23,15 @@ Genoverse.Track.View = Base.extend({
|
|
|
19
23
|
subFeatureJoinLineWidth : 0.5,
|
|
20
24
|
|
|
21
25
|
constructor: function (properties) {
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
Object.entries(properties).forEach(
|
|
27
|
+
([ key, val ]) => {
|
|
28
|
+
if (typeof val !== 'undefined') {
|
|
29
|
+
this[key] = val;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
wrapFunctions(this, 'View');
|
|
24
35
|
this.init();
|
|
25
36
|
},
|
|
26
37
|
|
|
@@ -33,17 +44,17 @@ Genoverse.Track.View = Base.extend({
|
|
|
33
44
|
setDefaults: function () {
|
|
34
45
|
this.featureMargin = this.featureMargin || { top: 3, right: 1, bottom: 1, left: 0 };
|
|
35
46
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
[ 'top', 'right', 'bottom', 'left' ].forEach(
|
|
48
|
+
(margin) => {
|
|
49
|
+
if (typeof this.featureMargin[margin] !== 'number') {
|
|
50
|
+
this.featureMargin[margin] = 0;
|
|
51
|
+
}
|
|
41
52
|
}
|
|
42
|
-
|
|
53
|
+
);
|
|
43
54
|
|
|
44
|
-
this.context =
|
|
55
|
+
this.context = this.browser.jQuery('<canvas>')[0].getContext('2d');
|
|
45
56
|
this.featureHeight = typeof this.featureHeight !== 'undefined' ? this.featureHeight : this.prop('defaultHeight');
|
|
46
|
-
this.font = this.fontWeight
|
|
57
|
+
this.font = `${this.fontWeight} ${this.fontHeight}px ${this.fontFamily}`;
|
|
47
58
|
this.labelUnits = [ 'bp', 'kb', 'Mb', 'Gb', 'Tb' ];
|
|
48
59
|
|
|
49
60
|
this.context.font = this.font;
|
|
@@ -54,19 +65,19 @@ Genoverse.Track.View = Base.extend({
|
|
|
54
65
|
},
|
|
55
66
|
|
|
56
67
|
setScaleSettings: function (scale) {
|
|
57
|
-
|
|
68
|
+
const chr = this.browser.chr;
|
|
58
69
|
|
|
59
70
|
if (!this.scaleSettings[chr]) {
|
|
60
71
|
this.scaleSettings[chr] = {};
|
|
61
72
|
}
|
|
62
73
|
|
|
63
74
|
if (!this.scaleSettings[chr][scale]) {
|
|
64
|
-
|
|
75
|
+
const featurePositions = new RTree();
|
|
65
76
|
|
|
66
77
|
this.scaleSettings[chr][scale] = {
|
|
67
|
-
imgContainers :
|
|
78
|
+
imgContainers : this.browser.jQuery(),
|
|
68
79
|
featurePositions : featurePositions,
|
|
69
|
-
labelPositions : this.labels === 'separate' ? new RTree() : featurePositions
|
|
80
|
+
labelPositions : this.labels === 'separate' ? new RTree() : featurePositions,
|
|
70
81
|
};
|
|
71
82
|
}
|
|
72
83
|
|
|
@@ -82,34 +93,35 @@ Genoverse.Track.View = Base.extend({
|
|
|
82
93
|
},
|
|
83
94
|
|
|
84
95
|
scaleFeatures: function (features, scale) {
|
|
85
|
-
|
|
86
|
-
var feature, j;
|
|
96
|
+
const add = this.roundPixelValue(Math.max(scale, this.widthCorrection));
|
|
87
97
|
|
|
88
|
-
|
|
89
|
-
feature
|
|
98
|
+
features.forEach(
|
|
99
|
+
(feature) => {
|
|
100
|
+
if (!feature.position) {
|
|
101
|
+
feature.position = {};
|
|
102
|
+
}
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
104
|
+
if (!feature.position[scale]) {
|
|
105
|
+
feature.position[scale] = {
|
|
106
|
+
start : this.roundPixelValue(feature.start * scale),
|
|
107
|
+
width : Math.max(this.roundPixelValue((feature.end - feature.start) * scale + add), this.minScaledWidth),
|
|
108
|
+
height : feature.height || this.featureHeight,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
94
111
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
112
|
+
if (feature.subFeatures) {
|
|
113
|
+
feature.subFeatures.forEach(
|
|
114
|
+
(subFeature) => {
|
|
115
|
+
if (typeof subFeature.height === 'undefined') {
|
|
116
|
+
subFeature.height = feature.position[scale].height;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
);
|
|
102
120
|
|
|
103
|
-
|
|
104
|
-
for (j = 0; j < feature.subFeatures.length; j++) {
|
|
105
|
-
if (typeof feature.subFeatures[j].height === 'undefined') {
|
|
106
|
-
feature.subFeatures[j].height = feature.position[scale].height;
|
|
107
|
-
}
|
|
121
|
+
this.scaleFeatures(feature.subFeatures, scale);
|
|
108
122
|
}
|
|
109
|
-
|
|
110
|
-
this.scaleFeatures(feature.subFeatures, scale);
|
|
111
123
|
}
|
|
112
|
-
|
|
124
|
+
);
|
|
113
125
|
|
|
114
126
|
return features;
|
|
115
127
|
},
|
|
@@ -117,9 +129,9 @@ Genoverse.Track.View = Base.extend({
|
|
|
117
129
|
positionFeatures: function (features, params) {
|
|
118
130
|
params.margin = this.prop('margin');
|
|
119
131
|
|
|
120
|
-
|
|
121
|
-
this.positionFeature(
|
|
122
|
-
|
|
132
|
+
features.forEach(
|
|
133
|
+
feature => this.positionFeature(feature, params)
|
|
134
|
+
);
|
|
123
135
|
|
|
124
136
|
params.width = Math.ceil(params.width);
|
|
125
137
|
params.height = Math.ceil(params.height);
|
|
@@ -130,33 +142,34 @@ Genoverse.Track.View = Base.extend({
|
|
|
130
142
|
},
|
|
131
143
|
|
|
132
144
|
positionFeature: function (feature, params) {
|
|
133
|
-
|
|
134
|
-
|
|
145
|
+
const scale = params.scale;
|
|
146
|
+
const scaleSettings = this.scaleSettings[feature.chr][scale];
|
|
135
147
|
|
|
136
148
|
if (!scaleSettings) {
|
|
137
149
|
return;
|
|
138
150
|
}
|
|
139
151
|
|
|
140
|
-
|
|
141
|
-
var i;
|
|
152
|
+
const subFeatures = feature.subFeatures || [];
|
|
142
153
|
|
|
143
154
|
feature.position[scale].X = feature.position[scale].start - params.scaledStart; // FIXME: always have to reposition for X, in case a feature appears in 2 images. Pass scaledStart around instead?
|
|
144
155
|
|
|
145
|
-
|
|
146
|
-
|
|
156
|
+
subFeatures.forEach(
|
|
157
|
+
(subFeature) => {
|
|
158
|
+
subFeature.position[scale].x = subFeature.position[scale].start - params.scaledStart;
|
|
147
159
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
160
|
+
if (this.subFeatureJoinStyle) {
|
|
161
|
+
subFeature.position[scale].join = subFeature.position[scale].join || {};
|
|
162
|
+
subFeature.position[scale].join.x = subFeature.position[scale].start + subFeature.position[scale].width - params.scaledStart;
|
|
163
|
+
}
|
|
151
164
|
}
|
|
152
|
-
|
|
165
|
+
);
|
|
153
166
|
|
|
154
167
|
if (this.alwaysReposition || !feature.position[scale].positioned) {
|
|
155
168
|
feature.position[scale].H = feature.position[scale].height + this.featureMargin.bottom;
|
|
156
169
|
feature.position[scale].W = feature.position[scale].width + (feature.marginRight || this.featureMargin.right);
|
|
157
170
|
feature.position[scale].Y = (
|
|
158
171
|
typeof feature.position[scale].y === 'number' ? feature.position[scale].y :
|
|
159
|
-
typeof feature.y
|
|
172
|
+
typeof feature.y === 'number' ? feature.y * feature.position[scale].H : 0
|
|
160
173
|
) + (feature.marginTop || this.featureMargin.top);
|
|
161
174
|
|
|
162
175
|
if (feature.label) {
|
|
@@ -164,10 +177,10 @@ Genoverse.Track.View = Base.extend({
|
|
|
164
177
|
feature.label = feature.label.split('\n');
|
|
165
178
|
}
|
|
166
179
|
|
|
167
|
-
|
|
180
|
+
const context = this.context;
|
|
168
181
|
|
|
169
182
|
feature.labelHeight = feature.labelHeight || (this.fontHeight + 2) * feature.label.length;
|
|
170
|
-
feature.labelWidth = feature.labelWidth || Math.max
|
|
183
|
+
feature.labelWidth = feature.labelWidth || Math.max(...feature.label.map(l => Math.ceil(context.measureText(l).width))) + 1;
|
|
171
184
|
|
|
172
185
|
if (this.labels === true) {
|
|
173
186
|
feature.position[scale].H += feature.labelHeight;
|
|
@@ -177,16 +190,16 @@ Genoverse.Track.View = Base.extend({
|
|
|
177
190
|
x : feature.position[scale].start,
|
|
178
191
|
y : feature.position[scale].Y,
|
|
179
192
|
w : feature.labelWidth,
|
|
180
|
-
h : feature.labelHeight
|
|
193
|
+
h : feature.labelHeight,
|
|
181
194
|
};
|
|
182
195
|
}
|
|
183
196
|
}
|
|
184
197
|
|
|
185
|
-
|
|
198
|
+
const bounds = {
|
|
186
199
|
x : feature.position[scale].start,
|
|
187
200
|
y : feature.position[scale].Y,
|
|
188
201
|
w : feature.position[scale].W,
|
|
189
|
-
h : feature.position[scale].H + (feature.marginTop || this.featureMargin.top)
|
|
202
|
+
h : feature.position[scale].H + (feature.marginTop || this.featureMargin.top),
|
|
190
203
|
};
|
|
191
204
|
|
|
192
205
|
feature.position[scale].bounds = bounds;
|
|
@@ -201,18 +214,24 @@ Genoverse.Track.View = Base.extend({
|
|
|
201
214
|
feature.position[scale].positioned = true;
|
|
202
215
|
}
|
|
203
216
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
217
|
+
const join = (
|
|
218
|
+
this.subFeatureJoinStyle && subFeatures.length
|
|
219
|
+
? {
|
|
220
|
+
height : (Math.max(...subFeatures.map(c => (c.fake ? 0 : c.position[scale].height))) / 2) * (feature.strand > 0 ? -1 : 1),
|
|
221
|
+
y : feature.position[scale].Y + feature.position[scale].height / 2,
|
|
222
|
+
}
|
|
223
|
+
: false
|
|
224
|
+
);
|
|
208
225
|
|
|
209
|
-
|
|
210
|
-
|
|
226
|
+
subFeatures.forEach(
|
|
227
|
+
(subFeature, i) => {
|
|
228
|
+
subFeature.position[scale].y = feature.position[scale].Y + (feature.position[scale].height - subFeature.position[scale].height) / 2;
|
|
211
229
|
|
|
212
|
-
|
|
213
|
-
|
|
230
|
+
if (join && subFeatures[i + 1]) {
|
|
231
|
+
Object.assign(subFeature.position[scale].join, { width: subFeatures[i + 1].position[scale].x - subFeature.position[scale].join.x, ...join });
|
|
232
|
+
}
|
|
214
233
|
}
|
|
215
|
-
|
|
234
|
+
);
|
|
216
235
|
|
|
217
236
|
if (this.labels === 'separate' && feature.position[scale].label) {
|
|
218
237
|
if (this.alwaysReposition || !feature.position[scale].label.positioned) {
|
|
@@ -233,20 +252,23 @@ Genoverse.Track.View = Base.extend({
|
|
|
233
252
|
|
|
234
253
|
// FIXME: should label bumping bounds be distinct from feature bumping bounds when label is smaller than feature?
|
|
235
254
|
bumpFeature: function (bounds, feature, scale, tree) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
255
|
+
const scaleSettings = this.scaleSettings[feature.chr][scale];
|
|
256
|
+
const labels = tree === scaleSettings.labelPositions && tree !== scaleSettings.featurePositions;
|
|
257
|
+
|
|
258
|
+
let bump = true;
|
|
259
|
+
let depth = 0;
|
|
240
260
|
|
|
241
|
-
|
|
261
|
+
while (bump) {
|
|
242
262
|
if (this.depth && ++depth >= this.depth) {
|
|
243
263
|
if (!labels) {
|
|
244
|
-
searchResults = scaleSettings.featurePositions.search(bounds);
|
|
245
|
-
|
|
264
|
+
const searchResults = scaleSettings.featurePositions.search(bounds);
|
|
265
|
+
|
|
266
|
+
let i = searchResults.length;
|
|
246
267
|
|
|
247
268
|
while (i--) {
|
|
248
269
|
if (searchResults[i].position[scale].visible !== false) {
|
|
249
270
|
feature.position[scale].visible = false;
|
|
271
|
+
|
|
250
272
|
break;
|
|
251
273
|
}
|
|
252
274
|
}
|
|
@@ -255,14 +277,14 @@ Genoverse.Track.View = Base.extend({
|
|
|
255
277
|
break;
|
|
256
278
|
}
|
|
257
279
|
|
|
258
|
-
|
|
259
|
-
clash = tree.search(bounds)[0];
|
|
280
|
+
const clash = tree.search(bounds)[0];
|
|
260
281
|
|
|
261
282
|
if (clash && clash.id !== feature.id) {
|
|
262
283
|
bounds.y = clash.position[scale][labels ? 'label' : 'bounds'].y + clash.position[scale][labels ? 'label' : 'bounds'].h;
|
|
263
|
-
|
|
284
|
+
} else {
|
|
285
|
+
bump = false;
|
|
264
286
|
}
|
|
265
|
-
}
|
|
287
|
+
}
|
|
266
288
|
|
|
267
289
|
if (!labels) {
|
|
268
290
|
feature.position[scale].Y = bounds.y;
|
|
@@ -270,29 +292,28 @@ Genoverse.Track.View = Base.extend({
|
|
|
270
292
|
},
|
|
271
293
|
|
|
272
294
|
draw: function (features, featureContext, labelContext, scale) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
feature.legendColor = f.color;
|
|
295
|
+
features.forEach(
|
|
296
|
+
(feature) => {
|
|
297
|
+
if (feature.position[scale].visible !== false) {
|
|
298
|
+
// TODO: extend with feature.position[scale], rationalize keys
|
|
299
|
+
const f = {
|
|
300
|
+
...feature,
|
|
301
|
+
x : feature.position[scale].X,
|
|
302
|
+
y : feature.position[scale].Y,
|
|
303
|
+
width : feature.position[scale].width,
|
|
304
|
+
height : feature.position[scale].height,
|
|
305
|
+
labelPosition : feature.position[scale].label,
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
this.drawFeature(f, featureContext, labelContext, scale);
|
|
309
|
+
|
|
310
|
+
if (f.legend !== feature.legend) {
|
|
311
|
+
feature.legend = f.legend;
|
|
312
|
+
feature.legendColor = f.color;
|
|
313
|
+
}
|
|
293
314
|
}
|
|
294
315
|
}
|
|
295
|
-
|
|
316
|
+
);
|
|
296
317
|
},
|
|
297
318
|
|
|
298
319
|
drawFeature: function (feature, featureContext, labelContext, scale) {
|
|
@@ -332,24 +353,26 @@ Genoverse.Track.View = Base.extend({
|
|
|
332
353
|
},
|
|
333
354
|
|
|
334
355
|
drawSubFeatures: function (feature, featureContext, labelContext, scale) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
356
|
+
const clonedFeature = this.browser.jQuery.extend(true, {}, feature, { subFeatures: false, label: false });
|
|
357
|
+
const subFeatures = this.browser.jQuery.extend(true, [], feature.subFeatures);
|
|
358
|
+
const joinColor = feature.joinColor || feature.color;
|
|
359
|
+
|
|
360
|
+
subFeatures.forEach(
|
|
361
|
+
(subFeature) => {
|
|
362
|
+
if (!subFeature.fake) {
|
|
363
|
+
this.drawFeature({ ...clonedFeature, ...subFeature.position[scale], ...subFeature }, featureContext, labelContext, scale);
|
|
364
|
+
}
|
|
343
365
|
|
|
344
|
-
|
|
345
|
-
|
|
366
|
+
if (subFeature.position[scale].join && subFeature.position[scale].join.width > 0) {
|
|
367
|
+
this.drawSubFeatureJoin({ color: joinColor, ...subFeature.position[scale].join }, featureContext);
|
|
368
|
+
}
|
|
346
369
|
}
|
|
347
|
-
|
|
370
|
+
);
|
|
348
371
|
},
|
|
349
372
|
|
|
350
373
|
drawLabel: function (feature, context, scale) {
|
|
351
|
-
|
|
352
|
-
|
|
374
|
+
const original = feature.untruncated;
|
|
375
|
+
const width = (original || feature).width;
|
|
353
376
|
|
|
354
377
|
if (this.labels === 'overlay' && feature.labelWidth >= Math.floor(width)) {
|
|
355
378
|
return;
|
|
@@ -363,14 +386,17 @@ Genoverse.Track.View = Base.extend({
|
|
|
363
386
|
feature.label = [ feature.label ];
|
|
364
387
|
}
|
|
365
388
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
389
|
+
const x = (original || feature).x;
|
|
390
|
+
|
|
391
|
+
let n = this.repeatLabels ? Math.ceil((width - Math.max(scale, 1) - (this.labels === 'overlay' ? feature.labelWidth : 0)) / this.width) || 1 : 1;
|
|
392
|
+
let spacing = width / n;
|
|
393
|
+
let label;
|
|
394
|
+
let y;
|
|
395
|
+
let h;
|
|
370
396
|
|
|
371
397
|
if (this.repeatLabels && (scale > 1 || this.labels !== 'overlay')) { // Ensure there's always a label in each image
|
|
372
398
|
spacing = this.browser.length * scale;
|
|
373
|
-
n
|
|
399
|
+
n = Math.ceil(width / spacing);
|
|
374
400
|
}
|
|
375
401
|
|
|
376
402
|
if (!feature.labelColor) {
|
|
@@ -389,35 +415,39 @@ Genoverse.Track.View = Base.extend({
|
|
|
389
415
|
h = this.fontHeight + 2;
|
|
390
416
|
}
|
|
391
417
|
|
|
392
|
-
|
|
393
|
-
|
|
418
|
+
let i = context.textAlign === 'center' ? 0.5 : 0;
|
|
419
|
+
|
|
420
|
+
const offset = feature.labelWidth * i;
|
|
394
421
|
|
|
395
422
|
if (n > 1) {
|
|
396
423
|
i += Math.max(Math.floor(-(feature.labelWidth + x) / spacing), 0);
|
|
397
424
|
}
|
|
398
425
|
|
|
399
426
|
for (; i < n; i++) {
|
|
400
|
-
start = x + (i * spacing);
|
|
427
|
+
const start = x + (i * spacing);
|
|
401
428
|
|
|
402
429
|
if (start + feature.labelWidth >= 0) {
|
|
403
430
|
if ((start - offset > this.width) || (i >= 1 && start + feature.labelWidth > feature.position[scale].X + feature.position[scale].width)) {
|
|
404
431
|
break;
|
|
405
432
|
}
|
|
406
433
|
|
|
407
|
-
|
|
408
|
-
|
|
434
|
+
label.forEach(
|
|
435
|
+
(line, j) => {
|
|
436
|
+
const currentY = y + (j * h);
|
|
409
437
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
438
|
+
if (context.labelPositions && context.labelPositions.search({ x: start, y: currentY, w: feature.labelWidth, h: h }).length) {
|
|
439
|
+
feature.position[scale].label.visible = false;
|
|
414
440
|
|
|
415
|
-
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
context.fillText(line, start, currentY);
|
|
416
445
|
|
|
417
|
-
|
|
418
|
-
|
|
446
|
+
if (context.labelPositions) {
|
|
447
|
+
context.labelPositions.insert({ x: start, y: currentY, w: feature.labelWidth, h: h }, line);
|
|
448
|
+
}
|
|
419
449
|
}
|
|
420
|
-
|
|
450
|
+
);
|
|
421
451
|
}
|
|
422
452
|
}
|
|
423
453
|
},
|
|
@@ -432,23 +462,24 @@ Genoverse.Track.View = Base.extend({
|
|
|
432
462
|
|
|
433
463
|
// Method to lighten a color by an amount, adapted from https://stackoverflow.com/questions/5560248/programmatically-lighten-or-darken-a-hex-color-or-rgb-and-blend-colors
|
|
434
464
|
shadeColor: function (color, percent) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
465
|
+
const f = parseInt(color.slice(1), 16);
|
|
466
|
+
const R = f >> 16;
|
|
467
|
+
const G = (f >> 8) & 0x00FF;
|
|
468
|
+
const B = f & 0x0000FF;
|
|
439
469
|
|
|
440
|
-
return
|
|
470
|
+
return `#${(
|
|
441
471
|
0x1000000 +
|
|
442
472
|
(Math.round((255 - R) * percent) + R) * 0x10000 +
|
|
443
473
|
(Math.round((255 - G) * percent) + G) * 0x100 +
|
|
444
474
|
(Math.round((255 - B) * percent) + B)
|
|
445
|
-
).toString(16).slice(1)
|
|
475
|
+
).toString(16).slice(1)}`;
|
|
446
476
|
},
|
|
447
477
|
|
|
448
478
|
// truncate features - make the features start at 1px outside the canvas to ensure no lines are drawn at the borders incorrectly
|
|
449
479
|
truncateForDrawing: function (feature) {
|
|
450
|
-
|
|
451
|
-
|
|
480
|
+
const start = Math.min(Math.max(feature.x, -1), this.width + 1);
|
|
481
|
+
|
|
482
|
+
let width = feature.x - start + feature.width;
|
|
452
483
|
|
|
453
484
|
if (width + start > this.width) {
|
|
454
485
|
width = this.width - start + 1;
|
|
@@ -460,13 +491,13 @@ Genoverse.Track.View = Base.extend({
|
|
|
460
491
|
},
|
|
461
492
|
|
|
462
493
|
drawSubFeatureJoin: function (join, context) {
|
|
463
|
-
|
|
494
|
+
const coords = this.truncateSubFeatureJoinForDrawing(join);
|
|
464
495
|
|
|
465
496
|
if (!coords) {
|
|
466
497
|
return;
|
|
467
498
|
}
|
|
468
499
|
|
|
469
|
-
|
|
500
|
+
const lineWidth = context.lineWidth;
|
|
470
501
|
|
|
471
502
|
context.strokeStyle = join.color;
|
|
472
503
|
context.lineWidth = this.subFeatureJoinLineWidth;
|
|
@@ -477,13 +508,16 @@ Genoverse.Track.View = Base.extend({
|
|
|
477
508
|
switch (this.subFeatureJoinStyle) {
|
|
478
509
|
case 'line':
|
|
479
510
|
context.lineTo(coords.x3, coords.y1);
|
|
511
|
+
|
|
480
512
|
break;
|
|
481
513
|
case 'peak':
|
|
482
514
|
context.lineTo(coords.x2, coords.y2);
|
|
483
515
|
context.lineTo(coords.x3, coords.y3);
|
|
516
|
+
|
|
484
517
|
break;
|
|
485
518
|
case 'curve':
|
|
486
519
|
context.quadraticCurveTo(coords.x2, coords.y2, coords.x3, coords.y3);
|
|
520
|
+
|
|
487
521
|
break;
|
|
488
522
|
default: break;
|
|
489
523
|
}
|
|
@@ -494,30 +528,33 @@ Genoverse.Track.View = Base.extend({
|
|
|
494
528
|
},
|
|
495
529
|
|
|
496
530
|
truncateSubFeatureJoinForDrawing: function (coords) {
|
|
497
|
-
|
|
498
|
-
|
|
531
|
+
let y1 = coords.y; // y coord of the ends of the line (half way down the exon box)
|
|
532
|
+
let y3 = y1;
|
|
499
533
|
|
|
500
534
|
if (this.subFeatureJoinStyle === 'line') {
|
|
501
535
|
this.truncateForDrawing(coords);
|
|
502
536
|
y1 += 0.5; // Sharpen line
|
|
503
537
|
}
|
|
504
538
|
|
|
505
|
-
|
|
506
|
-
|
|
539
|
+
let x1 = coords.x; // x coord of the right edge of the first exon
|
|
540
|
+
let x3 = coords.x + coords.width; // x coord of the left edge of the second exon
|
|
507
541
|
|
|
508
542
|
// Skip if completely outside the image's region
|
|
509
543
|
if (x3 < 0 || x1 > this.width) {
|
|
510
544
|
return false;
|
|
511
545
|
}
|
|
512
546
|
|
|
513
|
-
|
|
547
|
+
let x2;
|
|
548
|
+
let y2;
|
|
514
549
|
|
|
515
550
|
// Truncate the coordinates of the line being drawn, so it is inside the image's region
|
|
516
551
|
if (this.subFeatureJoinStyle === 'peak') {
|
|
517
|
-
xMid
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
552
|
+
const xMid = (x1 + x3) / 2;
|
|
553
|
+
|
|
554
|
+
x2 = xMid; // x coord of the peak of the peak/curve
|
|
555
|
+
y2 = coords.y + coords.height; // y coord of the peak of the peak/curve (level with the top (forward strand) or bottom (reverse strand) of the exon box)
|
|
556
|
+
|
|
557
|
+
const yScale = (y2 - y1) / (xMid - x1); // Scale factor for recalculating coords if points lie outside the image region
|
|
521
558
|
|
|
522
559
|
if (xMid < 0) {
|
|
523
560
|
y2 = coords.y + (yScale * x3);
|
|
@@ -543,24 +580,28 @@ Genoverse.Track.View = Base.extend({
|
|
|
543
580
|
}
|
|
544
581
|
|
|
545
582
|
return {
|
|
546
|
-
x1
|
|
547
|
-
y1
|
|
548
|
-
x2
|
|
549
|
-
y2
|
|
550
|
-
x3
|
|
551
|
-
y3
|
|
583
|
+
x1,
|
|
584
|
+
y1,
|
|
585
|
+
x2,
|
|
586
|
+
y2,
|
|
587
|
+
x3,
|
|
588
|
+
y3,
|
|
552
589
|
};
|
|
553
590
|
},
|
|
554
591
|
|
|
555
592
|
formatLabel: function (label) {
|
|
556
|
-
|
|
557
|
-
|
|
593
|
+
const power = Math.floor((label.toString().length - 1) / 3);
|
|
594
|
+
const unit = this.labelUnits[power];
|
|
558
595
|
|
|
559
|
-
label /=
|
|
596
|
+
label /= 10 ** (power * 3);
|
|
560
597
|
|
|
561
|
-
return Math.floor(label)
|
|
598
|
+
return `${Math.floor(label)}${(unit === 'bp' ? '' : `.${(label.toString().split('.')[1] || '').concat('00').substring(0, 2)}`)} ${unit}`;
|
|
562
599
|
},
|
|
563
600
|
|
|
564
|
-
drawBackground :
|
|
565
|
-
decorateFeature :
|
|
601
|
+
drawBackground : () => {},
|
|
602
|
+
decorateFeature : () => {}, // decoration for the features
|
|
603
|
+
|
|
604
|
+
destroy: function () {
|
|
605
|
+
delete this.scaleSettings;
|
|
606
|
+
},
|
|
566
607
|
});
|