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
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
import RTree from 'rtree';
|
|
2
|
+
import inflateBuffer from './dalliance/jszlib-inflate';
|
|
3
|
+
|
|
4
|
+
export default function (fileData, callback) {
|
|
5
|
+
const bbi = {
|
|
6
|
+
fetchedData: new RTree(),
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// constants: bigwig/bigbed file header signatures (magic numbers) (32 bit) , can be swapped ( big-endian | BE )
|
|
10
|
+
const BIG_WIG_MAGIC = 0x888FFC26;
|
|
11
|
+
const BIG_WIG_MAGIC_BE = 0x26FC8F88;
|
|
12
|
+
|
|
13
|
+
const BIG_BED_MAGIC = 0x8789F2EB;
|
|
14
|
+
const BIG_BED_MAGIC_BE = 0xEBF28987;
|
|
15
|
+
|
|
16
|
+
const CIRTREE_MAGIC = 0x78ca8c91;
|
|
17
|
+
const IDXTREE_MAGIC = 0x2468ace0;
|
|
18
|
+
|
|
19
|
+
// type of file converted to bigwig bedgraph |variable step wiggle | fixed step wiggle
|
|
20
|
+
const BIG_WIG_TYPE_GRAPH = 1;
|
|
21
|
+
const BIG_WIG_TYPE_VSTEP = 2;
|
|
22
|
+
const BIG_WIG_TYPE_FSTEP = 3;
|
|
23
|
+
|
|
24
|
+
const M1 = 256;
|
|
25
|
+
const M2 = 256 * 256;
|
|
26
|
+
const M3 = 256 * 256 * 256;
|
|
27
|
+
const M4 = 256 * 256 * 256 * 256;
|
|
28
|
+
|
|
29
|
+
// reads 8 bytes from data
|
|
30
|
+
const read64Bit = (ba, o) => {
|
|
31
|
+
const val = ba[o] + ba[o + 1] * M1 + ba[o + 2] * M2 + ba[o + 3] * M3 + ba[o + 4] * M4;
|
|
32
|
+
|
|
33
|
+
return val;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const WiggleParser = (data, query) => {
|
|
37
|
+
const arr = [];
|
|
38
|
+
const ba = new Uint8Array(data);
|
|
39
|
+
const sa = new Int16Array(data);
|
|
40
|
+
const la = new Int32Array(data);
|
|
41
|
+
const fa = new Float32Array(data);
|
|
42
|
+
const chromId = la[0];
|
|
43
|
+
const chr = parseInt(bbi.chroms[chromId].replace('chr', ''), 10);
|
|
44
|
+
const blockStart = la[1] + 1;
|
|
45
|
+
const itemStep = la[3];
|
|
46
|
+
const itemSpan = la[4];
|
|
47
|
+
const blockType = ba[20];
|
|
48
|
+
const itemCount = sa[11];
|
|
49
|
+
|
|
50
|
+
let i;
|
|
51
|
+
let start;
|
|
52
|
+
let end;
|
|
53
|
+
let score;
|
|
54
|
+
|
|
55
|
+
if (blockType === BIG_WIG_TYPE_FSTEP) { // fixedStep wiggle
|
|
56
|
+
for (i = 0; i < itemCount; i++) {
|
|
57
|
+
start = blockStart + i * itemStep;
|
|
58
|
+
end = start + itemSpan - 1;
|
|
59
|
+
score = fa[i + 6];
|
|
60
|
+
|
|
61
|
+
if (chromId == query.chrom) { // eslint-disable-line eqeqeq
|
|
62
|
+
arr.push({
|
|
63
|
+
chr : chr,
|
|
64
|
+
start : start,
|
|
65
|
+
end : end,
|
|
66
|
+
height : score,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} else if (blockType === BIG_WIG_TYPE_VSTEP) { // variable step wiggle
|
|
71
|
+
for (i = 0; i < itemCount; i++) {
|
|
72
|
+
start = la[i * 2 + 6] + 1;
|
|
73
|
+
end = start + itemSpan - 1;
|
|
74
|
+
score = fa[i * 2 + 7];
|
|
75
|
+
|
|
76
|
+
if (chromId == query.chrom) { // eslint-disable-line eqeqeq
|
|
77
|
+
arr.push({
|
|
78
|
+
chr : chr,
|
|
79
|
+
start : start,
|
|
80
|
+
end : end,
|
|
81
|
+
height : score,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} else if (blockType === BIG_WIG_TYPE_GRAPH) { // bedGraph
|
|
86
|
+
for (i = 0; i < itemCount; i++) {
|
|
87
|
+
start = la[i * 3 + 6] + 1;
|
|
88
|
+
end = la[i * 3 + 7];
|
|
89
|
+
score = fa[i * 3 + 8];
|
|
90
|
+
|
|
91
|
+
if (start > end) {
|
|
92
|
+
start = end;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (chromId == query.chrom) { // eslint-disable-line eqeqeq
|
|
96
|
+
arr.push({
|
|
97
|
+
chr : chr,
|
|
98
|
+
start : start,
|
|
99
|
+
end : end,
|
|
100
|
+
height : score,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return arr;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const BEDParser = (data, query) => {
|
|
110
|
+
const arr = [];
|
|
111
|
+
const ba = new Uint8Array(data);
|
|
112
|
+
const la = new Int32Array(data);
|
|
113
|
+
|
|
114
|
+
let offset = 0;
|
|
115
|
+
let bbRecord;
|
|
116
|
+
let ch;
|
|
117
|
+
let rest;
|
|
118
|
+
|
|
119
|
+
while (offset < la.length) {
|
|
120
|
+
bbRecord = {
|
|
121
|
+
chromid : la[offset],
|
|
122
|
+
chr : bbi.chroms[la[offset]],
|
|
123
|
+
start : la[offset + 1],
|
|
124
|
+
end : la[offset + 2],
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
offset += 12;
|
|
128
|
+
|
|
129
|
+
while (true) { // eslint-disable-line no-constant-condition
|
|
130
|
+
ch = ba[offset++];
|
|
131
|
+
|
|
132
|
+
if (ch !== 0) {
|
|
133
|
+
rest += String.fromCharCode(ch);
|
|
134
|
+
} else {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (bbRecord.chromid === query.chrom) {
|
|
140
|
+
arr.push([ bbRecord.chr, bbRecord.start, bbRecord.end, rest ].join('\t'));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return arr;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const getData = (start, length, cb) => {
|
|
148
|
+
const end = start + length;
|
|
149
|
+
const fetched = bbi.fetchedData.search({ x: start, w: length, y: 0, h: 1 }).filter(d => d[0] <= start && d[1] >= end);
|
|
150
|
+
|
|
151
|
+
if (fetched.length === 1) {
|
|
152
|
+
cb(fetched[0][2].slice(start - fetched[0][0], start + length));
|
|
153
|
+
} else {
|
|
154
|
+
fileData.slice(start, length).fetch((d) => {
|
|
155
|
+
bbi.fetchedData.insert({ x: start, w: length, y: 0, h: 1 }, [ start, start + length, d ]);
|
|
156
|
+
cb(d);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const getRTreeNode = (treedata, offset) => {
|
|
162
|
+
const ba = new Uint8Array(treedata);
|
|
163
|
+
const sa = new Uint16Array(treedata);
|
|
164
|
+
const la = new Uint32Array(treedata);
|
|
165
|
+
const children = sa[offset / 2 + 1];
|
|
166
|
+
|
|
167
|
+
let lo;
|
|
168
|
+
let i;
|
|
169
|
+
|
|
170
|
+
const node = {
|
|
171
|
+
isLeaf : ba[offset],
|
|
172
|
+
children : children,
|
|
173
|
+
chrIdxStart : new Array(children),
|
|
174
|
+
baseStart : new Array(children),
|
|
175
|
+
chrIdxEnd : new Array(children),
|
|
176
|
+
baseEnd : new Array(children),
|
|
177
|
+
dataOffset : new Array(children),
|
|
178
|
+
x : {},
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
if (node.isLeaf) {
|
|
182
|
+
node.x.size = new Array(children);
|
|
183
|
+
} else {
|
|
184
|
+
node.x.child = new Array(children);
|
|
185
|
+
|
|
186
|
+
for (i = 0; i < children; i++) {
|
|
187
|
+
node.x.child[i] = -1;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
offset += 4;
|
|
192
|
+
|
|
193
|
+
for (i = 0; i < children; i++) {
|
|
194
|
+
lo = offset / 4;
|
|
195
|
+
|
|
196
|
+
node.chrIdxStart[i] = la[lo];
|
|
197
|
+
node.baseStart[i] = la[lo + 1];
|
|
198
|
+
node.chrIdxEnd[i] = la[lo + 2];
|
|
199
|
+
node.baseEnd[i] = la[lo + 3];
|
|
200
|
+
node.dataOffset[i] = read64Bit(ba, offset + 16);
|
|
201
|
+
|
|
202
|
+
offset += 24;
|
|
203
|
+
|
|
204
|
+
if (node.isLeaf) {
|
|
205
|
+
node.x.size[i] = read64Bit(ba, offset);
|
|
206
|
+
offset += 8;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return node;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const getValues = (chrom, start, end, cb) => {
|
|
214
|
+
const vals = [];
|
|
215
|
+
|
|
216
|
+
let chromid = bbi.chroms.indexOf(chrom);
|
|
217
|
+
|
|
218
|
+
if (chromid === -1) {
|
|
219
|
+
chromid = bbi.chroms.indexOf(`chr${chrom}`);
|
|
220
|
+
|
|
221
|
+
if (chromid === -1) {
|
|
222
|
+
return cb([], 'chrom not found');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const query = {
|
|
227
|
+
chrom : chromid,
|
|
228
|
+
start : start,
|
|
229
|
+
end : end,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const findOverlaps = (node) => {
|
|
233
|
+
const children = node.children;
|
|
234
|
+
const overlaps = [];
|
|
235
|
+
|
|
236
|
+
for (let i = 0; i < children; i++) {
|
|
237
|
+
const startChrom = node.chrIdxStart[i];
|
|
238
|
+
const startBase = node.baseStart[i];
|
|
239
|
+
const endChrom = node.chrIdxEnd[i];
|
|
240
|
+
const endBase = node.baseEnd[i];
|
|
241
|
+
|
|
242
|
+
if (
|
|
243
|
+
((startChrom < query.chrom) || (startChrom == query.chrom && startBase <= query.end)) && // eslint-disable-line eqeqeq
|
|
244
|
+
((endChrom > query.chrom) || (endChrom == query.chrom && endBase >= query.start)) // eslint-disable-line eqeqeq
|
|
245
|
+
) {
|
|
246
|
+
overlaps.push(i);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return overlaps;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
function traverseRTree() {
|
|
254
|
+
let outstanding = 0;
|
|
255
|
+
|
|
256
|
+
const getBlocks = () => {
|
|
257
|
+
const parser = bbi.type === 'bigwig' ? WiggleParser : bbi.type === 'bigbed' ? BEDParser : false;
|
|
258
|
+
|
|
259
|
+
let result = [];
|
|
260
|
+
|
|
261
|
+
if (parser && vals.length) {
|
|
262
|
+
for (let i = 0; i < vals.length; i++) {
|
|
263
|
+
result = result.concat(parser(vals[i].data, query));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
cb(result);
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const fetchBlocks = () => {
|
|
271
|
+
vals.sort((b0, b1) => (b0.offset | 0) - (b1.offset | 0));
|
|
272
|
+
|
|
273
|
+
if (vals.length === 0) {
|
|
274
|
+
return getBlocks();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
let totalSize = 0;
|
|
278
|
+
|
|
279
|
+
const base = vals[0].offset;
|
|
280
|
+
|
|
281
|
+
for (let i = 0; i < vals.length; i++) {
|
|
282
|
+
totalSize += vals[i].size;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
getData(base, totalSize, (buffer) => {
|
|
286
|
+
let ioffset = 0;
|
|
287
|
+
let bi = 0;
|
|
288
|
+
let fb;
|
|
289
|
+
|
|
290
|
+
let
|
|
291
|
+
blockData;
|
|
292
|
+
|
|
293
|
+
while (ioffset < totalSize) {
|
|
294
|
+
fb = vals[bi];
|
|
295
|
+
|
|
296
|
+
if (bbi.uncompressBufSize > 0) {
|
|
297
|
+
blockData = inflateBuffer(buffer, ioffset + 2, fb.size - 2);
|
|
298
|
+
} else {
|
|
299
|
+
blockData = buffer.slice(ioffset, ioffset + fb.size);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
vals[bi].data = blockData;
|
|
303
|
+
ioffset += fb.size;
|
|
304
|
+
bi++;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
getBlocks();
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const traverseRTreeChildren = (treedata, offset, level, fetchChildren) => {
|
|
312
|
+
const node = getRTreeNode(treedata, offset);
|
|
313
|
+
const overlaps = findOverlaps(node);
|
|
314
|
+
|
|
315
|
+
let i;
|
|
316
|
+
|
|
317
|
+
if (node.isLeaf) {
|
|
318
|
+
for (i = 0; i < overlaps.length; i++) {
|
|
319
|
+
vals.push({
|
|
320
|
+
offset : node.dataOffset[overlaps[i]],
|
|
321
|
+
size : node.x.size[overlaps[i]],
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return [];
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
fetchChildren(overlaps.map(o => node.dataOffset[o]), level + 1);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const fetchRTreeChildren = (offset, level) => {
|
|
332
|
+
outstanding += offset.length;
|
|
333
|
+
|
|
334
|
+
const min = offset[0];
|
|
335
|
+
const maxNodeSize = 4 + bbi.Rheader.blockSize * 32;
|
|
336
|
+
const max = offset[offset.length - 1] + maxNodeSize;
|
|
337
|
+
|
|
338
|
+
getData(min, max - min, (treedata) => {
|
|
339
|
+
// traverse children
|
|
340
|
+
for (let i = 0; i < offset.length; i++) {
|
|
341
|
+
traverseRTreeChildren(treedata, offset[i] - min, level, fetchRTreeChildren);
|
|
342
|
+
|
|
343
|
+
if (--outstanding === 0) {
|
|
344
|
+
fetchBlocks();
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
fetchRTreeChildren([ bbi.rootOffset ], 1);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
traverseRTree();
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
// autoSQL could be present in some bigbed files
|
|
357
|
+
const readAutoSQL = (cb) => {
|
|
358
|
+
if (bbi.asOffset === 0) {
|
|
359
|
+
cb(); // no autoSQL present
|
|
360
|
+
} else {
|
|
361
|
+
// autoSQL present, need to parse
|
|
362
|
+
getData(bbi.asOffset, 2048, (d) => {
|
|
363
|
+
const ba = new Uint8Array(d);
|
|
364
|
+
|
|
365
|
+
let s = '';
|
|
366
|
+
|
|
367
|
+
for (let i = 0; i < ba.length; i++) {
|
|
368
|
+
if (ba[i] === 0) {
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
s += String.fromCharCode(ba[i]);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const headerRe = /(\w+)\s+(\w+)\s+("([^"]+)")?\s*\(\s*/;
|
|
376
|
+
const fieldRe = /([\w[]]+)\s+(\w+)\s*;\s*("([^"]+)")?\s*/g;
|
|
377
|
+
const headerMatch = headerRe.exec(s);
|
|
378
|
+
|
|
379
|
+
if (headerMatch) {
|
|
380
|
+
const as = {
|
|
381
|
+
declType : headerMatch[1],
|
|
382
|
+
name : headerMatch[2],
|
|
383
|
+
comment : headerMatch[4],
|
|
384
|
+
fields : [],
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
s = s.substring(headerMatch[0]);
|
|
388
|
+
|
|
389
|
+
for (let m = fieldRe.exec(s); m !== null; m = fieldRe.exec(s)) {
|
|
390
|
+
as.fields.push({
|
|
391
|
+
type : m[1],
|
|
392
|
+
name : m[2],
|
|
393
|
+
comment : m[4],
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
bbi.schema = as;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
cb();
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const readRTreeIndex = () => {
|
|
406
|
+
getData(bbi.unzoomedIndexOffset, 48, (d) => {
|
|
407
|
+
const ba = new Uint8Array(d);
|
|
408
|
+
const la = new Uint32Array(d);
|
|
409
|
+
const magic = la[0];
|
|
410
|
+
|
|
411
|
+
if (magic === IDXTREE_MAGIC) {
|
|
412
|
+
bbi.Rheader = {
|
|
413
|
+
blockSize : la[1],
|
|
414
|
+
nItems : read64Bit(ba, 8),
|
|
415
|
+
chrIdxStart : la[4],
|
|
416
|
+
baseStart : la[5],
|
|
417
|
+
chrIdxEnd : la[6],
|
|
418
|
+
baseEnd : la[7],
|
|
419
|
+
endFileOffset : read64Bit(ba, 32),
|
|
420
|
+
nItemsPerSlot : la[10],
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
bbi.rootOffset = bbi.unzoomedIndexOffset + 48;
|
|
424
|
+
bbi.getValues = getValues;
|
|
425
|
+
|
|
426
|
+
callback(bbi);
|
|
427
|
+
} else {
|
|
428
|
+
callback(null, 'R-tree not found!');
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
// reading B+ tree which maps chrom names to ids used in R-tree
|
|
434
|
+
const readChromTree = () => {
|
|
435
|
+
const length = bbi.unzoomedDataOffset - bbi.chromTreeOffset;
|
|
436
|
+
|
|
437
|
+
getData(bbi.chromTreeOffset, length + 4 - (length % 4), (d) => {
|
|
438
|
+
const ba = new Uint8Array(d);
|
|
439
|
+
const sa = new Uint16Array(d);
|
|
440
|
+
const la = new Uint32Array(d);
|
|
441
|
+
const magic = la[0];
|
|
442
|
+
|
|
443
|
+
let error;
|
|
444
|
+
|
|
445
|
+
const readChromTreeLeaf = (nodeOffset) => {
|
|
446
|
+
// padding 8 byte
|
|
447
|
+
let children = sa[(nodeOffset / 2) + 1];
|
|
448
|
+
let offset = nodeOffset + 4;
|
|
449
|
+
let chrom;
|
|
450
|
+
let i;
|
|
451
|
+
let c;
|
|
452
|
+
let idx;
|
|
453
|
+
let len;
|
|
454
|
+
|
|
455
|
+
while (children > 0) {
|
|
456
|
+
children--;
|
|
457
|
+
chrom = '';
|
|
458
|
+
|
|
459
|
+
for (i = 0; i < bbi.bpTree.keySize; i++) {
|
|
460
|
+
c = ba[offset + i];
|
|
461
|
+
|
|
462
|
+
if (c !== 0) {
|
|
463
|
+
chrom += String.fromCharCode(c);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
offset += bbi.bpTree.keySize;
|
|
468
|
+
|
|
469
|
+
idx = (ba[offset + 3] << 24) | (ba[offset + 2] << 16) | (ba[offset + 1] << 8) | (ba[offset + 0]);
|
|
470
|
+
len = (ba[offset + 7] << 24) | (ba[offset + 6] << 16) | (ba[offset + 5] << 8) | (ba[offset + 4]);
|
|
471
|
+
|
|
472
|
+
offset += 8;
|
|
473
|
+
|
|
474
|
+
bbi.chroms[idx] = chrom;
|
|
475
|
+
bbi.lengths[idx] = len;
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
if (magic === CIRTREE_MAGIC) {
|
|
480
|
+
bbi.bpTree = {
|
|
481
|
+
itemsPerBlock : la[1],
|
|
482
|
+
keySize : la[2],
|
|
483
|
+
valueSize : la[3],
|
|
484
|
+
itemCount : read64Bit(ba, 16),
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
bbi.chroms = new Array(bbi.bpTree.itemCount);
|
|
488
|
+
bbi.lengths = new Array(bbi.bpTree.itemCount);
|
|
489
|
+
} else {
|
|
490
|
+
error = 'chromosome id B+ tree not found!';
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if (error) {
|
|
494
|
+
callback(null, error);
|
|
495
|
+
} else {
|
|
496
|
+
readChromTreeLeaf(32);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
readRTreeIndex();
|
|
500
|
+
});
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
const checkSignature = () => {
|
|
504
|
+
getData(0, 512, (header) => {
|
|
505
|
+
const ba = new Uint8Array(header);
|
|
506
|
+
const sa = new Uint16Array(header);
|
|
507
|
+
const la = new Uint32Array(header);
|
|
508
|
+
const magic = la[0];
|
|
509
|
+
|
|
510
|
+
let error;
|
|
511
|
+
let reduction;
|
|
512
|
+
let dataOffset;
|
|
513
|
+
let indexOffset;
|
|
514
|
+
|
|
515
|
+
if (magic === BIG_WIG_MAGIC) {
|
|
516
|
+
bbi.type = 'bigwig';
|
|
517
|
+
} else if (magic === BIG_BED_MAGIC) {
|
|
518
|
+
bbi.type = 'bigbed';
|
|
519
|
+
} else if (magic === BIG_WIG_MAGIC_BE || magic === BIG_BED_MAGIC_BE) {
|
|
520
|
+
error = 'big-endian files not supported yet!';
|
|
521
|
+
} else {
|
|
522
|
+
error = 'unsupported file format';
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (error) {
|
|
526
|
+
callback(null, error);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
bbi.version = sa[2];
|
|
530
|
+
bbi.numZoomLevels = sa[3];
|
|
531
|
+
bbi.chromTreeOffset = read64Bit(ba, 8);
|
|
532
|
+
bbi.unzoomedDataOffset = read64Bit(ba, 16);
|
|
533
|
+
bbi.unzoomedIndexOffset = read64Bit(ba, 24);
|
|
534
|
+
bbi.fieldCount = sa[16];
|
|
535
|
+
bbi.definedFieldCount = sa[17];
|
|
536
|
+
bbi.asOffset = read64Bit(ba, 36);
|
|
537
|
+
bbi.totalSummaryOffset = read64Bit(ba, 44);
|
|
538
|
+
bbi.uncompressBufSize = la[13];
|
|
539
|
+
bbi.extHeaderOffset = read64Bit(ba, 56);
|
|
540
|
+
bbi.compressed = bbi.uncompressBufSize > 0;
|
|
541
|
+
bbi.summary = bbi.totalSummaryOffset > 0;
|
|
542
|
+
bbi.extHeader = bbi.extHeaderOffset > 0;
|
|
543
|
+
bbi.zoomHeaders = [];
|
|
544
|
+
|
|
545
|
+
for (let i = 0; i < bbi.numZoomLevels; i++) {
|
|
546
|
+
reduction = la[16 + 6 * i];
|
|
547
|
+
dataOffset = read64Bit(ba, 72 + 24 * i);
|
|
548
|
+
indexOffset = read64Bit(ba, 80 + 24 * i);
|
|
549
|
+
|
|
550
|
+
bbi.zoomHeaders.push({
|
|
551
|
+
reductionLevel : reduction,
|
|
552
|
+
dataOffset : dataOffset,
|
|
553
|
+
indexOffset : indexOffset,
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
readAutoSQL(readChromTree); // reading autoSQL passing next task as callback
|
|
558
|
+
});
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
checkSignature();
|
|
562
|
+
}
|