igv 2.13.4 → 2.13.6
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/README.md +10 -10
- package/dist/igv.esm.js +2655 -2520
- package/dist/igv.esm.min.js +5 -5
- package/dist/igv.esm.min.js.map +1 -1
- package/dist/igv.js +2192 -2076
- package/dist/igv.min.js +5 -5
- package/dist/igv.min.js.map +1 -1
- package/package.json +2 -2
package/dist/igv.js
CHANGED
|
@@ -16472,6 +16472,376 @@
|
|
|
16472
16472
|
}
|
|
16473
16473
|
}
|
|
16474
16474
|
|
|
16475
|
+
const appleCrayonRGBPalette = {
|
|
16476
|
+
cantaloupe: {
|
|
16477
|
+
r: 255,
|
|
16478
|
+
g: 206,
|
|
16479
|
+
b: 110
|
|
16480
|
+
},
|
|
16481
|
+
honeydew: {
|
|
16482
|
+
r: 206,
|
|
16483
|
+
g: 250,
|
|
16484
|
+
b: 110
|
|
16485
|
+
},
|
|
16486
|
+
spindrift: {
|
|
16487
|
+
r: 104,
|
|
16488
|
+
g: 251,
|
|
16489
|
+
b: 208
|
|
16490
|
+
},
|
|
16491
|
+
sky: {
|
|
16492
|
+
r: 106,
|
|
16493
|
+
g: 207,
|
|
16494
|
+
b: 255
|
|
16495
|
+
},
|
|
16496
|
+
lavender: {
|
|
16497
|
+
r: 210,
|
|
16498
|
+
g: 120,
|
|
16499
|
+
b: 255
|
|
16500
|
+
},
|
|
16501
|
+
carnation: {
|
|
16502
|
+
r: 255,
|
|
16503
|
+
g: 127,
|
|
16504
|
+
b: 211
|
|
16505
|
+
},
|
|
16506
|
+
licorice: {
|
|
16507
|
+
r: 0,
|
|
16508
|
+
g: 0,
|
|
16509
|
+
b: 0
|
|
16510
|
+
},
|
|
16511
|
+
snow: {
|
|
16512
|
+
r: 255,
|
|
16513
|
+
g: 255,
|
|
16514
|
+
b: 255
|
|
16515
|
+
},
|
|
16516
|
+
salmon: {
|
|
16517
|
+
r: 255,
|
|
16518
|
+
g: 114,
|
|
16519
|
+
b: 110
|
|
16520
|
+
},
|
|
16521
|
+
banana: {
|
|
16522
|
+
r: 255,
|
|
16523
|
+
g: 251,
|
|
16524
|
+
b: 109
|
|
16525
|
+
},
|
|
16526
|
+
flora: {
|
|
16527
|
+
r: 104,
|
|
16528
|
+
g: 249,
|
|
16529
|
+
b: 110
|
|
16530
|
+
},
|
|
16531
|
+
ice: {
|
|
16532
|
+
r: 104,
|
|
16533
|
+
g: 253,
|
|
16534
|
+
b: 255
|
|
16535
|
+
},
|
|
16536
|
+
orchid: {
|
|
16537
|
+
r: 110,
|
|
16538
|
+
g: 118,
|
|
16539
|
+
b: 255
|
|
16540
|
+
},
|
|
16541
|
+
bubblegum: {
|
|
16542
|
+
r: 255,
|
|
16543
|
+
g: 122,
|
|
16544
|
+
b: 255
|
|
16545
|
+
},
|
|
16546
|
+
lead: {
|
|
16547
|
+
r: 30,
|
|
16548
|
+
g: 30,
|
|
16549
|
+
b: 30
|
|
16550
|
+
},
|
|
16551
|
+
mercury: {
|
|
16552
|
+
r: 232,
|
|
16553
|
+
g: 232,
|
|
16554
|
+
b: 232
|
|
16555
|
+
},
|
|
16556
|
+
tangerine: {
|
|
16557
|
+
r: 255,
|
|
16558
|
+
g: 136,
|
|
16559
|
+
b: 2
|
|
16560
|
+
},
|
|
16561
|
+
lime: {
|
|
16562
|
+
r: 131,
|
|
16563
|
+
g: 249,
|
|
16564
|
+
b: 2
|
|
16565
|
+
},
|
|
16566
|
+
sea_foam: {
|
|
16567
|
+
r: 3,
|
|
16568
|
+
g: 249,
|
|
16569
|
+
b: 135
|
|
16570
|
+
},
|
|
16571
|
+
aqua: {
|
|
16572
|
+
r: 0,
|
|
16573
|
+
g: 140,
|
|
16574
|
+
b: 255
|
|
16575
|
+
},
|
|
16576
|
+
grape: {
|
|
16577
|
+
r: 137,
|
|
16578
|
+
g: 49,
|
|
16579
|
+
b: 255
|
|
16580
|
+
},
|
|
16581
|
+
strawberry: {
|
|
16582
|
+
r: 255,
|
|
16583
|
+
g: 41,
|
|
16584
|
+
b: 135
|
|
16585
|
+
},
|
|
16586
|
+
tungsten: {
|
|
16587
|
+
r: 58,
|
|
16588
|
+
g: 58,
|
|
16589
|
+
b: 58
|
|
16590
|
+
},
|
|
16591
|
+
silver: {
|
|
16592
|
+
r: 208,
|
|
16593
|
+
g: 208,
|
|
16594
|
+
b: 208
|
|
16595
|
+
},
|
|
16596
|
+
maraschino: {
|
|
16597
|
+
r: 255,
|
|
16598
|
+
g: 33,
|
|
16599
|
+
b: 1
|
|
16600
|
+
},
|
|
16601
|
+
lemon: {
|
|
16602
|
+
r: 255,
|
|
16603
|
+
g: 250,
|
|
16604
|
+
b: 3
|
|
16605
|
+
},
|
|
16606
|
+
spring: {
|
|
16607
|
+
r: 5,
|
|
16608
|
+
g: 248,
|
|
16609
|
+
b: 2
|
|
16610
|
+
},
|
|
16611
|
+
turquoise: {
|
|
16612
|
+
r: 0,
|
|
16613
|
+
g: 253,
|
|
16614
|
+
b: 255
|
|
16615
|
+
},
|
|
16616
|
+
blueberry: {
|
|
16617
|
+
r: 0,
|
|
16618
|
+
g: 46,
|
|
16619
|
+
b: 255
|
|
16620
|
+
},
|
|
16621
|
+
magenta: {
|
|
16622
|
+
r: 255,
|
|
16623
|
+
g: 57,
|
|
16624
|
+
b: 255
|
|
16625
|
+
},
|
|
16626
|
+
iron: {
|
|
16627
|
+
r: 84,
|
|
16628
|
+
g: 84,
|
|
16629
|
+
b: 83
|
|
16630
|
+
},
|
|
16631
|
+
magnesium: {
|
|
16632
|
+
r: 184,
|
|
16633
|
+
g: 184,
|
|
16634
|
+
b: 184
|
|
16635
|
+
},
|
|
16636
|
+
mocha: {
|
|
16637
|
+
r: 137,
|
|
16638
|
+
g: 72,
|
|
16639
|
+
b: 0
|
|
16640
|
+
},
|
|
16641
|
+
fern: {
|
|
16642
|
+
r: 69,
|
|
16643
|
+
g: 132,
|
|
16644
|
+
b: 1
|
|
16645
|
+
},
|
|
16646
|
+
moss: {
|
|
16647
|
+
r: 1,
|
|
16648
|
+
g: 132,
|
|
16649
|
+
b: 72
|
|
16650
|
+
},
|
|
16651
|
+
ocean: {
|
|
16652
|
+
r: 0,
|
|
16653
|
+
g: 74,
|
|
16654
|
+
b: 136
|
|
16655
|
+
},
|
|
16656
|
+
eggplant: {
|
|
16657
|
+
r: 73,
|
|
16658
|
+
g: 26,
|
|
16659
|
+
b: 136
|
|
16660
|
+
},
|
|
16661
|
+
maroon: {
|
|
16662
|
+
r: 137,
|
|
16663
|
+
g: 22,
|
|
16664
|
+
b: 72
|
|
16665
|
+
},
|
|
16666
|
+
steel: {
|
|
16667
|
+
r: 110,
|
|
16668
|
+
g: 110,
|
|
16669
|
+
b: 110
|
|
16670
|
+
},
|
|
16671
|
+
aluminum: {
|
|
16672
|
+
r: 160,
|
|
16673
|
+
g: 159,
|
|
16674
|
+
b: 160
|
|
16675
|
+
},
|
|
16676
|
+
cayenne: {
|
|
16677
|
+
r: 137,
|
|
16678
|
+
g: 17,
|
|
16679
|
+
b: 0
|
|
16680
|
+
},
|
|
16681
|
+
aspargus: {
|
|
16682
|
+
r: 136,
|
|
16683
|
+
g: 133,
|
|
16684
|
+
b: 1
|
|
16685
|
+
},
|
|
16686
|
+
clover: {
|
|
16687
|
+
r: 2,
|
|
16688
|
+
g: 132,
|
|
16689
|
+
b: 1
|
|
16690
|
+
},
|
|
16691
|
+
teal: {
|
|
16692
|
+
r: 0,
|
|
16693
|
+
g: 134,
|
|
16694
|
+
b: 136
|
|
16695
|
+
},
|
|
16696
|
+
midnight: {
|
|
16697
|
+
r: 0,
|
|
16698
|
+
g: 24,
|
|
16699
|
+
b: 136
|
|
16700
|
+
},
|
|
16701
|
+
plum: {
|
|
16702
|
+
r: 137,
|
|
16703
|
+
g: 30,
|
|
16704
|
+
b: 136
|
|
16705
|
+
},
|
|
16706
|
+
tin: {
|
|
16707
|
+
r: 135,
|
|
16708
|
+
g: 134,
|
|
16709
|
+
b: 135
|
|
16710
|
+
},
|
|
16711
|
+
nickel: {
|
|
16712
|
+
r: 136,
|
|
16713
|
+
g: 135,
|
|
16714
|
+
b: 135
|
|
16715
|
+
}
|
|
16716
|
+
};
|
|
16717
|
+
function appleCrayonRGB(name) {
|
|
16718
|
+
const {
|
|
16719
|
+
r,
|
|
16720
|
+
g,
|
|
16721
|
+
b
|
|
16722
|
+
} = appleCrayonRGBPalette[name];
|
|
16723
|
+
return `rgb(${r},${g},${b})`;
|
|
16724
|
+
}
|
|
16725
|
+
function appleCrayonRGBA(name, alpha) {
|
|
16726
|
+
const {
|
|
16727
|
+
r,
|
|
16728
|
+
g,
|
|
16729
|
+
b
|
|
16730
|
+
} = appleCrayonRGBPalette[name];
|
|
16731
|
+
return `rgba(${r},${g},${b},${alpha})`;
|
|
16732
|
+
}
|
|
16733
|
+
const colorPalettes = {
|
|
16734
|
+
Set1: ["rgb(228,26,28)", "rgb(55,126,184)", "rgb(77,175,74)", "rgb(166,86,40)", "rgb(152,78,163)", "rgb(255,127,0)", "rgb(247,129,191)", "rgb(153,153,153)", "rgb(255,255,51)"],
|
|
16735
|
+
Dark2: ["rgb(27,158,119)", "rgb(217,95,2)", "rgb(117,112,179)", "rgb(231,41,138)", "rgb(102,166,30)", "rgb(230,171,2)", "rgb(166,118,29)", "rgb(102,102,102)"],
|
|
16736
|
+
Set2: ["rgb(102, 194,165)", "rgb(252,141,98)", "rgb(141,160,203)", "rgb(231,138,195)", "rgb(166,216,84)", "rgb(255,217,47)", "rgb(229,196,148)", "rgb(179,179,179)"],
|
|
16737
|
+
Set3: ["rgb(141,211,199)", "rgb(255,255,179)", "rgb(190,186,218)", "rgb(251,128,114)", "rgb(128,177,211)", "rgb(253,180,98)", "rgb(179,222,105)", "rgb(252,205,229)", "rgb(217,217,217)", "rgb(188,128,189)", "rgb(204,235,197)", "rgb(255,237,111)"],
|
|
16738
|
+
Pastel1: ["rgb(251,180,174)", "rgb(179,205,227)", "rgb(204,235,197)", "rgb(222,203,228)", "rgb(254,217,166)", "rgb(255,255,204)", "rgb(229,216,189)", "rgb(253,218,236)"],
|
|
16739
|
+
Pastel2: ["rgb(173,226,207)", "rgb(253,205,172)", "rgb(203,213,232)", "rgb(244,202,228)", "rgb(230,245,201)", "rgb(255,242,174)", "rgb(243,225,206)"],
|
|
16740
|
+
Accent: ["rgb(127,201,127)", "rgb(190,174,212)", "rgb(253,192,134)", "rgb(255,255,153)", "rgb(56,108,176)", "rgb(240,2,127)", "rgb(191,91,23)"]
|
|
16741
|
+
};
|
|
16742
|
+
class PaletteColorTable {
|
|
16743
|
+
constructor(palette) {
|
|
16744
|
+
this.colors = colorPalettes[palette];
|
|
16745
|
+
if (!Array.isArray(this.colors)) this.colors = [];
|
|
16746
|
+
this.colorTable = {};
|
|
16747
|
+
this.nextIdx = 0;
|
|
16748
|
+
this.colorGenerator = new RandomColorGenerator();
|
|
16749
|
+
}
|
|
16750
|
+
getColor(key) {
|
|
16751
|
+
if (!this.colorTable.hasOwnProperty(key)) {
|
|
16752
|
+
if (this.nextIdx < this.colors.length) {
|
|
16753
|
+
this.colorTable[key] = this.colors[this.nextIdx];
|
|
16754
|
+
} else {
|
|
16755
|
+
this.colorTable[key] = this.colorGenerator.get();
|
|
16756
|
+
}
|
|
16757
|
+
this.nextIdx++;
|
|
16758
|
+
}
|
|
16759
|
+
return this.colorTable[key];
|
|
16760
|
+
}
|
|
16761
|
+
}
|
|
16762
|
+
class ColorTable {
|
|
16763
|
+
constructor(colors) {
|
|
16764
|
+
this.colorTable = colors || {};
|
|
16765
|
+
this.nextIdx = 0;
|
|
16766
|
+
this.colorGenerator = new RandomColorGenerator();
|
|
16767
|
+
}
|
|
16768
|
+
getColor(key) {
|
|
16769
|
+
if (!this.colorTable.hasOwnProperty(key)) {
|
|
16770
|
+
if (this.colorTable.hasOwnProperty("*")) {
|
|
16771
|
+
return this.colorTable["*"];
|
|
16772
|
+
}
|
|
16773
|
+
this.colorTable[key] = this.colorGenerator.get();
|
|
16774
|
+
}
|
|
16775
|
+
return this.colorTable[key];
|
|
16776
|
+
}
|
|
16777
|
+
}
|
|
16778
|
+
|
|
16779
|
+
// Random color generator from https://github.com/sterlingwes/RandomColor/blob/master/rcolor.js
|
|
16780
|
+
// Free to use & distribute under the MIT license
|
|
16781
|
+
// Wes Johnson (@SterlingWes)
|
|
16782
|
+
//
|
|
16783
|
+
// inspired by http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
|
16784
|
+
function RandomColorGenerator() {
|
|
16785
|
+
this.hue = Math.random();
|
|
16786
|
+
this.goldenRatio = 0.618033988749895;
|
|
16787
|
+
this.hexwidth = 2;
|
|
16788
|
+
}
|
|
16789
|
+
RandomColorGenerator.prototype.hsvToRgb = function (h, s, v) {
|
|
16790
|
+
var h_i = Math.floor(h * 6),
|
|
16791
|
+
f = h * 6 - h_i,
|
|
16792
|
+
p = v * (1 - s),
|
|
16793
|
+
q = v * (1 - f * s),
|
|
16794
|
+
t = v * (1 - (1 - f) * s),
|
|
16795
|
+
r = 255,
|
|
16796
|
+
g = 255,
|
|
16797
|
+
b = 255;
|
|
16798
|
+
switch (h_i) {
|
|
16799
|
+
case 0:
|
|
16800
|
+
r = v, g = t, b = p;
|
|
16801
|
+
break;
|
|
16802
|
+
case 1:
|
|
16803
|
+
r = q, g = v, b = p;
|
|
16804
|
+
break;
|
|
16805
|
+
case 2:
|
|
16806
|
+
r = p, g = v, b = t;
|
|
16807
|
+
break;
|
|
16808
|
+
case 3:
|
|
16809
|
+
r = p, g = q, b = v;
|
|
16810
|
+
break;
|
|
16811
|
+
case 4:
|
|
16812
|
+
r = t, g = p, b = v;
|
|
16813
|
+
break;
|
|
16814
|
+
case 5:
|
|
16815
|
+
r = v, g = p, b = q;
|
|
16816
|
+
break;
|
|
16817
|
+
}
|
|
16818
|
+
return [Math.floor(r * 256), Math.floor(g * 256), Math.floor(b * 256)];
|
|
16819
|
+
};
|
|
16820
|
+
RandomColorGenerator.prototype.padHex = function (str) {
|
|
16821
|
+
if (str.length > this.hexwidth) return str;
|
|
16822
|
+
return new Array(this.hexwidth - str.length + 1).join('0') + str;
|
|
16823
|
+
};
|
|
16824
|
+
RandomColorGenerator.prototype.get = function (saturation, value) {
|
|
16825
|
+
this.hue += this.goldenRatio;
|
|
16826
|
+
this.hue %= 1;
|
|
16827
|
+
if (typeof saturation !== "number") saturation = 0.5;
|
|
16828
|
+
if (typeof value !== "number") value = 0.95;
|
|
16829
|
+
var rgb = this.hsvToRgb(this.hue, saturation, value);
|
|
16830
|
+
return "#" + this.padHex(rgb[0].toString(16)) + this.padHex(rgb[1].toString(16)) + this.padHex(rgb[2].toString(16));
|
|
16831
|
+
};
|
|
16832
|
+
const randomColorGenerator = new RandomColorGenerator();
|
|
16833
|
+
function randomColor() {
|
|
16834
|
+
return randomColorGenerator.get();
|
|
16835
|
+
}
|
|
16836
|
+
function randomRGB$1(min, max) {
|
|
16837
|
+
min = IGVMath.clamp(min, 0, 255);
|
|
16838
|
+
max = IGVMath.clamp(max, 0, 255);
|
|
16839
|
+
const r = Math.round(Math.random() * (max - min) + min).toString(10);
|
|
16840
|
+
const g = Math.round(Math.random() * (max - min) + min).toString(10);
|
|
16841
|
+
const b = Math.round(Math.random() * (max - min) + min).toString(10);
|
|
16842
|
+
return `rgb(${r},${g},${b})`;
|
|
16843
|
+
}
|
|
16844
|
+
|
|
16475
16845
|
/*
|
|
16476
16846
|
* The MIT License (MIT)
|
|
16477
16847
|
*
|
|
@@ -16699,6 +17069,18 @@
|
|
|
16699
17069
|
if (fill) {
|
|
16700
17070
|
ctx.fill();
|
|
16701
17071
|
}
|
|
17072
|
+
},
|
|
17073
|
+
drawRandomColorVerticalLines: ctx => {
|
|
17074
|
+
for (let x = 0; x < ctx.canvas.width; x++) {
|
|
17075
|
+
IGVGraphics.fillRect(ctx, x, 0, 1, ctx.canvas.height, {
|
|
17076
|
+
fillStyle: randomRGB$1(100, 250)
|
|
17077
|
+
});
|
|
17078
|
+
}
|
|
17079
|
+
},
|
|
17080
|
+
labelTransformWithContext: (ctx, exe) => {
|
|
17081
|
+
ctx.translate(exe, 0);
|
|
17082
|
+
ctx.scale(-1, 1);
|
|
17083
|
+
ctx.translate(-exe, 0);
|
|
16702
17084
|
}
|
|
16703
17085
|
};
|
|
16704
17086
|
function doPath(ctx, x, y) {
|
|
@@ -18787,7 +19169,7 @@
|
|
|
18787
19169
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
18788
19170
|
* THE SOFTWARE.
|
|
18789
19171
|
*/
|
|
18790
|
-
const knownFileExtensions = new Set(["narrowpeak", "broadpeak", "regionpeak", "peaks", "bedgraph", "wig", "gff3", "gff", "gtf", "fusionjuncspan", "refflat", "seg", "aed", "bed", "vcf", "bb", "bigbed", "biginteract", "biggenepred", "bignarrowpeak", "bw", "bigwig", "bam", "tdf", "refgene", "genepred", "genepredext", "bedpe", "bp", "snp", "rmsk", "cram", "gwas", "maf", "mut", "tsv", "hiccups"]);
|
|
19172
|
+
const knownFileExtensions = new Set(["narrowpeak", "broadpeak", "regionpeak", "peaks", "bedgraph", "wig", "gff3", "gff", "gtf", "fusionjuncspan", "refflat", "seg", "aed", "bed", "vcf", "bb", "bigbed", "biginteract", "biggenepred", "bignarrowpeak", "bw", "bigwig", "bam", "tdf", "refgene", "genepred", "genepredext", "bedpe", "bp", "snp", "rmsk", "cram", "gwas", "maf", "mut", "tsv", "hiccups", "fasta", "fa", "fna"]);
|
|
18791
19173
|
|
|
18792
19174
|
/**
|
|
18793
19175
|
* Return a custom format object with the given name.
|
|
@@ -18842,6 +19224,10 @@
|
|
|
18842
19224
|
return "bigwig";
|
|
18843
19225
|
case "bb":
|
|
18844
19226
|
return "bigbed";
|
|
19227
|
+
case "fasta":
|
|
19228
|
+
case "fa":
|
|
19229
|
+
case "fna":
|
|
19230
|
+
return "fasta";
|
|
18845
19231
|
default:
|
|
18846
19232
|
if (knownFileExtensions.has(ext)) {
|
|
18847
19233
|
return ext;
|
|
@@ -18901,6 +19287,8 @@
|
|
|
18901
19287
|
case "biggenepred":
|
|
18902
19288
|
case "bignarrowpeak":
|
|
18903
19289
|
return "bedtype";
|
|
19290
|
+
case "fasta":
|
|
19291
|
+
return "sequence";
|
|
18904
19292
|
default:
|
|
18905
19293
|
return "annotation";
|
|
18906
19294
|
}
|
|
@@ -18982,6 +19370,14 @@
|
|
|
18982
19370
|
return comp;
|
|
18983
19371
|
}
|
|
18984
19372
|
|
|
19373
|
+
class Chromosome {
|
|
19374
|
+
constructor(name, order, bpLength) {
|
|
19375
|
+
this.name = name;
|
|
19376
|
+
this.order = order;
|
|
19377
|
+
this.bpLength = bpLength;
|
|
19378
|
+
}
|
|
19379
|
+
}
|
|
19380
|
+
|
|
18985
19381
|
/*
|
|
18986
19382
|
* The MIT License (MIT)
|
|
18987
19383
|
*
|
|
@@ -19006,318 +19402,160 @@
|
|
|
19006
19402
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19007
19403
|
* THE SOFTWARE.
|
|
19008
19404
|
*/
|
|
19009
|
-
const
|
|
19010
|
-
const
|
|
19011
|
-
|
|
19012
|
-
|
|
19013
|
-
|
|
19014
|
-
|
|
19015
|
-
|
|
19016
|
-
|
|
19017
|
-
|
|
19018
|
-
|
|
19019
|
-
|
|
19020
|
-
|
|
19021
|
-
|
|
19022
|
-
|
|
19023
|
-
|
|
19024
|
-
|
|
19025
|
-
|
|
19026
|
-
'GTG': 'V',
|
|
19027
|
-
'TCT': 'S',
|
|
19028
|
-
'TCC': 'S',
|
|
19029
|
-
'TCA': 'S',
|
|
19030
|
-
'TCG': 'S',
|
|
19031
|
-
'CCT': 'P',
|
|
19032
|
-
'CCC': 'P',
|
|
19033
|
-
'CCA': 'P',
|
|
19034
|
-
'CCG': 'P',
|
|
19035
|
-
'ACT': 'T',
|
|
19036
|
-
'ACC': 'T',
|
|
19037
|
-
'ACA': 'T',
|
|
19038
|
-
'ACG': 'T',
|
|
19039
|
-
'GCT': 'A',
|
|
19040
|
-
'GCC': 'A',
|
|
19041
|
-
'GCA': 'A',
|
|
19042
|
-
'GCG': 'A',
|
|
19043
|
-
'TAT': 'Y',
|
|
19044
|
-
'TAC': 'Y',
|
|
19045
|
-
'TAA': 'STOP',
|
|
19046
|
-
'TAG': 'STOP',
|
|
19047
|
-
'CAT': 'H',
|
|
19048
|
-
'CAC': 'H',
|
|
19049
|
-
'CAA': 'Q',
|
|
19050
|
-
'CAG': 'Q',
|
|
19051
|
-
'AAT': 'N',
|
|
19052
|
-
'AAC': 'N',
|
|
19053
|
-
'AAA': 'K',
|
|
19054
|
-
'AAG': 'K',
|
|
19055
|
-
'GAT': 'D',
|
|
19056
|
-
'GAC': 'D',
|
|
19057
|
-
'GAA': 'E',
|
|
19058
|
-
'GAG': 'E',
|
|
19059
|
-
'TGT': 'C',
|
|
19060
|
-
'TGC': 'C',
|
|
19061
|
-
'TGA': 'STOP',
|
|
19062
|
-
'TGG': 'W',
|
|
19063
|
-
'CGT': 'R',
|
|
19064
|
-
'CGC': 'R',
|
|
19065
|
-
'CGA': 'R',
|
|
19066
|
-
'CGG': 'R',
|
|
19067
|
-
'AGT': 'S',
|
|
19068
|
-
'AGC': 'S',
|
|
19069
|
-
'AGA': 'R',
|
|
19070
|
-
'AGG': 'R',
|
|
19071
|
-
'GGT': 'G',
|
|
19072
|
-
'GGC': 'G',
|
|
19073
|
-
'GGA': 'G',
|
|
19074
|
-
'GGG': 'G'
|
|
19075
|
-
};
|
|
19076
|
-
const complement = {};
|
|
19077
|
-
const t1 = ['A', 'G', 'C', 'T', 'Y', 'R', 'W', 'S', 'K', 'M', 'D', 'V', 'H', 'B', 'N', 'X'];
|
|
19078
|
-
const t2 = ['T', 'C', 'G', 'A', 'R', 'Y', 'W', 'S', 'M', 'K', 'H', 'B', 'D', 'V', 'N', 'X'];
|
|
19079
|
-
for (let i = 0; i < t1.length; i++) {
|
|
19080
|
-
complement[t1[i]] = t2[i];
|
|
19081
|
-
complement[t1[i].toLowerCase()] = t2[i].toLowerCase();
|
|
19082
|
-
}
|
|
19083
|
-
const DEFAULT_HEIGHT = 25;
|
|
19084
|
-
const TRANSLATED_HEIGHT = 115;
|
|
19085
|
-
const SEQUENCE_HEIGHT = 15;
|
|
19086
|
-
const FRAME_HEIGHT = 25;
|
|
19087
|
-
const FRAME_BORDER = 5;
|
|
19088
|
-
const BP_PER_PIXEL_THRESHOLD = 1 / 10;
|
|
19089
|
-
class SequenceTrack {
|
|
19090
|
-
constructor(config, browser) {
|
|
19091
|
-
this.type = "sequence";
|
|
19092
|
-
this.browser = browser;
|
|
19093
|
-
this.removable = false;
|
|
19405
|
+
const splitLines$4 = splitLines$5;
|
|
19406
|
+
const reservedProperties$1 = new Set(['fastaURL', 'indexURL', 'cytobandURL', 'indexed']);
|
|
19407
|
+
class NonIndexedFasta {
|
|
19408
|
+
constructor(reference) {
|
|
19409
|
+
this.fastaURL = reference.fastaURL;
|
|
19410
|
+
this.withCredentials = reference.withCredentials;
|
|
19411
|
+
this.chromosomeNames = [];
|
|
19412
|
+
this.chromosomes = {};
|
|
19413
|
+
this.sequences = new Map();
|
|
19414
|
+
|
|
19415
|
+
// Build a track-like config object from the referenceObject
|
|
19416
|
+
const config = {};
|
|
19417
|
+
for (let key in reference) {
|
|
19418
|
+
if (reference.hasOwnProperty(key) && !reservedProperties$1.has(key)) {
|
|
19419
|
+
config[key] = reference[key];
|
|
19420
|
+
}
|
|
19421
|
+
}
|
|
19094
19422
|
this.config = config;
|
|
19095
|
-
this.name = "Sequence";
|
|
19096
|
-
this.id = "sequence";
|
|
19097
|
-
this.sequenceType = config.sequenceType || "dna"; // dna | rna | prot
|
|
19098
|
-
this.disableButtons = false;
|
|
19099
|
-
this.order = config.order || defaultSequenceTrackOrder;
|
|
19100
|
-
this.ignoreTrackMenu = false;
|
|
19101
|
-
this.reversed = config.reversed === true;
|
|
19102
|
-
this.frameTranslate = config.frameTranslate === true;
|
|
19103
|
-
this.height = this.frameTranslate ? TRANSLATED_HEIGHT : DEFAULT_HEIGHT;
|
|
19104
19423
|
}
|
|
19105
|
-
|
|
19106
|
-
return
|
|
19107
|
-
name: this.reversed ? "Forward" : "Reverse",
|
|
19108
|
-
click: () => {
|
|
19109
|
-
this.reversed = !this.reversed;
|
|
19110
|
-
this.trackView.repaintViews();
|
|
19111
|
-
}
|
|
19112
|
-
}, {
|
|
19113
|
-
name: this.frameTranslate ? "Close Translation" : "Three-frame Translate",
|
|
19114
|
-
click: () => {
|
|
19115
|
-
this.frameTranslate = !this.frameTranslate;
|
|
19116
|
-
if (this.frameTranslate) {
|
|
19117
|
-
for (let vp of this.trackView.viewports) {
|
|
19118
|
-
vp.setContentHeight(TRANSLATED_HEIGHT);
|
|
19119
|
-
}
|
|
19120
|
-
this.trackView.setTrackHeight(TRANSLATED_HEIGHT);
|
|
19121
|
-
} else {
|
|
19122
|
-
for (let vp of this.trackView.viewports) {
|
|
19123
|
-
vp.setContentHeight(DEFAULT_HEIGHT);
|
|
19124
|
-
}
|
|
19125
|
-
this.trackView.setTrackHeight(DEFAULT_HEIGHT);
|
|
19126
|
-
}
|
|
19127
|
-
this.trackView.repaintViews();
|
|
19128
|
-
}
|
|
19129
|
-
}];
|
|
19424
|
+
async init() {
|
|
19425
|
+
return this.loadAll();
|
|
19130
19426
|
}
|
|
19131
|
-
|
|
19132
|
-
|
|
19133
|
-
if (viewport.referenceFrame.bpPerPixel <= 1) {
|
|
19134
|
-
const pixelWidth = viewport.getWidth();
|
|
19135
|
-
const bpWindow = pixelWidth * viewport.referenceFrame.bpPerPixel;
|
|
19136
|
-
const chr = viewport.referenceFrame.chr;
|
|
19137
|
-
const start = Math.floor(viewport.referenceFrame.start);
|
|
19138
|
-
const end = Math.ceil(start + bpWindow);
|
|
19139
|
-
const items = [{
|
|
19140
|
-
label: this.reversed ? 'View visible sequence (reversed)...' : 'View visible sequence...',
|
|
19141
|
-
click: async () => {
|
|
19142
|
-
let seq = await this.browser.genome.sequence.getSequence(chr, start, end);
|
|
19143
|
-
if (!seq) {
|
|
19144
|
-
seq = "Unknown sequence";
|
|
19145
|
-
} else if (this.reversed) {
|
|
19146
|
-
seq = reverseComplementSequence(seq);
|
|
19147
|
-
}
|
|
19148
|
-
this.browser.alert.present(seq);
|
|
19149
|
-
}
|
|
19150
|
-
}];
|
|
19151
|
-
if (isSecureContext()) {
|
|
19152
|
-
items.push({
|
|
19153
|
-
label: 'Copy visible sequence',
|
|
19154
|
-
click: async () => {
|
|
19155
|
-
let seq = await this.browser.genome.sequence.getSequence(chr, start, end);
|
|
19156
|
-
if (!seq) {
|
|
19157
|
-
seq = "Unknown sequence";
|
|
19158
|
-
} else if (this.reversed) {
|
|
19159
|
-
seq = reverseComplementSequence(seq);
|
|
19160
|
-
}
|
|
19161
|
-
try {
|
|
19162
|
-
await navigator.clipboard.writeText(seq);
|
|
19163
|
-
} catch (e) {
|
|
19164
|
-
console.error(e);
|
|
19165
|
-
this.browser.alert.present(`error copying sequence to clipboard ${e}`);
|
|
19166
|
-
}
|
|
19167
|
-
}
|
|
19168
|
-
});
|
|
19169
|
-
}
|
|
19170
|
-
items.push('<hr/>');
|
|
19171
|
-
return items;
|
|
19172
|
-
} else {
|
|
19427
|
+
async getSequence(chr, start, end) {
|
|
19428
|
+
if (!this.sequences.has(chr)) {
|
|
19173
19429
|
return undefined;
|
|
19174
19430
|
}
|
|
19175
|
-
|
|
19176
|
-
|
|
19177
|
-
|
|
19178
|
-
|
|
19179
|
-
|
|
19180
|
-
while (seq.length - idx >= 3) {
|
|
19181
|
-
let st = seq.slice(idx, idx + 3);
|
|
19182
|
-
if (this.reversed) {
|
|
19183
|
-
st = st.split('').reverse().join('');
|
|
19184
|
-
}
|
|
19185
|
-
const aa = translationDict[st.toUpperCase()] || "";
|
|
19186
|
-
threeFrame[fNum].push({
|
|
19187
|
-
codons: st,
|
|
19188
|
-
aminoA: aa
|
|
19189
|
-
});
|
|
19190
|
-
idx += 3;
|
|
19431
|
+
let seqSlice = this.sequences.get(chr).find(ss => ss.contains(start, end));
|
|
19432
|
+
if (!seqSlice) {
|
|
19433
|
+
seqSlice = this.sequences.get(chr).find(ss => ss.overlaps(start, end));
|
|
19434
|
+
if (!seqSlice) {
|
|
19435
|
+
return undefined;
|
|
19191
19436
|
}
|
|
19192
19437
|
}
|
|
19193
|
-
|
|
19194
|
-
|
|
19195
|
-
|
|
19196
|
-
start
|
|
19197
|
-
|
|
19198
|
-
|
|
19199
|
-
|
|
19200
|
-
}
|
|
19201
|
-
|
|
19202
|
-
return
|
|
19203
|
-
bpStart: start,
|
|
19204
|
-
sequence: sequence
|
|
19205
|
-
};
|
|
19438
|
+
start -= seqSlice.offset;
|
|
19439
|
+
end -= seqSlice.offset;
|
|
19440
|
+
let prefix = "";
|
|
19441
|
+
if (start < 0) {
|
|
19442
|
+
for (let i = start; i < Math.min(end, 0); i++) {
|
|
19443
|
+
prefix += "*";
|
|
19444
|
+
}
|
|
19445
|
+
}
|
|
19446
|
+
if (end <= 0) {
|
|
19447
|
+
return Promise.resolve(prefix);
|
|
19206
19448
|
}
|
|
19449
|
+
const seq = seqSlice.sequence;
|
|
19450
|
+
const seqEnd = Math.min(end, seq.length);
|
|
19451
|
+
return prefix + seq.substring(start, seqEnd);
|
|
19207
19452
|
}
|
|
19208
|
-
|
|
19209
|
-
|
|
19210
|
-
if (
|
|
19211
|
-
let
|
|
19212
|
-
|
|
19213
|
-
|
|
19214
|
-
|
|
19215
|
-
if (this.reversed) {
|
|
19216
|
-
sequence = sequence.split('').map(function (cv) {
|
|
19217
|
-
return complement[cv];
|
|
19218
|
-
}).join('');
|
|
19453
|
+
async loadAll() {
|
|
19454
|
+
let data;
|
|
19455
|
+
if (isDataURL(this.fastaURL)) {
|
|
19456
|
+
let bytes = decodeDataURI$1(this.fastaURL);
|
|
19457
|
+
data = "";
|
|
19458
|
+
for (let b of bytes) {
|
|
19459
|
+
data += String.fromCharCode(b);
|
|
19219
19460
|
}
|
|
19220
|
-
|
|
19221
|
-
|
|
19222
|
-
|
|
19223
|
-
|
|
19224
|
-
|
|
19225
|
-
|
|
19226
|
-
|
|
19227
|
-
|
|
19228
|
-
|
|
19229
|
-
|
|
19230
|
-
|
|
19231
|
-
|
|
19232
|
-
|
|
19233
|
-
|
|
19234
|
-
|
|
19235
|
-
|
|
19236
|
-
IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, {
|
|
19237
|
-
strokeStyle: color
|
|
19238
|
-
});
|
|
19239
|
-
}
|
|
19461
|
+
} else {
|
|
19462
|
+
data = await igvxhr.load(this.fastaURL, buildOptions(this.config));
|
|
19463
|
+
}
|
|
19464
|
+
const chrNameSet = new Set();
|
|
19465
|
+
const lines = splitLines$4(data);
|
|
19466
|
+
const len = lines.length;
|
|
19467
|
+
let lineNo = 0;
|
|
19468
|
+
let order = 0;
|
|
19469
|
+
let nextLine;
|
|
19470
|
+
let current = {};
|
|
19471
|
+
while (lineNo < len) {
|
|
19472
|
+
nextLine = lines[lineNo++].trim();
|
|
19473
|
+
if (nextLine.startsWith("#") || nextLine.length === 0) ; else if (nextLine.startsWith(">")) {
|
|
19474
|
+
// Start the next sequence
|
|
19475
|
+
if (current && current.seq) {
|
|
19476
|
+
pushChromosome.call(this, current, order++);
|
|
19240
19477
|
}
|
|
19241
|
-
|
|
19242
|
-
if (this.frameTranslate) {
|
|
19243
|
-
let y = SEQUENCE_HEIGHT + 2 * FRAME_BORDER;
|
|
19244
|
-
const translatedSequence = this.translateSequence(sequence);
|
|
19245
|
-
for (let fNum = 0; fNum < translatedSequence.length; fNum++) {
|
|
19246
|
-
// == 3, 1 for each frame
|
|
19247
|
-
|
|
19248
|
-
const aaSequence = translatedSequence[fNum]; // AA sequence for this frame
|
|
19249
|
-
|
|
19250
|
-
for (let idx = 0; idx < aaSequence.length; idx++) {
|
|
19251
|
-
let color = 0 === idx % 2 ? 'rgb(160,160,160)' : 'rgb(224,224,224)';
|
|
19252
|
-
const cv = aaSequence[idx];
|
|
19253
|
-
const bpPos = sequenceBpStart + fNum + idx * 3;
|
|
19254
|
-
const bpOffset = bpPos - options.bpStart;
|
|
19255
|
-
const p0 = Math.floor(bpOffset / options.bpPerPixel);
|
|
19256
|
-
const p1 = Math.floor((bpOffset + 3) / options.bpPerPixel);
|
|
19257
|
-
const pc = Math.round((p0 + p1) / 2);
|
|
19258
|
-
if (p1 < 0) {
|
|
19259
|
-
continue; // off left edge
|
|
19260
|
-
} else if (p0 > options.pixelWidth) {
|
|
19261
|
-
break; // off right edge
|
|
19262
|
-
}
|
|
19478
|
+
const parts = nextLine.substr(1).split(/\s+/);
|
|
19263
19479
|
|
|
19264
|
-
|
|
19265
|
-
|
|
19266
|
-
|
|
19267
|
-
|
|
19268
|
-
|
|
19269
|
-
|
|
19270
|
-
|
|
19271
|
-
|
|
19480
|
+
// Check for samtools style locus string. This is not perfect, and could fail on weird sequence names
|
|
19481
|
+
const nameParts = parts[0].split(':');
|
|
19482
|
+
current.chr = nameParts[0];
|
|
19483
|
+
current.seq = "";
|
|
19484
|
+
current.offset = 0;
|
|
19485
|
+
if (nameParts.length > 1 && nameParts[1].indexOf('-') > 0) {
|
|
19486
|
+
const locusParts = nameParts[1].split('-');
|
|
19487
|
+
if (locusParts.length === 2 && /^[0-9]+$/.test(locusParts[0]) && /^[0-9]+$/.test(locusParts[1])) ;
|
|
19488
|
+
const from = Number.parseInt(locusParts[0]);
|
|
19489
|
+
const to = Number.parseInt(locusParts[1]);
|
|
19490
|
+
if (to > from) {
|
|
19491
|
+
// TODO this should be an error
|
|
19492
|
+
current.offset = from - 1;
|
|
19493
|
+
}
|
|
19272
19494
|
|
|
19273
|
-
|
|
19274
|
-
|
|
19275
|
-
|
|
19276
|
-
|
|
19277
|
-
|
|
19495
|
+
// Check for chromosome length token
|
|
19496
|
+
if (parts.length > 1 && parts[1].startsWith("@len=")) {
|
|
19497
|
+
try {
|
|
19498
|
+
current.length = parseInt(parts[1].trim().substring(5));
|
|
19499
|
+
} catch (e) {
|
|
19500
|
+
current.length = undefined;
|
|
19501
|
+
console.error(`Error parsing sequence length for ${nextLine}`);
|
|
19278
19502
|
}
|
|
19503
|
+
} else {
|
|
19504
|
+
current.length = undefined;
|
|
19279
19505
|
}
|
|
19280
|
-
y += FRAME_HEIGHT + FRAME_BORDER;
|
|
19281
19506
|
}
|
|
19507
|
+
} else {
|
|
19508
|
+
current.seq += nextLine;
|
|
19509
|
+
}
|
|
19510
|
+
// add last seq
|
|
19511
|
+
if (current && current.seq) {
|
|
19512
|
+
pushChromosome.call(this, current, order);
|
|
19513
|
+
}
|
|
19514
|
+
}
|
|
19515
|
+
function pushChromosome(current, order) {
|
|
19516
|
+
const length = current.length || current.offset + current.seq.length;
|
|
19517
|
+
if (!chrNameSet.has(current.chr)) {
|
|
19518
|
+
this.chromosomeNames.push(current.chr);
|
|
19519
|
+
this.sequences.set(current.chr, []);
|
|
19520
|
+
this.chromosomes[current.chr] = new Chromosome(current.chr, order, length);
|
|
19521
|
+
chrNameSet.add(current.chr);
|
|
19522
|
+
} else {
|
|
19523
|
+
const c = this.chromosomes[current.chr];
|
|
19524
|
+
c.bpLength = Math.max(c.bpLength, length);
|
|
19282
19525
|
}
|
|
19526
|
+
this.sequences.get(current.chr).push(new SequenceSlice(current.offset, current.seq));
|
|
19283
19527
|
}
|
|
19284
19528
|
}
|
|
19285
|
-
|
|
19286
|
-
|
|
19529
|
+
}
|
|
19530
|
+
class SequenceSlice {
|
|
19531
|
+
constructor(offset, sequence) {
|
|
19532
|
+
this.offset = offset;
|
|
19533
|
+
this.sequence = sequence;
|
|
19287
19534
|
}
|
|
19288
|
-
|
|
19289
|
-
this.
|
|
19290
|
-
return this.height;
|
|
19535
|
+
contains(start, end) {
|
|
19536
|
+
return this.offset <= start && this.end >= end;
|
|
19291
19537
|
}
|
|
19292
|
-
|
|
19293
|
-
|
|
19294
|
-
return this.color;
|
|
19295
|
-
} else if ("dna" === this.sequenceType) {
|
|
19296
|
-
return this.browser.nucleotideColors[index] || 'gray';
|
|
19297
|
-
} else {
|
|
19298
|
-
return 'rgb(0, 0, 150)';
|
|
19299
|
-
}
|
|
19538
|
+
overlaps(start, end) {
|
|
19539
|
+
return this.offset < end && this.end > start;
|
|
19300
19540
|
}
|
|
19301
|
-
|
|
19302
|
-
|
|
19303
|
-
* Return the current state of the track. Used to create sessions and bookmarks.
|
|
19304
|
-
*
|
|
19305
|
-
* @returns {*|{}}
|
|
19306
|
-
*/
|
|
19307
|
-
getState() {
|
|
19308
|
-
const config = {
|
|
19309
|
-
type: "sequence"
|
|
19310
|
-
};
|
|
19311
|
-
if (this.order !== defaultSequenceTrackOrder) {
|
|
19312
|
-
config.order = this.order;
|
|
19313
|
-
}
|
|
19314
|
-
if (this.reversed) {
|
|
19315
|
-
config.revealed = true;
|
|
19316
|
-
}
|
|
19317
|
-
return config;
|
|
19541
|
+
get end() {
|
|
19542
|
+
return this.offset + this.sequence.length;
|
|
19318
19543
|
}
|
|
19319
19544
|
}
|
|
19320
19545
|
|
|
19546
|
+
const GenomicInterval = function (chr, start, end, features) {
|
|
19547
|
+
this.chr = chr;
|
|
19548
|
+
this.start = start;
|
|
19549
|
+
this.end = end;
|
|
19550
|
+
this.features = features;
|
|
19551
|
+
};
|
|
19552
|
+
GenomicInterval.prototype.contains = function (chr, start, end) {
|
|
19553
|
+
return this.chr === chr && this.start <= start && this.end >= end;
|
|
19554
|
+
};
|
|
19555
|
+
GenomicInterval.prototype.containsRange = function (range) {
|
|
19556
|
+
return this.chr === range.chr && this.start <= range.start && this.end >= range.end;
|
|
19557
|
+
};
|
|
19558
|
+
|
|
19321
19559
|
/*
|
|
19322
19560
|
* The MIT License (MIT)
|
|
19323
19561
|
*
|
|
@@ -19342,87 +19580,947 @@
|
|
|
19342
19580
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19343
19581
|
* THE SOFTWARE.
|
|
19344
19582
|
*/
|
|
19345
|
-
|
|
19346
|
-
|
|
19347
|
-
|
|
19348
|
-
|
|
19349
|
-
this.
|
|
19350
|
-
this.
|
|
19351
|
-
this
|
|
19352
|
-
|
|
19353
|
-
|
|
19354
|
-
|
|
19355
|
-
}
|
|
19356
|
-
|
|
19357
|
-
// Create an alert dialog for the sequence track to copy ref sequence to.
|
|
19358
|
-
if (trackView.track instanceof SequenceTrack) {
|
|
19359
|
-
this.alert = new AlertDialog(this.$viewport.get(0));
|
|
19360
|
-
}
|
|
19361
|
-
this.contentTop = 0;
|
|
19362
|
-
this.contentHeight = this.$viewport.height();
|
|
19363
|
-
this.$viewport.width(width);
|
|
19364
|
-
this.initializationHelper();
|
|
19365
|
-
}
|
|
19366
|
-
initializationHelper() {}
|
|
19367
|
-
showMessage(message) {
|
|
19368
|
-
if (!this.messageDiv) {
|
|
19369
|
-
this.messageDiv = document.createElement('div');
|
|
19370
|
-
this.messageDiv.className = 'igv-viewport-message';
|
|
19371
|
-
//this.contentDiv.append(this.messageDiv)
|
|
19372
|
-
this.$viewport.append($$1(this.messageDiv));
|
|
19373
|
-
}
|
|
19374
|
-
this.messageDiv.textContent = message;
|
|
19375
|
-
this.messageDiv.style.display = 'inline-block';
|
|
19376
|
-
}
|
|
19377
|
-
hideMessage(message) {
|
|
19378
|
-
if (this.messageDiv) this.messageDiv.style.display = 'none';
|
|
19379
|
-
}
|
|
19380
|
-
setTrackLabel(label) {}
|
|
19381
|
-
startSpinner() {}
|
|
19382
|
-
stopSpinner() {}
|
|
19383
|
-
checkZoomIn() {
|
|
19384
|
-
return true;
|
|
19385
|
-
}
|
|
19386
|
-
shift() {}
|
|
19387
|
-
setTop(contentTop) {
|
|
19388
|
-
this.contentTop = contentTop;
|
|
19389
|
-
this.$viewport.height();
|
|
19390
|
-
|
|
19391
|
-
//this.$content.css('top', `${contentTop}px`)
|
|
19392
|
-
//
|
|
19393
|
-
// if (undefined === this.canvasVerticalRange || this.canvasVerticalRange.bottom < viewBottom || this.canvasVerticalRange.top > viewTop) {
|
|
19394
|
-
// console.log("Repaint " + this.canvasVerticalRange)
|
|
19395
|
-
// this.repaint()
|
|
19396
|
-
// }
|
|
19397
|
-
}
|
|
19583
|
+
const splitLines$3 = splitLines$5;
|
|
19584
|
+
const reservedProperties = new Set(['fastaURL', 'indexURL', 'compressedIndexURL', 'cytobandURL', 'indexed']);
|
|
19585
|
+
class FastaSequence {
|
|
19586
|
+
constructor(reference) {
|
|
19587
|
+
this.file = reference.fastaURL;
|
|
19588
|
+
this.indexFile = reference.indexURL || reference.indexFile || this.file + ".fai";
|
|
19589
|
+
this.compressedIndexFile = reference.compressedIndexURL || false;
|
|
19590
|
+
this.withCredentials = reference.withCredentials;
|
|
19591
|
+
this.chromosomeNames = [];
|
|
19592
|
+
this.chromosomes = {};
|
|
19593
|
+
this.sequences = {};
|
|
19594
|
+
this.offsets = {};
|
|
19398
19595
|
|
|
19399
|
-
|
|
19400
|
-
|
|
19401
|
-
|
|
19402
|
-
|
|
19403
|
-
|
|
19404
|
-
draw(drawConfiguration, features, roiFeatures) {
|
|
19405
|
-
console.log('Viewport - draw(drawConfiguration, features, roiFeatures)');
|
|
19406
|
-
}
|
|
19407
|
-
checkContentHeight(features) {
|
|
19408
|
-
let track = this.trackView.track;
|
|
19409
|
-
features = features || this.cachedFeatures;
|
|
19410
|
-
if ("FILL" === track.displayMode) {
|
|
19411
|
-
this.setContentHeight(this.$viewport.height());
|
|
19412
|
-
} else if (typeof track.computePixelHeight === 'function') {
|
|
19413
|
-
if (features && features.length > 0) {
|
|
19414
|
-
let requiredContentHeight = track.computePixelHeight(features);
|
|
19415
|
-
//let currentContentHeight = this.$content.height()
|
|
19416
|
-
let currentContentHeight = this.contentHeight;
|
|
19417
|
-
if (requiredContentHeight !== currentContentHeight) {
|
|
19418
|
-
this.setContentHeight(requiredContentHeight);
|
|
19419
|
-
}
|
|
19596
|
+
// Build a track-like config object from the referenceObject
|
|
19597
|
+
const config = {};
|
|
19598
|
+
for (let key in reference) {
|
|
19599
|
+
if (reference.hasOwnProperty(key) && !reservedProperties.has(key)) {
|
|
19600
|
+
config[key] = reference[key];
|
|
19420
19601
|
}
|
|
19421
19602
|
}
|
|
19603
|
+
this.config = config;
|
|
19422
19604
|
}
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19605
|
+
async init() {
|
|
19606
|
+
return this.getIndex();
|
|
19607
|
+
}
|
|
19608
|
+
async getSequence(chr, start, end) {
|
|
19609
|
+
const hasCachedSquence = this.interval && this.interval.contains(chr, start, end);
|
|
19610
|
+
if (!hasCachedSquence) {
|
|
19611
|
+
// Expand query, to minimum of 50kb
|
|
19612
|
+
let qstart = start;
|
|
19613
|
+
let qend = end;
|
|
19614
|
+
if (end - start < 50000) {
|
|
19615
|
+
const w = end - start;
|
|
19616
|
+
const center = Math.round(start + w / 2);
|
|
19617
|
+
qstart = Math.max(0, center - 25000);
|
|
19618
|
+
qend = center + 25000;
|
|
19619
|
+
}
|
|
19620
|
+
const seqBytes = await this.readSequence(chr, qstart, qend);
|
|
19621
|
+
this.interval = new GenomicInterval(chr, qstart, qend, seqBytes);
|
|
19622
|
+
}
|
|
19623
|
+
const offset = start - this.interval.start;
|
|
19624
|
+
const n = end - start;
|
|
19625
|
+
const seq = this.interval.features ? this.interval.features.substr(offset, n) : null;
|
|
19626
|
+
return seq;
|
|
19627
|
+
}
|
|
19628
|
+
async getIndex() {
|
|
19629
|
+
if (this.index) {
|
|
19630
|
+
return this.index;
|
|
19631
|
+
} else {
|
|
19632
|
+
const data = await igvxhr.load(this.indexFile, buildOptions(this.config));
|
|
19633
|
+
const lines = splitLines$3(data);
|
|
19634
|
+
const len = lines.length;
|
|
19635
|
+
let lineNo = 0;
|
|
19636
|
+
let order = 0;
|
|
19637
|
+
this.index = {};
|
|
19638
|
+
while (lineNo < len) {
|
|
19639
|
+
const tokens = lines[lineNo++].split("\t");
|
|
19640
|
+
const nTokens = tokens.length;
|
|
19641
|
+
if (nTokens === 5) {
|
|
19642
|
+
// Parse the index line.
|
|
19643
|
+
const chr = tokens[0];
|
|
19644
|
+
const size = parseInt(tokens[1]);
|
|
19645
|
+
const position = parseInt(tokens[2]);
|
|
19646
|
+
const basesPerLine = parseInt(tokens[3]);
|
|
19647
|
+
const bytesPerLine = parseInt(tokens[4]);
|
|
19648
|
+
const indexEntry = {
|
|
19649
|
+
size: size,
|
|
19650
|
+
position: position,
|
|
19651
|
+
basesPerLine: basesPerLine,
|
|
19652
|
+
bytesPerLine: bytesPerLine
|
|
19653
|
+
};
|
|
19654
|
+
this.chromosomeNames.push(chr);
|
|
19655
|
+
this.index[chr] = indexEntry;
|
|
19656
|
+
this.chromosomes[chr] = new Chromosome(chr, order++, size);
|
|
19657
|
+
}
|
|
19658
|
+
}
|
|
19659
|
+
return this.index;
|
|
19660
|
+
}
|
|
19661
|
+
}
|
|
19662
|
+
|
|
19663
|
+
//Code is losely based on https://github.com/GMOD/bgzf-filehandle
|
|
19664
|
+
//Reworked however in orde to work with the igvxhr interface for loading files
|
|
19665
|
+
//Additionally, replaced calls to the Long.js interface with standard JS calls for ArrayBuffers and the associated views
|
|
19666
|
+
//
|
|
19667
|
+
//The compressed index is an array of blocks, with each block being a pair: compressed-position & uncompressed-position (both in bytes)
|
|
19668
|
+
async getCompressedIndex() {
|
|
19669
|
+
const GZI_NUM_BYTES_OFFSET = 8;
|
|
19670
|
+
const GZI_NUM_BYTES_BLOCK = 8;
|
|
19671
|
+
if (this.compressedIndex) {
|
|
19672
|
+
return this.compressedIndex;
|
|
19673
|
+
}
|
|
19674
|
+
if (!this.compressedIndexFile) {
|
|
19675
|
+
this.compressedIndex = [];
|
|
19676
|
+
return this.compressedIndex;
|
|
19677
|
+
}
|
|
19678
|
+
//In contrast to the 'normal' reference (for which the index is chromosome based), this index is block-based
|
|
19679
|
+
//As such there is not need to make it a hash. An array is sufficient.
|
|
19680
|
+
this.compressedIndex = [];
|
|
19681
|
+
const gziData = await igvxhr.loadArrayBuffer(this.compressedIndexFile, buildOptions(this.config));
|
|
19682
|
+
const givenFileSize = gziData.byteLength;
|
|
19683
|
+
if (givenFileSize < GZI_NUM_BYTES_OFFSET) {
|
|
19684
|
+
console.log("Cannot parse GZI index file: length (" + givenFileSize + " bytes) is insufficient to determine content of index.");
|
|
19685
|
+
return this.compressedIndex;
|
|
19686
|
+
}
|
|
19687
|
+
//First 8 bytes are a little endian unsigned bigint (64bit), indicating the number of blocks in the index.
|
|
19688
|
+
const numBlocksBuffer = gziData.slice(0, GZI_NUM_BYTES_OFFSET);
|
|
19689
|
+
const numBlocks = Number(new DataView(numBlocksBuffer).getBigUint64(0, true));
|
|
19690
|
+
//The remainder of the gzi content are pairs of little endian unsigned bigint (64bit) numbers.
|
|
19691
|
+
//The first of the pair is the compressed position of a block
|
|
19692
|
+
//The second of the pair is the uncompressed position of a block
|
|
19693
|
+
|
|
19694
|
+
//Sanity check:
|
|
19695
|
+
//Is the size of the array-buffer (of the entire file) correct with regards to the number of blocks detailled by the first 8 bytes of the file?
|
|
19696
|
+
//Total file-size should be:
|
|
19697
|
+
// 8 + 2*(num_entries*8) bytes, with the first 8 bytes indicating the number of entries
|
|
19698
|
+
const expectedFileSize = GZI_NUM_BYTES_OFFSET + numBlocks * 2 * GZI_NUM_BYTES_BLOCK;
|
|
19699
|
+
if (givenFileSize != expectedFileSize) {
|
|
19700
|
+
console.log("Incorrect file size of reference genome index. Expected : " + expectedFileSize + ". Received : " + givenFileSize);
|
|
19701
|
+
return this.compressedIndex;
|
|
19702
|
+
}
|
|
19703
|
+
|
|
19704
|
+
//Push the first block to the index: the first block always has positions 0 for both the compressed and uncompressed file
|
|
19705
|
+
this.compressedIndex.push([0, 0]);
|
|
19706
|
+
|
|
19707
|
+
//Further process all the blocks of the GZI index, and keep them in memory
|
|
19708
|
+
for (let blockNumber = 0; blockNumber < numBlocks; blockNumber++) {
|
|
19709
|
+
const bufferBlockStart = GZI_NUM_BYTES_OFFSET + blockNumber * 2 * GZI_NUM_BYTES_BLOCK;
|
|
19710
|
+
const bufferBlockEnd = GZI_NUM_BYTES_OFFSET + blockNumber * 2 * GZI_NUM_BYTES_BLOCK + 2 * GZI_NUM_BYTES_BLOCK;
|
|
19711
|
+
const bufferBlock = gziData.slice(bufferBlockStart, bufferBlockEnd);
|
|
19712
|
+
const viewBlock = new DataView(bufferBlock);
|
|
19713
|
+
const compressedPosition = Number(viewBlock.getBigUint64(0, true)); //First 8 bytes
|
|
19714
|
+
const uncompressedPosition = Number(viewBlock.getBigUint64(GZI_NUM_BYTES_BLOCK, true)); //Last 8 bytes
|
|
19715
|
+
this.compressedIndex.push([compressedPosition, uncompressedPosition]);
|
|
19716
|
+
}
|
|
19717
|
+
return this.compressedIndex;
|
|
19718
|
+
}
|
|
19719
|
+
|
|
19720
|
+
//The Fasta-index gives a byte-position of the chromosomal sequences within the FASTA file.
|
|
19721
|
+
//These locations need to be remapped to the locations within the zipped reference genome, using the GZI index
|
|
19722
|
+
//This function provides this functionality by
|
|
19723
|
+
//1) taking the indicated start/stop byte locations within the UNCOMPRESSED FASTA file
|
|
19724
|
+
//2) remapping these byte locations to the correct blocks (and associated positions) within the COMPRESSED FASTA file
|
|
19725
|
+
//Subsequently, the calling method can then extract the correct blocks from the compressed FASTA files and uncompressed the data
|
|
19726
|
+
async getRelevantCompressedBlockNumbers(queryPositionStart, queryPositionEnd) {
|
|
19727
|
+
const UNCOMPRESSED_POSITION = 1;
|
|
19728
|
+
//Fallback for impossible values
|
|
19729
|
+
if (queryPositionStart < 0 || queryPositionEnd < 0 || queryPositionEnd < queryPositionStart) {
|
|
19730
|
+
console.log("Incompatible query positions for reference-genome. Start:" + queryPositionStart + " | End:" + queryPositionEnd);
|
|
19731
|
+
return [];
|
|
19732
|
+
}
|
|
19733
|
+
//Ensure compressed index is loaded
|
|
19734
|
+
await this.getCompressedIndex();
|
|
19735
|
+
let result = [];
|
|
19736
|
+
//Now search for the correct block-numbers (going from 0 to length(compressed-index)) which overlap with the provided byte-positions
|
|
19737
|
+
const lowestBlockNumber = 0;
|
|
19738
|
+
const highestBlockNumber = this.compressedIndex.length - 1;
|
|
19739
|
+
//Failsafe if for some reason the compressed index wasn't loaded or doesn't contain any data
|
|
19740
|
+
if (this.compressedIndex.length == 0) {
|
|
19741
|
+
console.log("Compressed index does not contain any content");
|
|
19742
|
+
return [];
|
|
19743
|
+
}
|
|
19744
|
+
//Failsafe: if the queryPositionStart is greater than the uncompressed-position of the final block,
|
|
19745
|
+
//then this final block is the only possible result
|
|
19746
|
+
if (queryPositionStart > this.compressedIndex[highestBlockNumber][UNCOMPRESSED_POSITION]) {
|
|
19747
|
+
return [highestBlockNumber];
|
|
19748
|
+
}
|
|
19749
|
+
|
|
19750
|
+
//Rather than doing a linear search over all blocks, a binary search is done for speed considerations
|
|
19751
|
+
//We are searching for the highest block number for which its position is smaller than the query start position
|
|
19752
|
+
//Afterwards we will simply expand the blocks until the entire query range is covered
|
|
19753
|
+
let searchLow = lowestBlockNumber;
|
|
19754
|
+
let searchHigh = highestBlockNumber;
|
|
19755
|
+
let searchPosition = Math.floor(this.compressedIndex.length / 2);
|
|
19756
|
+
let maxIterations = this.compressedIndex.length + 1;
|
|
19757
|
+
let solutionFound = false;
|
|
19758
|
+
//instead of doing a while(true), this for-loop prevents eternal loops in case of issues
|
|
19759
|
+
for (let iteration = 0; iteration < maxIterations; iteration++) {
|
|
19760
|
+
const searchUncompressedPosition = this.compressedIndex[searchPosition][UNCOMPRESSED_POSITION];
|
|
19761
|
+
const nextSearchUncompressedPosition = searchPosition < this.compressedIndex.length - 1 ? this.compressedIndex[searchPosition + 1][UNCOMPRESSED_POSITION] : Infinity;
|
|
19762
|
+
//The query position lies within the current search block
|
|
19763
|
+
if (searchUncompressedPosition <= queryPositionStart && nextSearchUncompressedPosition > queryPositionStart) {
|
|
19764
|
+
solutionFound = true;
|
|
19765
|
+
break; //searchPosition is the correct block number index
|
|
19766
|
+
}
|
|
19767
|
+
//Current block lies before the query position
|
|
19768
|
+
else if (searchUncompressedPosition < queryPositionStart) {
|
|
19769
|
+
searchLow = searchPosition + 1;
|
|
19770
|
+
}
|
|
19771
|
+
//Current block lies after the query position
|
|
19772
|
+
else {
|
|
19773
|
+
searchHigh = searchPosition - 1;
|
|
19774
|
+
}
|
|
19775
|
+
searchPosition = Math.ceil((searchHigh - searchLow) / 2) + searchLow;
|
|
19776
|
+
}
|
|
19777
|
+
//If for some reason the binary search did not reveal a correct block index, then we return the empty result
|
|
19778
|
+
if (!solutionFound) {
|
|
19779
|
+
console.log("No blocks within compressed index found that correspond with query positions " + queryPositionStart + "," + queryPositionEnd);
|
|
19780
|
+
console.log(this.compressedIndex);
|
|
19781
|
+
return [];
|
|
19782
|
+
}
|
|
19783
|
+
|
|
19784
|
+
//Now extend the result by adding additional blocks until the entire query range is covered
|
|
19785
|
+
result.push(searchPosition);
|
|
19786
|
+
for (let blockIndex = searchPosition + 1; blockIndex < this.compressedIndex.length; blockIndex++) {
|
|
19787
|
+
result.push(blockIndex);
|
|
19788
|
+
const blockUncompressedPosition = this.compressedIndex[blockIndex][UNCOMPRESSED_POSITION];
|
|
19789
|
+
if (blockUncompressedPosition >= queryPositionEnd) {
|
|
19790
|
+
break;
|
|
19791
|
+
}
|
|
19792
|
+
}
|
|
19793
|
+
|
|
19794
|
+
//It is possible that the query end position lies AFTER the start of the final block
|
|
19795
|
+
//If this is the case, we add a 'fake' negative index which will be interpreted by the loadAndUncompressBlocks method as an indicator
|
|
19796
|
+
//to read until the end of the file
|
|
19797
|
+
const finalRelevantBlock = result[result.length - 1];
|
|
19798
|
+
const finalIndexBlock = this.compressedIndex.length - 1;
|
|
19799
|
+
if (finalRelevantBlock === finalIndexBlock && this.compressedIndex[finalRelevantBlock][UNCOMPRESSED_POSITION] < queryPositionEnd) {
|
|
19800
|
+
result.push(-1);
|
|
19801
|
+
}
|
|
19802
|
+
return result;
|
|
19803
|
+
}
|
|
19804
|
+
|
|
19805
|
+
//Load the content from the blockIndices.
|
|
19806
|
+
//This is done on a per-block basis
|
|
19807
|
+
//Content of the first block will be trimmed in order to match the expected offset
|
|
19808
|
+
async loadAndUncompressBlocks(blockIndices, startByte) {
|
|
19809
|
+
const COMPRESSED_POSITION = 0;
|
|
19810
|
+
const UNCOMPRESSED_POSITION = 1;
|
|
19811
|
+
//Normally the compressed index should already exist, we're just makeing sure here
|
|
19812
|
+
await this.getCompressedIndex();
|
|
19813
|
+
if (blockIndices.length == 0) {
|
|
19814
|
+
return "";
|
|
19815
|
+
}
|
|
19816
|
+
|
|
19817
|
+
//Storing data in seperate array with indices in order to assert order due to async behaviour of loops
|
|
19818
|
+
let resultCache = Array(blockIndices.length - 1);
|
|
19819
|
+
for (let i = 0; i < blockIndices.length - 1; i++) {
|
|
19820
|
+
const currentBlockNumber = blockIndices[i];
|
|
19821
|
+
const currentBlockInfo = this.compressedIndex[currentBlockNumber];
|
|
19822
|
+
const currentBlockCompressedPosition = currentBlockInfo[COMPRESSED_POSITION];
|
|
19823
|
+
const nextBlockNumber = blockIndices[i + 1];
|
|
19824
|
+
let compressedBytes = [];
|
|
19825
|
+
if (nextBlockNumber != -1) {
|
|
19826
|
+
//default : read current entire block only
|
|
19827
|
+
const nextBlockInfo = this.compressedIndex[nextBlockNumber];
|
|
19828
|
+
const nextBlockCompressedPosition = nextBlockInfo[COMPRESSED_POSITION];
|
|
19829
|
+
const compressedLength = nextBlockCompressedPosition - currentBlockCompressedPosition;
|
|
19830
|
+
compressedBytes = await igvxhr.loadArrayBuffer(this.file, buildOptions(this.config, {
|
|
19831
|
+
range: {
|
|
19832
|
+
start: currentBlockCompressedPosition,
|
|
19833
|
+
size: compressedLength
|
|
19834
|
+
}
|
|
19835
|
+
}));
|
|
19836
|
+
} else {
|
|
19837
|
+
// special case for query within final block: read until the end of the file
|
|
19838
|
+
compressedBytes = await igvxhr.loadArrayBuffer(this.file, buildOptions(this.config, {
|
|
19839
|
+
range: {
|
|
19840
|
+
start: currentBlockCompressedPosition
|
|
19841
|
+
}
|
|
19842
|
+
}));
|
|
19843
|
+
}
|
|
19844
|
+
//now unzip the compressed bytes, and store them in the resultCache
|
|
19845
|
+
const uncompressedBytes = await unbgzf(compressedBytes);
|
|
19846
|
+
resultCache[i] = uncompressedBytes;
|
|
19847
|
+
}
|
|
19848
|
+
|
|
19849
|
+
//Iterate over the result cache, create sequences from the data, and create a full sequence string from the data
|
|
19850
|
+
let result = "";
|
|
19851
|
+
for (let i = 0; i < resultCache.length; i++) {
|
|
19852
|
+
for (let j = 0; j < resultCache[i].length; j++) {
|
|
19853
|
+
const c = String.fromCharCode(resultCache[i][j]);
|
|
19854
|
+
result = result + c;
|
|
19855
|
+
}
|
|
19856
|
+
}
|
|
19857
|
+
|
|
19858
|
+
//postprocess this data: because entire blocks are read we need to remove the first N bases of the first used block,
|
|
19859
|
+
//which are not included in the original query positions
|
|
19860
|
+
const firstBlockInfo = this.compressedIndex[blockIndices[0]];
|
|
19861
|
+
const offset = startByte - firstBlockInfo[UNCOMPRESSED_POSITION];
|
|
19862
|
+
result = result.substring(offset);
|
|
19863
|
+
return result;
|
|
19864
|
+
}
|
|
19865
|
+
async readSequence(chr, qstart, qend) {
|
|
19866
|
+
await this.getIndex();
|
|
19867
|
+
await this.getCompressedIndex(); //This will work even if no compressed index file is set
|
|
19868
|
+
|
|
19869
|
+
const idxEntry = this.index[chr];
|
|
19870
|
+
if (!idxEntry) {
|
|
19871
|
+
console.log("No index entry for chr: " + chr);
|
|
19872
|
+
// Tag interval with null so we don't try again
|
|
19873
|
+
this.interval = new GenomicInterval(chr, qstart, qend, null);
|
|
19874
|
+
return null;
|
|
19875
|
+
}
|
|
19876
|
+
const start = Math.max(0, qstart); // qstart should never be < 0
|
|
19877
|
+
const end = Math.min(idxEntry.size, qend);
|
|
19878
|
+
const bytesPerLine = idxEntry.bytesPerLine;
|
|
19879
|
+
const basesPerLine = idxEntry.basesPerLine;
|
|
19880
|
+
const position = idxEntry.position;
|
|
19881
|
+
const nEndBytes = bytesPerLine - basesPerLine;
|
|
19882
|
+
const startLine = Math.floor(start / basesPerLine);
|
|
19883
|
+
const endLine = Math.floor(end / basesPerLine);
|
|
19884
|
+
const base0 = startLine * basesPerLine; // Base at beginning of start line
|
|
19885
|
+
const offset = start - base0;
|
|
19886
|
+
const startByte = position + startLine * bytesPerLine + offset;
|
|
19887
|
+
const base1 = endLine * basesPerLine;
|
|
19888
|
+
const offset1 = end - base1;
|
|
19889
|
+
const endByte = position + endLine * bytesPerLine + offset1 - 1;
|
|
19890
|
+
const byteCount = endByte - startByte + 1;
|
|
19891
|
+
if (byteCount <= 0) {
|
|
19892
|
+
console.error("No sequence for " + chr + ":" + qstart + "-" + qend);
|
|
19893
|
+
return null;
|
|
19894
|
+
}
|
|
19895
|
+
|
|
19896
|
+
//If the compressed index file is set, then we are dealing with a compressed genome sequence
|
|
19897
|
+
//The selection of startByte/endByte is done for the non-compressed genome sequence.
|
|
19898
|
+
//These need to be 'converted' to the correct byte positions in the compressed genome sequence,
|
|
19899
|
+
//by making use of the compressed index (GZI file)
|
|
19900
|
+
let allBytes;
|
|
19901
|
+
if (!this.compressedIndexFile) {
|
|
19902
|
+
allBytes = await igvxhr.load(this.file, buildOptions(this.config, {
|
|
19903
|
+
range: {
|
|
19904
|
+
start: startByte,
|
|
19905
|
+
size: byteCount
|
|
19906
|
+
}
|
|
19907
|
+
}));
|
|
19908
|
+
} else {
|
|
19909
|
+
let relevantBlockIndices = await this.getRelevantCompressedBlockNumbers(startByte, endByte);
|
|
19910
|
+
if (relevantBlockIndices.length === 0) {
|
|
19911
|
+
console.log("No blocks in the compressed index that correspond with the requested byte positions (" + startByte + "," + endByte + ")");
|
|
19912
|
+
return null;
|
|
19913
|
+
}
|
|
19914
|
+
allBytes = await this.loadAndUncompressBlocks(relevantBlockIndices, startByte);
|
|
19915
|
+
}
|
|
19916
|
+
if (!allBytes) {
|
|
19917
|
+
return null;
|
|
19918
|
+
}
|
|
19919
|
+
let nBases,
|
|
19920
|
+
seqBytes = "",
|
|
19921
|
+
srcPos = 0,
|
|
19922
|
+
allBytesLength = allBytes.length;
|
|
19923
|
+
if (offset > 0) {
|
|
19924
|
+
nBases = Math.min(end - start, basesPerLine - offset);
|
|
19925
|
+
seqBytes += allBytes.substr(srcPos, nBases);
|
|
19926
|
+
srcPos += nBases + nEndBytes;
|
|
19927
|
+
}
|
|
19928
|
+
while (srcPos < allBytesLength) {
|
|
19929
|
+
nBases = Math.min(basesPerLine, allBytesLength - srcPos);
|
|
19930
|
+
seqBytes += allBytes.substr(srcPos, nBases);
|
|
19931
|
+
srcPos += nBases + nEndBytes;
|
|
19932
|
+
}
|
|
19933
|
+
return seqBytes;
|
|
19934
|
+
}
|
|
19935
|
+
}
|
|
19936
|
+
|
|
19937
|
+
/*
|
|
19938
|
+
* The MIT License (MIT)
|
|
19939
|
+
*
|
|
19940
|
+
* Copyright (c) 2014 Broad Institute
|
|
19941
|
+
*
|
|
19942
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
19943
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
19944
|
+
* in the Software without restriction, including without limitation the rights
|
|
19945
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
19946
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
19947
|
+
* furnished to do so, subject to the following conditions:
|
|
19948
|
+
*
|
|
19949
|
+
* The above copyright notice and this permission notice shall be included in
|
|
19950
|
+
* all copies or substantial portions of the Software.
|
|
19951
|
+
*
|
|
19952
|
+
*
|
|
19953
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19954
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19955
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19956
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19957
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19958
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19959
|
+
* THE SOFTWARE.
|
|
19960
|
+
*/
|
|
19961
|
+
const splitLines$2 = splitLines$5;
|
|
19962
|
+
class ChromSizes {
|
|
19963
|
+
constructor(url) {
|
|
19964
|
+
this.url = url;
|
|
19965
|
+
this.chromosomeNames = [];
|
|
19966
|
+
this.chromosomes = {};
|
|
19967
|
+
}
|
|
19968
|
+
async init() {
|
|
19969
|
+
return this.loadAll();
|
|
19970
|
+
}
|
|
19971
|
+
async getSequence(chr, start, end) {
|
|
19972
|
+
return undefined; // TODO -- return array of "N"s?
|
|
19973
|
+
}
|
|
19974
|
+
|
|
19975
|
+
async loadAll() {
|
|
19976
|
+
let data;
|
|
19977
|
+
if (isDataURL(this.url)) {
|
|
19978
|
+
let bytes = decodeDataURI$1(this.fastaURL);
|
|
19979
|
+
data = "";
|
|
19980
|
+
for (let b of bytes) {
|
|
19981
|
+
data += String.fromCharCode(b);
|
|
19982
|
+
}
|
|
19983
|
+
} else {
|
|
19984
|
+
data = await igvxhr.load(this.url, {});
|
|
19985
|
+
}
|
|
19986
|
+
this.chromosomeNames = [];
|
|
19987
|
+
this.chromosomes = {};
|
|
19988
|
+
const lines = splitLines$2(data);
|
|
19989
|
+
let order = 0;
|
|
19990
|
+
for (let nextLine of lines) {
|
|
19991
|
+
const tokens = nextLine.split('\t');
|
|
19992
|
+
this.chromosomeNames.push(tokens[0]);
|
|
19993
|
+
const chrLength = Number.parseInt(tokens[1]);
|
|
19994
|
+
const chromosome = new Chromosome(tokens[0], order++, chrLength);
|
|
19995
|
+
this.chromosomes[tokens[0]] = chromosome;
|
|
19996
|
+
}
|
|
19997
|
+
}
|
|
19998
|
+
}
|
|
19999
|
+
|
|
20000
|
+
async function loadFasta(reference) {
|
|
20001
|
+
let fasta;
|
|
20002
|
+
if ("chromsizes" === reference.format) {
|
|
20003
|
+
fasta = new ChromSizes(reference.fastaURL);
|
|
20004
|
+
} else if (isDataURL(reference.fastaURL) || reference.indexed === false) {
|
|
20005
|
+
fasta = new NonIndexedFasta(reference);
|
|
20006
|
+
} else {
|
|
20007
|
+
fasta = new FastaSequence(reference);
|
|
20008
|
+
}
|
|
20009
|
+
await fasta.init();
|
|
20010
|
+
return fasta;
|
|
20011
|
+
}
|
|
20012
|
+
|
|
20013
|
+
const defaultNucleotideColors = {
|
|
20014
|
+
"A": "rgb( 0, 200, 0)",
|
|
20015
|
+
"C": "rgb( 0,0,200)",
|
|
20016
|
+
"T": "rgb(255,0,0)",
|
|
20017
|
+
"G": "rgb(209,113, 5)",
|
|
20018
|
+
"N": "rgb(80,80,80)"
|
|
20019
|
+
};
|
|
20020
|
+
|
|
20021
|
+
/*
|
|
20022
|
+
* The MIT License (MIT)
|
|
20023
|
+
*
|
|
20024
|
+
* Copyright (c) 2014 Broad Institute
|
|
20025
|
+
*
|
|
20026
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
20027
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
20028
|
+
* in the Software without restriction, including without limitation the rights
|
|
20029
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
20030
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
20031
|
+
* furnished to do so, subject to the following conditions:
|
|
20032
|
+
*
|
|
20033
|
+
* The above copyright notice and this permission notice shall be included in
|
|
20034
|
+
* all copies or substantial portions of the Software.
|
|
20035
|
+
*
|
|
20036
|
+
*
|
|
20037
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20038
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20039
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20040
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20041
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20042
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20043
|
+
* THE SOFTWARE.
|
|
20044
|
+
*/
|
|
20045
|
+
const defaultSequenceTrackOrder = Number.MIN_SAFE_INTEGER;
|
|
20046
|
+
const translationDict = {
|
|
20047
|
+
'TTT': 'F',
|
|
20048
|
+
'TTC': 'F',
|
|
20049
|
+
'TTA': 'L',
|
|
20050
|
+
'TTG': 'L',
|
|
20051
|
+
'CTT': 'L',
|
|
20052
|
+
'CTC': 'L',
|
|
20053
|
+
'CTA': 'L',
|
|
20054
|
+
'CTG': 'L',
|
|
20055
|
+
'ATT': 'I',
|
|
20056
|
+
'ATC': 'I',
|
|
20057
|
+
'ATA': 'I',
|
|
20058
|
+
'ATG': 'M',
|
|
20059
|
+
'GTT': 'V',
|
|
20060
|
+
'GTC': 'V',
|
|
20061
|
+
'GTA': 'V',
|
|
20062
|
+
'GTG': 'V',
|
|
20063
|
+
'TCT': 'S',
|
|
20064
|
+
'TCC': 'S',
|
|
20065
|
+
'TCA': 'S',
|
|
20066
|
+
'TCG': 'S',
|
|
20067
|
+
'CCT': 'P',
|
|
20068
|
+
'CCC': 'P',
|
|
20069
|
+
'CCA': 'P',
|
|
20070
|
+
'CCG': 'P',
|
|
20071
|
+
'ACT': 'T',
|
|
20072
|
+
'ACC': 'T',
|
|
20073
|
+
'ACA': 'T',
|
|
20074
|
+
'ACG': 'T',
|
|
20075
|
+
'GCT': 'A',
|
|
20076
|
+
'GCC': 'A',
|
|
20077
|
+
'GCA': 'A',
|
|
20078
|
+
'GCG': 'A',
|
|
20079
|
+
'TAT': 'Y',
|
|
20080
|
+
'TAC': 'Y',
|
|
20081
|
+
'TAA': 'STOP',
|
|
20082
|
+
'TAG': 'STOP',
|
|
20083
|
+
'CAT': 'H',
|
|
20084
|
+
'CAC': 'H',
|
|
20085
|
+
'CAA': 'Q',
|
|
20086
|
+
'CAG': 'Q',
|
|
20087
|
+
'AAT': 'N',
|
|
20088
|
+
'AAC': 'N',
|
|
20089
|
+
'AAA': 'K',
|
|
20090
|
+
'AAG': 'K',
|
|
20091
|
+
'GAT': 'D',
|
|
20092
|
+
'GAC': 'D',
|
|
20093
|
+
'GAA': 'E',
|
|
20094
|
+
'GAG': 'E',
|
|
20095
|
+
'TGT': 'C',
|
|
20096
|
+
'TGC': 'C',
|
|
20097
|
+
'TGA': 'STOP',
|
|
20098
|
+
'TGG': 'W',
|
|
20099
|
+
'CGT': 'R',
|
|
20100
|
+
'CGC': 'R',
|
|
20101
|
+
'CGA': 'R',
|
|
20102
|
+
'CGG': 'R',
|
|
20103
|
+
'AGT': 'S',
|
|
20104
|
+
'AGC': 'S',
|
|
20105
|
+
'AGA': 'R',
|
|
20106
|
+
'AGG': 'R',
|
|
20107
|
+
'GGT': 'G',
|
|
20108
|
+
'GGC': 'G',
|
|
20109
|
+
'GGA': 'G',
|
|
20110
|
+
'GGG': 'G'
|
|
20111
|
+
};
|
|
20112
|
+
const complement = {};
|
|
20113
|
+
const t1 = ['A', 'G', 'C', 'T', 'Y', 'R', 'W', 'S', 'K', 'M', 'D', 'V', 'H', 'B', 'N', 'X'];
|
|
20114
|
+
const t2 = ['T', 'C', 'G', 'A', 'R', 'Y', 'W', 'S', 'M', 'K', 'H', 'B', 'D', 'V', 'N', 'X'];
|
|
20115
|
+
for (let i = 0; i < t1.length; i++) {
|
|
20116
|
+
complement[t1[i]] = t2[i];
|
|
20117
|
+
complement[t1[i].toLowerCase()] = t2[i].toLowerCase();
|
|
20118
|
+
}
|
|
20119
|
+
const DEFAULT_HEIGHT = 25;
|
|
20120
|
+
const TRANSLATED_HEIGHT = 115;
|
|
20121
|
+
const SEQUENCE_HEIGHT = 15;
|
|
20122
|
+
const FRAME_HEIGHT = 25;
|
|
20123
|
+
const FRAME_BORDER = 5;
|
|
20124
|
+
const BP_PER_PIXEL_THRESHOLD = 1 / 10;
|
|
20125
|
+
const bppFeatureFetchThreshold = 10;
|
|
20126
|
+
class SequenceTrack {
|
|
20127
|
+
constructor(config, browser) {
|
|
20128
|
+
this.config = config;
|
|
20129
|
+
this.browser = browser;
|
|
20130
|
+
this.type = "sequence";
|
|
20131
|
+
this.removable = config.removable === undefined ? true : config.removable; // Defaults to true
|
|
20132
|
+
this.name = config.name;
|
|
20133
|
+
this.id = config.id;
|
|
20134
|
+
this.sequenceType = config.sequenceType || "dna"; // dna | rna | prot
|
|
20135
|
+
this.disableButtons = false;
|
|
20136
|
+
this.order = config.order || defaultSequenceTrackOrder;
|
|
20137
|
+
this.ignoreTrackMenu = false;
|
|
20138
|
+
this.reversed = config.reversed === true;
|
|
20139
|
+
this.frameTranslate = config.frameTranslate === true;
|
|
20140
|
+
this.height = this.frameTranslate ? TRANSLATED_HEIGHT : DEFAULT_HEIGHT;
|
|
20141
|
+
|
|
20142
|
+
// Hack for backward compatibility
|
|
20143
|
+
if (config.url) {
|
|
20144
|
+
config.fastaURL = config.url;
|
|
20145
|
+
}
|
|
20146
|
+
if (!config.fastaURL) {
|
|
20147
|
+
// Mark this as the genome reference sequence ==> backward compatibility convention
|
|
20148
|
+
this.id = config.id || "sequence";
|
|
20149
|
+
}
|
|
20150
|
+
}
|
|
20151
|
+
menuItemList() {
|
|
20152
|
+
return [{
|
|
20153
|
+
name: this.reversed ? "Forward" : "Reverse",
|
|
20154
|
+
click: () => {
|
|
20155
|
+
this.reversed = !this.reversed;
|
|
20156
|
+
this.trackView.repaintViews();
|
|
20157
|
+
}
|
|
20158
|
+
}, {
|
|
20159
|
+
name: this.frameTranslate ? "Close Translation" : "Three-frame Translate",
|
|
20160
|
+
click: () => {
|
|
20161
|
+
this.frameTranslate = !this.frameTranslate;
|
|
20162
|
+
if (this.frameTranslate) {
|
|
20163
|
+
for (let vp of this.trackView.viewports) {
|
|
20164
|
+
vp.setContentHeight(TRANSLATED_HEIGHT);
|
|
20165
|
+
}
|
|
20166
|
+
this.trackView.setTrackHeight(TRANSLATED_HEIGHT);
|
|
20167
|
+
} else {
|
|
20168
|
+
for (let vp of this.trackView.viewports) {
|
|
20169
|
+
vp.setContentHeight(DEFAULT_HEIGHT);
|
|
20170
|
+
}
|
|
20171
|
+
this.trackView.setTrackHeight(DEFAULT_HEIGHT);
|
|
20172
|
+
}
|
|
20173
|
+
this.trackView.repaintViews();
|
|
20174
|
+
}
|
|
20175
|
+
}];
|
|
20176
|
+
}
|
|
20177
|
+
contextMenuItemList(clickState) {
|
|
20178
|
+
const viewport = clickState.viewport;
|
|
20179
|
+
if (viewport.referenceFrame.bpPerPixel <= 1) {
|
|
20180
|
+
const pixelWidth = viewport.getWidth();
|
|
20181
|
+
const bpWindow = pixelWidth * viewport.referenceFrame.bpPerPixel;
|
|
20182
|
+
const chr = viewport.referenceFrame.chr;
|
|
20183
|
+
const start = Math.floor(viewport.referenceFrame.start);
|
|
20184
|
+
const end = Math.ceil(start + bpWindow);
|
|
20185
|
+
const items = [{
|
|
20186
|
+
label: this.reversed ? 'View visible sequence (reversed)...' : 'View visible sequence...',
|
|
20187
|
+
click: async () => {
|
|
20188
|
+
let seq = await this.browser.genome.sequence.getSequence(chr, start, end);
|
|
20189
|
+
if (!seq) {
|
|
20190
|
+
seq = "Unknown sequence";
|
|
20191
|
+
} else if (this.reversed) {
|
|
20192
|
+
seq = reverseComplementSequence(seq);
|
|
20193
|
+
}
|
|
20194
|
+
this.browser.alert.present(seq);
|
|
20195
|
+
}
|
|
20196
|
+
}];
|
|
20197
|
+
if (isSecureContext()) {
|
|
20198
|
+
items.push({
|
|
20199
|
+
label: 'Copy visible sequence',
|
|
20200
|
+
click: async () => {
|
|
20201
|
+
let seq = await this.browser.genome.sequence.getSequence(chr, start, end);
|
|
20202
|
+
if (!seq) {
|
|
20203
|
+
seq = "Unknown sequence";
|
|
20204
|
+
} else if (this.reversed) {
|
|
20205
|
+
seq = reverseComplementSequence(seq);
|
|
20206
|
+
}
|
|
20207
|
+
try {
|
|
20208
|
+
await navigator.clipboard.writeText(seq);
|
|
20209
|
+
} catch (e) {
|
|
20210
|
+
console.error(e);
|
|
20211
|
+
this.browser.alert.present(`error copying sequence to clipboard ${e}`);
|
|
20212
|
+
}
|
|
20213
|
+
}
|
|
20214
|
+
});
|
|
20215
|
+
}
|
|
20216
|
+
items.push('<hr/>');
|
|
20217
|
+
return items;
|
|
20218
|
+
} else {
|
|
20219
|
+
return undefined;
|
|
20220
|
+
}
|
|
20221
|
+
}
|
|
20222
|
+
translateSequence(seq) {
|
|
20223
|
+
const threeFrame = [[], [], []];
|
|
20224
|
+
for (let fNum of [0, 1, 2]) {
|
|
20225
|
+
let idx = fNum;
|
|
20226
|
+
while (seq.length - idx >= 3) {
|
|
20227
|
+
let st = seq.slice(idx, idx + 3);
|
|
20228
|
+
if (this.reversed) {
|
|
20229
|
+
st = st.split('').reverse().join('');
|
|
20230
|
+
}
|
|
20231
|
+
const aa = translationDict[st.toUpperCase()] || "";
|
|
20232
|
+
threeFrame[fNum].push({
|
|
20233
|
+
codons: st,
|
|
20234
|
+
aminoA: aa
|
|
20235
|
+
});
|
|
20236
|
+
idx += 3;
|
|
20237
|
+
}
|
|
20238
|
+
}
|
|
20239
|
+
return threeFrame;
|
|
20240
|
+
}
|
|
20241
|
+
|
|
20242
|
+
/**
|
|
20243
|
+
* Return the source for sequence. If an explicit fasta url is defined, use it, otherwise fetch sequence
|
|
20244
|
+
* from the current genome
|
|
20245
|
+
* *
|
|
20246
|
+
* @returns {Promise<WrappedFasta|*>}
|
|
20247
|
+
*/
|
|
20248
|
+
async getSequenceSource() {
|
|
20249
|
+
if (this.config.fastaURL) {
|
|
20250
|
+
if (!this.fasta) {
|
|
20251
|
+
this.fasta = new WrappedFasta(this.config, this.browser.genome);
|
|
20252
|
+
await this.fasta.init();
|
|
20253
|
+
}
|
|
20254
|
+
return this.fasta;
|
|
20255
|
+
} else {
|
|
20256
|
+
return this.browser.genome.sequence;
|
|
20257
|
+
}
|
|
20258
|
+
}
|
|
20259
|
+
async getFeatures(chr, start, end, bpPerPixel) {
|
|
20260
|
+
start = Math.floor(start);
|
|
20261
|
+
end = Math.floor(end);
|
|
20262
|
+
if (bpPerPixel && bpPerPixel > bppFeatureFetchThreshold) {
|
|
20263
|
+
return null;
|
|
20264
|
+
} else {
|
|
20265
|
+
const sequenceSource = await this.getSequenceSource();
|
|
20266
|
+
const sequence = await sequenceSource.getSequence(chr, start, end);
|
|
20267
|
+
return {
|
|
20268
|
+
bpStart: start,
|
|
20269
|
+
sequence: sequence
|
|
20270
|
+
};
|
|
20271
|
+
}
|
|
20272
|
+
}
|
|
20273
|
+
draw(options) {
|
|
20274
|
+
const ctx = options.context;
|
|
20275
|
+
if (options.features) {
|
|
20276
|
+
let sequence = options.features.sequence;
|
|
20277
|
+
if (!sequence) {
|
|
20278
|
+
return;
|
|
20279
|
+
}
|
|
20280
|
+
if (this.reversed) {
|
|
20281
|
+
sequence = sequence.split('').map(function (cv) {
|
|
20282
|
+
return complement[cv];
|
|
20283
|
+
}).join('');
|
|
20284
|
+
}
|
|
20285
|
+
const sequenceBpStart = options.features.bpStart; // genomic position at start of sequence
|
|
20286
|
+
const bpEnd = 1 + options.bpStart + options.pixelWidth * options.bpPerPixel;
|
|
20287
|
+
for (let bp = Math.floor(options.bpStart); bp <= bpEnd; bp++) {
|
|
20288
|
+
const seqIdx = Math.floor(bp - sequenceBpStart);
|
|
20289
|
+
if (seqIdx >= 0 && seqIdx < sequence.length) {
|
|
20290
|
+
const offsetBP = bp - options.bpStart;
|
|
20291
|
+
const aPixel = offsetBP / options.bpPerPixel;
|
|
20292
|
+
const pixelWidth = 1 / options.bpPerPixel;
|
|
20293
|
+
const baseLetter = sequence[seqIdx];
|
|
20294
|
+
const color = this.fillColor(baseLetter.toUpperCase());
|
|
20295
|
+
if (options.bpPerPixel > BP_PER_PIXEL_THRESHOLD) {
|
|
20296
|
+
IGVGraphics.fillRect(ctx, aPixel, FRAME_BORDER, pixelWidth, SEQUENCE_HEIGHT - FRAME_BORDER, {
|
|
20297
|
+
fillStyle: color
|
|
20298
|
+
});
|
|
20299
|
+
} else {
|
|
20300
|
+
const textPixel = aPixel + 0.5 * (pixelWidth - ctx.measureText(baseLetter).width);
|
|
20301
|
+
if ('y' === options.axis) {
|
|
20302
|
+
ctx.save();
|
|
20303
|
+
IGVGraphics.labelTransformWithContext(ctx, textPixel);
|
|
20304
|
+
IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, {
|
|
20305
|
+
strokeStyle: color
|
|
20306
|
+
});
|
|
20307
|
+
ctx.restore();
|
|
20308
|
+
} else {
|
|
20309
|
+
IGVGraphics.strokeText(ctx, baseLetter, textPixel, SEQUENCE_HEIGHT, {
|
|
20310
|
+
strokeStyle: color
|
|
20311
|
+
});
|
|
20312
|
+
}
|
|
20313
|
+
}
|
|
20314
|
+
}
|
|
20315
|
+
}
|
|
20316
|
+
if (this.frameTranslate) {
|
|
20317
|
+
let y = SEQUENCE_HEIGHT + 2 * FRAME_BORDER;
|
|
20318
|
+
const translatedSequence = this.translateSequence(sequence);
|
|
20319
|
+
for (let fNum = 0; fNum < translatedSequence.length; fNum++) {
|
|
20320
|
+
// == 3, 1 for each frame
|
|
20321
|
+
|
|
20322
|
+
const aaSequence = translatedSequence[fNum]; // AA sequence for this frame
|
|
20323
|
+
|
|
20324
|
+
for (let idx = 0; idx < aaSequence.length; idx++) {
|
|
20325
|
+
let color = 0 === idx % 2 ? 'rgb(160,160,160)' : 'rgb(224,224,224)';
|
|
20326
|
+
const cv = aaSequence[idx];
|
|
20327
|
+
const bpPos = sequenceBpStart + fNum + idx * 3;
|
|
20328
|
+
const bpOffset = bpPos - options.bpStart;
|
|
20329
|
+
const p0 = Math.floor(bpOffset / options.bpPerPixel);
|
|
20330
|
+
const p1 = Math.floor((bpOffset + 3) / options.bpPerPixel);
|
|
20331
|
+
const pc = Math.round((p0 + p1) / 2);
|
|
20332
|
+
if (p1 < 0) {
|
|
20333
|
+
continue; // off left edge
|
|
20334
|
+
} else if (p0 > options.pixelWidth) {
|
|
20335
|
+
break; // off right edge
|
|
20336
|
+
}
|
|
20337
|
+
|
|
20338
|
+
let aaLabel = cv.aminoA;
|
|
20339
|
+
if (cv.aminoA.indexOf('STOP') > -1) {
|
|
20340
|
+
color = 'rgb(255, 0, 0)';
|
|
20341
|
+
aaLabel = 'STOP'; //Color blind accessible
|
|
20342
|
+
} else if (cv.aminoA === 'M') {
|
|
20343
|
+
color = 'rgb(0, 153, 0)';
|
|
20344
|
+
aaLabel = 'START'; //Color blind accessible
|
|
20345
|
+
}
|
|
20346
|
+
|
|
20347
|
+
IGVGraphics.fillRect(ctx, p0, y, p1 - p0, FRAME_HEIGHT, {
|
|
20348
|
+
fillStyle: color
|
|
20349
|
+
});
|
|
20350
|
+
if (options.bpPerPixel <= 1 / 10) {
|
|
20351
|
+
IGVGraphics.strokeText(ctx, aaLabel, pc - ctx.measureText(aaLabel).width / 2, y + 15);
|
|
20352
|
+
}
|
|
20353
|
+
}
|
|
20354
|
+
y += FRAME_HEIGHT + FRAME_BORDER;
|
|
20355
|
+
}
|
|
20356
|
+
}
|
|
20357
|
+
}
|
|
20358
|
+
}
|
|
20359
|
+
get supportsWholeGenome() {
|
|
20360
|
+
return false;
|
|
20361
|
+
}
|
|
20362
|
+
computePixelHeight(ignore) {
|
|
20363
|
+
this.height = this.frameTranslate ? TRANSLATED_HEIGHT : DEFAULT_HEIGHT;
|
|
20364
|
+
return this.height;
|
|
20365
|
+
}
|
|
20366
|
+
fillColor(index) {
|
|
20367
|
+
if (this.color) {
|
|
20368
|
+
return this.color;
|
|
20369
|
+
} else if ("dna" === this.sequenceType) {
|
|
20370
|
+
// return this.browser.nucleotideColors[index] || 'gray'
|
|
20371
|
+
return defaultNucleotideColors[index] || 'gray';
|
|
20372
|
+
} else {
|
|
20373
|
+
return 'rgb(0, 0, 150)';
|
|
20374
|
+
}
|
|
20375
|
+
}
|
|
20376
|
+
|
|
20377
|
+
/**
|
|
20378
|
+
* Return the current state of the track. Used to create sessions and bookmarks.
|
|
20379
|
+
*
|
|
20380
|
+
* @returns {*|{}}
|
|
20381
|
+
*/
|
|
20382
|
+
getState() {
|
|
20383
|
+
const config = {
|
|
20384
|
+
type: "sequence"
|
|
20385
|
+
};
|
|
20386
|
+
if (this.order !== defaultSequenceTrackOrder) {
|
|
20387
|
+
config.order = this.order;
|
|
20388
|
+
}
|
|
20389
|
+
if (this.reversed) {
|
|
20390
|
+
config.revealed = true;
|
|
20391
|
+
}
|
|
20392
|
+
return config;
|
|
20393
|
+
}
|
|
20394
|
+
}
|
|
20395
|
+
|
|
20396
|
+
/**
|
|
20397
|
+
* Wrapper for a Fasta object that does chr name alias translation. This is not neccessary for the genome fasta,
|
|
20398
|
+
* as it defines the reference name, but can be neccessary if loading an additional fasta as a track
|
|
20399
|
+
*
|
|
20400
|
+
*/
|
|
20401
|
+
class WrappedFasta {
|
|
20402
|
+
constructor(config, genome) {
|
|
20403
|
+
this.config = config;
|
|
20404
|
+
this.genome = genome;
|
|
20405
|
+
}
|
|
20406
|
+
async init() {
|
|
20407
|
+
this.fasta = await loadFasta(this.config);
|
|
20408
|
+
this.chrNameMap = new Map();
|
|
20409
|
+
for (let name of this.fasta.chromosomeNames) {
|
|
20410
|
+
this.chrNameMap.set(this.genome.getChromosomeName(name), name);
|
|
20411
|
+
}
|
|
20412
|
+
}
|
|
20413
|
+
async getSequence(chr, start, end) {
|
|
20414
|
+
const chrName = this.chrNameMap.has(chr) ? this.chrNameMap.get(chr) : chr;
|
|
20415
|
+
return this.fasta.getSequence(chrName, start, end);
|
|
20416
|
+
}
|
|
20417
|
+
}
|
|
20418
|
+
|
|
20419
|
+
/*
|
|
20420
|
+
* The MIT License (MIT)
|
|
20421
|
+
*
|
|
20422
|
+
* Copyright (c) 2014 Broad Institute
|
|
20423
|
+
*
|
|
20424
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
20425
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
20426
|
+
* in the Software without restriction, including without limitation the rights
|
|
20427
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
20428
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
20429
|
+
* furnished to do so, subject to the following conditions:
|
|
20430
|
+
*
|
|
20431
|
+
* The above copyright notice and this permission notice shall be included in
|
|
20432
|
+
* all copies or substantial portions of the Software.
|
|
20433
|
+
*
|
|
20434
|
+
*
|
|
20435
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20436
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20437
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20438
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20439
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20440
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20441
|
+
* THE SOFTWARE.
|
|
20442
|
+
*/
|
|
20443
|
+
class Viewport {
|
|
20444
|
+
constructor(trackView, viewportColumn, referenceFrame, width) {
|
|
20445
|
+
this.guid = guid$2();
|
|
20446
|
+
this.trackView = trackView;
|
|
20447
|
+
this.referenceFrame = referenceFrame;
|
|
20448
|
+
this.browser = trackView.browser;
|
|
20449
|
+
this.$viewport = $$1('<div class="igv-viewport">');
|
|
20450
|
+
viewportColumn.appendChild(this.$viewport.get(0));
|
|
20451
|
+
if (trackView.track.height) {
|
|
20452
|
+
this.$viewport.get(0).style.height = `${trackView.track.height}px`;
|
|
20453
|
+
}
|
|
20454
|
+
|
|
20455
|
+
// Create an alert dialog for the sequence track to copy ref sequence to.
|
|
20456
|
+
if (trackView.track instanceof SequenceTrack) {
|
|
20457
|
+
this.alert = new AlertDialog(this.$viewport.get(0));
|
|
20458
|
+
}
|
|
20459
|
+
this.contentTop = 0;
|
|
20460
|
+
this.contentHeight = this.$viewport.height();
|
|
20461
|
+
this.$viewport.width(width);
|
|
20462
|
+
this.initializationHelper();
|
|
20463
|
+
}
|
|
20464
|
+
initializationHelper() {}
|
|
20465
|
+
showMessage(message) {
|
|
20466
|
+
if (!this.messageDiv) {
|
|
20467
|
+
this.messageDiv = document.createElement('div');
|
|
20468
|
+
this.messageDiv.className = 'igv-viewport-message';
|
|
20469
|
+
//this.contentDiv.append(this.messageDiv)
|
|
20470
|
+
this.$viewport.append($$1(this.messageDiv));
|
|
20471
|
+
}
|
|
20472
|
+
this.messageDiv.textContent = message;
|
|
20473
|
+
this.messageDiv.style.display = 'inline-block';
|
|
20474
|
+
}
|
|
20475
|
+
hideMessage(message) {
|
|
20476
|
+
if (this.messageDiv) this.messageDiv.style.display = 'none';
|
|
20477
|
+
}
|
|
20478
|
+
setTrackLabel(label) {}
|
|
20479
|
+
startSpinner() {}
|
|
20480
|
+
stopSpinner() {}
|
|
20481
|
+
checkZoomIn() {
|
|
20482
|
+
return true;
|
|
20483
|
+
}
|
|
20484
|
+
shift() {}
|
|
20485
|
+
setTop(contentTop) {
|
|
20486
|
+
this.contentTop = contentTop;
|
|
20487
|
+
this.$viewport.height();
|
|
20488
|
+
|
|
20489
|
+
//this.$content.css('top', `${contentTop}px`)
|
|
20490
|
+
//
|
|
20491
|
+
// if (undefined === this.canvasVerticalRange || this.canvasVerticalRange.bottom < viewBottom || this.canvasVerticalRange.top > viewTop) {
|
|
20492
|
+
// console.log("Repaint " + this.canvasVerticalRange)
|
|
20493
|
+
// this.repaint()
|
|
20494
|
+
// }
|
|
20495
|
+
}
|
|
20496
|
+
|
|
20497
|
+
async loadFeatures() {
|
|
20498
|
+
return undefined;
|
|
20499
|
+
}
|
|
20500
|
+
clearCache() {}
|
|
20501
|
+
async repaint() {}
|
|
20502
|
+
draw(drawConfiguration, features, roiFeatures) {
|
|
20503
|
+
console.log('Viewport - draw(drawConfiguration, features, roiFeatures)');
|
|
20504
|
+
}
|
|
20505
|
+
checkContentHeight(features) {
|
|
20506
|
+
let track = this.trackView.track;
|
|
20507
|
+
features = features || this.cachedFeatures;
|
|
20508
|
+
if ("FILL" === track.displayMode) {
|
|
20509
|
+
this.setContentHeight(this.$viewport.height());
|
|
20510
|
+
} else if (typeof track.computePixelHeight === 'function') {
|
|
20511
|
+
if (features && features.length > 0) {
|
|
20512
|
+
let requiredContentHeight = track.computePixelHeight(features);
|
|
20513
|
+
//let currentContentHeight = this.$content.height()
|
|
20514
|
+
let currentContentHeight = this.contentHeight;
|
|
20515
|
+
if (requiredContentHeight !== currentContentHeight) {
|
|
20516
|
+
this.setContentHeight(requiredContentHeight);
|
|
20517
|
+
}
|
|
20518
|
+
}
|
|
20519
|
+
}
|
|
20520
|
+
}
|
|
20521
|
+
getContentHeight() {
|
|
20522
|
+
//return this.$content.height()
|
|
20523
|
+
return this.contentHeight;
|
|
19426
20524
|
}
|
|
19427
20525
|
setContentHeight(contentHeight) {
|
|
19428
20526
|
this.contentHeight = contentHeight;
|
|
@@ -20096,1372 +21194,732 @@
|
|
|
20096
21194
|
y: y
|
|
20097
21195
|
}));
|
|
20098
21196
|
}
|
|
20099
|
-
/**
|
|
20100
|
-
* rotates the current element
|
|
20101
|
-
*/
|
|
20102
|
-
rotate(angle) {
|
|
20103
|
-
var degrees = angle * 180 / Math.PI;
|
|
20104
|
-
this.__addTransform(format("rotate({angle},{cx},{cy})", {
|
|
20105
|
-
angle: degrees,
|
|
20106
|
-
cx: 0,
|
|
20107
|
-
cy: 0
|
|
20108
|
-
}));
|
|
20109
|
-
}
|
|
20110
|
-
/**
|
|
20111
|
-
* translates the current element
|
|
20112
|
-
*/
|
|
20113
|
-
translate(x, y) {
|
|
20114
|
-
this.__addTransform(format("translate({x},{y})", {
|
|
20115
|
-
x: x,
|
|
20116
|
-
y: y
|
|
20117
|
-
}));
|
|
20118
|
-
}
|
|
20119
|
-
/**
|
|
20120
|
-
* applies a transform to the current element
|
|
20121
|
-
*/
|
|
20122
|
-
transform(a, b, c, d, e, f) {
|
|
20123
|
-
this.__addTransform(format("matrix({a},{b},{c},{d},{e},{f})", {
|
|
20124
|
-
a: a,
|
|
20125
|
-
b: b,
|
|
20126
|
-
c: c,
|
|
20127
|
-
d: d,
|
|
20128
|
-
e: e,
|
|
20129
|
-
f: f
|
|
20130
|
-
}));
|
|
20131
|
-
}
|
|
20132
|
-
/**
|
|
20133
|
-
* Create a new Path Element
|
|
20134
|
-
*/
|
|
20135
|
-
beginPath() {
|
|
20136
|
-
var path, parent;
|
|
20137
|
-
|
|
20138
|
-
// Note that there is only one current default path, it is not part of the drawing state.
|
|
20139
|
-
// See also: https://html.spec.whatwg.org/multipage/scripting.html#current-default-path
|
|
20140
|
-
this.__currentDefaultPath = "";
|
|
20141
|
-
this.__currentPosition = {};
|
|
20142
|
-
path = this.__createElement("path", {}, true);
|
|
20143
|
-
parent = this.__closestGroupOrSvg();
|
|
20144
|
-
parent.appendChild(path);
|
|
20145
|
-
this.__currentElement = path;
|
|
20146
|
-
}
|
|
20147
|
-
/**
|
|
20148
|
-
* Helper function to apply currentDefaultPath to current path element
|
|
20149
|
-
* @private
|
|
20150
|
-
*/
|
|
20151
|
-
__applyCurrentDefaultPath() {
|
|
20152
|
-
var currentElement = this.__currentElement;
|
|
20153
|
-
if (currentElement.nodeName === "path") {
|
|
20154
|
-
currentElement.setAttribute("d", this.__currentDefaultPath);
|
|
20155
|
-
} else {
|
|
20156
|
-
console.error("Attempted to apply path command to node", currentElement.nodeName);
|
|
20157
|
-
}
|
|
20158
|
-
}
|
|
20159
|
-
/**
|
|
20160
|
-
* Helper function to add path command
|
|
20161
|
-
* @private
|
|
20162
|
-
*/
|
|
20163
|
-
__addPathCommand(command) {
|
|
20164
|
-
this.__currentDefaultPath += " ";
|
|
20165
|
-
this.__currentDefaultPath += command;
|
|
20166
|
-
}
|
|
20167
|
-
/**
|
|
20168
|
-
* Adds the move command to the current path element,
|
|
20169
|
-
* if the currentPathElement is not empty create a new path element
|
|
20170
|
-
*/
|
|
20171
|
-
moveTo(x, y) {
|
|
20172
|
-
if (this.__currentElement.nodeName !== "path") {
|
|
20173
|
-
this.beginPath();
|
|
20174
|
-
}
|
|
20175
|
-
|
|
20176
|
-
// creates a new subpath with the given point
|
|
20177
|
-
this.__currentPosition = {
|
|
20178
|
-
x: x,
|
|
20179
|
-
y: y
|
|
20180
|
-
};
|
|
20181
|
-
this.__addPathCommand(format("M {x} {y}", {
|
|
20182
|
-
x: x,
|
|
20183
|
-
y: y
|
|
20184
|
-
}));
|
|
20185
|
-
}
|
|
20186
|
-
/**
|
|
20187
|
-
* Closes the current path
|
|
20188
|
-
*/
|
|
20189
|
-
closePath() {
|
|
20190
|
-
if (this.__currentDefaultPath) {
|
|
20191
|
-
this.__addPathCommand("Z");
|
|
20192
|
-
}
|
|
20193
|
-
}
|
|
20194
|
-
/**
|
|
20195
|
-
* Adds a line to command
|
|
20196
|
-
*/
|
|
20197
|
-
lineTo(x, y) {
|
|
20198
|
-
this.__currentPosition = {
|
|
20199
|
-
x: x,
|
|
20200
|
-
y: y
|
|
20201
|
-
};
|
|
20202
|
-
if (this.__currentDefaultPath && this.__currentDefaultPath.indexOf('M') > -1) {
|
|
20203
|
-
this.__addPathCommand(format("L {x} {y}", {
|
|
20204
|
-
x: x,
|
|
20205
|
-
y: y
|
|
20206
|
-
}));
|
|
20207
|
-
} else {
|
|
20208
|
-
this.__addPathCommand(format("M {x} {y}", {
|
|
20209
|
-
x: x,
|
|
20210
|
-
y: y
|
|
20211
|
-
}));
|
|
20212
|
-
}
|
|
20213
|
-
}
|
|
20214
|
-
/**
|
|
20215
|
-
* Add a bezier command
|
|
20216
|
-
*/
|
|
20217
|
-
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
20218
|
-
this.__currentPosition = {
|
|
20219
|
-
x: x,
|
|
20220
|
-
y: y
|
|
20221
|
-
};
|
|
20222
|
-
this.__addPathCommand(format("C {cp1x} {cp1y} {cp2x} {cp2y} {x} {y}", {
|
|
20223
|
-
cp1x: cp1x,
|
|
20224
|
-
cp1y: cp1y,
|
|
20225
|
-
cp2x: cp2x,
|
|
20226
|
-
cp2y: cp2y,
|
|
20227
|
-
x: x,
|
|
20228
|
-
y: y
|
|
20229
|
-
}));
|
|
20230
|
-
}
|
|
20231
|
-
/**
|
|
20232
|
-
* Adds a quadratic curve to command
|
|
20233
|
-
*/
|
|
20234
|
-
quadraticCurveTo(cpx, cpy, x, y) {
|
|
20235
|
-
this.__currentPosition = {
|
|
20236
|
-
x: x,
|
|
20237
|
-
y: y
|
|
20238
|
-
};
|
|
20239
|
-
this.__addPathCommand(format("Q {cpx} {cpy} {x} {y}", {
|
|
20240
|
-
cpx: cpx,
|
|
20241
|
-
cpy: cpy,
|
|
20242
|
-
x: x,
|
|
20243
|
-
y: y
|
|
20244
|
-
}));
|
|
20245
|
-
}
|
|
20246
|
-
/**
|
|
20247
|
-
* Adds the arcTo to the current path
|
|
20248
|
-
*
|
|
20249
|
-
* @see http://www.w3.org/TR/2015/WD-2dcontext-20150514/#dom-context-2d-arcto
|
|
20250
|
-
*/
|
|
20251
|
-
arcTo(x1, y1, x2, y2, radius) {
|
|
20252
|
-
// Let the point (x0, y0) be the last point in the subpath.
|
|
20253
|
-
var x0 = this.__currentPosition && this.__currentPosition.x;
|
|
20254
|
-
var y0 = this.__currentPosition && this.__currentPosition.y;
|
|
20255
|
-
|
|
20256
|
-
// First ensure there is a subpath for (x1, y1).
|
|
20257
|
-
if (typeof x0 == "undefined" || typeof y0 == "undefined") {
|
|
20258
|
-
return;
|
|
20259
|
-
}
|
|
20260
|
-
|
|
20261
|
-
// Negative values for radius must cause the implementation to throw an IndexSizeError exception.
|
|
20262
|
-
if (radius < 0) {
|
|
20263
|
-
throw new Error("IndexSizeError: The radius provided (" + radius + ") is negative.");
|
|
20264
|
-
}
|
|
20265
|
-
|
|
20266
|
-
// If the point (x0, y0) is equal to the point (x1, y1),
|
|
20267
|
-
// or if the point (x1, y1) is equal to the point (x2, y2),
|
|
20268
|
-
// or if the radius radius is zero,
|
|
20269
|
-
// then the method must add the point (x1, y1) to the subpath,
|
|
20270
|
-
// and connect that point to the previous point (x0, y0) by a straight line.
|
|
20271
|
-
if (x0 === x1 && y0 === y1 || x1 === x2 && y1 === y2 || radius === 0) {
|
|
20272
|
-
this.lineTo(x1, y1);
|
|
20273
|
-
return;
|
|
20274
|
-
}
|
|
20275
|
-
|
|
20276
|
-
// Otherwise, if the points (x0, y0), (x1, y1), and (x2, y2) all lie on a single straight line,
|
|
20277
|
-
// then the method must add the point (x1, y1) to the subpath,
|
|
20278
|
-
// and connect that point to the previous point (x0, y0) by a straight line.
|
|
20279
|
-
var unit_vec_p1_p0 = normalize$1([x0 - x1, y0 - y1]);
|
|
20280
|
-
var unit_vec_p1_p2 = normalize$1([x2 - x1, y2 - y1]);
|
|
20281
|
-
if (unit_vec_p1_p0[0] * unit_vec_p1_p2[1] === unit_vec_p1_p0[1] * unit_vec_p1_p2[0]) {
|
|
20282
|
-
this.lineTo(x1, y1);
|
|
20283
|
-
return;
|
|
20284
|
-
}
|
|
20285
|
-
|
|
20286
|
-
// Otherwise, let The Arc be the shortest arc given by circumference of the circle that has radius radius,
|
|
20287
|
-
// and that has one point tangent to the half-infinite line that crosses the point (x0, y0) and ends at the point (x1, y1),
|
|
20288
|
-
// and that has a different point tangent to the half-infinite line that ends at the point (x1, y1), and crosses the point (x2, y2).
|
|
20289
|
-
// The points at which this circle touches these two lines are called the start and end tangent points respectively.
|
|
20290
|
-
|
|
20291
|
-
// note that both vectors are unit vectors, so the length is 1
|
|
20292
|
-
var cos = unit_vec_p1_p0[0] * unit_vec_p1_p2[0] + unit_vec_p1_p0[1] * unit_vec_p1_p2[1];
|
|
20293
|
-
var theta = Math.acos(Math.abs(cos));
|
|
20294
|
-
|
|
20295
|
-
// Calculate origin
|
|
20296
|
-
var unit_vec_p1_origin = normalize$1([unit_vec_p1_p0[0] + unit_vec_p1_p2[0], unit_vec_p1_p0[1] + unit_vec_p1_p2[1]]);
|
|
20297
|
-
var len_p1_origin = radius / Math.sin(theta / 2);
|
|
20298
|
-
var x = x1 + len_p1_origin * unit_vec_p1_origin[0];
|
|
20299
|
-
var y = y1 + len_p1_origin * unit_vec_p1_origin[1];
|
|
20300
|
-
|
|
20301
|
-
// Calculate start angle and end angle
|
|
20302
|
-
// rotate 90deg clockwise (note that y axis points to its down)
|
|
20303
|
-
var unit_vec_origin_start_tangent = [-unit_vec_p1_p0[1], unit_vec_p1_p0[0]];
|
|
20304
|
-
// rotate 90deg counter clockwise (note that y axis points to its down)
|
|
20305
|
-
var unit_vec_origin_end_tangent = [unit_vec_p1_p2[1], -unit_vec_p1_p2[0]];
|
|
20306
|
-
var getAngle = function (vector) {
|
|
20307
|
-
// get angle (clockwise) between vector and (1, 0)
|
|
20308
|
-
var x = vector[0];
|
|
20309
|
-
var y = vector[1];
|
|
20310
|
-
if (y >= 0) {
|
|
20311
|
-
// note that y axis points to its down
|
|
20312
|
-
return Math.acos(x);
|
|
20313
|
-
} else {
|
|
20314
|
-
return -Math.acos(x);
|
|
20315
|
-
}
|
|
20316
|
-
};
|
|
20317
|
-
var startAngle = getAngle(unit_vec_origin_start_tangent);
|
|
20318
|
-
var endAngle = getAngle(unit_vec_origin_end_tangent);
|
|
20319
|
-
|
|
20320
|
-
// Connect the point (x0, y0) to the start tangent point by a straight line
|
|
20321
|
-
this.lineTo(x + unit_vec_origin_start_tangent[0] * radius, y + unit_vec_origin_start_tangent[1] * radius);
|
|
20322
|
-
|
|
20323
|
-
// Connect the start tangent point to the end tangent point by arc
|
|
20324
|
-
// and adding the end tangent point to the subpath.
|
|
20325
|
-
this.arc(x, y, radius, startAngle, endAngle);
|
|
20326
|
-
}
|
|
20327
|
-
/**
|
|
20328
|
-
* Sets the stroke property on the current element
|
|
20329
|
-
*/
|
|
20330
|
-
stroke() {
|
|
20331
|
-
if (this.__currentElement.nodeName === "path") {
|
|
20332
|
-
this.__currentElement.setAttribute("paint-order", "fill stroke markers");
|
|
20333
|
-
}
|
|
20334
|
-
this.__applyCurrentDefaultPath();
|
|
20335
|
-
this.__applyStyleToCurrentElement("stroke");
|
|
20336
|
-
}
|
|
20337
|
-
/**
|
|
20338
|
-
* Sets fill properties on the current element
|
|
20339
|
-
*/
|
|
20340
|
-
fill() {
|
|
20341
|
-
if (this.__currentElement.nodeName === "path") {
|
|
20342
|
-
this.__currentElement.setAttribute("paint-order", "stroke fill markers");
|
|
20343
|
-
}
|
|
20344
|
-
this.__applyCurrentDefaultPath();
|
|
20345
|
-
this.__applyStyleToCurrentElement("fill");
|
|
20346
|
-
}
|
|
20347
|
-
/**
|
|
20348
|
-
* Adds a rectangle to the path.
|
|
20349
|
-
*/
|
|
20350
|
-
rect(x, y, width, height) {
|
|
20351
|
-
if (this.__currentElement.nodeName !== "path") {
|
|
20352
|
-
this.beginPath();
|
|
20353
|
-
}
|
|
20354
|
-
this.moveTo(x, y);
|
|
20355
|
-
this.lineTo(x + width, y);
|
|
20356
|
-
this.lineTo(x + width, y + height);
|
|
20357
|
-
this.lineTo(x, y + height);
|
|
20358
|
-
this.lineTo(x, y);
|
|
20359
|
-
this.closePath();
|
|
20360
|
-
}
|
|
20361
|
-
/**
|
|
20362
|
-
* adds a rectangle element
|
|
20363
|
-
*/
|
|
20364
|
-
fillRect(x, y, width, height) {
|
|
20365
|
-
if (height < 0) {
|
|
20366
|
-
y += height;
|
|
20367
|
-
height = -height;
|
|
20368
|
-
}
|
|
20369
|
-
if (width < 0) {
|
|
20370
|
-
x += width;
|
|
20371
|
-
width = -width;
|
|
20372
|
-
}
|
|
20373
|
-
// See if rect intersects current viewbox
|
|
20374
|
-
var r2 = {
|
|
20375
|
-
x: x,
|
|
20376
|
-
y: y,
|
|
20377
|
-
width: width,
|
|
20378
|
-
height: height
|
|
20379
|
-
};
|
|
20380
|
-
if (this.viewbox) {
|
|
20381
|
-
if (!intersectRect(this.viewbox, r2)) {
|
|
20382
|
-
return;
|
|
20383
|
-
}
|
|
20384
|
-
}
|
|
20385
|
-
var rect, parent;
|
|
20386
|
-
rect = this.__createElement("rect", r2, true);
|
|
20387
|
-
parent = this.__closestGroupOrSvg();
|
|
20388
|
-
parent.appendChild(rect);
|
|
20389
|
-
this.__currentElement = rect;
|
|
20390
|
-
this.__applyStyleToCurrentElement("fill");
|
|
20391
|
-
}
|
|
20392
|
-
/**
|
|
20393
|
-
* Draws a rectangle with no fill
|
|
20394
|
-
* @param x
|
|
20395
|
-
* @param y
|
|
20396
|
-
* @param width
|
|
20397
|
-
* @param height
|
|
20398
|
-
*/
|
|
20399
|
-
strokeRect(x, y, width, height) {
|
|
20400
|
-
var rect, parent;
|
|
20401
|
-
rect = this.__createElement("rect", {
|
|
20402
|
-
x: x,
|
|
20403
|
-
y: y,
|
|
20404
|
-
width: width,
|
|
20405
|
-
height: height
|
|
20406
|
-
}, true);
|
|
20407
|
-
parent = this.__closestGroupOrSvg();
|
|
20408
|
-
parent.appendChild(rect);
|
|
20409
|
-
this.__currentElement = rect;
|
|
20410
|
-
this.__applyStyleToCurrentElement("stroke");
|
|
20411
|
-
}
|
|
20412
|
-
// stroke ellipse
|
|
20413
|
-
strokeEllipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW) {
|
|
20414
|
-
this.__ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, 'stroke');
|
|
20415
|
-
}
|
|
20416
|
-
|
|
20417
|
-
// fill ellipse
|
|
20418
|
-
fillEllipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW) {
|
|
20419
|
-
this.__ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, 'fill');
|
|
20420
|
-
}
|
|
20421
|
-
|
|
20422
|
-
// ellipse helper
|
|
20423
|
-
__ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, style) {
|
|
20424
|
-
const config = {
|
|
20425
|
-
cx,
|
|
20426
|
-
cy,
|
|
20427
|
-
rx,
|
|
20428
|
-
ry
|
|
20429
|
-
};
|
|
20430
|
-
const element = this.__createElement('ellipse', config, true);
|
|
20431
|
-
const parent = this.__closestGroupOrSvg();
|
|
20432
|
-
parent.appendChild(element);
|
|
20433
|
-
this.__currentElement = element;
|
|
20434
|
-
this.__applyStyleToCurrentElement(style);
|
|
20435
|
-
}
|
|
20436
|
-
|
|
20437
|
-
/**
|
|
20438
|
-
* Clear entire canvas:
|
|
20439
|
-
* 1. save current transforms
|
|
20440
|
-
* 2. remove all the childNodes of the root g element
|
|
20441
|
-
*/
|
|
20442
|
-
__clearCanvas() {
|
|
20443
|
-
var current = this.__closestGroupOrSvg(),
|
|
20444
|
-
transform = current.getAttribute("transform");
|
|
20445
|
-
var rootGroup = this.__root.childNodes[1];
|
|
20446
|
-
var childNodes = rootGroup.childNodes;
|
|
20447
|
-
for (var i = childNodes.length - 1; i >= 0; i--) {
|
|
20448
|
-
if (childNodes[i]) {
|
|
20449
|
-
rootGroup.removeChild(childNodes[i]);
|
|
20450
|
-
}
|
|
20451
|
-
}
|
|
20452
|
-
this.__currentElement = rootGroup;
|
|
20453
|
-
//reset __groupStack as all the child group nodes are all removed.
|
|
20454
|
-
this.__groupStack = [];
|
|
20455
|
-
if (transform) {
|
|
20456
|
-
this.__addTransform(transform);
|
|
20457
|
-
}
|
|
20458
|
-
}
|
|
20459
|
-
/**
|
|
20460
|
-
* "Clears" a canvas by just drawing a white rectangle in the current group.
|
|
20461
|
-
*/
|
|
20462
|
-
clearRect(x, y, width, height) {
|
|
20463
|
-
//clear entire canvas
|
|
20464
|
-
if (x === 0 && y === 0 && width === this.width && height === this.height) {
|
|
20465
|
-
this.__clearCanvas();
|
|
20466
|
-
return;
|
|
20467
|
-
}
|
|
20468
|
-
var rect,
|
|
20469
|
-
parent = this.__closestGroupOrSvg();
|
|
20470
|
-
rect = this.__createElement("rect", {
|
|
20471
|
-
x: x,
|
|
20472
|
-
y: y,
|
|
20473
|
-
width: width,
|
|
20474
|
-
height: height,
|
|
20475
|
-
fill: "#FFFFFF"
|
|
20476
|
-
}, true);
|
|
20477
|
-
parent.appendChild(rect);
|
|
21197
|
+
/**
|
|
21198
|
+
* rotates the current element
|
|
21199
|
+
*/
|
|
21200
|
+
rotate(angle) {
|
|
21201
|
+
var degrees = angle * 180 / Math.PI;
|
|
21202
|
+
this.__addTransform(format("rotate({angle},{cx},{cy})", {
|
|
21203
|
+
angle: degrees,
|
|
21204
|
+
cx: 0,
|
|
21205
|
+
cy: 0
|
|
21206
|
+
}));
|
|
20478
21207
|
}
|
|
20479
21208
|
/**
|
|
20480
|
-
*
|
|
20481
|
-
* Returns a canvas gradient object that has a reference to it's parent def
|
|
21209
|
+
* translates the current element
|
|
20482
21210
|
*/
|
|
20483
|
-
|
|
20484
|
-
|
|
20485
|
-
|
|
20486
|
-
|
|
20487
|
-
|
|
20488
|
-
y1: y1 + "px",
|
|
20489
|
-
y2: y2 + "px",
|
|
20490
|
-
"gradientUnits": "userSpaceOnUse"
|
|
20491
|
-
}, false);
|
|
20492
|
-
this.__defs.appendChild(grad);
|
|
20493
|
-
return new CanvasGradient(grad, this);
|
|
21211
|
+
translate(x, y) {
|
|
21212
|
+
this.__addTransform(format("translate({x},{y})", {
|
|
21213
|
+
x: x,
|
|
21214
|
+
y: y
|
|
21215
|
+
}));
|
|
20494
21216
|
}
|
|
20495
21217
|
/**
|
|
20496
|
-
*
|
|
20497
|
-
* Returns a canvas gradient object that has a reference to it's parent def
|
|
21218
|
+
* applies a transform to the current element
|
|
20498
21219
|
*/
|
|
20499
|
-
|
|
20500
|
-
|
|
20501
|
-
|
|
20502
|
-
|
|
20503
|
-
|
|
20504
|
-
|
|
20505
|
-
|
|
20506
|
-
|
|
20507
|
-
|
|
20508
|
-
}, false);
|
|
20509
|
-
this.__defs.appendChild(grad);
|
|
20510
|
-
return new CanvasGradient(grad, this);
|
|
21220
|
+
transform(a, b, c, d, e, f) {
|
|
21221
|
+
this.__addTransform(format("matrix({a},{b},{c},{d},{e},{f})", {
|
|
21222
|
+
a: a,
|
|
21223
|
+
b: b,
|
|
21224
|
+
c: c,
|
|
21225
|
+
d: d,
|
|
21226
|
+
e: e,
|
|
21227
|
+
f: f
|
|
21228
|
+
}));
|
|
20511
21229
|
}
|
|
20512
21230
|
/**
|
|
20513
|
-
*
|
|
20514
|
-
* @private
|
|
21231
|
+
* Create a new Path Element
|
|
20515
21232
|
*/
|
|
20516
|
-
|
|
20517
|
-
var
|
|
20518
|
-
var fontPart = regex.exec(this.font);
|
|
20519
|
-
var data = {
|
|
20520
|
-
style: fontPart[1] || 'normal',
|
|
20521
|
-
size: fontPart[4] || '10px',
|
|
20522
|
-
family: fontPart[6] || 'sans-serif',
|
|
20523
|
-
weight: fontPart[3] || 'normal',
|
|
20524
|
-
decoration: fontPart[2] || 'normal',
|
|
20525
|
-
href: null
|
|
20526
|
-
};
|
|
20527
|
-
|
|
20528
|
-
//canvas doesn't support underline natively, but we can pass this attribute
|
|
20529
|
-
if (this.__fontUnderline === "underline") {
|
|
20530
|
-
data.decoration = "underline";
|
|
20531
|
-
}
|
|
21233
|
+
beginPath() {
|
|
21234
|
+
var path, parent;
|
|
20532
21235
|
|
|
20533
|
-
//
|
|
20534
|
-
|
|
20535
|
-
|
|
20536
|
-
}
|
|
20537
|
-
|
|
21236
|
+
// Note that there is only one current default path, it is not part of the drawing state.
|
|
21237
|
+
// See also: https://html.spec.whatwg.org/multipage/scripting.html#current-default-path
|
|
21238
|
+
this.__currentDefaultPath = "";
|
|
21239
|
+
this.__currentPosition = {};
|
|
21240
|
+
path = this.__createElement("path", {}, true);
|
|
21241
|
+
parent = this.__closestGroupOrSvg();
|
|
21242
|
+
parent.appendChild(path);
|
|
21243
|
+
this.__currentElement = path;
|
|
20538
21244
|
}
|
|
20539
21245
|
/**
|
|
20540
|
-
* Helper to
|
|
20541
|
-
* @param font
|
|
20542
|
-
* @param element
|
|
20543
|
-
* @return {*}
|
|
21246
|
+
* Helper function to apply currentDefaultPath to current path element
|
|
20544
21247
|
* @private
|
|
20545
21248
|
*/
|
|
20546
|
-
|
|
20547
|
-
|
|
20548
|
-
|
|
20549
|
-
|
|
20550
|
-
|
|
20551
|
-
|
|
21249
|
+
__applyCurrentDefaultPath() {
|
|
21250
|
+
var currentElement = this.__currentElement;
|
|
21251
|
+
if (currentElement.nodeName === "path") {
|
|
21252
|
+
currentElement.setAttribute("d", this.__currentDefaultPath);
|
|
21253
|
+
} else {
|
|
21254
|
+
console.error("Attempted to apply path command to node", currentElement.nodeName);
|
|
20552
21255
|
}
|
|
20553
|
-
return element;
|
|
20554
21256
|
}
|
|
20555
21257
|
/**
|
|
20556
|
-
*
|
|
20557
|
-
* @param text
|
|
20558
|
-
* @param x
|
|
20559
|
-
* @param y
|
|
20560
|
-
* @param action - stroke or fill
|
|
21258
|
+
* Helper function to add path command
|
|
20561
21259
|
* @private
|
|
20562
21260
|
*/
|
|
20563
|
-
|
|
20564
|
-
|
|
20565
|
-
|
|
20566
|
-
textElement = this.__createElement("text", {
|
|
20567
|
-
"font-family": font.family,
|
|
20568
|
-
"font-size": font.size,
|
|
20569
|
-
"font-style": font.style,
|
|
20570
|
-
"font-weight": font.weight,
|
|
20571
|
-
"text-decoration": font.decoration,
|
|
20572
|
-
"x": x,
|
|
20573
|
-
"y": y,
|
|
20574
|
-
"text-anchor": getTextAnchor(this.textAlign),
|
|
20575
|
-
"dominant-baseline": getDominantBaseline(this.textBaseline)
|
|
20576
|
-
}, true);
|
|
20577
|
-
textElement.appendChild(this.__document.createTextNode(text));
|
|
20578
|
-
this.__currentElement = textElement;
|
|
20579
|
-
this.__applyStyleToCurrentElement(action);
|
|
20580
|
-
parent.appendChild(this.__wrapTextLink(font, textElement));
|
|
21261
|
+
__addPathCommand(command) {
|
|
21262
|
+
this.__currentDefaultPath += " ";
|
|
21263
|
+
this.__currentDefaultPath += command;
|
|
20581
21264
|
}
|
|
20582
21265
|
/**
|
|
20583
|
-
*
|
|
20584
|
-
*
|
|
20585
|
-
* @param x
|
|
20586
|
-
* @param y
|
|
21266
|
+
* Adds the move command to the current path element,
|
|
21267
|
+
* if the currentPathElement is not empty create a new path element
|
|
20587
21268
|
*/
|
|
20588
|
-
|
|
20589
|
-
this.
|
|
21269
|
+
moveTo(x, y) {
|
|
21270
|
+
if (this.__currentElement.nodeName !== "path") {
|
|
21271
|
+
this.beginPath();
|
|
21272
|
+
}
|
|
21273
|
+
|
|
21274
|
+
// creates a new subpath with the given point
|
|
21275
|
+
this.__currentPosition = {
|
|
21276
|
+
x: x,
|
|
21277
|
+
y: y
|
|
21278
|
+
};
|
|
21279
|
+
this.__addPathCommand(format("M {x} {y}", {
|
|
21280
|
+
x: x,
|
|
21281
|
+
y: y
|
|
21282
|
+
}));
|
|
20590
21283
|
}
|
|
20591
21284
|
/**
|
|
20592
|
-
*
|
|
20593
|
-
* @param text
|
|
20594
|
-
* @param x
|
|
20595
|
-
* @param y
|
|
21285
|
+
* Closes the current path
|
|
20596
21286
|
*/
|
|
20597
|
-
|
|
20598
|
-
this.
|
|
21287
|
+
closePath() {
|
|
21288
|
+
if (this.__currentDefaultPath) {
|
|
21289
|
+
this.__addPathCommand("Z");
|
|
21290
|
+
}
|
|
20599
21291
|
}
|
|
20600
21292
|
/**
|
|
20601
|
-
*
|
|
20602
|
-
* @param text
|
|
20603
|
-
* @return {TextMetrics}
|
|
21293
|
+
* Adds a line to command
|
|
20604
21294
|
*/
|
|
20605
|
-
|
|
20606
|
-
this.
|
|
20607
|
-
|
|
21295
|
+
lineTo(x, y) {
|
|
21296
|
+
this.__currentPosition = {
|
|
21297
|
+
x: x,
|
|
21298
|
+
y: y
|
|
21299
|
+
};
|
|
21300
|
+
if (this.__currentDefaultPath && this.__currentDefaultPath.indexOf('M') > -1) {
|
|
21301
|
+
this.__addPathCommand(format("L {x} {y}", {
|
|
21302
|
+
x: x,
|
|
21303
|
+
y: y
|
|
21304
|
+
}));
|
|
21305
|
+
} else {
|
|
21306
|
+
this.__addPathCommand(format("M {x} {y}", {
|
|
21307
|
+
x: x,
|
|
21308
|
+
y: y
|
|
21309
|
+
}));
|
|
21310
|
+
}
|
|
20608
21311
|
}
|
|
20609
21312
|
/**
|
|
20610
|
-
*
|
|
21313
|
+
* Add a bezier command
|
|
20611
21314
|
*/
|
|
20612
|
-
|
|
20613
|
-
// in canvas no circle is drawn if no angle is provided.
|
|
20614
|
-
if (startAngle === endAngle) {
|
|
20615
|
-
return;
|
|
20616
|
-
}
|
|
20617
|
-
startAngle = startAngle % (2 * Math.PI);
|
|
20618
|
-
endAngle = endAngle % (2 * Math.PI);
|
|
20619
|
-
if (startAngle === endAngle) {
|
|
20620
|
-
//circle time! subtract some of the angle so svg is happy (svg elliptical arc can't draw a full circle)
|
|
20621
|
-
endAngle = (endAngle + 2 * Math.PI - 0.001 * (counterClockwise ? -1 : 1)) % (2 * Math.PI);
|
|
20622
|
-
}
|
|
20623
|
-
var endX = x + radius * Math.cos(endAngle),
|
|
20624
|
-
endY = y + radius * Math.sin(endAngle),
|
|
20625
|
-
startX = x + radius * Math.cos(startAngle),
|
|
20626
|
-
startY = y + radius * Math.sin(startAngle),
|
|
20627
|
-
sweepFlag = counterClockwise ? 0 : 1,
|
|
20628
|
-
largeArcFlag = 0,
|
|
20629
|
-
diff = endAngle - startAngle;
|
|
20630
|
-
|
|
20631
|
-
// https://github.com/gliffy/canvas2svg/issues/4
|
|
20632
|
-
if (diff < 0) {
|
|
20633
|
-
diff += 2 * Math.PI;
|
|
20634
|
-
}
|
|
20635
|
-
if (counterClockwise) {
|
|
20636
|
-
largeArcFlag = diff > Math.PI ? 0 : 1;
|
|
20637
|
-
} else {
|
|
20638
|
-
largeArcFlag = diff > Math.PI ? 1 : 0;
|
|
20639
|
-
}
|
|
20640
|
-
this.lineTo(startX, startY);
|
|
20641
|
-
this.__addPathCommand(format("A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}", {
|
|
20642
|
-
rx: radius,
|
|
20643
|
-
ry: radius,
|
|
20644
|
-
xAxisRotation: 0,
|
|
20645
|
-
largeArcFlag: largeArcFlag,
|
|
20646
|
-
sweepFlag: sweepFlag,
|
|
20647
|
-
endX: endX,
|
|
20648
|
-
endY: endY
|
|
20649
|
-
}));
|
|
21315
|
+
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
20650
21316
|
this.__currentPosition = {
|
|
20651
|
-
x:
|
|
20652
|
-
y:
|
|
21317
|
+
x: x,
|
|
21318
|
+
y: y
|
|
20653
21319
|
};
|
|
21320
|
+
this.__addPathCommand(format("C {cp1x} {cp1y} {cp2x} {cp2y} {x} {y}", {
|
|
21321
|
+
cp1x: cp1x,
|
|
21322
|
+
cp1y: cp1y,
|
|
21323
|
+
cp2x: cp2x,
|
|
21324
|
+
cp2y: cp2y,
|
|
21325
|
+
x: x,
|
|
21326
|
+
y: y
|
|
21327
|
+
}));
|
|
20654
21328
|
}
|
|
20655
21329
|
/**
|
|
20656
|
-
*
|
|
20657
|
-
* starts at startAngle and ends at endAngle, and travels in the direction given by counterclockwise (defaulting to clockwise).
|
|
20658
|
-
*/
|
|
20659
|
-
// ellipse (x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise) {
|
|
20660
|
-
// // TODO -- implement
|
|
20661
|
-
// }
|
|
20662
|
-
|
|
20663
|
-
/**
|
|
20664
|
-
* Generates a ClipPath from the clip command.
|
|
21330
|
+
* Adds a quadratic curve to command
|
|
20665
21331
|
*/
|
|
20666
|
-
|
|
20667
|
-
|
|
20668
|
-
|
|
20669
|
-
|
|
20670
|
-
|
|
20671
|
-
this.
|
|
20672
|
-
|
|
20673
|
-
|
|
20674
|
-
|
|
20675
|
-
|
|
20676
|
-
|
|
20677
|
-
//set the clip path to this group
|
|
20678
|
-
group.setAttribute("clip-path", format("url(#{id})", {
|
|
20679
|
-
id: id
|
|
21332
|
+
quadraticCurveTo(cpx, cpy, x, y) {
|
|
21333
|
+
this.__currentPosition = {
|
|
21334
|
+
x: x,
|
|
21335
|
+
y: y
|
|
21336
|
+
};
|
|
21337
|
+
this.__addPathCommand(format("Q {cpx} {cpy} {x} {y}", {
|
|
21338
|
+
cpx: cpx,
|
|
21339
|
+
cpy: cpy,
|
|
21340
|
+
x: x,
|
|
21341
|
+
y: y
|
|
20680
21342
|
}));
|
|
20681
|
-
|
|
20682
|
-
//clip paths can be scaled and transformed, we need to add another wrapper group to avoid later transformations
|
|
20683
|
-
// to this path
|
|
20684
|
-
group.appendChild(newGroup);
|
|
20685
|
-
this.__currentElement = newGroup;
|
|
20686
21343
|
}
|
|
20687
21344
|
/**
|
|
20688
|
-
*
|
|
20689
|
-
*
|
|
20690
|
-
* http://www.
|
|
21345
|
+
* Adds the arcTo to the current path
|
|
21346
|
+
*
|
|
21347
|
+
* @see http://www.w3.org/TR/2015/WD-2dcontext-20150514/#dom-context-2d-arcto
|
|
20691
21348
|
*/
|
|
20692
|
-
|
|
20693
|
-
//
|
|
20694
|
-
var
|
|
20695
|
-
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
sx = 0,
|
|
20701
|
-
sy = 0,
|
|
20702
|
-
sw,
|
|
20703
|
-
sh,
|
|
20704
|
-
parent,
|
|
20705
|
-
svg,
|
|
20706
|
-
defs,
|
|
20707
|
-
group,
|
|
20708
|
-
svgImage,
|
|
20709
|
-
canvas,
|
|
20710
|
-
context,
|
|
20711
|
-
id;
|
|
20712
|
-
if (args.length === 3) {
|
|
20713
|
-
dx = args[1];
|
|
20714
|
-
dy = args[2];
|
|
20715
|
-
sw = image.width;
|
|
20716
|
-
sh = image.height;
|
|
20717
|
-
dw = sw;
|
|
20718
|
-
dh = sh;
|
|
20719
|
-
} else if (args.length === 5) {
|
|
20720
|
-
dx = args[1];
|
|
20721
|
-
dy = args[2];
|
|
20722
|
-
dw = args[3];
|
|
20723
|
-
dh = args[4];
|
|
20724
|
-
sw = image.width;
|
|
20725
|
-
sh = image.height;
|
|
20726
|
-
} else if (args.length === 9) {
|
|
20727
|
-
sx = args[1];
|
|
20728
|
-
sy = args[2];
|
|
20729
|
-
sw = args[3];
|
|
20730
|
-
sh = args[4];
|
|
20731
|
-
dx = args[5];
|
|
20732
|
-
dy = args[6];
|
|
20733
|
-
dw = args[7];
|
|
20734
|
-
dh = args[8];
|
|
20735
|
-
} else {
|
|
20736
|
-
throw new Error("Invalid number of arguments passed to drawImage: " + arguments.length);
|
|
21349
|
+
arcTo(x1, y1, x2, y2, radius) {
|
|
21350
|
+
// Let the point (x0, y0) be the last point in the subpath.
|
|
21351
|
+
var x0 = this.__currentPosition && this.__currentPosition.x;
|
|
21352
|
+
var y0 = this.__currentPosition && this.__currentPosition.y;
|
|
21353
|
+
|
|
21354
|
+
// First ensure there is a subpath for (x1, y1).
|
|
21355
|
+
if (typeof x0 == "undefined" || typeof y0 == "undefined") {
|
|
21356
|
+
return;
|
|
20737
21357
|
}
|
|
20738
|
-
|
|
20739
|
-
|
|
20740
|
-
|
|
20741
|
-
|
|
20742
|
-
//canvas2svg mock canvas context. In the future we may want to clone nodes instead.
|
|
20743
|
-
//also I'm currently ignoring dw, dh, sw, sh, sx, sy for a mock context.
|
|
20744
|
-
svg = image.getSvg().cloneNode(true);
|
|
20745
|
-
if (svg.childNodes && svg.childNodes.length > 1) {
|
|
20746
|
-
defs = svg.childNodes[0];
|
|
20747
|
-
while (defs.childNodes.length) {
|
|
20748
|
-
id = defs.childNodes[0].getAttribute("id");
|
|
20749
|
-
this.__ids[id] = id;
|
|
20750
|
-
this.__defs.appendChild(defs.childNodes[0]);
|
|
20751
|
-
}
|
|
20752
|
-
group = svg.childNodes[1];
|
|
20753
|
-
if (group) {
|
|
20754
|
-
//save original transform
|
|
20755
|
-
var originTransform = group.getAttribute("transform");
|
|
20756
|
-
var transformDirective;
|
|
20757
|
-
if (originTransform) {
|
|
20758
|
-
transformDirective = originTransform + " " + translateDirective;
|
|
20759
|
-
} else {
|
|
20760
|
-
transformDirective = translateDirective;
|
|
20761
|
-
}
|
|
20762
|
-
group.setAttribute("transform", transformDirective);
|
|
20763
|
-
parent.appendChild(group);
|
|
20764
|
-
}
|
|
20765
|
-
}
|
|
20766
|
-
} else if (image.nodeName === "CANVAS" || image.nodeName === "IMG") {
|
|
20767
|
-
//canvas or image
|
|
20768
|
-
svgImage = this.__createElement("image");
|
|
20769
|
-
svgImage.setAttribute("width", dw);
|
|
20770
|
-
svgImage.setAttribute("height", dh);
|
|
20771
|
-
svgImage.setAttribute("preserveAspectRatio", "none");
|
|
20772
|
-
if (sx || sy || sw !== image.width || sh !== image.height) {
|
|
20773
|
-
//crop the image using a temporary canvas
|
|
20774
|
-
canvas = this.__document.createElement("canvas");
|
|
20775
|
-
canvas.width = dw;
|
|
20776
|
-
canvas.height = dh;
|
|
20777
|
-
context = canvas.getContext("2d");
|
|
20778
|
-
context.drawImage(image, sx, sy, sw, sh, 0, 0, dw, dh);
|
|
20779
|
-
image = canvas;
|
|
20780
|
-
}
|
|
20781
|
-
svgImage.setAttribute("transform", translateDirective);
|
|
20782
|
-
svgImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", image.nodeName === "CANVAS" ? image.toDataURL() : image.getAttribute("src"));
|
|
20783
|
-
parent.appendChild(svgImage);
|
|
21358
|
+
|
|
21359
|
+
// Negative values for radius must cause the implementation to throw an IndexSizeError exception.
|
|
21360
|
+
if (radius < 0) {
|
|
21361
|
+
throw new Error("IndexSizeError: The radius provided (" + radius + ") is negative.");
|
|
20784
21362
|
}
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
20790
|
-
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
|
|
20794
|
-
pattern.setAttribute("width", image.width);
|
|
20795
|
-
pattern.setAttribute("height", image.height);
|
|
20796
|
-
if (image.nodeName === "CANVAS" || image.nodeName === "IMG") {
|
|
20797
|
-
img = this.__createElement("image");
|
|
20798
|
-
img.setAttribute("width", image.width);
|
|
20799
|
-
img.setAttribute("height", image.height);
|
|
20800
|
-
img.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", image.nodeName === "CANVAS" ? image.toDataURL() : image.getAttribute("src"));
|
|
20801
|
-
pattern.appendChild(img);
|
|
20802
|
-
this.__defs.appendChild(pattern);
|
|
20803
|
-
} else if (image instanceof ctx) {
|
|
20804
|
-
pattern.appendChild(image.__root.childNodes[1]);
|
|
20805
|
-
this.__defs.appendChild(pattern);
|
|
21363
|
+
|
|
21364
|
+
// If the point (x0, y0) is equal to the point (x1, y1),
|
|
21365
|
+
// or if the point (x1, y1) is equal to the point (x2, y2),
|
|
21366
|
+
// or if the radius radius is zero,
|
|
21367
|
+
// then the method must add the point (x1, y1) to the subpath,
|
|
21368
|
+
// and connect that point to the previous point (x0, y0) by a straight line.
|
|
21369
|
+
if (x0 === x1 && y0 === y1 || x1 === x2 && y1 === y2 || radius === 0) {
|
|
21370
|
+
this.lineTo(x1, y1);
|
|
21371
|
+
return;
|
|
20806
21372
|
}
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
|
|
20811
|
-
|
|
20812
|
-
|
|
20813
|
-
|
|
21373
|
+
|
|
21374
|
+
// Otherwise, if the points (x0, y0), (x1, y1), and (x2, y2) all lie on a single straight line,
|
|
21375
|
+
// then the method must add the point (x1, y1) to the subpath,
|
|
21376
|
+
// and connect that point to the previous point (x0, y0) by a straight line.
|
|
21377
|
+
var unit_vec_p1_p0 = normalize$1([x0 - x1, y0 - y1]);
|
|
21378
|
+
var unit_vec_p1_p2 = normalize$1([x2 - x1, y2 - y1]);
|
|
21379
|
+
if (unit_vec_p1_p0[0] * unit_vec_p1_p2[1] === unit_vec_p1_p0[1] * unit_vec_p1_p2[0]) {
|
|
21380
|
+
this.lineTo(x1, y1);
|
|
21381
|
+
return;
|
|
20814
21382
|
}
|
|
20815
|
-
}
|
|
20816
|
-
/**
|
|
20817
|
-
* Not yet implemented
|
|
20818
|
-
*/
|
|
20819
|
-
drawFocusRing() {}
|
|
20820
|
-
createImageData() {}
|
|
20821
|
-
getImageData() {}
|
|
20822
|
-
putImageData() {}
|
|
20823
|
-
globalCompositeOperation() {}
|
|
20824
|
-
setTransform() {}
|
|
20825
|
-
}
|
|
20826
21383
|
|
|
20827
|
-
|
|
20828
|
-
|
|
20829
|
-
|
|
20830
|
-
this
|
|
20831
|
-
this.bpLength = bpLength;
|
|
20832
|
-
}
|
|
20833
|
-
}
|
|
21384
|
+
// Otherwise, let The Arc be the shortest arc given by circumference of the circle that has radius radius,
|
|
21385
|
+
// and that has one point tangent to the half-infinite line that crosses the point (x0, y0) and ends at the point (x1, y1),
|
|
21386
|
+
// and that has a different point tangent to the half-infinite line that ends at the point (x1, y1), and crosses the point (x2, y2).
|
|
21387
|
+
// The points at which this circle touches these two lines are called the start and end tangent points respectively.
|
|
20834
21388
|
|
|
20835
|
-
|
|
20836
|
-
|
|
20837
|
-
|
|
20838
|
-
* Copyright (c) 2014 Broad Institute
|
|
20839
|
-
*
|
|
20840
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
20841
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
20842
|
-
* in the Software without restriction, including without limitation the rights
|
|
20843
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
20844
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
20845
|
-
* furnished to do so, subject to the following conditions:
|
|
20846
|
-
*
|
|
20847
|
-
* The above copyright notice and this permission notice shall be included in
|
|
20848
|
-
* all copies or substantial portions of the Software.
|
|
20849
|
-
*
|
|
20850
|
-
*
|
|
20851
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20852
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20853
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20854
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20855
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20856
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
20857
|
-
* THE SOFTWARE.
|
|
20858
|
-
*/
|
|
20859
|
-
const splitLines$4 = splitLines$5;
|
|
20860
|
-
const reservedProperties$1 = new Set(['fastaURL', 'indexURL', 'cytobandURL', 'indexed']);
|
|
20861
|
-
class NonIndexedFasta {
|
|
20862
|
-
constructor(reference) {
|
|
20863
|
-
this.fastaURL = reference.fastaURL;
|
|
20864
|
-
this.withCredentials = reference.withCredentials;
|
|
20865
|
-
this.chromosomeNames = [];
|
|
20866
|
-
this.chromosomes = {};
|
|
20867
|
-
this.sequences = new Map();
|
|
21389
|
+
// note that both vectors are unit vectors, so the length is 1
|
|
21390
|
+
var cos = unit_vec_p1_p0[0] * unit_vec_p1_p2[0] + unit_vec_p1_p0[1] * unit_vec_p1_p2[1];
|
|
21391
|
+
var theta = Math.acos(Math.abs(cos));
|
|
20868
21392
|
|
|
20869
|
-
//
|
|
20870
|
-
|
|
20871
|
-
|
|
20872
|
-
|
|
20873
|
-
|
|
21393
|
+
// Calculate origin
|
|
21394
|
+
var unit_vec_p1_origin = normalize$1([unit_vec_p1_p0[0] + unit_vec_p1_p2[0], unit_vec_p1_p0[1] + unit_vec_p1_p2[1]]);
|
|
21395
|
+
var len_p1_origin = radius / Math.sin(theta / 2);
|
|
21396
|
+
var x = x1 + len_p1_origin * unit_vec_p1_origin[0];
|
|
21397
|
+
var y = y1 + len_p1_origin * unit_vec_p1_origin[1];
|
|
21398
|
+
|
|
21399
|
+
// Calculate start angle and end angle
|
|
21400
|
+
// rotate 90deg clockwise (note that y axis points to its down)
|
|
21401
|
+
var unit_vec_origin_start_tangent = [-unit_vec_p1_p0[1], unit_vec_p1_p0[0]];
|
|
21402
|
+
// rotate 90deg counter clockwise (note that y axis points to its down)
|
|
21403
|
+
var unit_vec_origin_end_tangent = [unit_vec_p1_p2[1], -unit_vec_p1_p2[0]];
|
|
21404
|
+
var getAngle = function (vector) {
|
|
21405
|
+
// get angle (clockwise) between vector and (1, 0)
|
|
21406
|
+
var x = vector[0];
|
|
21407
|
+
var y = vector[1];
|
|
21408
|
+
if (y >= 0) {
|
|
21409
|
+
// note that y axis points to its down
|
|
21410
|
+
return Math.acos(x);
|
|
21411
|
+
} else {
|
|
21412
|
+
return -Math.acos(x);
|
|
20874
21413
|
}
|
|
20875
|
-
}
|
|
20876
|
-
|
|
21414
|
+
};
|
|
21415
|
+
var startAngle = getAngle(unit_vec_origin_start_tangent);
|
|
21416
|
+
var endAngle = getAngle(unit_vec_origin_end_tangent);
|
|
21417
|
+
|
|
21418
|
+
// Connect the point (x0, y0) to the start tangent point by a straight line
|
|
21419
|
+
this.lineTo(x + unit_vec_origin_start_tangent[0] * radius, y + unit_vec_origin_start_tangent[1] * radius);
|
|
21420
|
+
|
|
21421
|
+
// Connect the start tangent point to the end tangent point by arc
|
|
21422
|
+
// and adding the end tangent point to the subpath.
|
|
21423
|
+
this.arc(x, y, radius, startAngle, endAngle);
|
|
20877
21424
|
}
|
|
20878
|
-
|
|
20879
|
-
|
|
21425
|
+
/**
|
|
21426
|
+
* Sets the stroke property on the current element
|
|
21427
|
+
*/
|
|
21428
|
+
stroke() {
|
|
21429
|
+
if (this.__currentElement.nodeName === "path") {
|
|
21430
|
+
this.__currentElement.setAttribute("paint-order", "fill stroke markers");
|
|
21431
|
+
}
|
|
21432
|
+
this.__applyCurrentDefaultPath();
|
|
21433
|
+
this.__applyStyleToCurrentElement("stroke");
|
|
20880
21434
|
}
|
|
20881
|
-
|
|
20882
|
-
|
|
20883
|
-
|
|
21435
|
+
/**
|
|
21436
|
+
* Sets fill properties on the current element
|
|
21437
|
+
*/
|
|
21438
|
+
fill() {
|
|
21439
|
+
if (this.__currentElement.nodeName === "path") {
|
|
21440
|
+
this.__currentElement.setAttribute("paint-order", "stroke fill markers");
|
|
20884
21441
|
}
|
|
20885
|
-
|
|
20886
|
-
|
|
20887
|
-
|
|
20888
|
-
|
|
20889
|
-
|
|
20890
|
-
|
|
21442
|
+
this.__applyCurrentDefaultPath();
|
|
21443
|
+
this.__applyStyleToCurrentElement("fill");
|
|
21444
|
+
}
|
|
21445
|
+
/**
|
|
21446
|
+
* Adds a rectangle to the path.
|
|
21447
|
+
*/
|
|
21448
|
+
rect(x, y, width, height) {
|
|
21449
|
+
if (this.__currentElement.nodeName !== "path") {
|
|
21450
|
+
this.beginPath();
|
|
20891
21451
|
}
|
|
20892
|
-
|
|
20893
|
-
|
|
20894
|
-
|
|
20895
|
-
|
|
20896
|
-
|
|
20897
|
-
|
|
20898
|
-
|
|
21452
|
+
this.moveTo(x, y);
|
|
21453
|
+
this.lineTo(x + width, y);
|
|
21454
|
+
this.lineTo(x + width, y + height);
|
|
21455
|
+
this.lineTo(x, y + height);
|
|
21456
|
+
this.lineTo(x, y);
|
|
21457
|
+
this.closePath();
|
|
21458
|
+
}
|
|
21459
|
+
/**
|
|
21460
|
+
* adds a rectangle element
|
|
21461
|
+
*/
|
|
21462
|
+
fillRect(x, y, width, height) {
|
|
21463
|
+
if (height < 0) {
|
|
21464
|
+
y += height;
|
|
21465
|
+
height = -height;
|
|
20899
21466
|
}
|
|
20900
|
-
if (
|
|
20901
|
-
|
|
21467
|
+
if (width < 0) {
|
|
21468
|
+
x += width;
|
|
21469
|
+
width = -width;
|
|
20902
21470
|
}
|
|
20903
|
-
|
|
20904
|
-
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
20911
|
-
|
|
20912
|
-
|
|
20913
|
-
data += String.fromCharCode(b);
|
|
21471
|
+
// See if rect intersects current viewbox
|
|
21472
|
+
var r2 = {
|
|
21473
|
+
x: x,
|
|
21474
|
+
y: y,
|
|
21475
|
+
width: width,
|
|
21476
|
+
height: height
|
|
21477
|
+
};
|
|
21478
|
+
if (this.viewbox) {
|
|
21479
|
+
if (!intersectRect(this.viewbox, r2)) {
|
|
21480
|
+
return;
|
|
20914
21481
|
}
|
|
20915
|
-
} else {
|
|
20916
|
-
data = await igvxhr.load(this.fastaURL, buildOptions(this.config));
|
|
20917
21482
|
}
|
|
20918
|
-
|
|
20919
|
-
|
|
20920
|
-
|
|
20921
|
-
|
|
20922
|
-
|
|
20923
|
-
|
|
20924
|
-
|
|
20925
|
-
|
|
20926
|
-
|
|
20927
|
-
|
|
20928
|
-
|
|
20929
|
-
|
|
20930
|
-
|
|
20931
|
-
|
|
20932
|
-
|
|
21483
|
+
var rect, parent;
|
|
21484
|
+
rect = this.__createElement("rect", r2, true);
|
|
21485
|
+
parent = this.__closestGroupOrSvg();
|
|
21486
|
+
parent.appendChild(rect);
|
|
21487
|
+
this.__currentElement = rect;
|
|
21488
|
+
this.__applyStyleToCurrentElement("fill");
|
|
21489
|
+
}
|
|
21490
|
+
/**
|
|
21491
|
+
* Draws a rectangle with no fill
|
|
21492
|
+
* @param x
|
|
21493
|
+
* @param y
|
|
21494
|
+
* @param width
|
|
21495
|
+
* @param height
|
|
21496
|
+
*/
|
|
21497
|
+
strokeRect(x, y, width, height) {
|
|
21498
|
+
var rect, parent;
|
|
21499
|
+
rect = this.__createElement("rect", {
|
|
21500
|
+
x: x,
|
|
21501
|
+
y: y,
|
|
21502
|
+
width: width,
|
|
21503
|
+
height: height
|
|
21504
|
+
}, true);
|
|
21505
|
+
parent = this.__closestGroupOrSvg();
|
|
21506
|
+
parent.appendChild(rect);
|
|
21507
|
+
this.__currentElement = rect;
|
|
21508
|
+
this.__applyStyleToCurrentElement("stroke");
|
|
21509
|
+
}
|
|
21510
|
+
// stroke ellipse
|
|
21511
|
+
strokeEllipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW) {
|
|
21512
|
+
this.__ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, 'stroke');
|
|
21513
|
+
}
|
|
20933
21514
|
|
|
20934
|
-
|
|
20935
|
-
|
|
20936
|
-
|
|
20937
|
-
|
|
20938
|
-
current.offset = 0;
|
|
20939
|
-
if (nameParts.length > 1 && nameParts[1].indexOf('-') > 0) {
|
|
20940
|
-
const locusParts = nameParts[1].split('-');
|
|
20941
|
-
if (locusParts.length === 2 && /^[0-9]+$/.test(locusParts[0]) && /^[0-9]+$/.test(locusParts[1])) ;
|
|
20942
|
-
const from = Number.parseInt(locusParts[0]);
|
|
20943
|
-
const to = Number.parseInt(locusParts[1]);
|
|
20944
|
-
if (to > from) {
|
|
20945
|
-
// TODO this should be an error
|
|
20946
|
-
current.offset = from - 1;
|
|
20947
|
-
}
|
|
21515
|
+
// fill ellipse
|
|
21516
|
+
fillEllipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW) {
|
|
21517
|
+
this.__ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, 'fill');
|
|
21518
|
+
}
|
|
20948
21519
|
|
|
20949
|
-
|
|
20950
|
-
|
|
20951
|
-
|
|
20952
|
-
|
|
20953
|
-
|
|
20954
|
-
|
|
20955
|
-
|
|
20956
|
-
|
|
20957
|
-
|
|
20958
|
-
|
|
20959
|
-
|
|
20960
|
-
|
|
20961
|
-
|
|
20962
|
-
|
|
20963
|
-
|
|
20964
|
-
|
|
20965
|
-
|
|
20966
|
-
|
|
21520
|
+
// ellipse helper
|
|
21521
|
+
__ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, style) {
|
|
21522
|
+
const config = {
|
|
21523
|
+
cx,
|
|
21524
|
+
cy,
|
|
21525
|
+
rx,
|
|
21526
|
+
ry
|
|
21527
|
+
};
|
|
21528
|
+
const element = this.__createElement('ellipse', config, true);
|
|
21529
|
+
const parent = this.__closestGroupOrSvg();
|
|
21530
|
+
parent.appendChild(element);
|
|
21531
|
+
this.__currentElement = element;
|
|
21532
|
+
this.__applyStyleToCurrentElement(style);
|
|
21533
|
+
}
|
|
21534
|
+
|
|
21535
|
+
/**
|
|
21536
|
+
* Clear entire canvas:
|
|
21537
|
+
* 1. save current transforms
|
|
21538
|
+
* 2. remove all the childNodes of the root g element
|
|
21539
|
+
*/
|
|
21540
|
+
__clearCanvas() {
|
|
21541
|
+
var current = this.__closestGroupOrSvg(),
|
|
21542
|
+
transform = current.getAttribute("transform");
|
|
21543
|
+
var rootGroup = this.__root.childNodes[1];
|
|
21544
|
+
var childNodes = rootGroup.childNodes;
|
|
21545
|
+
for (var i = childNodes.length - 1; i >= 0; i--) {
|
|
21546
|
+
if (childNodes[i]) {
|
|
21547
|
+
rootGroup.removeChild(childNodes[i]);
|
|
20967
21548
|
}
|
|
20968
21549
|
}
|
|
20969
|
-
|
|
20970
|
-
|
|
20971
|
-
|
|
20972
|
-
|
|
20973
|
-
|
|
20974
|
-
this.chromosomes[current.chr] = new Chromosome(current.chr, order, length);
|
|
20975
|
-
chrNameSet.add(current.chr);
|
|
20976
|
-
} else {
|
|
20977
|
-
const c = this.chromosomes[current.chr];
|
|
20978
|
-
c.bpLength = Math.max(c.bpLength, length);
|
|
20979
|
-
}
|
|
20980
|
-
this.sequences.get(current.chr).push(new SequenceSlice(current.offset, current.seq));
|
|
21550
|
+
this.__currentElement = rootGroup;
|
|
21551
|
+
//reset __groupStack as all the child group nodes are all removed.
|
|
21552
|
+
this.__groupStack = [];
|
|
21553
|
+
if (transform) {
|
|
21554
|
+
this.__addTransform(transform);
|
|
20981
21555
|
}
|
|
20982
21556
|
}
|
|
20983
|
-
|
|
20984
|
-
|
|
20985
|
-
|
|
20986
|
-
|
|
20987
|
-
|
|
20988
|
-
|
|
20989
|
-
|
|
20990
|
-
|
|
21557
|
+
/**
|
|
21558
|
+
* "Clears" a canvas by just drawing a white rectangle in the current group.
|
|
21559
|
+
*/
|
|
21560
|
+
clearRect(x, y, width, height) {
|
|
21561
|
+
//clear entire canvas
|
|
21562
|
+
if (x === 0 && y === 0 && width === this.width && height === this.height) {
|
|
21563
|
+
this.__clearCanvas();
|
|
21564
|
+
return;
|
|
21565
|
+
}
|
|
21566
|
+
var rect,
|
|
21567
|
+
parent = this.__closestGroupOrSvg();
|
|
21568
|
+
rect = this.__createElement("rect", {
|
|
21569
|
+
x: x,
|
|
21570
|
+
y: y,
|
|
21571
|
+
width: width,
|
|
21572
|
+
height: height,
|
|
21573
|
+
fill: "#FFFFFF"
|
|
21574
|
+
}, true);
|
|
21575
|
+
parent.appendChild(rect);
|
|
20991
21576
|
}
|
|
20992
|
-
|
|
20993
|
-
|
|
21577
|
+
/**
|
|
21578
|
+
* Adds a linear gradient to a defs tag.
|
|
21579
|
+
* Returns a canvas gradient object that has a reference to it's parent def
|
|
21580
|
+
*/
|
|
21581
|
+
createLinearGradient(x1, y1, x2, y2) {
|
|
21582
|
+
var grad = this.__createElement("linearGradient", {
|
|
21583
|
+
id: randomString(this.__ids),
|
|
21584
|
+
x1: x1 + "px",
|
|
21585
|
+
x2: x2 + "px",
|
|
21586
|
+
y1: y1 + "px",
|
|
21587
|
+
y2: y2 + "px",
|
|
21588
|
+
"gradientUnits": "userSpaceOnUse"
|
|
21589
|
+
}, false);
|
|
21590
|
+
this.__defs.appendChild(grad);
|
|
21591
|
+
return new CanvasGradient(grad, this);
|
|
20994
21592
|
}
|
|
20995
|
-
|
|
20996
|
-
|
|
21593
|
+
/**
|
|
21594
|
+
* Adds a radial gradient to a defs tag.
|
|
21595
|
+
* Returns a canvas gradient object that has a reference to it's parent def
|
|
21596
|
+
*/
|
|
21597
|
+
createRadialGradient(x0, y0, r0, x1, y1, r1) {
|
|
21598
|
+
var grad = this.__createElement("radialGradient", {
|
|
21599
|
+
id: randomString(this.__ids),
|
|
21600
|
+
cx: x1 + "px",
|
|
21601
|
+
cy: y1 + "px",
|
|
21602
|
+
r: r1 + "px",
|
|
21603
|
+
fx: x0 + "px",
|
|
21604
|
+
fy: y0 + "px",
|
|
21605
|
+
"gradientUnits": "userSpaceOnUse"
|
|
21606
|
+
}, false);
|
|
21607
|
+
this.__defs.appendChild(grad);
|
|
21608
|
+
return new CanvasGradient(grad, this);
|
|
20997
21609
|
}
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
|
|
21001
|
-
|
|
21002
|
-
|
|
21003
|
-
|
|
21004
|
-
|
|
21005
|
-
|
|
21006
|
-
|
|
21007
|
-
|
|
21008
|
-
|
|
21009
|
-
|
|
21010
|
-
|
|
21011
|
-
|
|
21610
|
+
/**
|
|
21611
|
+
* Parses the font string and returns svg mapping
|
|
21612
|
+
* @private
|
|
21613
|
+
*/
|
|
21614
|
+
__parseFont() {
|
|
21615
|
+
var regex = /^\s*(?=(?:(?:[-a-z]+\s*){0,2}(italic|oblique))?)(?=(?:(?:[-a-z]+\s*){0,2}(small-caps))?)(?=(?:(?:[-a-z]+\s*){0,2}(bold(?:er)?|lighter|[1-9]00))?)(?:(?:normal|\1|\2|\3)\s*){0,3}((?:xx?-)?(?:small|large)|medium|smaller|larger|[.\d]+(?:\%|in|[cem]m|ex|p[ctx]))(?:\s*\/\s*(normal|[.\d]+(?:\%|in|[cem]m|ex|p[ctx])))?\s*([-,\'\"\sa-z0-9]+?)\s*$/i;
|
|
21616
|
+
var fontPart = regex.exec(this.font);
|
|
21617
|
+
var data = {
|
|
21618
|
+
style: fontPart[1] || 'normal',
|
|
21619
|
+
size: fontPart[4] || '10px',
|
|
21620
|
+
family: fontPart[6] || 'sans-serif',
|
|
21621
|
+
weight: fontPart[3] || 'normal',
|
|
21622
|
+
decoration: fontPart[2] || 'normal',
|
|
21623
|
+
href: null
|
|
21624
|
+
};
|
|
21012
21625
|
|
|
21013
|
-
|
|
21014
|
-
|
|
21015
|
-
|
|
21016
|
-
|
|
21017
|
-
*
|
|
21018
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
21019
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
21020
|
-
* in the Software without restriction, including without limitation the rights
|
|
21021
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21022
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
21023
|
-
* furnished to do so, subject to the following conditions:
|
|
21024
|
-
*
|
|
21025
|
-
* The above copyright notice and this permission notice shall be included in
|
|
21026
|
-
* all copies or substantial portions of the Software.
|
|
21027
|
-
*
|
|
21028
|
-
*
|
|
21029
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21030
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21031
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21032
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21033
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21034
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21035
|
-
* THE SOFTWARE.
|
|
21036
|
-
*/
|
|
21037
|
-
const splitLines$3 = splitLines$5;
|
|
21038
|
-
const reservedProperties = new Set(['fastaURL', 'indexURL', 'compressedIndexURL', 'cytobandURL', 'indexed']);
|
|
21039
|
-
class FastaSequence {
|
|
21040
|
-
constructor(reference) {
|
|
21041
|
-
this.file = reference.fastaURL;
|
|
21042
|
-
this.indexFile = reference.indexURL || reference.indexFile || this.file + ".fai";
|
|
21043
|
-
this.compressedIndexFile = reference.compressedIndexURL || false;
|
|
21044
|
-
this.withCredentials = reference.withCredentials;
|
|
21045
|
-
this.chromosomeNames = [];
|
|
21046
|
-
this.chromosomes = {};
|
|
21047
|
-
this.sequences = {};
|
|
21048
|
-
this.offsets = {};
|
|
21626
|
+
//canvas doesn't support underline natively, but we can pass this attribute
|
|
21627
|
+
if (this.__fontUnderline === "underline") {
|
|
21628
|
+
data.decoration = "underline";
|
|
21629
|
+
}
|
|
21049
21630
|
|
|
21050
|
-
//
|
|
21051
|
-
|
|
21052
|
-
|
|
21053
|
-
if (reference.hasOwnProperty(key) && !reservedProperties.has(key)) {
|
|
21054
|
-
config[key] = reference[key];
|
|
21055
|
-
}
|
|
21631
|
+
//canvas also doesn't support linking, but we can pass this as well
|
|
21632
|
+
if (this.__fontHref) {
|
|
21633
|
+
data.href = this.__fontHref;
|
|
21056
21634
|
}
|
|
21057
|
-
|
|
21058
|
-
}
|
|
21059
|
-
async init() {
|
|
21060
|
-
return this.getIndex();
|
|
21635
|
+
return data;
|
|
21061
21636
|
}
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
|
|
21065
|
-
|
|
21066
|
-
|
|
21067
|
-
|
|
21068
|
-
|
|
21069
|
-
|
|
21070
|
-
|
|
21071
|
-
|
|
21072
|
-
|
|
21073
|
-
|
|
21074
|
-
|
|
21075
|
-
this.interval = new GenomicInterval(chr, qstart, qend, seqBytes);
|
|
21637
|
+
/**
|
|
21638
|
+
* Helper to link text fragments
|
|
21639
|
+
* @param font
|
|
21640
|
+
* @param element
|
|
21641
|
+
* @return {*}
|
|
21642
|
+
* @private
|
|
21643
|
+
*/
|
|
21644
|
+
__wrapTextLink(font, element) {
|
|
21645
|
+
if (font.href) {
|
|
21646
|
+
var a = this.__createElement("a");
|
|
21647
|
+
a.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", font.href);
|
|
21648
|
+
a.appendChild(element);
|
|
21649
|
+
return a;
|
|
21076
21650
|
}
|
|
21077
|
-
|
|
21078
|
-
const n = end - start;
|
|
21079
|
-
const seq = this.interval.features ? this.interval.features.substr(offset, n) : null;
|
|
21080
|
-
return seq;
|
|
21651
|
+
return element;
|
|
21081
21652
|
}
|
|
21082
|
-
|
|
21083
|
-
|
|
21084
|
-
|
|
21085
|
-
|
|
21086
|
-
|
|
21087
|
-
|
|
21088
|
-
|
|
21089
|
-
|
|
21090
|
-
|
|
21091
|
-
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
21096
|
-
|
|
21097
|
-
|
|
21098
|
-
|
|
21099
|
-
|
|
21100
|
-
|
|
21101
|
-
|
|
21102
|
-
|
|
21103
|
-
|
|
21104
|
-
|
|
21105
|
-
|
|
21106
|
-
|
|
21107
|
-
|
|
21108
|
-
this.chromosomeNames.push(chr);
|
|
21109
|
-
this.index[chr] = indexEntry;
|
|
21110
|
-
this.chromosomes[chr] = new Chromosome(chr, order++, size);
|
|
21111
|
-
}
|
|
21112
|
-
}
|
|
21113
|
-
return this.index;
|
|
21114
|
-
}
|
|
21653
|
+
/**
|
|
21654
|
+
* Fills or strokes text
|
|
21655
|
+
* @param text
|
|
21656
|
+
* @param x
|
|
21657
|
+
* @param y
|
|
21658
|
+
* @param action - stroke or fill
|
|
21659
|
+
* @private
|
|
21660
|
+
*/
|
|
21661
|
+
__applyText(text, x, y, action) {
|
|
21662
|
+
var font = this.__parseFont(),
|
|
21663
|
+
parent = this.__closestGroupOrSvg(),
|
|
21664
|
+
textElement = this.__createElement("text", {
|
|
21665
|
+
"font-family": font.family,
|
|
21666
|
+
"font-size": font.size,
|
|
21667
|
+
"font-style": font.style,
|
|
21668
|
+
"font-weight": font.weight,
|
|
21669
|
+
"text-decoration": font.decoration,
|
|
21670
|
+
"x": x,
|
|
21671
|
+
"y": y,
|
|
21672
|
+
"text-anchor": getTextAnchor(this.textAlign),
|
|
21673
|
+
"dominant-baseline": getDominantBaseline(this.textBaseline)
|
|
21674
|
+
}, true);
|
|
21675
|
+
textElement.appendChild(this.__document.createTextNode(text));
|
|
21676
|
+
this.__currentElement = textElement;
|
|
21677
|
+
this.__applyStyleToCurrentElement(action);
|
|
21678
|
+
parent.appendChild(this.__wrapTextLink(font, textElement));
|
|
21115
21679
|
}
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21125
|
-
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21129
|
-
|
|
21130
|
-
|
|
21680
|
+
/**
|
|
21681
|
+
* Creates a text element
|
|
21682
|
+
* @param text
|
|
21683
|
+
* @param x
|
|
21684
|
+
* @param y
|
|
21685
|
+
*/
|
|
21686
|
+
fillText(text, x, y) {
|
|
21687
|
+
this.__applyText(text, x, y, "fill");
|
|
21688
|
+
}
|
|
21689
|
+
/**
|
|
21690
|
+
* Strokes text
|
|
21691
|
+
* @param text
|
|
21692
|
+
* @param x
|
|
21693
|
+
* @param y
|
|
21694
|
+
*/
|
|
21695
|
+
strokeText(text, x, y) {
|
|
21696
|
+
this.__applyText(text, x, y, "stroke");
|
|
21697
|
+
}
|
|
21698
|
+
/**
|
|
21699
|
+
* No need to implement this for svg.
|
|
21700
|
+
* @param text
|
|
21701
|
+
* @return {TextMetrics}
|
|
21702
|
+
*/
|
|
21703
|
+
measureText(text) {
|
|
21704
|
+
this.__ctx.font = this.font;
|
|
21705
|
+
return this.__ctx.measureText(text);
|
|
21706
|
+
}
|
|
21707
|
+
/**
|
|
21708
|
+
* Arc command!
|
|
21709
|
+
*/
|
|
21710
|
+
arc(x, y, radius, startAngle, endAngle, counterClockwise) {
|
|
21711
|
+
// in canvas no circle is drawn if no angle is provided.
|
|
21712
|
+
if (startAngle === endAngle) {
|
|
21713
|
+
return;
|
|
21131
21714
|
}
|
|
21132
|
-
|
|
21133
|
-
|
|
21134
|
-
|
|
21135
|
-
|
|
21136
|
-
|
|
21137
|
-
if (givenFileSize < GZI_NUM_BYTES_OFFSET) {
|
|
21138
|
-
console.log("Cannot parse GZI index file: length (" + givenFileSize + " bytes) is insufficient to determine content of index.");
|
|
21139
|
-
return this.compressedIndex;
|
|
21715
|
+
startAngle = startAngle % (2 * Math.PI);
|
|
21716
|
+
endAngle = endAngle % (2 * Math.PI);
|
|
21717
|
+
if (startAngle === endAngle) {
|
|
21718
|
+
//circle time! subtract some of the angle so svg is happy (svg elliptical arc can't draw a full circle)
|
|
21719
|
+
endAngle = (endAngle + 2 * Math.PI - 0.001 * (counterClockwise ? -1 : 1)) % (2 * Math.PI);
|
|
21140
21720
|
}
|
|
21141
|
-
|
|
21142
|
-
|
|
21143
|
-
|
|
21144
|
-
|
|
21145
|
-
|
|
21146
|
-
|
|
21721
|
+
var endX = x + radius * Math.cos(endAngle),
|
|
21722
|
+
endY = y + radius * Math.sin(endAngle),
|
|
21723
|
+
startX = x + radius * Math.cos(startAngle),
|
|
21724
|
+
startY = y + radius * Math.sin(startAngle),
|
|
21725
|
+
sweepFlag = counterClockwise ? 0 : 1,
|
|
21726
|
+
largeArcFlag = 0,
|
|
21727
|
+
diff = endAngle - startAngle;
|
|
21147
21728
|
|
|
21148
|
-
//
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
// 8 + 2*(num_entries*8) bytes, with the first 8 bytes indicating the number of entries
|
|
21152
|
-
const expectedFileSize = GZI_NUM_BYTES_OFFSET + numBlocks * 2 * GZI_NUM_BYTES_BLOCK;
|
|
21153
|
-
if (givenFileSize != expectedFileSize) {
|
|
21154
|
-
console.log("Incorrect file size of reference genome index. Expected : " + expectedFileSize + ". Received : " + givenFileSize);
|
|
21155
|
-
return this.compressedIndex;
|
|
21729
|
+
// https://github.com/gliffy/canvas2svg/issues/4
|
|
21730
|
+
if (diff < 0) {
|
|
21731
|
+
diff += 2 * Math.PI;
|
|
21156
21732
|
}
|
|
21157
|
-
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
//Further process all the blocks of the GZI index, and keep them in memory
|
|
21162
|
-
for (let blockNumber = 0; blockNumber < numBlocks; blockNumber++) {
|
|
21163
|
-
const bufferBlockStart = GZI_NUM_BYTES_OFFSET + blockNumber * 2 * GZI_NUM_BYTES_BLOCK;
|
|
21164
|
-
const bufferBlockEnd = GZI_NUM_BYTES_OFFSET + blockNumber * 2 * GZI_NUM_BYTES_BLOCK + 2 * GZI_NUM_BYTES_BLOCK;
|
|
21165
|
-
const bufferBlock = gziData.slice(bufferBlockStart, bufferBlockEnd);
|
|
21166
|
-
const viewBlock = new DataView(bufferBlock);
|
|
21167
|
-
const compressedPosition = Number(viewBlock.getBigUint64(0, true)); //First 8 bytes
|
|
21168
|
-
const uncompressedPosition = Number(viewBlock.getBigUint64(GZI_NUM_BYTES_BLOCK, true)); //Last 8 bytes
|
|
21169
|
-
this.compressedIndex.push([compressedPosition, uncompressedPosition]);
|
|
21733
|
+
if (counterClockwise) {
|
|
21734
|
+
largeArcFlag = diff > Math.PI ? 0 : 1;
|
|
21735
|
+
} else {
|
|
21736
|
+
largeArcFlag = diff > Math.PI ? 1 : 0;
|
|
21170
21737
|
}
|
|
21171
|
-
|
|
21738
|
+
this.lineTo(startX, startY);
|
|
21739
|
+
this.__addPathCommand(format("A {rx} {ry} {xAxisRotation} {largeArcFlag} {sweepFlag} {endX} {endY}", {
|
|
21740
|
+
rx: radius,
|
|
21741
|
+
ry: radius,
|
|
21742
|
+
xAxisRotation: 0,
|
|
21743
|
+
largeArcFlag: largeArcFlag,
|
|
21744
|
+
sweepFlag: sweepFlag,
|
|
21745
|
+
endX: endX,
|
|
21746
|
+
endY: endY
|
|
21747
|
+
}));
|
|
21748
|
+
this.__currentPosition = {
|
|
21749
|
+
x: endX,
|
|
21750
|
+
y: endY
|
|
21751
|
+
};
|
|
21172
21752
|
}
|
|
21753
|
+
/**
|
|
21754
|
+
* The ellipse() method creates an elliptical arc centered at (x, y) with the radii radiusX and radiusY. The path
|
|
21755
|
+
* starts at startAngle and ends at endAngle, and travels in the direction given by counterclockwise (defaulting to clockwise).
|
|
21756
|
+
*/
|
|
21757
|
+
// ellipse (x, y, radiusX, radiusY, rotation, startAngle, endAngle, counterclockwise) {
|
|
21758
|
+
// // TODO -- implement
|
|
21759
|
+
// }
|
|
21173
21760
|
|
|
21174
|
-
|
|
21175
|
-
|
|
21176
|
-
|
|
21177
|
-
|
|
21178
|
-
|
|
21179
|
-
|
|
21180
|
-
|
|
21181
|
-
|
|
21182
|
-
|
|
21183
|
-
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
|
|
21187
|
-
//Ensure compressed index is loaded
|
|
21188
|
-
await this.getCompressedIndex();
|
|
21189
|
-
let result = [];
|
|
21190
|
-
//Now search for the correct block-numbers (going from 0 to length(compressed-index)) which overlap with the provided byte-positions
|
|
21191
|
-
const lowestBlockNumber = 0;
|
|
21192
|
-
const highestBlockNumber = this.compressedIndex.length - 1;
|
|
21193
|
-
//Failsafe if for some reason the compressed index wasn't loaded or doesn't contain any data
|
|
21194
|
-
if (this.compressedIndex.length == 0) {
|
|
21195
|
-
console.log("Compressed index does not contain any content");
|
|
21196
|
-
return [];
|
|
21197
|
-
}
|
|
21198
|
-
//Failsafe: if the queryPositionStart is greater than the uncompressed-position of the final block,
|
|
21199
|
-
//then this final block is the only possible result
|
|
21200
|
-
if (queryPositionStart > this.compressedIndex[highestBlockNumber][UNCOMPRESSED_POSITION]) {
|
|
21201
|
-
return [highestBlockNumber];
|
|
21202
|
-
}
|
|
21203
|
-
|
|
21204
|
-
//Rather than doing a linear search over all blocks, a binary search is done for speed considerations
|
|
21205
|
-
//We are searching for the highest block number for which its position is smaller than the query start position
|
|
21206
|
-
//Afterwards we will simply expand the blocks until the entire query range is covered
|
|
21207
|
-
let searchLow = lowestBlockNumber;
|
|
21208
|
-
let searchHigh = highestBlockNumber;
|
|
21209
|
-
let searchPosition = Math.floor(this.compressedIndex.length / 2);
|
|
21210
|
-
let maxIterations = this.compressedIndex.length + 1;
|
|
21211
|
-
let solutionFound = false;
|
|
21212
|
-
//instead of doing a while(true), this for-loop prevents eternal loops in case of issues
|
|
21213
|
-
for (let iteration = 0; iteration < maxIterations; iteration++) {
|
|
21214
|
-
const searchUncompressedPosition = this.compressedIndex[searchPosition][UNCOMPRESSED_POSITION];
|
|
21215
|
-
const nextSearchUncompressedPosition = searchPosition < this.compressedIndex.length - 1 ? this.compressedIndex[searchPosition + 1][UNCOMPRESSED_POSITION] : Infinity;
|
|
21216
|
-
//The query position lies within the current search block
|
|
21217
|
-
if (searchUncompressedPosition <= queryPositionStart && nextSearchUncompressedPosition > queryPositionStart) {
|
|
21218
|
-
solutionFound = true;
|
|
21219
|
-
break; //searchPosition is the correct block number index
|
|
21220
|
-
}
|
|
21221
|
-
//Current block lies before the query position
|
|
21222
|
-
else if (searchUncompressedPosition < queryPositionStart) {
|
|
21223
|
-
searchLow = searchPosition + 1;
|
|
21224
|
-
}
|
|
21225
|
-
//Current block lies after the query position
|
|
21226
|
-
else {
|
|
21227
|
-
searchHigh = searchPosition - 1;
|
|
21228
|
-
}
|
|
21229
|
-
searchPosition = Math.ceil((searchHigh - searchLow) / 2) + searchLow;
|
|
21230
|
-
}
|
|
21231
|
-
//If for some reason the binary search did not reveal a correct block index, then we return the empty result
|
|
21232
|
-
if (!solutionFound) {
|
|
21233
|
-
console.log("No blocks within compressed index found that correspond with query positions " + queryPositionStart + "," + queryPositionEnd);
|
|
21234
|
-
console.log(this.compressedIndex);
|
|
21235
|
-
return [];
|
|
21236
|
-
}
|
|
21761
|
+
/**
|
|
21762
|
+
* Generates a ClipPath from the clip command.
|
|
21763
|
+
*/
|
|
21764
|
+
clip() {
|
|
21765
|
+
var group = this.__closestGroupOrSvg(),
|
|
21766
|
+
clipPath = this.__createElement("clipPath"),
|
|
21767
|
+
id = randomString(this.__ids),
|
|
21768
|
+
newGroup = this.__createElement("g");
|
|
21769
|
+
this.__applyCurrentDefaultPath();
|
|
21770
|
+
group.removeChild(this.__currentElement);
|
|
21771
|
+
clipPath.setAttribute("id", id);
|
|
21772
|
+
clipPath.appendChild(this.__currentElement);
|
|
21773
|
+
this.__defs.appendChild(clipPath);
|
|
21237
21774
|
|
|
21238
|
-
//
|
|
21239
|
-
|
|
21240
|
-
|
|
21241
|
-
|
|
21242
|
-
const blockUncompressedPosition = this.compressedIndex[blockIndex][UNCOMPRESSED_POSITION];
|
|
21243
|
-
if (blockUncompressedPosition >= queryPositionEnd) {
|
|
21244
|
-
break;
|
|
21245
|
-
}
|
|
21246
|
-
}
|
|
21775
|
+
//set the clip path to this group
|
|
21776
|
+
group.setAttribute("clip-path", format("url(#{id})", {
|
|
21777
|
+
id: id
|
|
21778
|
+
}));
|
|
21247
21779
|
|
|
21248
|
-
//
|
|
21249
|
-
//
|
|
21250
|
-
|
|
21251
|
-
|
|
21252
|
-
const finalIndexBlock = this.compressedIndex.length - 1;
|
|
21253
|
-
if (finalRelevantBlock === finalIndexBlock && this.compressedIndex[finalRelevantBlock][UNCOMPRESSED_POSITION] < queryPositionEnd) {
|
|
21254
|
-
result.push(-1);
|
|
21255
|
-
}
|
|
21256
|
-
return result;
|
|
21780
|
+
//clip paths can be scaled and transformed, we need to add another wrapper group to avoid later transformations
|
|
21781
|
+
// to this path
|
|
21782
|
+
group.appendChild(newGroup);
|
|
21783
|
+
this.__currentElement = newGroup;
|
|
21257
21784
|
}
|
|
21258
|
-
|
|
21259
|
-
|
|
21260
|
-
|
|
21261
|
-
|
|
21262
|
-
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21267
|
-
|
|
21268
|
-
|
|
21785
|
+
/**
|
|
21786
|
+
* Draws a canvas, image or mock context to this canvas.
|
|
21787
|
+
* Note that all svg dom manipulation uses node.childNodes rather than node.children for IE support.
|
|
21788
|
+
* http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage
|
|
21789
|
+
*/
|
|
21790
|
+
drawImage() {
|
|
21791
|
+
//convert arguments to a real array
|
|
21792
|
+
var args = Array.prototype.slice.call(arguments),
|
|
21793
|
+
image = args[0],
|
|
21794
|
+
dx,
|
|
21795
|
+
dy,
|
|
21796
|
+
dw,
|
|
21797
|
+
dh,
|
|
21798
|
+
sx = 0,
|
|
21799
|
+
sy = 0,
|
|
21800
|
+
sw,
|
|
21801
|
+
sh,
|
|
21802
|
+
parent,
|
|
21803
|
+
svg,
|
|
21804
|
+
defs,
|
|
21805
|
+
group,
|
|
21806
|
+
svgImage,
|
|
21807
|
+
canvas,
|
|
21808
|
+
context,
|
|
21809
|
+
id;
|
|
21810
|
+
if (args.length === 3) {
|
|
21811
|
+
dx = args[1];
|
|
21812
|
+
dy = args[2];
|
|
21813
|
+
sw = image.width;
|
|
21814
|
+
sh = image.height;
|
|
21815
|
+
dw = sw;
|
|
21816
|
+
dh = sh;
|
|
21817
|
+
} else if (args.length === 5) {
|
|
21818
|
+
dx = args[1];
|
|
21819
|
+
dy = args[2];
|
|
21820
|
+
dw = args[3];
|
|
21821
|
+
dh = args[4];
|
|
21822
|
+
sw = image.width;
|
|
21823
|
+
sh = image.height;
|
|
21824
|
+
} else if (args.length === 9) {
|
|
21825
|
+
sx = args[1];
|
|
21826
|
+
sy = args[2];
|
|
21827
|
+
sw = args[3];
|
|
21828
|
+
sh = args[4];
|
|
21829
|
+
dx = args[5];
|
|
21830
|
+
dy = args[6];
|
|
21831
|
+
dw = args[7];
|
|
21832
|
+
dh = args[8];
|
|
21833
|
+
} else {
|
|
21834
|
+
throw new Error("Invalid number of arguments passed to drawImage: " + arguments.length);
|
|
21269
21835
|
}
|
|
21270
|
-
|
|
21271
|
-
|
|
21272
|
-
|
|
21273
|
-
|
|
21274
|
-
|
|
21275
|
-
|
|
21276
|
-
|
|
21277
|
-
|
|
21278
|
-
|
|
21279
|
-
|
|
21280
|
-
|
|
21281
|
-
|
|
21282
|
-
|
|
21283
|
-
|
|
21284
|
-
|
|
21285
|
-
|
|
21286
|
-
|
|
21287
|
-
|
|
21288
|
-
|
|
21289
|
-
|
|
21290
|
-
|
|
21291
|
-
|
|
21292
|
-
|
|
21293
|
-
range: {
|
|
21294
|
-
start: currentBlockCompressedPosition
|
|
21836
|
+
parent = this.__closestGroupOrSvg();
|
|
21837
|
+
this.__currentElement;
|
|
21838
|
+
var translateDirective = "translate(" + dx + ", " + dy + ")";
|
|
21839
|
+
if (image instanceof ctx) {
|
|
21840
|
+
//canvas2svg mock canvas context. In the future we may want to clone nodes instead.
|
|
21841
|
+
//also I'm currently ignoring dw, dh, sw, sh, sx, sy for a mock context.
|
|
21842
|
+
svg = image.getSvg().cloneNode(true);
|
|
21843
|
+
if (svg.childNodes && svg.childNodes.length > 1) {
|
|
21844
|
+
defs = svg.childNodes[0];
|
|
21845
|
+
while (defs.childNodes.length) {
|
|
21846
|
+
id = defs.childNodes[0].getAttribute("id");
|
|
21847
|
+
this.__ids[id] = id;
|
|
21848
|
+
this.__defs.appendChild(defs.childNodes[0]);
|
|
21849
|
+
}
|
|
21850
|
+
group = svg.childNodes[1];
|
|
21851
|
+
if (group) {
|
|
21852
|
+
//save original transform
|
|
21853
|
+
var originTransform = group.getAttribute("transform");
|
|
21854
|
+
var transformDirective;
|
|
21855
|
+
if (originTransform) {
|
|
21856
|
+
transformDirective = originTransform + " " + translateDirective;
|
|
21857
|
+
} else {
|
|
21858
|
+
transformDirective = translateDirective;
|
|
21295
21859
|
}
|
|
21296
|
-
|
|
21860
|
+
group.setAttribute("transform", transformDirective);
|
|
21861
|
+
parent.appendChild(group);
|
|
21862
|
+
}
|
|
21297
21863
|
}
|
|
21298
|
-
|
|
21299
|
-
|
|
21300
|
-
|
|
21301
|
-
|
|
21302
|
-
|
|
21303
|
-
|
|
21304
|
-
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
|
|
21308
|
-
|
|
21864
|
+
} else if (image.nodeName === "CANVAS" || image.nodeName === "IMG") {
|
|
21865
|
+
//canvas or image
|
|
21866
|
+
svgImage = this.__createElement("image");
|
|
21867
|
+
svgImage.setAttribute("width", dw);
|
|
21868
|
+
svgImage.setAttribute("height", dh);
|
|
21869
|
+
svgImage.setAttribute("preserveAspectRatio", "none");
|
|
21870
|
+
if (sx || sy || sw !== image.width || sh !== image.height) {
|
|
21871
|
+
//crop the image using a temporary canvas
|
|
21872
|
+
canvas = this.__document.createElement("canvas");
|
|
21873
|
+
canvas.width = dw;
|
|
21874
|
+
canvas.height = dh;
|
|
21875
|
+
context = canvas.getContext("2d");
|
|
21876
|
+
context.drawImage(image, sx, sy, sw, sh, 0, 0, dw, dh);
|
|
21877
|
+
image = canvas;
|
|
21309
21878
|
}
|
|
21879
|
+
svgImage.setAttribute("transform", translateDirective);
|
|
21880
|
+
svgImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", image.nodeName === "CANVAS" ? image.toDataURL() : image.getAttribute("src"));
|
|
21881
|
+
parent.appendChild(svgImage);
|
|
21310
21882
|
}
|
|
21311
|
-
|
|
21312
|
-
//postprocess this data: because entire blocks are read we need to remove the first N bases of the first used block,
|
|
21313
|
-
//which are not included in the original query positions
|
|
21314
|
-
const firstBlockInfo = this.compressedIndex[blockIndices[0]];
|
|
21315
|
-
const offset = startByte - firstBlockInfo[UNCOMPRESSED_POSITION];
|
|
21316
|
-
result = result.substring(offset);
|
|
21317
|
-
return result;
|
|
21318
21883
|
}
|
|
21319
|
-
|
|
21320
|
-
|
|
21321
|
-
|
|
21322
|
-
|
|
21323
|
-
|
|
21324
|
-
|
|
21325
|
-
|
|
21326
|
-
|
|
21327
|
-
|
|
21328
|
-
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
21332
|
-
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
|
|
21336
|
-
|
|
21337
|
-
|
|
21338
|
-
|
|
21339
|
-
const offset = start - base0;
|
|
21340
|
-
const startByte = position + startLine * bytesPerLine + offset;
|
|
21341
|
-
const base1 = endLine * basesPerLine;
|
|
21342
|
-
const offset1 = end - base1;
|
|
21343
|
-
const endByte = position + endLine * bytesPerLine + offset1 - 1;
|
|
21344
|
-
const byteCount = endByte - startByte + 1;
|
|
21345
|
-
if (byteCount <= 0) {
|
|
21346
|
-
console.error("No sequence for " + chr + ":" + qstart + "-" + qend);
|
|
21347
|
-
return null;
|
|
21348
|
-
}
|
|
21349
|
-
|
|
21350
|
-
//If the compressed index file is set, then we are dealing with a compressed genome sequence
|
|
21351
|
-
//The selection of startByte/endByte is done for the non-compressed genome sequence.
|
|
21352
|
-
//These need to be 'converted' to the correct byte positions in the compressed genome sequence,
|
|
21353
|
-
//by making use of the compressed index (GZI file)
|
|
21354
|
-
let allBytes;
|
|
21355
|
-
if (!this.compressedIndexFile) {
|
|
21356
|
-
allBytes = await igvxhr.load(this.file, buildOptions(this.config, {
|
|
21357
|
-
range: {
|
|
21358
|
-
start: startByte,
|
|
21359
|
-
size: byteCount
|
|
21360
|
-
}
|
|
21361
|
-
}));
|
|
21362
|
-
} else {
|
|
21363
|
-
let relevantBlockIndices = await this.getRelevantCompressedBlockNumbers(startByte, endByte);
|
|
21364
|
-
if (relevantBlockIndices.length === 0) {
|
|
21365
|
-
console.log("No blocks in the compressed index that correspond with the requested byte positions (" + startByte + "," + endByte + ")");
|
|
21366
|
-
return null;
|
|
21367
|
-
}
|
|
21368
|
-
allBytes = await this.loadAndUncompressBlocks(relevantBlockIndices, startByte);
|
|
21369
|
-
}
|
|
21370
|
-
if (!allBytes) {
|
|
21371
|
-
return null;
|
|
21372
|
-
}
|
|
21373
|
-
let nBases,
|
|
21374
|
-
seqBytes = "",
|
|
21375
|
-
srcPos = 0,
|
|
21376
|
-
allBytesLength = allBytes.length;
|
|
21377
|
-
if (offset > 0) {
|
|
21378
|
-
nBases = Math.min(end - start, basesPerLine - offset);
|
|
21379
|
-
seqBytes += allBytes.substr(srcPos, nBases);
|
|
21380
|
-
srcPos += nBases + nEndBytes;
|
|
21381
|
-
}
|
|
21382
|
-
while (srcPos < allBytesLength) {
|
|
21383
|
-
nBases = Math.min(basesPerLine, allBytesLength - srcPos);
|
|
21384
|
-
seqBytes += allBytes.substr(srcPos, nBases);
|
|
21385
|
-
srcPos += nBases + nEndBytes;
|
|
21884
|
+
/**
|
|
21885
|
+
* Generates a pattern tag
|
|
21886
|
+
*/
|
|
21887
|
+
createPattern(image, repetition) {
|
|
21888
|
+
let pattern = this.__document.__createElement("pattern");
|
|
21889
|
+
let id = randomString(this.__ids);
|
|
21890
|
+
let img;
|
|
21891
|
+
pattern.setAttribute("id", id);
|
|
21892
|
+
pattern.setAttribute("width", image.width);
|
|
21893
|
+
pattern.setAttribute("height", image.height);
|
|
21894
|
+
if (image.nodeName === "CANVAS" || image.nodeName === "IMG") {
|
|
21895
|
+
img = this.__createElement("image");
|
|
21896
|
+
img.setAttribute("width", image.width);
|
|
21897
|
+
img.setAttribute("height", image.height);
|
|
21898
|
+
img.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", image.nodeName === "CANVAS" ? image.toDataURL() : image.getAttribute("src"));
|
|
21899
|
+
pattern.appendChild(img);
|
|
21900
|
+
this.__defs.appendChild(pattern);
|
|
21901
|
+
} else if (image instanceof ctx) {
|
|
21902
|
+
pattern.appendChild(image.__root.childNodes[1]);
|
|
21903
|
+
this.__defs.appendChild(pattern);
|
|
21386
21904
|
}
|
|
21387
|
-
return
|
|
21388
|
-
}
|
|
21389
|
-
}
|
|
21390
|
-
|
|
21391
|
-
/*
|
|
21392
|
-
* The MIT License (MIT)
|
|
21393
|
-
*
|
|
21394
|
-
* Copyright (c) 2014 Broad Institute
|
|
21395
|
-
*
|
|
21396
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
21397
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
21398
|
-
* in the Software without restriction, including without limitation the rights
|
|
21399
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
21400
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
21401
|
-
* furnished to do so, subject to the following conditions:
|
|
21402
|
-
*
|
|
21403
|
-
* The above copyright notice and this permission notice shall be included in
|
|
21404
|
-
* all copies or substantial portions of the Software.
|
|
21405
|
-
*
|
|
21406
|
-
*
|
|
21407
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21408
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21409
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21410
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21411
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21412
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21413
|
-
* THE SOFTWARE.
|
|
21414
|
-
*/
|
|
21415
|
-
const splitLines$2 = splitLines$5;
|
|
21416
|
-
class ChromSizes {
|
|
21417
|
-
constructor(url) {
|
|
21418
|
-
this.url = url;
|
|
21419
|
-
this.chromosomeNames = [];
|
|
21420
|
-
this.chromosomes = {};
|
|
21421
|
-
}
|
|
21422
|
-
async init() {
|
|
21423
|
-
return this.loadAll();
|
|
21424
|
-
}
|
|
21425
|
-
async getSequence(chr, start, end) {
|
|
21426
|
-
return undefined; // TODO -- return array of "N"s?
|
|
21905
|
+
return new CanvasPattern(pattern, this);
|
|
21427
21906
|
}
|
|
21428
|
-
|
|
21429
|
-
|
|
21430
|
-
|
|
21431
|
-
if (isDataURL(this.url)) {
|
|
21432
|
-
let bytes = decodeDataURI$1(this.fastaURL);
|
|
21433
|
-
data = "";
|
|
21434
|
-
for (let b of bytes) {
|
|
21435
|
-
data += String.fromCharCode(b);
|
|
21436
|
-
}
|
|
21907
|
+
setLineDash(dashArray) {
|
|
21908
|
+
if (dashArray && dashArray.length > 0) {
|
|
21909
|
+
this.lineDash = dashArray.join(",");
|
|
21437
21910
|
} else {
|
|
21438
|
-
|
|
21439
|
-
}
|
|
21440
|
-
this.chromosomeNames = [];
|
|
21441
|
-
this.chromosomes = {};
|
|
21442
|
-
const lines = splitLines$2(data);
|
|
21443
|
-
let order = 0;
|
|
21444
|
-
for (let nextLine of lines) {
|
|
21445
|
-
const tokens = nextLine.split('\t');
|
|
21446
|
-
this.chromosomeNames.push(tokens[0]);
|
|
21447
|
-
const chrLength = Number.parseInt(tokens[1]);
|
|
21448
|
-
const chromosome = new Chromosome(tokens[0], order++, chrLength);
|
|
21449
|
-
this.chromosomes[tokens[0]] = chromosome;
|
|
21911
|
+
this.lineDash = null;
|
|
21450
21912
|
}
|
|
21451
21913
|
}
|
|
21452
|
-
|
|
21453
|
-
|
|
21454
|
-
|
|
21455
|
-
|
|
21456
|
-
|
|
21457
|
-
|
|
21458
|
-
|
|
21459
|
-
|
|
21460
|
-
|
|
21461
|
-
fasta = new FastaSequence(reference);
|
|
21462
|
-
}
|
|
21463
|
-
await fasta.init();
|
|
21464
|
-
return fasta;
|
|
21914
|
+
/**
|
|
21915
|
+
* Not yet implemented
|
|
21916
|
+
*/
|
|
21917
|
+
drawFocusRing() {}
|
|
21918
|
+
createImageData() {}
|
|
21919
|
+
getImageData() {}
|
|
21920
|
+
putImageData() {}
|
|
21921
|
+
globalCompositeOperation() {}
|
|
21922
|
+
setTransform() {}
|
|
21465
21923
|
}
|
|
21466
21924
|
|
|
21467
21925
|
const Cytoband = function (start, end, name, typestain) {
|
|
@@ -21481,7 +21939,7 @@
|
|
|
21481
21939
|
}
|
|
21482
21940
|
};
|
|
21483
21941
|
|
|
21484
|
-
const _version = "2.13.
|
|
21942
|
+
const _version = "2.13.6";
|
|
21485
21943
|
function version$1() {
|
|
21486
21944
|
return _version;
|
|
21487
21945
|
}
|
|
@@ -21960,7 +22418,7 @@
|
|
|
21960
22418
|
return visibilityWindow !== undefined && visibilityWindow > 0 && this.referenceFrame.bpPerPixel * this.$viewport.width() > visibilityWindow;
|
|
21961
22419
|
}
|
|
21962
22420
|
};
|
|
21963
|
-
if (this.trackView.track && "sequence" === this.trackView.track.type && this.referenceFrame.bpPerPixel >
|
|
22421
|
+
if (this.trackView.track && "sequence" === this.trackView.track.type && this.referenceFrame.bpPerPixel > bppFeatureFetchThreshold) {
|
|
21964
22422
|
$$1(this.canvas).remove();
|
|
21965
22423
|
this.canvas = undefined;
|
|
21966
22424
|
//this.featureCache = undefined
|
|
@@ -23166,6 +23624,9 @@
|
|
|
23166
23624
|
feature.attributes = {};
|
|
23167
23625
|
for (let kv of attributeKVs) {
|
|
23168
23626
|
feature.attributes[kv[0]] = kv[1];
|
|
23627
|
+
if (header.nameField != undefined && kv[0] === header.nameField) {
|
|
23628
|
+
feature.name = kv[1];
|
|
23629
|
+
}
|
|
23169
23630
|
}
|
|
23170
23631
|
}
|
|
23171
23632
|
if (!feature.name) {
|
|
@@ -29402,25 +29863,12 @@
|
|
|
29402
29863
|
var FunctionPrototype$2 = Function.prototype;
|
|
29403
29864
|
var call$2 = FunctionPrototype$2.call;
|
|
29404
29865
|
var uncurryThisWithBind = functionBindNative && FunctionPrototype$2.bind.bind(call$2, call$2);
|
|
29405
|
-
var
|
|
29866
|
+
var functionUncurryThis = functionBindNative ? uncurryThisWithBind : function (fn) {
|
|
29406
29867
|
return function () {
|
|
29407
29868
|
return call$2.apply(fn, arguments);
|
|
29408
29869
|
};
|
|
29409
29870
|
};
|
|
29410
29871
|
|
|
29411
|
-
var toString$1 = functionUncurryThisRaw({}.toString);
|
|
29412
|
-
var stringSlice = functionUncurryThisRaw(''.slice);
|
|
29413
|
-
var classofRaw = function (it) {
|
|
29414
|
-
return stringSlice(toString$1(it), 8, -1);
|
|
29415
|
-
};
|
|
29416
|
-
|
|
29417
|
-
var functionUncurryThis = function (fn) {
|
|
29418
|
-
// Nashorn bug:
|
|
29419
|
-
// https://github.com/zloirock/core-js/issues/1128
|
|
29420
|
-
// https://github.com/zloirock/core-js/issues/1130
|
|
29421
|
-
if (classofRaw(fn) === 'Function') return functionUncurryThisRaw(fn);
|
|
29422
|
-
};
|
|
29423
|
-
|
|
29424
29872
|
// we can't use just `it == null` since of `document.all` special case
|
|
29425
29873
|
// https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-aec
|
|
29426
29874
|
var isNullOrUndefined = function (it) {
|
|
@@ -29643,19 +30091,19 @@
|
|
|
29643
30091
|
(module.exports = function (key, value) {
|
|
29644
30092
|
return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {});
|
|
29645
30093
|
})('versions', []).push({
|
|
29646
|
-
version: '3.26.
|
|
30094
|
+
version: '3.26.1',
|
|
29647
30095
|
mode: 'global',
|
|
29648
30096
|
copyright: '© 2014-2022 Denis Pushkarev (zloirock.ru)',
|
|
29649
|
-
license: 'https://github.com/zloirock/core-js/blob/v3.26.
|
|
30097
|
+
license: 'https://github.com/zloirock/core-js/blob/v3.26.1/LICENSE',
|
|
29650
30098
|
source: 'https://github.com/zloirock/core-js'
|
|
29651
30099
|
});
|
|
29652
30100
|
});
|
|
29653
30101
|
|
|
29654
30102
|
var id = 0;
|
|
29655
30103
|
var postfix = Math.random();
|
|
29656
|
-
var toString = functionUncurryThis(1.0.toString);
|
|
30104
|
+
var toString$1 = functionUncurryThis(1.0.toString);
|
|
29657
30105
|
var uid = function (key) {
|
|
29658
|
-
return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString(++id + postfix, 36);
|
|
30106
|
+
return 'Symbol(' + (key === undefined ? '' : key) + ')_' + toString$1(++id + postfix, 36);
|
|
29659
30107
|
};
|
|
29660
30108
|
|
|
29661
30109
|
var WellKnownSymbolsStore = shared('wks');
|
|
@@ -30659,368 +31107,6 @@
|
|
|
30659
31107
|
}
|
|
30660
31108
|
}
|
|
30661
31109
|
|
|
30662
|
-
const appleCrayonRGBPalette = {
|
|
30663
|
-
cantaloupe: {
|
|
30664
|
-
r: 255,
|
|
30665
|
-
g: 206,
|
|
30666
|
-
b: 110
|
|
30667
|
-
},
|
|
30668
|
-
honeydew: {
|
|
30669
|
-
r: 206,
|
|
30670
|
-
g: 250,
|
|
30671
|
-
b: 110
|
|
30672
|
-
},
|
|
30673
|
-
spindrift: {
|
|
30674
|
-
r: 104,
|
|
30675
|
-
g: 251,
|
|
30676
|
-
b: 208
|
|
30677
|
-
},
|
|
30678
|
-
sky: {
|
|
30679
|
-
r: 106,
|
|
30680
|
-
g: 207,
|
|
30681
|
-
b: 255
|
|
30682
|
-
},
|
|
30683
|
-
lavender: {
|
|
30684
|
-
r: 210,
|
|
30685
|
-
g: 120,
|
|
30686
|
-
b: 255
|
|
30687
|
-
},
|
|
30688
|
-
carnation: {
|
|
30689
|
-
r: 255,
|
|
30690
|
-
g: 127,
|
|
30691
|
-
b: 211
|
|
30692
|
-
},
|
|
30693
|
-
licorice: {
|
|
30694
|
-
r: 0,
|
|
30695
|
-
g: 0,
|
|
30696
|
-
b: 0
|
|
30697
|
-
},
|
|
30698
|
-
snow: {
|
|
30699
|
-
r: 255,
|
|
30700
|
-
g: 255,
|
|
30701
|
-
b: 255
|
|
30702
|
-
},
|
|
30703
|
-
salmon: {
|
|
30704
|
-
r: 255,
|
|
30705
|
-
g: 114,
|
|
30706
|
-
b: 110
|
|
30707
|
-
},
|
|
30708
|
-
banana: {
|
|
30709
|
-
r: 255,
|
|
30710
|
-
g: 251,
|
|
30711
|
-
b: 109
|
|
30712
|
-
},
|
|
30713
|
-
flora: {
|
|
30714
|
-
r: 104,
|
|
30715
|
-
g: 249,
|
|
30716
|
-
b: 110
|
|
30717
|
-
},
|
|
30718
|
-
ice: {
|
|
30719
|
-
r: 104,
|
|
30720
|
-
g: 253,
|
|
30721
|
-
b: 255
|
|
30722
|
-
},
|
|
30723
|
-
orchid: {
|
|
30724
|
-
r: 110,
|
|
30725
|
-
g: 118,
|
|
30726
|
-
b: 255
|
|
30727
|
-
},
|
|
30728
|
-
bubblegum: {
|
|
30729
|
-
r: 255,
|
|
30730
|
-
g: 122,
|
|
30731
|
-
b: 255
|
|
30732
|
-
},
|
|
30733
|
-
lead: {
|
|
30734
|
-
r: 30,
|
|
30735
|
-
g: 30,
|
|
30736
|
-
b: 30
|
|
30737
|
-
},
|
|
30738
|
-
mercury: {
|
|
30739
|
-
r: 232,
|
|
30740
|
-
g: 232,
|
|
30741
|
-
b: 232
|
|
30742
|
-
},
|
|
30743
|
-
tangerine: {
|
|
30744
|
-
r: 255,
|
|
30745
|
-
g: 136,
|
|
30746
|
-
b: 2
|
|
30747
|
-
},
|
|
30748
|
-
lime: {
|
|
30749
|
-
r: 131,
|
|
30750
|
-
g: 249,
|
|
30751
|
-
b: 2
|
|
30752
|
-
},
|
|
30753
|
-
sea_foam: {
|
|
30754
|
-
r: 3,
|
|
30755
|
-
g: 249,
|
|
30756
|
-
b: 135
|
|
30757
|
-
},
|
|
30758
|
-
aqua: {
|
|
30759
|
-
r: 0,
|
|
30760
|
-
g: 140,
|
|
30761
|
-
b: 255
|
|
30762
|
-
},
|
|
30763
|
-
grape: {
|
|
30764
|
-
r: 137,
|
|
30765
|
-
g: 49,
|
|
30766
|
-
b: 255
|
|
30767
|
-
},
|
|
30768
|
-
strawberry: {
|
|
30769
|
-
r: 255,
|
|
30770
|
-
g: 41,
|
|
30771
|
-
b: 135
|
|
30772
|
-
},
|
|
30773
|
-
tungsten: {
|
|
30774
|
-
r: 58,
|
|
30775
|
-
g: 58,
|
|
30776
|
-
b: 58
|
|
30777
|
-
},
|
|
30778
|
-
silver: {
|
|
30779
|
-
r: 208,
|
|
30780
|
-
g: 208,
|
|
30781
|
-
b: 208
|
|
30782
|
-
},
|
|
30783
|
-
maraschino: {
|
|
30784
|
-
r: 255,
|
|
30785
|
-
g: 33,
|
|
30786
|
-
b: 1
|
|
30787
|
-
},
|
|
30788
|
-
lemon: {
|
|
30789
|
-
r: 255,
|
|
30790
|
-
g: 250,
|
|
30791
|
-
b: 3
|
|
30792
|
-
},
|
|
30793
|
-
spring: {
|
|
30794
|
-
r: 5,
|
|
30795
|
-
g: 248,
|
|
30796
|
-
b: 2
|
|
30797
|
-
},
|
|
30798
|
-
turquoise: {
|
|
30799
|
-
r: 0,
|
|
30800
|
-
g: 253,
|
|
30801
|
-
b: 255
|
|
30802
|
-
},
|
|
30803
|
-
blueberry: {
|
|
30804
|
-
r: 0,
|
|
30805
|
-
g: 46,
|
|
30806
|
-
b: 255
|
|
30807
|
-
},
|
|
30808
|
-
magenta: {
|
|
30809
|
-
r: 255,
|
|
30810
|
-
g: 57,
|
|
30811
|
-
b: 255
|
|
30812
|
-
},
|
|
30813
|
-
iron: {
|
|
30814
|
-
r: 84,
|
|
30815
|
-
g: 84,
|
|
30816
|
-
b: 83
|
|
30817
|
-
},
|
|
30818
|
-
magnesium: {
|
|
30819
|
-
r: 184,
|
|
30820
|
-
g: 184,
|
|
30821
|
-
b: 184
|
|
30822
|
-
},
|
|
30823
|
-
mocha: {
|
|
30824
|
-
r: 137,
|
|
30825
|
-
g: 72,
|
|
30826
|
-
b: 0
|
|
30827
|
-
},
|
|
30828
|
-
fern: {
|
|
30829
|
-
r: 69,
|
|
30830
|
-
g: 132,
|
|
30831
|
-
b: 1
|
|
30832
|
-
},
|
|
30833
|
-
moss: {
|
|
30834
|
-
r: 1,
|
|
30835
|
-
g: 132,
|
|
30836
|
-
b: 72
|
|
30837
|
-
},
|
|
30838
|
-
ocean: {
|
|
30839
|
-
r: 0,
|
|
30840
|
-
g: 74,
|
|
30841
|
-
b: 136
|
|
30842
|
-
},
|
|
30843
|
-
eggplant: {
|
|
30844
|
-
r: 73,
|
|
30845
|
-
g: 26,
|
|
30846
|
-
b: 136
|
|
30847
|
-
},
|
|
30848
|
-
maroon: {
|
|
30849
|
-
r: 137,
|
|
30850
|
-
g: 22,
|
|
30851
|
-
b: 72
|
|
30852
|
-
},
|
|
30853
|
-
steel: {
|
|
30854
|
-
r: 110,
|
|
30855
|
-
g: 110,
|
|
30856
|
-
b: 110
|
|
30857
|
-
},
|
|
30858
|
-
aluminum: {
|
|
30859
|
-
r: 160,
|
|
30860
|
-
g: 159,
|
|
30861
|
-
b: 160
|
|
30862
|
-
},
|
|
30863
|
-
cayenne: {
|
|
30864
|
-
r: 137,
|
|
30865
|
-
g: 17,
|
|
30866
|
-
b: 0
|
|
30867
|
-
},
|
|
30868
|
-
aspargus: {
|
|
30869
|
-
r: 136,
|
|
30870
|
-
g: 133,
|
|
30871
|
-
b: 1
|
|
30872
|
-
},
|
|
30873
|
-
clover: {
|
|
30874
|
-
r: 2,
|
|
30875
|
-
g: 132,
|
|
30876
|
-
b: 1
|
|
30877
|
-
},
|
|
30878
|
-
teal: {
|
|
30879
|
-
r: 0,
|
|
30880
|
-
g: 134,
|
|
30881
|
-
b: 136
|
|
30882
|
-
},
|
|
30883
|
-
midnight: {
|
|
30884
|
-
r: 0,
|
|
30885
|
-
g: 24,
|
|
30886
|
-
b: 136
|
|
30887
|
-
},
|
|
30888
|
-
plum: {
|
|
30889
|
-
r: 137,
|
|
30890
|
-
g: 30,
|
|
30891
|
-
b: 136
|
|
30892
|
-
},
|
|
30893
|
-
tin: {
|
|
30894
|
-
r: 135,
|
|
30895
|
-
g: 134,
|
|
30896
|
-
b: 135
|
|
30897
|
-
},
|
|
30898
|
-
nickel: {
|
|
30899
|
-
r: 136,
|
|
30900
|
-
g: 135,
|
|
30901
|
-
b: 135
|
|
30902
|
-
}
|
|
30903
|
-
};
|
|
30904
|
-
function appleCrayonRGB(name) {
|
|
30905
|
-
const {
|
|
30906
|
-
r,
|
|
30907
|
-
g,
|
|
30908
|
-
b
|
|
30909
|
-
} = appleCrayonRGBPalette[name];
|
|
30910
|
-
return `rgb(${r},${g},${b})`;
|
|
30911
|
-
}
|
|
30912
|
-
function appleCrayonRGBA(name, alpha) {
|
|
30913
|
-
const {
|
|
30914
|
-
r,
|
|
30915
|
-
g,
|
|
30916
|
-
b
|
|
30917
|
-
} = appleCrayonRGBPalette[name];
|
|
30918
|
-
return `rgba(${r},${g},${b},${alpha})`;
|
|
30919
|
-
}
|
|
30920
|
-
const colorPalettes = {
|
|
30921
|
-
Set1: ["rgb(228,26,28)", "rgb(55,126,184)", "rgb(77,175,74)", "rgb(166,86,40)", "rgb(152,78,163)", "rgb(255,127,0)", "rgb(247,129,191)", "rgb(153,153,153)", "rgb(255,255,51)"],
|
|
30922
|
-
Dark2: ["rgb(27,158,119)", "rgb(217,95,2)", "rgb(117,112,179)", "rgb(231,41,138)", "rgb(102,166,30)", "rgb(230,171,2)", "rgb(166,118,29)", "rgb(102,102,102)"],
|
|
30923
|
-
Set2: ["rgb(102, 194,165)", "rgb(252,141,98)", "rgb(141,160,203)", "rgb(231,138,195)", "rgb(166,216,84)", "rgb(255,217,47)", "rgb(229,196,148)", "rgb(179,179,179)"],
|
|
30924
|
-
Set3: ["rgb(141,211,199)", "rgb(255,255,179)", "rgb(190,186,218)", "rgb(251,128,114)", "rgb(128,177,211)", "rgb(253,180,98)", "rgb(179,222,105)", "rgb(252,205,229)", "rgb(217,217,217)", "rgb(188,128,189)", "rgb(204,235,197)", "rgb(255,237,111)"],
|
|
30925
|
-
Pastel1: ["rgb(251,180,174)", "rgb(179,205,227)", "rgb(204,235,197)", "rgb(222,203,228)", "rgb(254,217,166)", "rgb(255,255,204)", "rgb(229,216,189)", "rgb(253,218,236)"],
|
|
30926
|
-
Pastel2: ["rgb(173,226,207)", "rgb(253,205,172)", "rgb(203,213,232)", "rgb(244,202,228)", "rgb(230,245,201)", "rgb(255,242,174)", "rgb(243,225,206)"],
|
|
30927
|
-
Accent: ["rgb(127,201,127)", "rgb(190,174,212)", "rgb(253,192,134)", "rgb(255,255,153)", "rgb(56,108,176)", "rgb(240,2,127)", "rgb(191,91,23)"]
|
|
30928
|
-
};
|
|
30929
|
-
class PaletteColorTable {
|
|
30930
|
-
constructor(palette) {
|
|
30931
|
-
this.colors = colorPalettes[palette];
|
|
30932
|
-
if (!Array.isArray(this.colors)) this.colors = [];
|
|
30933
|
-
this.colorTable = {};
|
|
30934
|
-
this.nextIdx = 0;
|
|
30935
|
-
this.colorGenerator = new RandomColorGenerator();
|
|
30936
|
-
}
|
|
30937
|
-
getColor(key) {
|
|
30938
|
-
if (!this.colorTable.hasOwnProperty(key)) {
|
|
30939
|
-
if (this.nextIdx < this.colors.length) {
|
|
30940
|
-
this.colorTable[key] = this.colors[this.nextIdx];
|
|
30941
|
-
} else {
|
|
30942
|
-
this.colorTable[key] = this.colorGenerator.get();
|
|
30943
|
-
}
|
|
30944
|
-
this.nextIdx++;
|
|
30945
|
-
}
|
|
30946
|
-
return this.colorTable[key];
|
|
30947
|
-
}
|
|
30948
|
-
}
|
|
30949
|
-
class ColorTable {
|
|
30950
|
-
constructor(colors) {
|
|
30951
|
-
this.colorTable = colors || {};
|
|
30952
|
-
this.nextIdx = 0;
|
|
30953
|
-
this.colorGenerator = new RandomColorGenerator();
|
|
30954
|
-
}
|
|
30955
|
-
getColor(key) {
|
|
30956
|
-
if (!this.colorTable.hasOwnProperty(key)) {
|
|
30957
|
-
if (this.colorTable.hasOwnProperty("*")) {
|
|
30958
|
-
return this.colorTable["*"];
|
|
30959
|
-
}
|
|
30960
|
-
this.colorTable[key] = this.colorGenerator.get();
|
|
30961
|
-
}
|
|
30962
|
-
return this.colorTable[key];
|
|
30963
|
-
}
|
|
30964
|
-
}
|
|
30965
|
-
|
|
30966
|
-
// Random color generator from https://github.com/sterlingwes/RandomColor/blob/master/rcolor.js
|
|
30967
|
-
// Free to use & distribute under the MIT license
|
|
30968
|
-
// Wes Johnson (@SterlingWes)
|
|
30969
|
-
//
|
|
30970
|
-
// inspired by http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/
|
|
30971
|
-
function RandomColorGenerator() {
|
|
30972
|
-
this.hue = Math.random();
|
|
30973
|
-
this.goldenRatio = 0.618033988749895;
|
|
30974
|
-
this.hexwidth = 2;
|
|
30975
|
-
}
|
|
30976
|
-
RandomColorGenerator.prototype.hsvToRgb = function (h, s, v) {
|
|
30977
|
-
var h_i = Math.floor(h * 6),
|
|
30978
|
-
f = h * 6 - h_i,
|
|
30979
|
-
p = v * (1 - s),
|
|
30980
|
-
q = v * (1 - f * s),
|
|
30981
|
-
t = v * (1 - (1 - f) * s),
|
|
30982
|
-
r = 255,
|
|
30983
|
-
g = 255,
|
|
30984
|
-
b = 255;
|
|
30985
|
-
switch (h_i) {
|
|
30986
|
-
case 0:
|
|
30987
|
-
r = v, g = t, b = p;
|
|
30988
|
-
break;
|
|
30989
|
-
case 1:
|
|
30990
|
-
r = q, g = v, b = p;
|
|
30991
|
-
break;
|
|
30992
|
-
case 2:
|
|
30993
|
-
r = p, g = v, b = t;
|
|
30994
|
-
break;
|
|
30995
|
-
case 3:
|
|
30996
|
-
r = p, g = q, b = v;
|
|
30997
|
-
break;
|
|
30998
|
-
case 4:
|
|
30999
|
-
r = t, g = p, b = v;
|
|
31000
|
-
break;
|
|
31001
|
-
case 5:
|
|
31002
|
-
r = v, g = p, b = q;
|
|
31003
|
-
break;
|
|
31004
|
-
}
|
|
31005
|
-
return [Math.floor(r * 256), Math.floor(g * 256), Math.floor(b * 256)];
|
|
31006
|
-
};
|
|
31007
|
-
RandomColorGenerator.prototype.padHex = function (str) {
|
|
31008
|
-
if (str.length > this.hexwidth) return str;
|
|
31009
|
-
return new Array(this.hexwidth - str.length + 1).join('0') + str;
|
|
31010
|
-
};
|
|
31011
|
-
RandomColorGenerator.prototype.get = function (saturation, value) {
|
|
31012
|
-
this.hue += this.goldenRatio;
|
|
31013
|
-
this.hue %= 1;
|
|
31014
|
-
if (typeof saturation !== "number") saturation = 0.5;
|
|
31015
|
-
if (typeof value !== "number") value = 0.95;
|
|
31016
|
-
var rgb = this.hsvToRgb(this.hue, saturation, value);
|
|
31017
|
-
return "#" + this.padHex(rgb[0].toString(16)) + this.padHex(rgb[1].toString(16)) + this.padHex(rgb[2].toString(16));
|
|
31018
|
-
};
|
|
31019
|
-
const randomColorGenerator = new RandomColorGenerator();
|
|
31020
|
-
function randomColor() {
|
|
31021
|
-
return randomColorGenerator.get();
|
|
31022
|
-
}
|
|
31023
|
-
|
|
31024
31110
|
/*
|
|
31025
31111
|
* The MIT License (MIT)
|
|
31026
31112
|
*
|
|
@@ -33546,6 +33632,12 @@
|
|
|
33546
33632
|
f: f$3
|
|
33547
33633
|
};
|
|
33548
33634
|
|
|
33635
|
+
var toString = functionUncurryThis({}.toString);
|
|
33636
|
+
var stringSlice = functionUncurryThis(''.slice);
|
|
33637
|
+
var classofRaw = function (it) {
|
|
33638
|
+
return stringSlice(toString(it), 8, -1);
|
|
33639
|
+
};
|
|
33640
|
+
|
|
33549
33641
|
var $Object = Object;
|
|
33550
33642
|
var split = functionUncurryThis(''.split);
|
|
33551
33643
|
|
|
@@ -33803,7 +33895,14 @@
|
|
|
33803
33895
|
return call.apply(apply, arguments);
|
|
33804
33896
|
});
|
|
33805
33897
|
|
|
33806
|
-
var
|
|
33898
|
+
var functionUncurryThisClause = function (fn) {
|
|
33899
|
+
// Nashorn bug:
|
|
33900
|
+
// https://github.com/zloirock/core-js/issues/1128
|
|
33901
|
+
// https://github.com/zloirock/core-js/issues/1130
|
|
33902
|
+
if (classofRaw(fn) === 'Function') return functionUncurryThis(fn);
|
|
33903
|
+
};
|
|
33904
|
+
|
|
33905
|
+
var bind = functionUncurryThisClause(functionUncurryThisClause.bind);
|
|
33807
33906
|
|
|
33808
33907
|
// optional / simple context binding
|
|
33809
33908
|
var functionBindContext = function (fn, that) {
|
|
@@ -53173,7 +53272,14 @@
|
|
|
53173
53272
|
const lastLabelX = options.rowLastLabelX[feature.row] || -Number.MAX_SAFE_INTEGER;
|
|
53174
53273
|
if (options.labelAllFeatures || xleft > lastLabelX || gtexSelection) {
|
|
53175
53274
|
options.rowLastLabelX[feature.row] = xright;
|
|
53176
|
-
|
|
53275
|
+
if ('y' === options.axis) {
|
|
53276
|
+
ctx.save();
|
|
53277
|
+
IGVGraphics.labelTransformWithContext(ctx, centerX);
|
|
53278
|
+
IGVGraphics.fillText(ctx, name, centerX, labelY, geneFontStyle, transform);
|
|
53279
|
+
ctx.restore();
|
|
53280
|
+
} else {
|
|
53281
|
+
IGVGraphics.fillText(ctx, name, centerX, labelY, geneFontStyle, transform);
|
|
53282
|
+
}
|
|
53177
53283
|
}
|
|
53178
53284
|
} finally {
|
|
53179
53285
|
ctx.restore();
|
|
@@ -58609,14 +58715,6 @@
|
|
|
58609
58715
|
});
|
|
58610
58716
|
}
|
|
58611
58717
|
|
|
58612
|
-
const defaultNucleotideColors = {
|
|
58613
|
-
"A": "rgb( 0, 200, 0)",
|
|
58614
|
-
"C": "rgb( 0,0,200)",
|
|
58615
|
-
"T": "rgb(255,0,0)",
|
|
58616
|
-
"G": "rgb(209,113, 5)",
|
|
58617
|
-
"N": "rgb(80,80,80)"
|
|
58618
|
-
};
|
|
58619
|
-
|
|
58620
58718
|
const DEFAULT_SEARCH_CONFIG = {
|
|
58621
58719
|
timeout: 5000,
|
|
58622
58720
|
type: "plain",
|
|
@@ -58919,8 +59017,8 @@
|
|
|
58919
59017
|
constructor(browser) {
|
|
58920
59018
|
this.browser = browser;
|
|
58921
59019
|
}
|
|
58922
|
-
navbarDidResize(width
|
|
58923
|
-
this.updateNavbar(this.createResponsiveClassSchedule(width
|
|
59020
|
+
navbarDidResize(width) {
|
|
59021
|
+
this.updateNavbar(this.createResponsiveClassSchedule(width));
|
|
58924
59022
|
}
|
|
58925
59023
|
updateNavbar(responsiveClassSchedule) {
|
|
58926
59024
|
this.browser.$toggle_button_container.removeClass();
|
|
@@ -58928,9 +59026,10 @@
|
|
|
58928
59026
|
$$1(this.browser.zoomWidget.zoomContainer).removeClass();
|
|
58929
59027
|
$$1(this.browser.zoomWidget.zoomContainer).addClass(responsiveClassSchedule.zoomContainer);
|
|
58930
59028
|
}
|
|
58931
|
-
createResponsiveClassSchedule(navbarWidth
|
|
59029
|
+
createResponsiveClassSchedule(navbarWidth) {
|
|
58932
59030
|
let candidates = {};
|
|
58933
|
-
|
|
59031
|
+
const isWGV = this.browser.isMultiLocusWholeGenomeView() || this.browser.referenceFrameList && GenomeUtils.isWholeGenomeView(this.browser.referenceFrameList[0].chr);
|
|
59032
|
+
if (isWGV) {
|
|
58934
59033
|
this.browser.windowSizePanel.hide();
|
|
58935
59034
|
} else {
|
|
58936
59035
|
this.browser.windowSizePanel.show();
|
|
@@ -58949,7 +59048,7 @@
|
|
|
58949
59048
|
candidates.zoomContainer = 'igv-zoom-widget-900';
|
|
58950
59049
|
this.browser.windowSizePanel.hide();
|
|
58951
59050
|
}
|
|
58952
|
-
if (
|
|
59051
|
+
if (isWGV) {
|
|
58953
59052
|
candidates['zoomContainer'] = 'igv-zoom-widget-hidden';
|
|
58954
59053
|
}
|
|
58955
59054
|
return candidates;
|
|
@@ -59118,40 +59217,33 @@
|
|
|
59118
59217
|
} = translateMouseCoordinates$1(event, this.columnContainer);
|
|
59119
59218
|
this.horizontalGuide.style.top = `${y}px`;
|
|
59120
59219
|
const target = document.elementFromPoint(event.clientX, event.clientY);
|
|
59121
|
-
|
|
59122
|
-
if (
|
|
59123
|
-
|
|
59124
|
-
|
|
59125
|
-
|
|
59126
|
-
|
|
59127
|
-
|
|
59128
|
-
|
|
59129
|
-
|
|
59130
|
-
|
|
59131
|
-
|
|
59132
|
-
|
|
59133
|
-
|
|
59134
|
-
|
|
59135
|
-
|
|
59136
|
-
|
|
59137
|
-
|
|
59138
|
-
|
|
59139
|
-
|
|
59140
|
-
|
|
59141
|
-
|
|
59220
|
+
const viewport = findAncestorOfClass(target, 'igv-viewport');
|
|
59221
|
+
if (viewport && browser.getRulerTrackView()) {
|
|
59222
|
+
this.verticalGuide.style.left = `${x}px`;
|
|
59223
|
+
const columns = browser.root.querySelectorAll('.igv-column');
|
|
59224
|
+
let index = undefined;
|
|
59225
|
+
const viewportParent = viewport.parentElement;
|
|
59226
|
+
for (let i = 0; i < columns.length; i++) {
|
|
59227
|
+
if (undefined === index && viewportParent === columns[i]) {
|
|
59228
|
+
index = i;
|
|
59229
|
+
}
|
|
59230
|
+
}
|
|
59231
|
+
const rulerViewport = browser.getRulerTrackView().viewports[index];
|
|
59232
|
+
const result = rulerViewport.mouseMove(event);
|
|
59233
|
+
if (result) {
|
|
59234
|
+
const {
|
|
59235
|
+
start,
|
|
59236
|
+
bp,
|
|
59237
|
+
end
|
|
59238
|
+
} = result;
|
|
59239
|
+
const interpolant = (bp - start) / (end - start);
|
|
59240
|
+
if (this.customMouseHandler) {
|
|
59241
|
+
this.customMouseHandler({
|
|
59142
59242
|
start,
|
|
59143
59243
|
bp,
|
|
59144
|
-
end
|
|
59145
|
-
|
|
59146
|
-
|
|
59147
|
-
if (this.customMouseHandler) {
|
|
59148
|
-
this.customMouseHandler({
|
|
59149
|
-
start,
|
|
59150
|
-
bp,
|
|
59151
|
-
end,
|
|
59152
|
-
interpolant
|
|
59153
|
-
});
|
|
59154
|
-
}
|
|
59244
|
+
end,
|
|
59245
|
+
interpolant
|
|
59246
|
+
});
|
|
59155
59247
|
}
|
|
59156
59248
|
}
|
|
59157
59249
|
}
|
|
@@ -59182,6 +59274,23 @@
|
|
|
59182
59274
|
}
|
|
59183
59275
|
}
|
|
59184
59276
|
|
|
59277
|
+
/**
|
|
59278
|
+
* Walk up the tree until a parent is found with the given classname. If no ancestor is found return undefined.
|
|
59279
|
+
* @param target
|
|
59280
|
+
* @param classname
|
|
59281
|
+
* @returns {*}
|
|
59282
|
+
*/
|
|
59283
|
+
function findAncestorOfClass(target, classname) {
|
|
59284
|
+
while (target.parentElement) {
|
|
59285
|
+
if (target.parentElement.classList.contains(classname)) {
|
|
59286
|
+
return target.parentElement;
|
|
59287
|
+
} else {
|
|
59288
|
+
target = target.parentElement;
|
|
59289
|
+
}
|
|
59290
|
+
}
|
|
59291
|
+
return undefined;
|
|
59292
|
+
}
|
|
59293
|
+
|
|
59185
59294
|
/*
|
|
59186
59295
|
* The MIT License (MIT)
|
|
59187
59296
|
*
|
|
@@ -61116,7 +61225,12 @@
|
|
|
61116
61225
|
|
|
61117
61226
|
// Track gear column
|
|
61118
61227
|
createColumn(this.columnContainer, 'igv-gear-menu-column');
|
|
61119
|
-
const
|
|
61228
|
+
const genomeOrReference = session.reference || session.genome;
|
|
61229
|
+
if (!genomeOrReference) {
|
|
61230
|
+
console.warn("No genome or reference object specified");
|
|
61231
|
+
return;
|
|
61232
|
+
}
|
|
61233
|
+
const genomeConfig = await GenomeUtils.expandReference(this.alert, genomeOrReference);
|
|
61120
61234
|
await this.loadReference(genomeConfig, session.locus);
|
|
61121
61235
|
this.centerLineList = this.createCenterLineList(this.columnContainer);
|
|
61122
61236
|
|
|
@@ -61171,8 +61285,8 @@
|
|
|
61171
61285
|
const genomeTracks = genomeConfig.tracks || [];
|
|
61172
61286
|
const trackConfigurations = session.tracks ? genomeTracks.concat(session.tracks) : genomeTracks;
|
|
61173
61287
|
|
|
61174
|
-
// Insure that we always have a sequence track
|
|
61175
|
-
const pushSequenceTrack = trackConfigurations.filter(track => track.type
|
|
61288
|
+
// Insure that we always have a sequence track with no explicit URL (=> the reference genome sequence track)
|
|
61289
|
+
const pushSequenceTrack = trackConfigurations.filter(track => 'sequence' === track.type && !track.url && !track.fastaURL).length === 0;
|
|
61176
61290
|
if (pushSequenceTrack /*&& false !== this.config.showSequence*/) {
|
|
61177
61291
|
trackConfigurations.push({
|
|
61178
61292
|
type: "sequence",
|
|
@@ -61500,13 +61614,15 @@
|
|
|
61500
61614
|
*/
|
|
61501
61615
|
async createTrack(config) {
|
|
61502
61616
|
// Resolve function and promise urls
|
|
61503
|
-
let url = await resolveURL(config.url);
|
|
61617
|
+
let url = await resolveURL(config.url || config.fastaURL);
|
|
61504
61618
|
if (isString$2(url)) {
|
|
61505
61619
|
url = url.trim();
|
|
61506
61620
|
}
|
|
61507
61621
|
if (url) {
|
|
61508
61622
|
if (config.format) {
|
|
61509
61623
|
config.format = config.format.toLowerCase();
|
|
61624
|
+
} else if (config.fastaURL) {
|
|
61625
|
+
config.format = "fasta"; // by definition
|
|
61510
61626
|
} else {
|
|
61511
61627
|
let filename = config.filename;
|
|
61512
61628
|
if (!filename) {
|
|
@@ -61518,7 +61634,7 @@
|
|
|
61518
61634
|
} else if (format) {
|
|
61519
61635
|
config.format = format;
|
|
61520
61636
|
} else {
|
|
61521
|
-
if (config.sourceType ===
|
|
61637
|
+
if (config.sourceType === "htsget") {
|
|
61522
61638
|
// Check for htsget URL. This is a longshot
|
|
61523
61639
|
await HtsgetReader.inferFormat(config);
|
|
61524
61640
|
}
|
|
@@ -62570,8 +62686,7 @@
|
|
|
62570
62686
|
} else {
|
|
62571
62687
|
await browser.loadSessionObject(config);
|
|
62572
62688
|
}
|
|
62573
|
-
|
|
62574
|
-
browser.navbarManager.navbarDidResize(browser.$navigation.width(), isWGV);
|
|
62689
|
+
browser.navbarManager.navbarDidResize(browser.$navigation.width());
|
|
62575
62690
|
return browser;
|
|
62576
62691
|
}
|
|
62577
62692
|
function removeBrowser(browser) {
|
|
@@ -62728,7 +62843,7 @@
|
|
|
62728
62843
|
}
|
|
62729
62844
|
|
|
62730
62845
|
function embedCSS() {
|
|
62731
|
-
var css = '.igv-navbar {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n color: #444;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n line-height: 32px;\n padding-left: 8px;\n padding-right: 8px;\n margin-top: 2px;\n margin-bottom: 6px;\n height: 32px;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: #f3f3f3;\n}\n.igv-navbar .igv-navbar-left-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px;\n}\n.igv-navbar .igv-navbar-left-container .igv-logo {\n width: 34px;\n height: 32px;\n margin-right: 8px;\n}\n.igv-navbar .igv-navbar-left-container .igv-current-genome {\n height: 32px;\n margin-left: 4px;\n margin-right: 4px;\n user-select: none;\n line-height: 32px;\n vertical-align: middle;\n text-align: center;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container {\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n height: 100%;\n width: 125px;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container select {\n display: block;\n cursor: pointer;\n width: 100px;\n height: 75%;\n outline: none;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n margin-left: 8px;\n height: 22px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 210px;\n height: 22px;\n line-height: 22px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container input.igv-search-input {\n cursor: text;\n width: 85%;\n height: 22px;\n line-height: 22px;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n text-align: left;\n padding-left: 8px;\n margin-right: 8px;\n outline: none;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: white;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container .igv-search-icon-container {\n cursor: pointer;\n height: 16px;\n width: 16px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-windowsize-panel-container {\n margin-left: 4px;\n user-select: none;\n}\n.igv-navbar .igv-navbar-right-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container div {\n margin-left: 0;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container div:last-child {\n margin-left: 0;\n margin-right: 0;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container-750 {\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:first-child {\n height: 24px;\n width: 24px;\n margin-left: unset;\n margin-right: 8px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:last-child {\n height: 24px;\n width: 24px;\n margin-left: 8px;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:nth-child(even) {\n display: block;\n height: fit-content;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget input {\n display: block;\n width: 125px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget svg {\n display: block;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:first-child {\n height: 24px;\n width: 24px;\n margin-left: unset;\n margin-right: 8px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:last-child {\n height: 24px;\n width: 24px;\n margin-left: 8px;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:nth-child(even) {\n width: 0;\n height: 0;\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 input {\n width: 0;\n height: 0;\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 svg {\n display: block;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-hidden {\n display: none;\n}\n\n.igv-navbar-button {\n display: block;\n box-sizing: unset;\n padding-left: 6px;\n padding-right: 6px;\n height: 18px;\n text-transform: capitalize;\n user-select: none;\n line-height: 18px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 11px;\n font-weight: 200;\n color: #737373;\n background-color: #f3f3f3;\n border-color: #737373;\n border-style: solid;\n border-width: thin;\n border-radius: 6px;\n}\n\n.igv-navbar-button-clicked {\n color: white;\n background-color: #737373;\n}\n\n.igv-navbar-button:hover {\n cursor: pointer;\n}\n\n.igv-zoom-in-notice-container {\n z-index: 1024;\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translate(-50%, 0%);\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n background-color: white;\n}\n.igv-zoom-in-notice-container > div {\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n width: 100%;\n height: 100%;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #3f3f3f;\n}\n\n.igv-zoom-in-notice {\n position: absolute;\n top: 10px;\n left: 50%;\n}\n.igv-zoom-in-notice div {\n position: relative;\n left: -50%;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #3f3f3f;\n background-color: rgba(255, 255, 255, 0.51);\n z-index: 64;\n}\n\n.igv-container-spinner {\n position: absolute;\n top: 90%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1024;\n width: 24px;\n height: 24px;\n pointer-events: none;\n color: #737373;\n}\n\n.igv-multi-locus-close-button {\n position: absolute;\n top: 2px;\n right: 0;\n padding-left: 2px;\n padding-right: 2px;\n width: 18px;\n height: 18px;\n color: #666666;\n background-color: white;\n z-index: 1000;\n}\n.igv-multi-locus-close-button > svg {\n vertical-align: top;\n}\n\n.igv-multi-locus-close-button:hover {\n cursor: pointer;\n color: #434343;\n}\n\n.igv-multi-locus-ruler-label {\n z-index: 64;\n position: absolute;\n top: 2px;\n left: 0;\n width: 100%;\n height: 14px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-multi-locus-ruler-label div {\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: rgb(16, 16, 16);\n background-color: white;\n}\n\n.igv-multi-locus-ruler-label-square-dot {\n z-index: 64;\n position: absolute;\n left: 50%;\n top: 5%;\n transform: translate(-50%, 0%);\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-multi-locus-ruler-label-square-dot > div:first-child {\n width: 14px;\n height: 14px;\n}\n.igv-multi-locus-ruler-label-square-dot > div:last-child {\n margin-left: 16px;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: rgb(16, 16, 16);\n}\n\n.igv-multi-locus-ruler-label:hover {\n cursor: pointer;\n}\n\n.igv-ruler-sweeper {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 26px;\n bottom: 0;\n left: 0;\n width: 0;\n z-index: 99999;\n background-color: rgba(68, 134, 247, 0.25);\n}\n\n.igv-ruler-tooltip {\n pointer-events: none;\n z-index: 128;\n position: absolute;\n top: 0;\n left: 0;\n width: 1px;\n height: 32px;\n background-color: transparent;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ruler-tooltip > div {\n pointer-events: none;\n width: 128px;\n height: auto;\n padding: 1px;\n color: #373737;\n font-size: 10px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n background-color: white;\n border-style: solid;\n border-width: thin;\n border-color: #373737;\n}\n\n.igv-track-label {\n position: absolute;\n left: 8px;\n top: 8px;\n width: auto;\n height: auto;\n max-width: 200px;\n padding-left: 4px;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n text-align: center;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-color: #444;\n border-radius: 2px;\n border-style: solid;\n border-width: thin;\n background-color: white;\n z-index: 128;\n cursor: pointer;\n}\n\n.igv-track-label:hover,\n.igv-track-label:focus,\n.igv-track-label:active {\n background-color: #e8e8e8;\n}\n\n.igv-track-label-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-top: 4px;\n}\n\n.igv-center-line {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n z-index: 8;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-left-style: dashed;\n border-left-width: thin;\n border-right-style: dashed;\n border-right-width: thin;\n}\n\n.igv-center-line-wide {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(127, 127, 127, 0.51);\n}\n\n.igv-center-line-thin {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(0, 0, 0, 0);\n}\n\n.igv-cursor-guide-horizontal {\n display: none;\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n height: 1px;\n z-index: 1;\n margin-left: 50px;\n margin-right: 54px;\n border-top-style: dotted;\n border-top-width: thin;\n border-top-color: rgba(127, 127, 127, 0.76);\n}\n\n.igv-cursor-guide-vertical {\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n z-index: 1;\n border-left-style: dotted;\n border-left-width: thin;\n border-left-color: rgba(127, 127, 127, 0.76);\n display: none;\n}\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent;\n}\n.igv-user-feedback div:first-child div:first-child {\n left: 8px;\n}\n.igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px;\n}\n.igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0;\n}\n.igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px;\n}\n\n.igv-generic-dialog-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-generic-dialog-container .igv-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input input {\n font-size: 16px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f;\n}\n\n.igv-generic-container {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-container div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd;\n}\n.igv-generic-container div:first-child i {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px;\n}\n\n.igv-menu-popup {\n position: absolute;\n top: 0;\n left: 0;\n width: max-content;\n z-index: 4096;\n cursor: pointer;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background: white;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-end;\n text-align: left;\n}\n.igv-menu-popup > div:not(:first-child) {\n width: 100%;\n}\n.igv-menu-popup > div:not(:first-child) > div {\n background: white;\n}\n.igv-menu-popup > div:not(:first-child) > div.context-menu {\n padding-left: 4px;\n padding-right: 4px;\n}\n.igv-menu-popup > div:not(:first-child) > div:last-child {\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-menu-popup > div:not(:first-child) > div:hover {\n background: #efefef;\n}\n\n.igv-menu-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-bottom: 1px;\n padding-top: 1px;\n}\n\n.igv-menu-popup-header {\n position: relative;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-menu-popup-header div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-menu-popup-header div:hover {\n cursor: pointer;\n color: #444;\n}\n\n.igv-menu-popup-check-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 20px;\n margin-right: 4px;\n background-color: transparent;\n}\n.igv-menu-popup-check-container div {\n padding-top: 2px;\n padding-left: 8px;\n}\n.igv-menu-popup-check-container div:first-child {\n position: relative;\n width: 12px;\n height: 12px;\n}\n.igv-menu-popup-check-container div:first-child svg {\n position: absolute;\n width: 12px;\n height: 12px;\n}\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent;\n}\n.igv-user-feedback div:first-child div:first-child {\n left: 8px;\n}\n.igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px;\n}\n.igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0;\n}\n.igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px;\n}\n\n.igv-loading-spinner-container {\n z-index: 1024;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 32px;\n height: 32px;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-loading-spinner-container > div {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 4px solid rgba(128, 128, 128, 0.5);\n border-top-color: rgb(255, 255, 255);\n animation: spin 1s ease-in-out infinite;\n -webkit-animation: spin 1s ease-in-out infinite;\n}\n\n@keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n@-webkit-keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n.igv-roi-menu-next-gen {\n position: absolute;\n z-index: 512;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background-color: white;\n width: 192px;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-menu-next-gen > div:first-child {\n height: 24px;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-roi-menu-next-gen > div:first-child > div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-roi-menu-next-gen > div:first-child > div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-menu-next-gen > div:last-child {\n background-color: white;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: 0;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n text-align: start;\n vertical-align: middle;\n cursor: pointer;\n}\n.igv-roi-menu-next-gen > div:last-child > div {\n height: 24px;\n padding-left: 4px;\n border-bottom-style: solid;\n border-bottom-width: thin;\n border-bottom-color: #7f7f7f;\n}\n.igv-roi-menu-next-gen > div:last-child > div:not(:first-child):hover {\n background-color: rgba(127, 127, 127, 0.1);\n}\n.igv-roi-menu-next-gen > div:last-child div:first-child {\n cursor: default;\n font-style: italic;\n text-align: center;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-menu-next-gen > div:last-child > div:last-child {\n border-bottom-width: 0;\n border-bottom-color: transparent;\n}\n\n.igv-roi-placeholder {\n font-style: normal;\n color: rgba(75, 75, 75, 0.6);\n}\n\n.igv-roi-table {\n position: absolute;\n z-index: 1024;\n width: fit-content;\n border-color: #7f7f7f;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-table > div {\n height: 24px;\n font-size: 14px;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n}\n.igv-roi-table > div:first-child {\n border-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-top-width: 0;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-roi-table > div:first-child > div:first-child {\n text-align: center;\n width: calc(100% - 4px - 12px);\n}\n.igv-roi-table > div:first-child > div:last-child {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7f7f7f;\n}\n.igv-roi-table > div:first-child > div:last-child > svg {\n display: block;\n}\n.igv-roi-table > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-table > .igv-roi-table-column-titles {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n padding-right: 16px;\n background-color: white;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: center;\n margin-left: 4px;\n margin-right: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(1) {\n width: 20%;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(2) {\n width: 15%;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(3) {\n width: 15%;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(4) {\n width: 30%;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(5) {\n width: 20%;\n}\n.igv-roi-table > .igv-roi-table-row-container {\n resize: both;\n overflow: scroll;\n min-width: 512px;\n min-height: 72px;\n height: 144px;\n max-height: 480px;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: center;\n margin-left: 4px;\n margin-right: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(1) {\n width: 20%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(2) {\n width: 15%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(3) {\n width: 15%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(4) {\n width: 30%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(5) {\n width: 20%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row-hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n.igv-roi-table > div:last-child {\n height: 32px;\n line-height: 32px;\n border-top-color: #7f7f7f;\n border-top-style: solid;\n border-top-width: thin;\n border-bottom-color: transparent;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-width: 0;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n\n.igv-roi-table-four-column {\n position: absolute;\n z-index: 1024;\n width: fit-content;\n border-color: #7f7f7f;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-table-four-column > div {\n height: 24px;\n font-size: 14px;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n}\n.igv-roi-table-four-column > div:first-child {\n border-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-top-width: 0;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-roi-table-four-column > div:first-child > div:first-child {\n text-align: center;\n width: calc(100% - 4px - 12px);\n}\n.igv-roi-table-four-column > div:first-child > div:last-child {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7f7f7f;\n}\n.igv-roi-table-four-column > div:first-child > div:last-child > svg {\n display: block;\n}\n.igv-roi-table-four-column > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n padding-right: 16px;\n background-color: white;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: center;\n margin-left: 4px;\n margin-right: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div:nth-child(1) {\n width: 25%;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div:nth-child(2) {\n width: 20%;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div:nth-child(3) {\n width: 20%;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div:nth-child(4) {\n width: 35%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container {\n resize: both;\n overflow: scroll;\n min-width: 512px;\n min-height: 72px;\n height: 144px;\n max-height: 480px;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: center;\n margin-left: 4px;\n margin-right: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(1) {\n width: 25%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(2) {\n width: 20%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(3) {\n width: 20%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(4) {\n width: 35%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row-hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n.igv-roi-table-four-column > div:last-child {\n height: 32px;\n line-height: 32px;\n border-top-color: #7f7f7f;\n border-top-style: solid;\n border-top-width: thin;\n border-bottom-color: transparent;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-width: 0;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n\n.igv-roi-table-row-selected {\n background-color: rgba(0, 0, 0, 0.125);\n}\n\n.igv-roi-table-button {\n height: 20px;\n user-select: none;\n line-height: 20px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 13px;\n font-weight: 400;\n color: black;\n padding-left: 6px;\n padding-right: 6px;\n background-color: rgb(239, 239, 239);\n border-color: black;\n border-style: solid;\n border-width: thin;\n border-radius: 3px;\n}\n\n.igv-roi-table-button:hover {\n cursor: pointer;\n font-weight: 400;\n background-color: rgba(0, 0, 0, 0.13);\n}\n\n.igv-roi-region {\n z-index: 64;\n position: absolute;\n top: 0;\n bottom: 0;\n pointer-events: none;\n overflow: visible;\n margin-top: 44px;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-region > div {\n position: relative;\n width: 100%;\n height: 8px;\n cursor: pointer;\n pointer-events: auto;\n}\n\n.igv-roi-menu {\n position: absolute;\n z-index: 1024;\n width: 144px;\n border-color: #7f7f7f;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-menu > div:not(:last-child) {\n border-bottom-color: rgba(128, 128, 128, 0.5);\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-roi-menu > div:first-child {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-top-color: transparent;\n border-top-style: solid;\n border-top-width: 0;\n}\n.igv-roi-menu > div:last-child {\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: 0;\n}\n\n.igv-roi-menu-row {\n height: 24px;\n padding-left: 8px;\n font-size: small;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n background-color: white;\n}\n\n.igv-roi-menu-row-edit-description {\n width: -webkit-fill-available;\n font-size: small;\n text-align: start;\n vertical-align: middle;\n background-color: white;\n padding-left: 4px;\n padding-right: 4px;\n padding-bottom: 4px;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-menu-row-edit-description > label {\n margin-left: 2px;\n margin-bottom: 0;\n display: block;\n width: -webkit-fill-available;\n}\n.igv-roi-menu-row-edit-description > input {\n display: block;\n margin-left: 2px;\n margin-right: 2px;\n margin-bottom: 1px;\n width: -webkit-fill-available;\n}\n\n.igv-container {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n padding-top: 4px;\n user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n}\n\n.igv-viewport {\n position: relative;\n margin-top: 5px;\n overflow-x: hidden;\n overflow-y: hidden;\n}\n\n.igv-viewport-content {\n position: relative;\n width: 100%;\n}\n.igv-viewport-content > canvas {\n position: relative;\n display: block;\n}\n\n.igv-column-container {\n position: relative;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n width: 100%;\n}\n\n.igv-column-shim {\n width: 1px;\n margin-left: 2px;\n margin-right: 2px;\n background-color: #545453;\n}\n\n.igv-column {\n position: relative;\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-axis-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 50px;\n}\n.igv-axis-column > div {\n margin-top: 5px;\n width: 100%;\n}\n\n.igv-sample-name-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-scrollbar-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 14px;\n}\n.igv-scrollbar-column > div {\n position: relative;\n margin-top: 5px;\n width: 14px;\n}\n.igv-scrollbar-column > div > div {\n cursor: pointer;\n position: absolute;\n top: 0;\n left: 2px;\n width: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: #c4c4c4;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.igv-scrollbar-column > div > div:hover {\n background-color: #c4c4c4;\n}\n\n.igv-track-drag-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 12px;\n background-color: white;\n}\n.igv-track-drag-column > .igv-track-drag-handle {\n z-index: 512;\n position: relative;\n cursor: pointer;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n background-color: #c4c4c4;\n}\n.igv-track-drag-column .igv-track-drag-handle-hover {\n background-color: #787878;\n}\n.igv-track-drag-column > .igv-track-drag-shim {\n position: relative;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n}\n\n.igv-gear-menu-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 28px;\n}\n.igv-gear-menu-column > div {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n margin-top: 5px;\n width: 100%;\n background: white;\n}\n.igv-gear-menu-column > div > div {\n position: relative;\n margin-top: 4px;\n width: 16px;\n height: 16px;\n color: #7F7F7F;\n}\n.igv-gear-menu-column > div > div:hover {\n cursor: pointer;\n color: #444;\n}\n\n/*# sourceMappingURL=dom.css.map */\n';
|
|
62846
|
+
var css = '.igv-navbar {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n box-sizing: border-box;\n width: 100%;\n color: #444;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n line-height: 32px;\n padding-left: 8px;\n padding-right: 8px;\n margin-top: 2px;\n margin-bottom: 6px;\n height: 32px;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: #f3f3f3;\n}\n.igv-navbar .igv-navbar-left-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px;\n}\n.igv-navbar .igv-navbar-left-container .igv-logo {\n width: 34px;\n height: 32px;\n margin-right: 8px;\n}\n.igv-navbar .igv-navbar-left-container .igv-current-genome {\n height: 32px;\n margin-left: 4px;\n margin-right: 4px;\n user-select: none;\n line-height: 32px;\n vertical-align: middle;\n text-align: center;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container {\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n height: 100%;\n width: 125px;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-chromosome-select-widget-container select {\n display: block;\n cursor: pointer;\n width: 100px;\n height: 75%;\n outline: none;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n margin-left: 8px;\n height: 22px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 210px;\n height: 22px;\n line-height: 22px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container input.igv-search-input {\n cursor: text;\n width: 85%;\n height: 22px;\n line-height: 22px;\n font-size: 12px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n text-align: left;\n padding-left: 8px;\n margin-right: 8px;\n outline: none;\n border-style: solid;\n border-radius: 3px;\n border-width: thin;\n border-color: #bfbfbf;\n background-color: white;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-search-container .igv-search-icon-container {\n cursor: pointer;\n height: 16px;\n width: 16px;\n}\n.igv-navbar .igv-navbar-left-container .igv-navbar-genomic-location .igv-locus-size-group .igv-windowsize-panel-container {\n margin-left: 4px;\n user-select: none;\n}\n.igv-navbar .igv-navbar-right-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 32px;\n line-height: 32px;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n height: 100%;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container div {\n margin-left: 0;\n margin-right: 4px;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container div:last-child {\n margin-left: 0;\n margin-right: 0;\n}\n.igv-navbar .igv-navbar-right-container .igv-navbar-toggle-button-container-750 {\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:first-child {\n height: 24px;\n width: 24px;\n margin-left: unset;\n margin-right: 8px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:last-child {\n height: 24px;\n width: 24px;\n margin-left: 8px;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget div:nth-child(even) {\n display: block;\n height: fit-content;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget input {\n display: block;\n width: 125px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget svg {\n display: block;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 {\n color: #737373;\n font-size: 18px;\n height: 32px;\n line-height: 32px;\n margin-left: 8px;\n user-select: none;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div {\n cursor: pointer;\n margin-left: unset;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:first-child {\n height: 24px;\n width: 24px;\n margin-left: unset;\n margin-right: 8px;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:last-child {\n height: 24px;\n width: 24px;\n margin-left: 8px;\n margin-right: unset;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 div:nth-child(even) {\n width: 0;\n height: 0;\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 input {\n width: 0;\n height: 0;\n display: none;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-900 svg {\n display: block;\n}\n.igv-navbar .igv-navbar-right-container .igv-zoom-widget-hidden {\n display: none;\n}\n\n.igv-navbar-button {\n display: block;\n box-sizing: unset;\n padding-left: 6px;\n padding-right: 6px;\n height: 18px;\n text-transform: capitalize;\n user-select: none;\n line-height: 18px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 11px;\n font-weight: 200;\n color: #737373;\n background-color: #f3f3f3;\n border-color: #737373;\n border-style: solid;\n border-width: thin;\n border-radius: 6px;\n}\n\n.igv-navbar-button-clicked {\n color: white;\n background-color: #737373;\n}\n\n.igv-navbar-button:hover {\n cursor: pointer;\n}\n\n.igv-zoom-in-notice-container {\n z-index: 1024;\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translate(-50%, 0%);\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n background-color: white;\n}\n.igv-zoom-in-notice-container > div {\n padding-left: 4px;\n padding-right: 4px;\n padding-top: 2px;\n padding-bottom: 2px;\n width: 100%;\n height: 100%;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: #3f3f3f;\n}\n\n.igv-zoom-in-notice {\n position: absolute;\n top: 10px;\n left: 50%;\n}\n.igv-zoom-in-notice div {\n position: relative;\n left: -50%;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #3f3f3f;\n background-color: rgba(255, 255, 255, 0.51);\n z-index: 64;\n}\n\n.igv-container-spinner {\n position: absolute;\n top: 90%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 1024;\n width: 24px;\n height: 24px;\n pointer-events: none;\n color: #737373;\n}\n\n.igv-multi-locus-close-button {\n position: absolute;\n top: 2px;\n right: 0;\n padding-left: 2px;\n padding-right: 2px;\n width: 18px;\n height: 18px;\n color: #666666;\n background-color: white;\n z-index: 1000;\n}\n.igv-multi-locus-close-button > svg {\n vertical-align: top;\n}\n\n.igv-multi-locus-close-button:hover {\n cursor: pointer;\n color: #434343;\n}\n\n.igv-multi-locus-ruler-label {\n z-index: 64;\n position: absolute;\n top: 2px;\n left: 0;\n width: 100%;\n height: 14px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-multi-locus-ruler-label div {\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: rgb(16, 16, 16);\n background-color: white;\n}\n\n.igv-multi-locus-ruler-label-square-dot {\n z-index: 64;\n position: absolute;\n left: 50%;\n top: 5%;\n transform: translate(-50%, 0%);\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-multi-locus-ruler-label-square-dot > div:first-child {\n width: 14px;\n height: 14px;\n}\n.igv-multi-locus-ruler-label-square-dot > div:last-child {\n margin-left: 16px;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n color: rgb(16, 16, 16);\n}\n\n.igv-multi-locus-ruler-label:hover {\n cursor: pointer;\n}\n\n.igv-ruler-sweeper {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 26px;\n bottom: 0;\n left: 0;\n width: 0;\n z-index: 99999;\n background-color: rgba(68, 134, 247, 0.25);\n}\n\n.igv-ruler-tooltip {\n pointer-events: none;\n z-index: 128;\n position: absolute;\n top: 0;\n left: 0;\n width: 1px;\n height: 32px;\n background-color: transparent;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-ruler-tooltip > div {\n pointer-events: none;\n width: 128px;\n height: auto;\n padding: 1px;\n color: #373737;\n font-size: 10px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n background-color: white;\n border-style: solid;\n border-width: thin;\n border-color: #373737;\n}\n\n.igv-track-label {\n position: absolute;\n left: 8px;\n top: 8px;\n width: auto;\n height: auto;\n max-width: 50%;\n padding-left: 4px;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n text-align: center;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-color: #444;\n border-radius: 2px;\n border-style: solid;\n border-width: thin;\n background-color: white;\n z-index: 128;\n cursor: pointer;\n}\n\n.igv-track-label:hover,\n.igv-track-label:focus,\n.igv-track-label:active {\n background-color: #e8e8e8;\n}\n\n.igv-track-label-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-top: 4px;\n}\n\n.igv-center-line {\n display: none;\n pointer-events: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n z-index: 8;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n border-left-style: dashed;\n border-left-width: thin;\n border-right-style: dashed;\n border-right-width: thin;\n}\n\n.igv-center-line-wide {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(127, 127, 127, 0.51);\n}\n\n.igv-center-line-thin {\n background-color: rgba(0, 0, 0, 0);\n border-left-color: rgba(127, 127, 127, 0.51);\n border-right-color: rgba(0, 0, 0, 0);\n}\n\n.igv-cursor-guide-horizontal {\n display: none;\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n left: 0;\n right: 0;\n top: 50%;\n height: 1px;\n z-index: 1;\n margin-left: 50px;\n margin-right: 54px;\n border-top-style: dotted;\n border-top-width: thin;\n border-top-color: rgba(127, 127, 127, 0.76);\n}\n\n.igv-cursor-guide-vertical {\n pointer-events: none;\n user-select: none;\n -moz-user-select: none;\n -webkit-user-select: none;\n position: absolute;\n top: 0;\n bottom: 0;\n left: 50%;\n width: 1px;\n z-index: 1;\n border-left-style: dotted;\n border-left-width: thin;\n border-left-color: rgba(127, 127, 127, 0.76);\n display: none;\n}\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent;\n}\n.igv-user-feedback div:first-child div:first-child {\n left: 8px;\n}\n.igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px;\n}\n.igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0;\n}\n.igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px;\n}\n\n.igv-generic-dialog-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 300px;\n height: 200px;\n border-color: #7F7F7F;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n z-index: 2048;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header div {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-generic-dialog-container .igv-generic-dialog-header div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-generic-dialog-container .igv-generic-dialog-one-liner {\n color: #373737;\n width: 95%;\n height: 24px;\n line-height: 24px;\n text-align: left;\n margin-top: 8px;\n padding-left: 8px;\n overflow-wrap: break-word;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input {\n margin-top: 8px;\n width: 95%;\n height: 24px;\n color: #373737;\n line-height: 24px;\n padding-left: 8px;\n background-color: white;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input div {\n width: 30%;\n height: 100%;\n font-size: 16px;\n text-align: right;\n padding-right: 8px;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-label-input input {\n width: 50%;\n font-size: 16px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input {\n margin-top: 8px;\n width: calc(100% - 16px);\n height: 24px;\n color: #373737;\n line-height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input input {\n display: block;\n height: 100%;\n width: 100%;\n padding-left: 4px;\n font-family: \"Open Sans\", sans-serif;\n font-weight: 400;\n color: #373737;\n text-align: left;\n outline: none;\n border-style: solid;\n border-width: thin;\n border-color: #7F7F7F;\n background-color: white;\n}\n.igv-generic-dialog-container .igv-generic-dialog-input input {\n font-size: 16px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel {\n width: 100%;\n height: 28px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div {\n margin-top: 32px;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: 14px;\n font-weight: 400;\n width: 75px;\n height: 28px;\n line-height: 28px;\n text-align: center;\n border-color: transparent;\n border-style: solid;\n border-width: thin;\n border-radius: 2px;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child {\n margin-left: 32px;\n margin-right: 0;\n background-color: #5ea4e0;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child {\n margin-left: 0;\n margin-right: 32px;\n background-color: #c4c4c4;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:first-child:hover {\n cursor: pointer;\n background-color: #3b5c7f;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok-cancel div:last-child:hover {\n cursor: pointer;\n background-color: #7f7f7f;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok {\n width: 100%;\n height: 36px;\n margin-top: 32px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok div {\n width: 98px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n color: white;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n border-color: white;\n border-style: solid;\n border-width: thin;\n border-radius: 4px;\n background-color: #2B81AF;\n}\n.igv-generic-dialog-container .igv-generic-dialog-ok div:hover {\n cursor: pointer;\n background-color: #25597f;\n}\n\n.igv-generic-container {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 2048;\n background-color: white;\n cursor: pointer;\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-generic-container div:first-child {\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n height: 24px;\n width: 100%;\n background-color: #dddddd;\n}\n.igv-generic-container div:first-child i {\n display: block;\n color: #5f5f5f;\n cursor: pointer;\n width: 14px;\n height: 14px;\n margin-right: 8px;\n margin-bottom: 4px;\n}\n\n.igv-menu-popup {\n position: absolute;\n top: 0;\n left: 0;\n width: max-content;\n z-index: 4096;\n cursor: pointer;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background: white;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-end;\n text-align: left;\n}\n.igv-menu-popup > div:not(:first-child) {\n width: 100%;\n}\n.igv-menu-popup > div:not(:first-child) > div {\n background: white;\n}\n.igv-menu-popup > div:not(:first-child) > div.context-menu {\n padding-left: 4px;\n padding-right: 4px;\n}\n.igv-menu-popup > div:not(:first-child) > div:last-child {\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-menu-popup > div:not(:first-child) > div:hover {\n background: #efefef;\n}\n\n.igv-menu-popup-shim {\n padding-left: 8px;\n padding-right: 8px;\n padding-bottom: 1px;\n padding-top: 1px;\n}\n\n.igv-menu-popup-header {\n position: relative;\n width: 100%;\n height: 24px;\n cursor: move;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-menu-popup-header div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-menu-popup-header div:hover {\n cursor: pointer;\n color: #444;\n}\n\n.igv-menu-popup-check-container {\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n height: 20px;\n margin-right: 4px;\n background-color: transparent;\n}\n.igv-menu-popup-check-container div {\n padding-top: 2px;\n padding-left: 8px;\n}\n.igv-menu-popup-check-container div:first-child {\n position: relative;\n width: 12px;\n height: 12px;\n}\n.igv-menu-popup-check-container div:first-child svg {\n position: absolute;\n width: 12px;\n height: 12px;\n}\n\n.igv-user-feedback {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 512px;\n height: 360px;\n z-index: 2048;\n background-color: white;\n border-color: #a2a2a2;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: medium;\n font-weight: 400;\n color: #444;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n}\n.igv-user-feedback div:first-child {\n position: relative;\n height: 24px;\n width: 100%;\n background-color: white;\n border-bottom-color: #a2a2a2;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-user-feedback div:first-child div {\n position: absolute;\n top: 2px;\n width: 16px;\n height: 16px;\n background-color: transparent;\n}\n.igv-user-feedback div:first-child div:first-child {\n left: 8px;\n}\n.igv-user-feedback div:first-child div:last-child {\n cursor: pointer;\n right: 8px;\n}\n.igv-user-feedback div:last-child {\n width: 100%;\n height: calc(100% - 24px);\n border-width: 0;\n}\n.igv-user-feedback div:last-child div {\n width: auto;\n height: auto;\n margin: 8px;\n}\n\n.igv-loading-spinner-container {\n z-index: 1024;\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 32px;\n height: 32px;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: center;\n align-items: center;\n}\n.igv-loading-spinner-container > div {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 4px solid rgba(128, 128, 128, 0.5);\n border-top-color: rgb(255, 255, 255);\n animation: spin 1s ease-in-out infinite;\n -webkit-animation: spin 1s ease-in-out infinite;\n}\n\n@keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n@-webkit-keyframes spin {\n to {\n -webkit-transform: rotate(360deg);\n transform: rotate(360deg);\n }\n}\n.igv-roi-menu-next-gen {\n position: absolute;\n z-index: 512;\n font-family: \"Open Sans\", sans-serif;\n font-size: small;\n font-weight: 400;\n color: #4b4b4b;\n background-color: white;\n width: 192px;\n border-radius: 4px;\n border-color: #7F7F7F;\n border-style: solid;\n border-width: thin;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-menu-next-gen > div:first-child {\n height: 24px;\n border-top-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-color: #7F7F7F;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: flex-end;\n align-items: center;\n}\n.igv-roi-menu-next-gen > div:first-child > div {\n margin-right: 4px;\n height: 12px;\n width: 12px;\n color: #7F7F7F;\n}\n.igv-roi-menu-next-gen > div:first-child > div:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-menu-next-gen > div:last-child {\n background-color: white;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: 0;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n text-align: start;\n vertical-align: middle;\n cursor: pointer;\n}\n.igv-roi-menu-next-gen > div:last-child > div {\n height: 24px;\n padding-left: 4px;\n border-bottom-style: solid;\n border-bottom-width: thin;\n border-bottom-color: #7f7f7f;\n}\n.igv-roi-menu-next-gen > div:last-child > div:not(:first-child):hover {\n background-color: rgba(127, 127, 127, 0.1);\n}\n.igv-roi-menu-next-gen > div:last-child div:first-child {\n cursor: default;\n font-style: italic;\n text-align: center;\n padding-right: 4px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-menu-next-gen > div:last-child > div:last-child {\n border-bottom-width: 0;\n border-bottom-color: transparent;\n}\n\n.igv-roi-placeholder {\n font-style: normal;\n color: rgba(75, 75, 75, 0.6);\n}\n\n.igv-roi-table {\n position: absolute;\n z-index: 1024;\n width: fit-content;\n border-color: #7f7f7f;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-table > div {\n height: 24px;\n font-size: 14px;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n}\n.igv-roi-table > div:first-child {\n border-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-top-width: 0;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-roi-table > div:first-child > div:first-child {\n text-align: center;\n width: calc(100% - 4px - 12px);\n}\n.igv-roi-table > div:first-child > div:last-child {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7f7f7f;\n}\n.igv-roi-table > div:first-child > div:last-child > svg {\n display: block;\n}\n.igv-roi-table > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-table > .igv-roi-table-column-titles {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n padding-right: 16px;\n background-color: white;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: center;\n margin-left: 4px;\n margin-right: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(1) {\n width: 20%;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(2) {\n width: 15%;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(3) {\n width: 15%;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(4) {\n width: 30%;\n}\n.igv-roi-table > .igv-roi-table-column-titles > div:nth-child(5) {\n width: 20%;\n}\n.igv-roi-table > .igv-roi-table-row-container {\n resize: both;\n overflow: scroll;\n min-width: 512px;\n min-height: 72px;\n height: 144px;\n max-height: 480px;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: center;\n margin-left: 4px;\n margin-right: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(1) {\n width: 20%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(2) {\n width: 15%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(3) {\n width: 15%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(4) {\n width: 30%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(5) {\n width: 20%;\n}\n.igv-roi-table > .igv-roi-table-row-container > .igv-roi-table-row-hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n.igv-roi-table > div:last-child {\n height: 32px;\n line-height: 32px;\n border-top-color: #7f7f7f;\n border-top-style: solid;\n border-top-width: thin;\n border-bottom-color: transparent;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-width: 0;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n\n.igv-roi-table-four-column {\n position: absolute;\n z-index: 1024;\n width: fit-content;\n border-color: #7f7f7f;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n font-size: 12px;\n font-weight: 400;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-table-four-column > div {\n height: 24px;\n font-size: 14px;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n}\n.igv-roi-table-four-column > div:first-child {\n border-color: transparent;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-top-width: 0;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n background-color: #eee;\n cursor: move;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-between;\n align-items: center;\n}\n.igv-roi-table-four-column > div:first-child > div:first-child {\n text-align: center;\n width: calc(100% - 4px - 12px);\n}\n.igv-roi-table-four-column > div:first-child > div:last-child {\n margin-right: 4px;\n margin-bottom: 2px;\n height: 12px;\n width: 12px;\n color: #7f7f7f;\n}\n.igv-roi-table-four-column > div:first-child > div:last-child > svg {\n display: block;\n}\n.igv-roi-table-four-column > div:first-child > div:last-child:hover {\n cursor: pointer;\n color: #444;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n padding-right: 16px;\n background-color: white;\n border-bottom-color: #7f7f7f;\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: center;\n margin-left: 4px;\n margin-right: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div:nth-child(1) {\n width: 25%;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div:nth-child(2) {\n width: 20%;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div:nth-child(3) {\n width: 20%;\n}\n.igv-roi-table-four-column > .igv-roi-table-column-titles > div:nth-child(4) {\n width: 35%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container {\n resize: both;\n overflow: scroll;\n min-width: 512px;\n min-height: 72px;\n height: 144px;\n max-height: 480px;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row {\n height: 24px;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div {\n font-size: 14px;\n vertical-align: middle;\n line-height: 24px;\n text-align: center;\n margin-left: 4px;\n margin-right: 4px;\n height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(1) {\n width: 25%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(2) {\n width: 20%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(3) {\n width: 20%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row > div:nth-child(4) {\n width: 35%;\n}\n.igv-roi-table-four-column > .igv-roi-table-row-container > .igv-roi-table-row-hover {\n background-color: rgba(0, 0, 0, 0.04);\n}\n.igv-roi-table-four-column > div:last-child {\n height: 32px;\n line-height: 32px;\n border-top-color: #7f7f7f;\n border-top-style: solid;\n border-top-width: thin;\n border-bottom-color: transparent;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-width: 0;\n display: flex;\n flex-flow: row;\n flex-wrap: nowrap;\n justify-content: space-around;\n align-items: center;\n}\n\n.igv-roi-table-row-selected {\n background-color: rgba(0, 0, 0, 0.125);\n}\n\n.igv-roi-table-button {\n height: 20px;\n user-select: none;\n line-height: 20px;\n text-align: center;\n vertical-align: middle;\n font-family: \"Open Sans\", sans-serif;\n font-size: 13px;\n font-weight: 400;\n color: black;\n padding-left: 6px;\n padding-right: 6px;\n background-color: rgb(239, 239, 239);\n border-color: black;\n border-style: solid;\n border-width: thin;\n border-radius: 3px;\n}\n\n.igv-roi-table-button:hover {\n cursor: pointer;\n font-weight: 400;\n background-color: rgba(0, 0, 0, 0.13);\n}\n\n.igv-roi-region {\n z-index: 64;\n position: absolute;\n top: 0;\n bottom: 0;\n pointer-events: none;\n overflow: visible;\n margin-top: 44px;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-region > div {\n position: relative;\n width: 100%;\n height: 8px;\n cursor: pointer;\n pointer-events: auto;\n}\n\n.igv-roi-menu {\n position: absolute;\n z-index: 1024;\n width: 144px;\n border-color: #7f7f7f;\n border-radius: 4px;\n border-style: solid;\n border-width: thin;\n font-family: \"Open Sans\", sans-serif;\n background-color: white;\n display: flex;\n flex-flow: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n}\n.igv-roi-menu > div:not(:last-child) {\n border-bottom-color: rgba(128, 128, 128, 0.5);\n border-bottom-style: solid;\n border-bottom-width: thin;\n}\n.igv-roi-menu > div:first-child {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-top-color: transparent;\n border-top-style: solid;\n border-top-width: 0;\n}\n.igv-roi-menu > div:last-child {\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n border-bottom-color: transparent;\n border-bottom-style: solid;\n border-bottom-width: 0;\n}\n\n.igv-roi-menu-row {\n height: 24px;\n padding-left: 8px;\n font-size: small;\n text-align: start;\n vertical-align: middle;\n line-height: 24px;\n background-color: white;\n}\n\n.igv-roi-menu-row-edit-description {\n width: -webkit-fill-available;\n font-size: small;\n text-align: start;\n vertical-align: middle;\n background-color: white;\n padding-left: 4px;\n padding-right: 4px;\n padding-bottom: 4px;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: stretch;\n align-items: stretch;\n}\n.igv-roi-menu-row-edit-description > label {\n margin-left: 2px;\n margin-bottom: 0;\n display: block;\n width: -webkit-fill-available;\n}\n.igv-roi-menu-row-edit-description > input {\n display: block;\n margin-left: 2px;\n margin-right: 2px;\n margin-bottom: 1px;\n width: -webkit-fill-available;\n}\n\n.igv-container {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n padding-top: 4px;\n user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n}\n\n.igv-viewport {\n position: relative;\n margin-top: 5px;\n line-height: 1;\n overflow-x: hidden;\n overflow-y: hidden;\n}\n\n.igv-viewport-content {\n position: relative;\n width: 100%;\n}\n.igv-viewport-content > canvas {\n position: relative;\n display: block;\n}\n\n.igv-column-container {\n position: relative;\n display: flex;\n flex-direction: row;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: stretch;\n width: 100%;\n}\n\n.igv-column-shim {\n width: 1px;\n margin-left: 2px;\n margin-right: 2px;\n background-color: #545453;\n}\n\n.igv-column {\n position: relative;\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-axis-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 50px;\n}\n.igv-axis-column > div {\n margin-top: 5px;\n width: 100%;\n}\n\n.igv-sample-name-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n}\n\n.igv-scrollbar-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 14px;\n}\n.igv-scrollbar-column > div {\n position: relative;\n margin-top: 5px;\n width: 14px;\n}\n.igv-scrollbar-column > div > div {\n cursor: pointer;\n position: absolute;\n top: 0;\n left: 2px;\n width: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: #c4c4c4;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.igv-scrollbar-column > div > div:hover {\n background-color: #c4c4c4;\n}\n\n.igv-track-drag-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 12px;\n background-color: white;\n}\n.igv-track-drag-column > .igv-track-drag-handle {\n z-index: 512;\n position: relative;\n cursor: pointer;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n background-color: #c4c4c4;\n}\n.igv-track-drag-column .igv-track-drag-handle-hover {\n background-color: #787878;\n}\n.igv-track-drag-column > .igv-track-drag-shim {\n position: relative;\n margin-top: 5px;\n width: 100%;\n border-style: solid;\n border-width: 0;\n}\n\n.igv-gear-menu-column {\n position: relative;\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: flex-start;\n box-sizing: border-box;\n height: 100%;\n width: 28px;\n}\n.igv-gear-menu-column > div {\n display: flex;\n flex-direction: column;\n flex-wrap: nowrap;\n justify-content: flex-start;\n align-items: center;\n margin-top: 5px;\n width: 100%;\n background: white;\n}\n.igv-gear-menu-column > div > div {\n position: relative;\n margin-top: 4px;\n width: 16px;\n height: 16px;\n color: #7F7F7F;\n}\n.igv-gear-menu-column > div > div:hover {\n cursor: pointer;\n color: #444;\n}\n\n/*# sourceMappingURL=dom.css.map */\n';
|
|
62732
62847
|
var style = document.createElement('style');
|
|
62733
62848
|
style.setAttribute('type', 'text/css');
|
|
62734
62849
|
style.innerHTML = css;
|
|
@@ -62759,7 +62874,8 @@
|
|
|
62759
62874
|
version: version$1,
|
|
62760
62875
|
setApiKey,
|
|
62761
62876
|
doAutoscale,
|
|
62762
|
-
TrackView
|
|
62877
|
+
TrackView,
|
|
62878
|
+
GenomeUtils
|
|
62763
62879
|
};
|
|
62764
62880
|
|
|
62765
62881
|
return index;
|