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.
- package/.eslintrc.js +197 -0
- package/.github/workflows/test.yml +24 -0
- package/LICENSE.TXT +24 -0
- package/README.md +11 -0
- package/css/controlPanel.css +200 -0
- package/css/fileDrop.css +22 -0
- package/css/font-awesome.css +3 -0
- package/css/fullscreen.css +19 -0
- package/css/genoverse.css +466 -0
- package/css/karyotype.css +85 -0
- package/css/resizer.css +36 -0
- package/css/tooltips.css +26 -0
- package/css/trackControls.css +111 -0
- package/expanded.html +120 -0
- package/fontawesome/css/fontawesome.min.css +5 -0
- package/fontawesome/css/regular.min.css +5 -0
- package/fontawesome/css/solid.min.css +5 -0
- 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/i/sort_handle.png +0 -0
- package/index.html +68 -0
- package/index.js +83 -0
- package/jest.config.js +4 -0
- package/js/Genoverse.js +1681 -0
- package/js/Track/Controller/Sequence.js +17 -0
- package/js/Track/Controller/Stranded.js +73 -0
- package/js/Track/Controller.js +620 -0
- package/js/Track/Model/File/BAM.js +44 -0
- package/js/Track/Model/File/BED.js +116 -0
- package/js/Track/Model/File/GFF.js +40 -0
- package/js/Track/Model/File/VCF.js +101 -0
- package/js/Track/Model/File/WIG.js +67 -0
- package/js/Track/Model/File.js +36 -0
- package/js/Track/Model/Gene/Ensembl.js +22 -0
- package/js/Track/Model/Gene.js +5 -0
- package/js/Track/Model/Sequence/Ensembl.js +4 -0
- package/js/Track/Model/Sequence/Fasta.js +60 -0
- package/js/Track/Model/Sequence.js +50 -0
- package/js/Track/Model/SequenceVariation.js +41 -0
- package/js/Track/Model/Stranded.js +28 -0
- package/js/Track/Model/Transcript/Ensembl.js +67 -0
- package/js/Track/Model/Transcript.js +5 -0
- package/js/Track/Model.js +303 -0
- package/js/Track/View/Gene/Ensembl.js +46 -0
- package/js/Track/View/Gene.js +6 -0
- package/js/Track/View/Sequence/Variation.js +115 -0
- package/js/Track/View/Sequence.js +63 -0
- package/js/Track/View/Transcript/Ensembl.js +12 -0
- package/js/Track/View/Transcript.js +28 -0
- package/js/Track/View.js +566 -0
- package/js/Track/library/Chromosome.js +145 -0
- package/js/Track/library/File/BAM.js +30 -0
- package/js/Track/library/File/BED.js +24 -0
- package/js/Track/library/File/BIGBED.js +47 -0
- package/js/Track/library/File/BIGWIG.js +52 -0
- package/js/Track/library/File/GFF.js +9 -0
- package/js/Track/library/File/VCF.js +71 -0
- package/js/Track/library/File/WIG.js +5 -0
- package/js/Track/library/File.js +10 -0
- package/js/Track/library/Gene.js +37 -0
- package/js/Track/library/Graph/Bar.js +235 -0
- package/js/Track/library/Graph/Line.js +296 -0
- package/js/Track/library/Graph.js +355 -0
- package/js/Track/library/HighlightRegion.js +292 -0
- package/js/Track/library/Legend.js +224 -0
- package/js/Track/library/Scalebar.js +227 -0
- package/js/Track/library/Scaleline.js +91 -0
- package/js/Track/library/Static.js +78 -0
- package/js/Track/library/dbSNP.js +142 -0
- package/js/Track.js +632 -0
- package/js/genomes/grch37.js +990 -0
- package/js/genomes/grch38.js +990 -0
- package/js/genoverse.min.js +2 -0
- package/js/genoverse.min.js.map +1 -0
- package/js/lib/BWReader.js +578 -0
- package/js/lib/Base.js +145 -0
- package/js/lib/VCFReader.js +286 -0
- package/js/lib/dalliance/js/bam.js +494 -0
- package/js/lib/dalliance/js/bin.js +185 -0
- package/js/lib/dalliance/js/das.js +749 -0
- package/js/lib/dalliance/js/utils.js +370 -0
- package/js/lib/dalliance-lib.js +3594 -0
- package/js/lib/dalliance-lib.min.js +68 -0
- package/js/lib/jDataView.js +2 -0
- package/js/lib/jParser.js +192 -0
- package/js/lib/jquery-ui.js +8 -0
- package/js/lib/jquery.js +2 -0
- package/js/lib/jquery.mousehold.js +53 -0
- package/js/lib/jquery.mousewheel.js +84 -0
- package/js/lib/jquery.tipsy.js +258 -0
- package/js/lib/rtree.js +1 -0
- package/js/plugins/controlPanel.js +395 -0
- package/js/plugins/fileDrop.js +62 -0
- package/js/plugins/focusRegion.js +12 -0
- package/js/plugins/fullscreen.js +77 -0
- package/js/plugins/karyotype.js +210 -0
- package/js/plugins/resizer.js +45 -0
- package/js/plugins/tooltips.js +94 -0
- package/js/plugins/trackControls.js +143 -0
- package/package.json +43 -0
- package/test/View/__snapshots__/render-bar-graph.test.js.snap +111 -0
- package/test/View/__snapshots__/render-blocks.test.js.snap +105 -0
- package/test/View/__snapshots__/render-chromosome.test.js.snap +5 -0
- package/test/View/__snapshots__/render-highlights.test.js.snap +73 -0
- package/test/View/__snapshots__/render-insert-variants.test.js.snap +9 -0
- package/test/View/__snapshots__/render-labels.test.js.snap +241 -0
- package/test/View/__snapshots__/render-legends.test.js.snap +13 -0
- package/test/View/__snapshots__/render-line-graph.test.js.snap +349 -0
- package/test/View/__snapshots__/render-scalebar.test.js.snap +49 -0
- package/test/View/__snapshots__/render-scaleline.test.js.snap +31 -0
- package/test/View/__snapshots__/render-sequence.test.js.snap +23 -0
- package/test/View/__snapshots__/render-stranded.test.js.snap +5 -0
- package/test/View/__snapshots__/render-transcripts.test.js.snap +193 -0
- package/test/View/render-bar-graph.test.js +87 -0
- package/test/View/render-blocks.test.js +171 -0
- package/test/View/render-chromosome.test.js +40 -0
- package/test/View/render-highlights.test.js +67 -0
- package/test/View/render-insert-variants.test.js +11 -0
- package/test/View/render-labels.test.js +266 -0
- package/test/View/render-legends.test.js +31 -0
- package/test/View/render-line-graph.test.js +169 -0
- package/test/View/render-scalebar.test.js +36 -0
- package/test/View/render-scaleline.test.js +28 -0
- package/test/View/render-sequence.test.js +49 -0
- package/test/View/render-stranded.test.js +10 -0
- package/test/View/render-transcripts.test.js +165 -0
- package/test/create-and-destroy.test.js +63 -0
- package/test/track-ordering.test.js +514 -0
- package/test/track_config/__snapshots__/config-settings.test.js.snap +23 -0
- package/test/track_config/config-settings.test.js +321 -0
- package/test/track_config/zoom-level-settings.test.js +98 -0
- package/test/utils.js +80 -0
- package/utils/createGenome.js +52 -0
- package/utils/devServer.js +36 -0
- package/utils/expandedTemplate.html +46 -0
- package/utils/git-hooks/post-commit +9 -0
- package/utils/git-hooks/pre-commit +7 -0
- package/utils/git-hooks/setup +6 -0
- package/utils/makeExpanded.js +19 -0
- package/webpack.config.js +39 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/* -*- mode: javascript; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
|
|
3
|
+
//
|
|
4
|
+
// Dalliance Genome Explorer
|
|
5
|
+
// (c) Thomas Down 2006-2011
|
|
6
|
+
//
|
|
7
|
+
// bam.js: indexed binary alignments
|
|
8
|
+
//
|
|
9
|
+
var BAM_MAGIC = 21840194;
|
|
10
|
+
var BAI_MAGIC = 21578050;
|
|
11
|
+
|
|
12
|
+
function BamFile() {}
|
|
13
|
+
|
|
14
|
+
function Vob(b, o) {
|
|
15
|
+
this.block = b;
|
|
16
|
+
this.offset = o;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
Vob.prototype.toString = function() {
|
|
20
|
+
return '' + this.block + ':' + this.offset;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function Chunk(minv, maxv) {
|
|
24
|
+
this.minv = minv;
|
|
25
|
+
this.maxv = maxv;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function makeBam(data, bai, callback) {
|
|
29
|
+
var bam = new BamFile();
|
|
30
|
+
bam.data = data;
|
|
31
|
+
bam.bai = bai;
|
|
32
|
+
|
|
33
|
+
bam.data.slice(0, 65536).fetch(function(r) {
|
|
34
|
+
if (!r) {
|
|
35
|
+
return dlog("Couldn't access BAM");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
var unc = unbgzf(r);
|
|
39
|
+
var uncba = new Uint8Array(unc);
|
|
40
|
+
|
|
41
|
+
var magic = readInt(uncba, 0);
|
|
42
|
+
var headLen = readInt(uncba, 4);
|
|
43
|
+
var header = '';
|
|
44
|
+
for (var i = 0; i < headLen; ++i) {
|
|
45
|
+
header += String.fromCharCode(uncba[i + 8]);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var nRef = readInt(uncba, headLen + 8);
|
|
49
|
+
var p = headLen + 12;
|
|
50
|
+
|
|
51
|
+
bam.chrToIndex = {};
|
|
52
|
+
bam.indexToChr = [];
|
|
53
|
+
for (var i = 0; i < nRef; ++i) {
|
|
54
|
+
var lName = readInt(uncba, p);
|
|
55
|
+
var name = '';
|
|
56
|
+
for (var j = 0; j < lName - 1; ++j) {
|
|
57
|
+
name += String.fromCharCode(uncba[p + 4 + j]);
|
|
58
|
+
}
|
|
59
|
+
var lRef = readInt(uncba, p + lName + 4);
|
|
60
|
+
// dlog(name + ': ' + lRef);
|
|
61
|
+
bam.chrToIndex[name] = i;
|
|
62
|
+
if (name.indexOf('chr') == 0) {
|
|
63
|
+
bam.chrToIndex[name.substring(3)] = i;
|
|
64
|
+
} else {
|
|
65
|
+
bam.chrToIndex['chr' + name] = i;
|
|
66
|
+
}
|
|
67
|
+
bam.indexToChr.push(name);
|
|
68
|
+
|
|
69
|
+
p = p + 8 + lName;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (bam.indices) {
|
|
73
|
+
return callback(bam);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
bam.bai.fetch(function(header) { // Do we really need to fetch the whole thing? :-(
|
|
78
|
+
if (!header) {
|
|
79
|
+
return dlog("Couldn't access BAI");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
var uncba = new Uint8Array(header);
|
|
83
|
+
var baiMagic = readInt(uncba, 0);
|
|
84
|
+
if (baiMagic != BAI_MAGIC) {
|
|
85
|
+
return dlog('Not a BAI file');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
var nref = readInt(uncba, 4);
|
|
89
|
+
|
|
90
|
+
bam.indices = [];
|
|
91
|
+
|
|
92
|
+
var p = 8;
|
|
93
|
+
for (var ref = 0; ref < nref; ++ref) {
|
|
94
|
+
var blockStart = p;
|
|
95
|
+
var nbin = readInt(uncba, p);
|
|
96
|
+
p += 4;
|
|
97
|
+
for (var b = 0; b < nbin; ++b) {
|
|
98
|
+
var bin = readInt(uncba, p);
|
|
99
|
+
var nchnk = readInt(uncba, p + 4);
|
|
100
|
+
p += 8 + (nchnk * 16);
|
|
101
|
+
}
|
|
102
|
+
var nintv = readInt(uncba, p);
|
|
103
|
+
p += 4;
|
|
104
|
+
p += (nintv * 8);
|
|
105
|
+
if (nbin > 0) {
|
|
106
|
+
bam.indices[ref] = new Uint8Array(header, blockStart, p - blockStart);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (bam.chrToIndex) {
|
|
110
|
+
return callback(bam);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
BamFile.prototype.blocksForRange = function(refId, min, max) {
|
|
118
|
+
var index = this.indices[refId];
|
|
119
|
+
if (!index) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
var intBinsL = reg2bins(min, max);
|
|
124
|
+
var intBins = [];
|
|
125
|
+
for (var i = 0; i < intBinsL.length; ++i) {
|
|
126
|
+
intBins[intBinsL[i]] = true;
|
|
127
|
+
}
|
|
128
|
+
var leafChunks = [],
|
|
129
|
+
otherChunks = [];
|
|
130
|
+
|
|
131
|
+
var nbin = readInt(index, 0);
|
|
132
|
+
var p = 4;
|
|
133
|
+
for (var b = 0; b < nbin; ++b) {
|
|
134
|
+
var bin = readInt(index, p);
|
|
135
|
+
var nchnk = readInt(index, p + 4);
|
|
136
|
+
// dlog('bin=' + bin + '; nchnk=' + nchnk);
|
|
137
|
+
p += 8;
|
|
138
|
+
if (intBins[bin]) {
|
|
139
|
+
for (var c = 0; c < nchnk; ++c) {
|
|
140
|
+
var cs = readVob(index, p);
|
|
141
|
+
var ce = readVob(index, p + 8);
|
|
142
|
+
(bin < 4681 ? otherChunks : leafChunks).push(new Chunk(cs, ce));
|
|
143
|
+
p += 16;
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
p += (nchnk * 16);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// dlog('leafChunks = ' + miniJSONify(leafChunks));
|
|
150
|
+
// dlog('otherChunks = ' + miniJSONify(otherChunks));
|
|
151
|
+
var nintv = readInt(index, p);
|
|
152
|
+
var lowest = null;
|
|
153
|
+
var minLin = Math.min(min >> 14, nintv - 1),
|
|
154
|
+
maxLin = Math.min(max >> 14, nintv - 1);
|
|
155
|
+
for (var i = minLin; i <= maxLin; ++i) {
|
|
156
|
+
var lb = readVob(index, p + 4 + (i * 8));
|
|
157
|
+
if (!lb) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (!lowest || lb.block < lowest.block || lb.offset < lowest.offset) {
|
|
161
|
+
lowest = lb;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// dlog('Lowest LB = ' + lowest);
|
|
165
|
+
var prunedOtherChunks = [];
|
|
166
|
+
if (lowest != null) {
|
|
167
|
+
for (var i = 0; i < otherChunks.length; ++i) {
|
|
168
|
+
var chnk = otherChunks[i];
|
|
169
|
+
if (chnk.maxv.block >= lowest.block && chnk.maxv.offset >= lowest.offset) {
|
|
170
|
+
prunedOtherChunks.push(chnk);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// dlog('prunedOtherChunks = ' + miniJSONify(prunedOtherChunks));
|
|
175
|
+
otherChunks = prunedOtherChunks;
|
|
176
|
+
|
|
177
|
+
var intChunks = [];
|
|
178
|
+
for (var i = 0; i < otherChunks.length; ++i) {
|
|
179
|
+
intChunks.push(otherChunks[i]);
|
|
180
|
+
}
|
|
181
|
+
for (var i = 0; i < leafChunks.length; ++i) {
|
|
182
|
+
intChunks.push(leafChunks[i]);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
intChunks.sort(function(c0, c1) {
|
|
186
|
+
var dif = c0.minv.block - c1.minv.block;
|
|
187
|
+
if (dif != 0) {
|
|
188
|
+
return dif;
|
|
189
|
+
} else {
|
|
190
|
+
return c0.minv.offset - c1.minv.offset;
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
var mergedChunks = [];
|
|
194
|
+
if (intChunks.length > 0) {
|
|
195
|
+
var cur = intChunks[0];
|
|
196
|
+
for (var i = 1; i < intChunks.length; ++i) {
|
|
197
|
+
var nc = intChunks[i];
|
|
198
|
+
if (nc.minv.block == cur.maxv.block /* && nc.minv.offset == cur.maxv.offset */ ) { // no point splitting mid-block
|
|
199
|
+
cur = new Chunk(cur.minv, nc.maxv);
|
|
200
|
+
} else {
|
|
201
|
+
mergedChunks.push(cur);
|
|
202
|
+
cur = nc;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
mergedChunks.push(cur);
|
|
206
|
+
}
|
|
207
|
+
// dlog('mergedChunks = ' + miniJSONify(mergedChunks));
|
|
208
|
+
return mergedChunks;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
BamFile.prototype.fetch = function(chr, min, max, callback) {
|
|
212
|
+
var thisB = this;
|
|
213
|
+
|
|
214
|
+
var chrId = this.chrToIndex[chr];
|
|
215
|
+
var chunks;
|
|
216
|
+
if (chrId === undefined) {
|
|
217
|
+
chunks = [];
|
|
218
|
+
} else {
|
|
219
|
+
chunks = this.blocksForRange(chrId, min, max);
|
|
220
|
+
if (!chunks) {
|
|
221
|
+
callback(null, 'Error in index fetch');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
var records = [];
|
|
226
|
+
var index = 0;
|
|
227
|
+
var data;
|
|
228
|
+
|
|
229
|
+
function tramp() {
|
|
230
|
+
if (index >= chunks.length) {
|
|
231
|
+
return callback(records);
|
|
232
|
+
} else if (!data) {
|
|
233
|
+
// dlog('fetching ' + index);
|
|
234
|
+
var c = chunks[index];
|
|
235
|
+
var fetchMin = c.minv.block;
|
|
236
|
+
var fetchMax = c.maxv.block + (1 << 16); // *sigh*
|
|
237
|
+
thisB.data.slice(fetchMin, fetchMax - fetchMin).fetch(function(r) {
|
|
238
|
+
data = unbgzf(r, c.maxv.block - c.minv.block + 1);
|
|
239
|
+
return tramp();
|
|
240
|
+
});
|
|
241
|
+
} else {
|
|
242
|
+
var ba = new Uint8Array(data);
|
|
243
|
+
thisB.readBamRecords(ba, chunks[index].minv.offset, records, min, max, chrId);
|
|
244
|
+
data = null;
|
|
245
|
+
++index;
|
|
246
|
+
return tramp();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
tramp();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
var SEQRET_DECODER = ['=', 'A', 'C', 'x', 'G', 'x', 'x', 'x', 'T', 'x', 'x', 'x', 'x', 'x', 'x', 'N'];
|
|
253
|
+
var CIGAR_DECODER = ['M', 'I', 'D', 'N', 'S', 'H', 'P', '=', 'X', '?', '?', '?', '?', '?', '?', '?'];
|
|
254
|
+
|
|
255
|
+
function BamRecord() {}
|
|
256
|
+
|
|
257
|
+
BamFile.prototype.readBamRecords = function(ba, offset, sink, min, max, chrId) {
|
|
258
|
+
while (true) {
|
|
259
|
+
var blockSize = readInt(ba, offset);
|
|
260
|
+
var blockEnd = offset + blockSize + 4;
|
|
261
|
+
if (blockEnd >= ba.length) {
|
|
262
|
+
return sink;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
var record = new BamRecord();
|
|
266
|
+
|
|
267
|
+
var refID = readInt(ba, offset + 4);
|
|
268
|
+
var pos = readInt(ba, offset + 8);
|
|
269
|
+
|
|
270
|
+
var bmn = readInt(ba, offset + 12);
|
|
271
|
+
var bin = (bmn & 0xffff0000) >> 16;
|
|
272
|
+
var mq = (bmn & 0xff00) >> 8;
|
|
273
|
+
var nl = bmn & 0xff;
|
|
274
|
+
|
|
275
|
+
var flag_nc = readInt(ba, offset + 16);
|
|
276
|
+
var flag = (flag_nc & 0xffff0000) >> 16;
|
|
277
|
+
var nc = flag_nc & 0xffff;
|
|
278
|
+
|
|
279
|
+
var lseq = readInt(ba, offset + 20);
|
|
280
|
+
|
|
281
|
+
var nextRef = readInt(ba, offset + 24);
|
|
282
|
+
var nextPos = readInt(ba, offset + 28);
|
|
283
|
+
|
|
284
|
+
var tlen = readInt(ba, offset + 32);
|
|
285
|
+
|
|
286
|
+
var readName = '';
|
|
287
|
+
for (var j = 0; j < nl - 1; ++j) {
|
|
288
|
+
readName += String.fromCharCode(ba[offset + 36 + j]);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
var p = offset + 36 + nl;
|
|
292
|
+
|
|
293
|
+
var cigar = '';
|
|
294
|
+
for (var c = 0; c < nc; ++c) {
|
|
295
|
+
var cigop = readInt(ba, p);
|
|
296
|
+
cigar = cigar + (cigop >> 4) + CIGAR_DECODER[cigop & 0xf];
|
|
297
|
+
p += 4;
|
|
298
|
+
}
|
|
299
|
+
record.cigar = cigar;
|
|
300
|
+
|
|
301
|
+
var seq = '';
|
|
302
|
+
var seqBytes = (lseq + 1) >> 1;
|
|
303
|
+
for (var j = 0; j < seqBytes; ++j) {
|
|
304
|
+
var sb = ba[p + j];
|
|
305
|
+
seq += SEQRET_DECODER[(sb & 0xf0) >> 4];
|
|
306
|
+
seq += SEQRET_DECODER[(sb & 0x0f)];
|
|
307
|
+
}
|
|
308
|
+
p += seqBytes;
|
|
309
|
+
record.seq = seq;
|
|
310
|
+
|
|
311
|
+
var qseq = '';
|
|
312
|
+
for (var j = 0; j < lseq; ++j) {
|
|
313
|
+
qseq += String.fromCharCode(ba[p + j]);
|
|
314
|
+
}
|
|
315
|
+
p += lseq;
|
|
316
|
+
record.quals = qseq;
|
|
317
|
+
|
|
318
|
+
record.pos = pos;
|
|
319
|
+
record.mq = mq;
|
|
320
|
+
record.readName = readName;
|
|
321
|
+
record.segment = this.indexToChr[refID];
|
|
322
|
+
|
|
323
|
+
while (p < blockEnd) {
|
|
324
|
+
var tag = String.fromCharCode(ba[p]) + String.fromCharCode(ba[p + 1]);
|
|
325
|
+
var type = String.fromCharCode(ba[p + 2]);
|
|
326
|
+
var value;
|
|
327
|
+
|
|
328
|
+
if (type == 'A') {
|
|
329
|
+
value = String.fromCharCode(ba[p + 3]);
|
|
330
|
+
p += 4;
|
|
331
|
+
} else if (type == 'i' || type == 'I') {
|
|
332
|
+
value = readInt(ba, p + 3);
|
|
333
|
+
p += 7;
|
|
334
|
+
} else if (type == 'c' || type == 'C') {
|
|
335
|
+
value = ba[p + 3];
|
|
336
|
+
p += 4;
|
|
337
|
+
} else if (type == 's' || type == 'S') {
|
|
338
|
+
value = readShort(ba, p + 3);
|
|
339
|
+
p += 5;
|
|
340
|
+
} else if (type == 'f') {
|
|
341
|
+
throw 'FIXME need floats';
|
|
342
|
+
} else if (type == 'Z' || type == 'H') {
|
|
343
|
+
p += 3;
|
|
344
|
+
value = '';
|
|
345
|
+
for (;;) {
|
|
346
|
+
var cc = ba[p++];
|
|
347
|
+
if (cc == 0) {
|
|
348
|
+
break;
|
|
349
|
+
} else {
|
|
350
|
+
value += String.fromCharCode(cc);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
} else if (type == 'B') {
|
|
354
|
+
var atype = String.fromCharCode(ba[p + 3]);
|
|
355
|
+
var alen = readInt(ba, p + 4);
|
|
356
|
+
var elen;
|
|
357
|
+
var reader;
|
|
358
|
+
if (atype == 'i' || atype == 'I' || atype == 'f') {
|
|
359
|
+
elen = 4;
|
|
360
|
+
if (atype == 'f') reader = readFloat;
|
|
361
|
+
else reader = readInt;
|
|
362
|
+
} else if (atype == 's' || atype == 'S') {
|
|
363
|
+
elen = 2;
|
|
364
|
+
reader = readShort;
|
|
365
|
+
} else if (atype == 'c' || atype == 'C') {
|
|
366
|
+
elen = 1;
|
|
367
|
+
reader = readByte;
|
|
368
|
+
} else {
|
|
369
|
+
throw 'Unknown array type ' + atype;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
p += 8;
|
|
373
|
+
value = [];
|
|
374
|
+
for (var i = 0; i < alen; ++i) {
|
|
375
|
+
value.push(reader(ba, p));
|
|
376
|
+
p += elen;
|
|
377
|
+
}
|
|
378
|
+
} else {
|
|
379
|
+
throw 'Unknown type ' + type;
|
|
380
|
+
}
|
|
381
|
+
record[tag] = value;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (!min || record.pos <= max && record.pos + lseq >= min) {
|
|
385
|
+
if (chrId === undefined || refID == chrId) {
|
|
386
|
+
sink.push(record);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
offset = blockEnd;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Exits via top of loop.
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
(function() {
|
|
396
|
+
var convertBuffer = new ArrayBuffer(8);
|
|
397
|
+
var ba = new Uint8Array(convertBuffer);
|
|
398
|
+
var fa = new Float32Array(convertBuffer);
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
window.readFloat = function(buf, offset) {
|
|
402
|
+
ba[0] = buf[offset];
|
|
403
|
+
ba[1] = buf[offset + 1];
|
|
404
|
+
ba[2] = buf[offset + 2];
|
|
405
|
+
ba[3] = buf[offset + 3];
|
|
406
|
+
return fa[0];
|
|
407
|
+
};
|
|
408
|
+
})();
|
|
409
|
+
|
|
410
|
+
function readInt64(ba, offset) {
|
|
411
|
+
return (ba[offset + 7] << 24) | (ba[offset + 6] << 16) | (ba[offset + 5] << 8) | (ba[offset + 4]);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
function readInt(ba, offset) {
|
|
415
|
+
return (ba[offset + 3] << 24) | (ba[offset + 2] << 16) | (ba[offset + 1] << 8) | (ba[offset]);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function readShort(ba, offset) {
|
|
419
|
+
return (ba[offset + 1] << 8) | (ba[offset]);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function readByte(ba, offset) {
|
|
423
|
+
return ba[offset];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function readVob(ba, offset) {
|
|
427
|
+
var block = ((ba[offset + 6] & 0xff) * 0x100000000) + ((ba[offset + 5] & 0xff) * 0x1000000) + ((ba[offset + 4] & 0xff) * 0x10000) + ((ba[offset + 3] & 0xff) * 0x100) + ((ba[offset + 2] & 0xff));
|
|
428
|
+
var bint = (ba[offset + 1] << 8) | (ba[offset]);
|
|
429
|
+
if (block == 0 && bint == 0) {
|
|
430
|
+
return null; // Should only happen in the linear index?
|
|
431
|
+
} else {
|
|
432
|
+
return new Vob(block, bint);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function unbgzf(data, lim) {
|
|
437
|
+
lim = Math.min(lim || 1, data.byteLength - 100);
|
|
438
|
+
var oBlockList = [];
|
|
439
|
+
var ptr = [0];
|
|
440
|
+
var totalSize = 0;
|
|
441
|
+
|
|
442
|
+
while (ptr[0] < lim) {
|
|
443
|
+
var ba = new Uint8Array(data, ptr[0], 100); // FIXME is this enough for all credible BGZF block headers?
|
|
444
|
+
var xlen = (ba[11] << 8) | (ba[10]);
|
|
445
|
+
// dlog('xlen[' + (ptr[0]) +']=' + xlen);
|
|
446
|
+
var unc = jszlib_inflate_buffer(data, 12 + xlen + ptr[0], Math.min(65536, data.byteLength - 12 - xlen - ptr[0]), ptr);
|
|
447
|
+
ptr[0] += 8;
|
|
448
|
+
totalSize += unc.byteLength;
|
|
449
|
+
oBlockList.push(unc);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (oBlockList.length == 1) {
|
|
453
|
+
return oBlockList[0];
|
|
454
|
+
} else {
|
|
455
|
+
var out = new Uint8Array(totalSize);
|
|
456
|
+
var cursor = 0;
|
|
457
|
+
for (var i = 0; i < oBlockList.length; ++i) {
|
|
458
|
+
var b = new Uint8Array(oBlockList[i]);
|
|
459
|
+
arrayCopy(b, 0, out, cursor, b.length);
|
|
460
|
+
cursor += b.length;
|
|
461
|
+
}
|
|
462
|
+
return out.buffer;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
//
|
|
467
|
+
// Binning (transliterated from SAM1.3 spec)
|
|
468
|
+
//
|
|
469
|
+
/* calculate bin given an alignment covering [beg,end) (zero-based, half-close-half-open) */
|
|
470
|
+
function reg2bin(beg, end) {
|
|
471
|
+
--end;
|
|
472
|
+
if (beg >> 14 == end >> 14) return ((1 << 15) - 1) / 7 + (beg >> 14);
|
|
473
|
+
if (beg >> 17 == end >> 17) return ((1 << 12) - 1) / 7 + (beg >> 17);
|
|
474
|
+
if (beg >> 20 == end >> 20) return ((1 << 9) - 1) / 7 + (beg >> 20);
|
|
475
|
+
if (beg >> 23 == end >> 23) return ((1 << 6) - 1) / 7 + (beg >> 23);
|
|
476
|
+
if (beg >> 26 == end >> 26) return ((1 << 3) - 1) / 7 + (beg >> 26);
|
|
477
|
+
return 0;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/* calculate the list of bins that may overlap with region [beg,end) (zero-based) */
|
|
481
|
+
var MAX_BIN = (((1 << 18) - 1) / 7);
|
|
482
|
+
|
|
483
|
+
function reg2bins(beg, end) {
|
|
484
|
+
var i = 0,
|
|
485
|
+
k, list = [];
|
|
486
|
+
--end;
|
|
487
|
+
list.push(0);
|
|
488
|
+
for (k = 1 + (beg >> 26); k <= 1 + (end >> 26); ++k) list.push(k);
|
|
489
|
+
for (k = 9 + (beg >> 23); k <= 9 + (end >> 23); ++k) list.push(k);
|
|
490
|
+
for (k = 73 + (beg >> 20); k <= 73 + (end >> 20); ++k) list.push(k);
|
|
491
|
+
for (k = 585 + (beg >> 17); k <= 585 + (end >> 17); ++k) list.push(k);
|
|
492
|
+
for (k = 4681 + (beg >> 14); k <= 4681 + (end >> 14); ++k) list.push(k);
|
|
493
|
+
return list;
|
|
494
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/* -*- mode: javascript; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
|
|
3
|
+
//
|
|
4
|
+
// Dalliance Genome Explorer
|
|
5
|
+
// (c) Thomas Down 2006-2011
|
|
6
|
+
//
|
|
7
|
+
// bin.js general binary data support
|
|
8
|
+
//
|
|
9
|
+
|
|
10
|
+
function BlobFetchable(b) {
|
|
11
|
+
this.blob = b;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
BlobFetchable.prototype.slice = function(start, length) {
|
|
15
|
+
var b;
|
|
16
|
+
|
|
17
|
+
if (this.blob.slice) {
|
|
18
|
+
if (length) {
|
|
19
|
+
b = this.blob.slice(start, start + length);
|
|
20
|
+
} else {
|
|
21
|
+
b = this.blob.slice(start);
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
if (length) {
|
|
25
|
+
b = this.blob.webkitSlice(start, start + length);
|
|
26
|
+
} else {
|
|
27
|
+
b = this.blob.webkitSlice(start);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return new BlobFetchable(b);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
BlobFetchable.prototype.fetch = function(callback) {
|
|
34
|
+
var reader = new FileReader();
|
|
35
|
+
reader.onloadend = function(ev) {
|
|
36
|
+
callback(bstringToBuffer(reader.result));
|
|
37
|
+
};
|
|
38
|
+
reader.readAsBinaryString(this.blob);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function URLFetchable(url, start, end, opts) {
|
|
42
|
+
if (!opts) {
|
|
43
|
+
if (typeof start === 'object') {
|
|
44
|
+
opts = start;
|
|
45
|
+
start = undefined;
|
|
46
|
+
} else {
|
|
47
|
+
opts = {};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.url = url;
|
|
52
|
+
this.start = start || 0;
|
|
53
|
+
if (end) {
|
|
54
|
+
this.end = end;
|
|
55
|
+
}
|
|
56
|
+
this.opts = opts;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
URLFetchable.prototype.slice = function(s, l) {
|
|
60
|
+
if (s < 0) {
|
|
61
|
+
throw 'Bad slice ' + s;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
var ns = this.start, ne = this.end;
|
|
65
|
+
if (ns && s) {
|
|
66
|
+
ns = ns + s;
|
|
67
|
+
} else {
|
|
68
|
+
ns = s || ns;
|
|
69
|
+
}
|
|
70
|
+
if (l && ns) {
|
|
71
|
+
ne = ns + l - 1;
|
|
72
|
+
} else {
|
|
73
|
+
ne = ne || l - 1;
|
|
74
|
+
}
|
|
75
|
+
return new URLFetchable(this.url, ns, ne, this.opts);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
var seed=0;
|
|
79
|
+
var isIOS = navigator.userAgent.indexOf('Safari') >= 0 && navigator.userAgent.indexOf('Chrome') < 0 ;
|
|
80
|
+
|
|
81
|
+
URLFetchable.prototype.fetchAsText = function(callback) {
|
|
82
|
+
var req = new XMLHttpRequest();
|
|
83
|
+
var length;
|
|
84
|
+
var url = this.url;
|
|
85
|
+
if (isIOS) {
|
|
86
|
+
url = url + '?salt=' + (++seed);
|
|
87
|
+
}
|
|
88
|
+
req.open('GET', url, true);
|
|
89
|
+
|
|
90
|
+
if (this.end) {
|
|
91
|
+
if (this.end - this.start > 100000000) {
|
|
92
|
+
throw 'Monster fetch!';
|
|
93
|
+
}
|
|
94
|
+
req.setRequestHeader('Range', 'bytes=' + this.start + '-' + this.end);
|
|
95
|
+
length = this.end - this.start + 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
req.onreadystatechange = function() {
|
|
99
|
+
if (req.readyState == 4) {
|
|
100
|
+
if (req.status == 200 || req.status == 206) {
|
|
101
|
+
return callback(req.responseText);
|
|
102
|
+
} else {
|
|
103
|
+
return callback(null);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
if (this.opts.credentials) {
|
|
108
|
+
req.withCredentials = true;
|
|
109
|
+
}
|
|
110
|
+
req.send('');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
URLFetchable.prototype.fetch = function(callback, attempt, truncatedLength) {
|
|
114
|
+
var thisB = this;
|
|
115
|
+
|
|
116
|
+
attempt = attempt || 1;
|
|
117
|
+
if (attempt > 3) {
|
|
118
|
+
return callback(null);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
var req = new XMLHttpRequest();
|
|
122
|
+
var length;
|
|
123
|
+
var url = this.url;
|
|
124
|
+
if (isIOS) {
|
|
125
|
+
// console.log('Safari hack');
|
|
126
|
+
url = url + '?salt=' + (++seed);
|
|
127
|
+
}
|
|
128
|
+
req.open('GET', url, true);
|
|
129
|
+
req.overrideMimeType('text/plain; charset=x-user-defined');
|
|
130
|
+
if (this.end) {
|
|
131
|
+
if (this.end - this.start > 100000000) {
|
|
132
|
+
throw 'Monster fetch!';
|
|
133
|
+
}
|
|
134
|
+
// console.log('req bytes=' + this.start + '-' + this.end);
|
|
135
|
+
req.setRequestHeader('Range', 'bytes=' + this.start + '-' + this.end);
|
|
136
|
+
length = this.end - this.start + 1;
|
|
137
|
+
}
|
|
138
|
+
req.responseType = 'arraybuffer';
|
|
139
|
+
req.onreadystatechange = function() {
|
|
140
|
+
if (req.readyState == 4) {
|
|
141
|
+
if (req.status == 200 || req.status == 206) {
|
|
142
|
+
if (req.response) {
|
|
143
|
+
var bl = req.response.byteLength;
|
|
144
|
+
// console.log('Got ' + bl + ' expected ' + length);
|
|
145
|
+
if (length && length != bl && (!truncatedLength || bl != truncatedLength)) {
|
|
146
|
+
return thisB.fetch(callback, attempt + 1, bl);
|
|
147
|
+
} else {
|
|
148
|
+
return callback(req.response);
|
|
149
|
+
}
|
|
150
|
+
} else if (req.mozResponseArrayBuffer) {
|
|
151
|
+
return callback(req.mozResponseArrayBuffer);
|
|
152
|
+
} else {
|
|
153
|
+
var r = req.responseText;
|
|
154
|
+
if (length && length != r.length && (!truncatedLength || r.length != truncatedLength)) {
|
|
155
|
+
return thisB.fetch(callback, attempt + 1, r.length);
|
|
156
|
+
} else {
|
|
157
|
+
return callback(bstringToBuffer(req.responseText));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
return thisB.fetch(callback, attempt + 1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
if (this.opts.credentials) {
|
|
166
|
+
req.withCredentials = true;
|
|
167
|
+
}
|
|
168
|
+
req.send('');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function bstringToBuffer(result) {
|
|
172
|
+
if (!result) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// var before = Date.now();
|
|
177
|
+
var ba = new Uint8Array(result.length);
|
|
178
|
+
for (var i = 0; i < ba.length; ++i) {
|
|
179
|
+
ba[i] = result.charCodeAt(i);
|
|
180
|
+
}
|
|
181
|
+
// var after = Date.now();
|
|
182
|
+
// dlog('bb took ' + (after - before) + 'ms');
|
|
183
|
+
return ba.buffer;
|
|
184
|
+
}
|
|
185
|
+
|