igv-rails 1.0.1.1 → 1.0.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9b14b36ca912ca0d14b709224cbdf18392e12ff9
4
- data.tar.gz: 7550d6da08e32f6455c11d4eb90e1d719982d32d
3
+ metadata.gz: 76161467f05802730c2f1f2076a7d6de438fc135
4
+ data.tar.gz: 6bf22fd3d74470c663a0c9b9b7bae0c56a1f7955
5
5
  SHA512:
6
- metadata.gz: 284238238869906313d826a90ac393f0b8cb242baae31b4fdf23796c9ce79dcc54fe34aeab4e333fe101db41274c201e6fd23883220d267ebcadc9bef1ca8cf1
7
- data.tar.gz: 06fbe6125b6a60dfccc217d0ce3913f843947ca855753b0b29afd660fa7d0f190195a5f04d5b9491886287c8dcd1e7a397630012d718c90dc34d5d883cd379fd
6
+ metadata.gz: 3b4e7cec64c16cc4dfa1e8cd7c39a322217b374e0d8dfd19723226db3d465db1297bb28be0b42b246f99f4b573ba340702cbc9c8e8fbe558063cb13100ce85dc
7
+ data.tar.gz: 0590b833c50d84ab96b00e8dbec3ce6382b4c6c1c96301485688d8fb509a9f0cc465ef9edd620d6b0bafba6567fc69da7631e04687afd952100aa786d33cd64a
data/README.md CHANGED
@@ -89,9 +89,9 @@ This is [igv-web](https://www.broadinstitute.org/software/igv/home) GEMified for
89
89
  bundle gem igv-rails
90
90
  cd igv-rails
91
91
  mkdir -p vendor/assets/javascripts
92
- curl http://igv.org/web/release/1.0.1/igv-1.0.1.js -o vendor/assets/javascripts/igv.js
92
+ curl http://igv.org/web/release/1.0.9/igv-1.0.9.js -o vendor/assets/javascripts/igv.js
93
93
  mkdir -p vendor/assets/stylesheets
94
- curl http://igv.org/web/release/1.0.1/igv-1.0.1.css -o vendor/assets/stylesheets/igv.css
94
+ curl http://igv.org/web/release/1.0.9/igv-1.0.9.css -o vendor/assets/stylesheets/igv.css
95
95
  echo "" >> README.md; echo "# igv appended README #" >> README.md; echo "" >> README.md
96
96
  curl https://github.com/broadinstitute/igv-web/blob/master/README.md >> README.md
97
97
  echo "" >> LICENSE; echo "# igv appended LICENSE #" >> LICENSE; echo "" >> LICENSE
@@ -102,7 +102,7 @@ This is [igv-web](https://www.broadinstitute.org/software/igv/home) GEMified for
102
102
 
103
103
  * modify **lib/igv/rails/version.rb** to match igv-all.js version
104
104
 
105
- VERSION = "1.0.0.*"
105
+ VERSION = "1.0.9.*"
106
106
 
107
107
  * modify **lib/igv/rails.rb** to subclass Rails::Engine
108
108
 
@@ -1,5 +1,5 @@
1
1
  module Igv
2
2
  module Rails
3
- VERSION = "1.0.1.1"
3
+ VERSION = "1.0.9.1"
4
4
  end
5
5
  end
@@ -25,8 +25,7 @@
25
25
  */
26
26
 
27
27
  var igv = (function (igv) {
28
-
29
- var downSample = true;
28
+
30
29
 
31
30
  function canBePaired(alignment) {
32
31
  return alignment.isPaired() &&
@@ -49,9 +48,7 @@ var igv = (function (igv) {
49
48
  this.downsampledIntervals = [];
50
49
 
51
50
  this.samplingWindowSize = samplingWindowSize === undefined ? 100 : samplingWindowSize;
52
- this.samplingDepth = downSample ?
53
- samplingDepth === undefined ? 50 : samplingDepth :
54
- Number.MAX_VALUE;
51
+ this.samplingDepth = samplingDepth === undefined ? 50 : samplingDepth;
55
52
 
56
53
  this.pairsSupported = pairsSupported;
57
54
  this.paired = false; // false until proven otherwise
@@ -59,9 +56,7 @@ var igv = (function (igv) {
59
56
 
60
57
  this.downsampledReads = new Set();
61
58
 
62
- this.currentBucket = downSample ?
63
- new DownsampleBucket(this.start, this.start + this.samplingWindowSize, this) :
64
- new DownsampleBucket(this.start, Number.MAX_VALUE, this);
59
+ this.currentBucket = new DownsampleBucket(this.start, this.start + this.samplingWindowSize, this);
65
60
 
66
61
  this.filter = function filter(alignment) { // TODO -- pass this in
67
62
  return alignment.isMapped() && !alignment.isFailsVendorQualityCheck();
@@ -213,6 +208,7 @@ var igv = (function (igv) {
213
208
  }
214
209
 
215
210
 
211
+ // TODO -- refactor this to use an object, rather than an array, if end-start is > some threshold
216
212
  function CoverageMap(chr, start, end) {
217
213
 
218
214
  this.chr = chr;
@@ -547,7 +543,7 @@ var igv = (function (igv) {
547
543
  nameValues.push("<hr>");
548
544
  nameValues.push({ name: 'First in Pair', value: !this.isSecondOfPair(), borderTop: true });
549
545
  nameValues.push({ name: 'Mate is Mapped', value: yesNo(this.isMateMapped()) });
550
- if (this.isMapped()) {
546
+ if (this.isMateMapped()) {
551
547
  nameValues.push({ name: 'Mate Chromosome', value: this.mate.chr });
552
548
  nameValues.push({ name: 'Mate Start', value: (this.mate.position + 1)});
553
549
  nameValues.push({ name: 'Mate Strand', value: (true === this.mate.strand ? '(+)' : '(-)')});
@@ -813,64 +809,75 @@ var igv = (function (igv) {
813
809
  withCredentials: config.withCredentials
814
810
  }).then(function (arrayBuffer) {
815
811
 
816
- var indices = [],
817
- magic, nbin, nintv, nref, parser,
818
- blockMin = Number.MAX_VALUE,
819
- blockMax = 0,
820
- binIndex, linearIndex, binNumber, cs, ce, b, i, ref, sequenceIndexMap;
821
-
822
- if (!arrayBuffer) {
823
- fulfill(null);
824
- return;
825
- }
812
+ var indices = [],
813
+ magic, nbin, nintv, nref, parser,
814
+ blockMin = Number.MAX_VALUE,
815
+ blockMax = 0,
816
+ binIndex, linearIndex, binNumber, cs, ce, b, i, ref, sequenceIndexMap;
826
817
 
827
- if (tabix) {
828
- var inflate = new Zlib.Gunzip(new Uint8Array(arrayBuffer));
829
- arrayBuffer = inflate.decompress().buffer;
830
- }
818
+ if (!arrayBuffer) {
819
+ fulfill(null);
820
+ return;
821
+ }
831
822
 
832
- parser = new igv.BinaryParser(new DataView(arrayBuffer));
823
+ if (tabix) {
824
+ var inflate = new Zlib.Gunzip(new Uint8Array(arrayBuffer));
825
+ arrayBuffer = inflate.decompress().buffer;
826
+ }
833
827
 
834
- magic = parser.getInt();
828
+ parser = new igv.BinaryParser(new DataView(arrayBuffer));
835
829
 
836
- if (magic === BAI_MAGIC || (tabix && magic === TABIX_MAGIC)) {
830
+ magic = parser.getInt();
837
831
 
838
- nref = parser.getInt();
832
+ if (magic === BAI_MAGIC || (tabix && magic === TABIX_MAGIC)) {
839
833
 
834
+ nref = parser.getInt();
840
835
 
841
- if (tabix) {
842
- // Tabix header parameters aren't used, but they must be read to advance the pointer
843
- var format = parser.getInt();
844
- var col_seq = parser.getInt();
845
- var col_beg = parser.getInt();
846
- var col_end = parser.getInt();
847
- var meta = parser.getInt();
848
- var skip = parser.getInt();
849
- var l_nm = parser.getInt();
850
836
 
851
- sequenceIndexMap = {};
852
- for (i = 0; i < nref; i++) {
853
- var seq_name = parser.getString();
837
+ if (tabix) {
838
+ // Tabix header parameters aren't used, but they must be read to advance the pointer
839
+ var format = parser.getInt();
840
+ var col_seq = parser.getInt();
841
+ var col_beg = parser.getInt();
842
+ var col_end = parser.getInt();
843
+ var meta = parser.getInt();
844
+ var skip = parser.getInt();
845
+ var l_nm = parser.getInt();
846
+
847
+ sequenceIndexMap = {};
848
+ for (i = 0; i < nref; i++) {
849
+ var seq_name = parser.getString();
850
+
851
+ // Translate to "official" chr name.
852
+ if (genome) seq_name = genome.getChromosomeName(seq_name);
853
+
854
+ sequenceIndexMap[seq_name] = i;
855
+ }
856
+ }
854
857
 
855
- // Translate to "official" chr name.
856
- if (genome) seq_name = genome.getChromosomeName(seq_name);
858
+ for (ref = 0; ref < nref; ++ref) {
857
859
 
858
- sequenceIndexMap[seq_name] = i;
859
- }
860
- }
860
+ binIndex = {};
861
+ linearIndex = [];
861
862
 
862
- for (ref = 0; ref < nref; ++ref) {
863
+ nbin = parser.getInt();
863
864
 
864
- binIndex = {};
865
- linearIndex = [];
865
+ for (b = 0; b < nbin; ++b) {
866
866
 
867
- nbin = parser.getInt();
867
+ binNumber = parser.getInt();
868
868
 
869
- for (b = 0; b < nbin; ++b) {
869
+ if (binNumber == 37450) {
870
+ // This is a psuedo bin, not used but we have to consume the bytes
871
+ nchnk = parser.getInt(); // # of chunks for this bin
872
+ cs = parser.getVPointer(); // unmapped beg
873
+ ce = parser.getVPointer(); // unmapped end
874
+ var n_maped = parser.getLong();
875
+ var nUnmapped = parser.getLong();
870
876
 
871
- binNumber = parser.getInt();
877
+ }
878
+ else {
879
+
872
880
  binIndex[binNumber] = [];
873
-
874
881
  var nchnk = parser.getInt(); // # of chunks for this bin
875
882
 
876
883
  for (i = 0; i < nchnk; i++) {
@@ -887,37 +894,37 @@ var igv = (function (igv) {
887
894
  }
888
895
  }
889
896
  }
897
+ }
890
898
 
891
899
 
892
- nintv = parser.getInt();
893
- for (i = 0; i < nintv; i++) {
894
- cs = parser.getVPointer();
895
- linearIndex.push(cs); // Might be null
896
- }
900
+ nintv = parser.getInt();
901
+ for (i = 0; i < nintv; i++) {
902
+ cs = parser.getVPointer();
903
+ linearIndex.push(cs); // Might be null
904
+ }
897
905
 
898
- if (nbin > 0) {
899
- indices[ref] = {
900
- binIndex: binIndex,
901
- linearIndex: linearIndex
902
- }
906
+ if (nbin > 0) {
907
+ indices[ref] = {
908
+ binIndex: binIndex,
909
+ linearIndex: linearIndex
903
910
  }
904
911
  }
905
-
906
- } else {
907
- throw new Error(indexURL + " is not a " + (tabix ? "tabix" : "bai") + " file");
908
912
  }
909
- fulfill(new igv.BamIndex(indices, blockMin, blockMax, sequenceIndexMap, tabix));
910
- }).catch(reject);
913
+
914
+ } else {
915
+ throw new Error(indexURL + " is not a " + (tabix ? "tabix" : "bai") + " file");
916
+ }
917
+ fulfill(new igv.BamIndex(indices, blockMin, sequenceIndexMap, tabix));
918
+ }).catch(reject);
911
919
  })
912
920
  }
913
921
 
914
922
 
915
- igv.BamIndex = function (indices, headerSize, blockMax, sequenceIndexMap, tabix) {
916
- this.headerSize = headerSize;
923
+ igv.BamIndex = function (indices, blockMin, sequenceIndexMap, tabix) {
924
+ this.firstAlignmentBlock = blockMin;
917
925
  this.indices = indices;
918
926
  this.sequenceIndexMap = sequenceIndexMap;
919
927
  this.tabix = tabix;
920
- this.blockMax = blockMax;
921
928
 
922
929
  }
923
930
 
@@ -972,7 +979,7 @@ var igv = (function (igv) {
972
979
  }
973
980
  });
974
981
 
975
- // Use the linear index to find the lowest block that could contain alignments in the region
982
+ // Use the linear index to find the lowest chunk that could contain alignments in the region
976
983
  nintv = ba.linearIndex.length;
977
984
  lowest = null;
978
985
  minLin = Math.min(min >> 14, nintv - 1), maxLin = Math.min(max >> 14, nintv - 1);
@@ -986,12 +993,12 @@ var igv = (function (igv) {
986
993
  }
987
994
  }
988
995
 
989
- // Prune chunks that end before the lowest block
996
+ // Prune chunks that end before the lowest chunk
990
997
  prunedOtherChunks = [];
991
998
  if (lowest != null) {
992
999
  for (i = 0; i < otherChunks.length; ++i) {
993
1000
  chnk = otherChunks[i];
994
- if (chnk.maxv.block >= lowest.block && chnk.maxv.offset >= lowest.offset) {
1001
+ if (chnk.maxv.block > lowest.block || (chnk.maxv.block == lowest.block && chnk.maxv.offset >= lowest.offset)) {
995
1002
  prunedOtherChunks.push(chnk);
996
1003
  }
997
1004
  }
@@ -1066,12 +1073,6 @@ var igv = (function (igv) {
1066
1073
  var CIGAR_DECODER = ['M', 'I', 'D', 'N', 'S', 'H', 'P', '=', 'X', '?', '?', '?', '?', '?', '?', '?'];
1067
1074
  var READ_STRAND_FLAG = 0x10;
1068
1075
  var MATE_STRAND_FLAG = 0x20;
1069
- var READ_PAIRED_FLAG = 0x1;
1070
- var PROPER_PAIR_FLAG = 0x2;
1071
- var READ_UNMAPPED_FLAG = 0x4;
1072
- var MATE_UNMAPPED_FLAG = 0x8;
1073
- var READ_STRAND_FLAG = 0x10;
1074
- var MATE_STRAND_FLAG = 0x20;
1075
1076
  var FIRST_OF_PAIR_FLAG = 0x40;
1076
1077
  var SECOND_OF_PAIR_FLAG = 0x80;
1077
1078
  var NOT_PRIMARY_ALIGNMENT_FLAG = 0x100;
@@ -1079,8 +1080,10 @@ var igv = (function (igv) {
1079
1080
  var DUPLICATE_READ_FLAG = 0x400;
1080
1081
  var SUPPLEMENTARY_FLAG = 0x800;
1081
1082
 
1082
- const MAX_GZIP_BLOCK_SIZE = (1 << 16); // APPARENTLY. Where is this documented???
1083
-
1083
+ const MAX_GZIP_BLOCK_SIZE = 65536; // APPARENTLY. Where is this documented???
1084
+ const DEFAULT_SAMPLING_WINDOW_SIZE = 100;
1085
+ const DEFAULT_SAMPLING_DEPTH = 50;
1086
+ const MAXIMUM_SAMPLING_DEPTH = 2500;
1084
1087
 
1085
1088
  /**
1086
1089
  * Class for reading a bam file
@@ -1094,17 +1097,18 @@ var igv = (function (igv) {
1094
1097
 
1095
1098
  this.filter = config.filter || new igv.BamFilter();
1096
1099
 
1097
- this.bamPath = 'gcs' === config.sourceType ?
1098
- igv.translateGoogleCloudURL(config.url) :
1099
- config.url;
1100
- this.baiPath = 'gcs' === config.sourceType ?
1101
- igv.translateGoogleCloudURL(config.url + ".bai") :
1102
- config.url + ".bai"; // Todo - deal with Picard convention. WHY DOES THERE HAVE TO BE 2?
1103
- this.baiPath = config.indexURL || this.baiPath; // If there is an indexURL provided, use it!
1100
+ this.bamPath = config.url;
1101
+ // Todo - deal with Picard convention. WHY DOES THERE HAVE TO BE 2?
1102
+ this.baiPath = config.indexURL || this.bamPath + ".bai"; // If there is an indexURL provided, use it!
1104
1103
  this.headPath = config.headURL || this.bamPath;
1105
1104
 
1106
- this.samplingWindowSize = config.samplingWindowSize === undefined ? 100 : config.samplingWindowSize;
1107
- this.samplingDepth = config.samplingDepth === undefined ? 50 : config.samplingDepth;
1105
+
1106
+ this.samplingWindowSize = config.samplingWindowSize === undefined ? DEFAULT_SAMPLING_WINDOW_SIZE : config.samplingWindowSize;
1107
+ this.samplingDepth = config.samplingDepth === undefined ? DEFAULT_SAMPLING_DEPTH : config.samplingDepth;
1108
+ if(this.samplingDepth > MAXIMUM_SAMPLING_DEPTH) {
1109
+ igv.log("Warning: attempt to set sampling depth > maximum value of 2500");
1110
+ this.samplingDepth = MAXIMUM_SAMPLING_DEPTH;
1111
+ }
1108
1112
 
1109
1113
  if (config.viewAsPairs) {
1110
1114
  this.pairsSupported = true;
@@ -1147,17 +1151,14 @@ var igv = (function (igv) {
1147
1151
  fulfill(alignmentContainer);
1148
1152
  return;
1149
1153
  }
1150
- //console.log("# chunks = " + chunks.length);
1154
+
1151
1155
  chunks.forEach(function (c) {
1152
1156
 
1153
1157
  promises.push(new Promise(function (fulfill, reject) {
1154
1158
 
1155
1159
  var fetchMin = c.minv.block,
1156
- fetchMax = c.maxv.block + 65000, // Make sure we get the whole block.
1157
- range =
1158
- (self.contentLength > 0 && fetchMax > self.contentLength) ?
1159
- {start: fetchMin} :
1160
- {start: fetchMin, size: fetchMax - fetchMin + 1};
1160
+ fetchMax = c.maxv.block + MAX_GZIP_BLOCK_SIZE, // Make sure we get the whole block.
1161
+ range = {start: fetchMin, size: fetchMax - fetchMin + 1};
1161
1162
 
1162
1163
  igvxhr.loadArrayBuffer(self.bamPath,
1163
1164
  {
@@ -1166,30 +1167,20 @@ var igv = (function (igv) {
1166
1167
  withCredentials: self.config.withCredentials
1167
1168
  }).then(function (compressed) {
1168
1169
 
1169
- var ba = new Uint8Array(igv.unbgzf(compressed)); //new Uint8Array(igv.unbgzf(compressed)); //, c.maxv.block - c.minv.block + 1));
1170
- decodeBamRecords(ba, c.minv.offset, alignmentContainer, bpStart, bpEnd, chrId, self.filter);
1170
+ var ba = new Uint8Array(igv.unbgzf(compressed)); //new Uint8Array(igv.unbgzf(compressed)); //, c.maxv.block - c.minv.block + 1));
1171
+ decodeBamRecords(ba, c.minv.offset, alignmentContainer, bpStart, bpEnd, chrId, self.filter);
1171
1172
 
1172
- fulfill(alignmentContainer);
1173
+ fulfill(alignmentContainer);
1173
1174
 
1174
- }).catch(function (obj) {
1175
- reject(obj);
1176
- });
1175
+ }).catch(function (obj) {
1176
+ reject(obj);
1177
+ });
1177
1178
 
1178
1179
  }))
1179
1180
  });
1180
1181
 
1181
1182
 
1182
1183
  Promise.all(promises).then(function (ignored) {
1183
-
1184
- //if (chunks.length > 1) {
1185
- // alignments.sort(function (a, b) {
1186
- // return a.start - b.start;
1187
- // });
1188
- //}
1189
- //var alignmentContainer = new igv.AlignmentContainer(chr, bpStart, bpEnd, self.samplingWindowSize, self.samplingDepth);
1190
- //alignments.forEach(function (a) {
1191
- // alignmentContainer.push(a);
1192
- //})
1193
1184
  alignmentContainer.finish();
1194
1185
  fulfill(alignmentContainer);
1195
1186
  }).catch(function (obj) {
@@ -1201,7 +1192,7 @@ var igv = (function (igv) {
1201
1192
  });
1202
1193
 
1203
1194
 
1204
- function decodeBamRecords(ba, offset, alignments, min, max, chrId, filter) {
1195
+ function decodeBamRecords(ba, offset, alignmentContainer, min, max, chrId, filter) {
1205
1196
 
1206
1197
  var blockSize,
1207
1198
  blockEnd,
@@ -1234,7 +1225,7 @@ var igv = (function (igv) {
1234
1225
  blockSize = readInt(ba, offset);
1235
1226
  blockEnd = offset + blockSize + 4;
1236
1227
 
1237
- if (blockEnd >= ba.length) {
1228
+ if (blockEnd > ba.length) {
1238
1229
  return;
1239
1230
  }
1240
1231
 
@@ -1243,8 +1234,15 @@ var igv = (function (igv) {
1243
1234
  refID = readInt(ba, offset + 4);
1244
1235
  pos = readInt(ba, offset + 8);
1245
1236
 
1246
- if (refID > chrId || pos > max) return; // We've gone off the right edge => we're done
1247
- else if (refID < chrId) continue; // Not sure this is possible
1237
+ if(refID < 0) {
1238
+ return; // unmapped reads
1239
+ }
1240
+ else if (refID > chrId || pos > max) {
1241
+ return; // off right edge, we're done
1242
+ }
1243
+ else if (refID < chrId) {
1244
+ continue; // to left of start, not sure this is possible
1245
+ }
1248
1246
 
1249
1247
  bmn = readInt(ba, offset + 12);
1250
1248
  bin = (bmn & 0xffff0000) >> 16;
@@ -1342,7 +1340,7 @@ var igv = (function (igv) {
1342
1340
  blocks = makeBlocks(alignment, cigarArray);
1343
1341
  alignment.blocks = blocks.blocks;
1344
1342
  alignment.insertions = blocks.insertions;
1345
- alignments.push(alignment);
1343
+ alignmentContainer.push(alignment);
1346
1344
  }
1347
1345
  }
1348
1346
  offset = blockEnd;
@@ -1434,14 +1432,7 @@ var igv = (function (igv) {
1434
1432
 
1435
1433
  getIndex(self).then(function (index) {
1436
1434
 
1437
- var contentLength = index.blockMax,
1438
- len = index.headerSize + MAX_GZIP_BLOCK_SIZE + 100; // Insure we get the complete compressed block containing the header
1439
-
1440
- if (contentLength <= 0) contentLength = index.blockMax; // Approximate
1441
-
1442
- self.contentLength = contentLength;
1443
-
1444
- if (contentLength > 0) len = Math.min(contentLength, len);
1435
+ var len = index.firstAlignmentBlock + MAX_GZIP_BLOCK_SIZE; // Insure we get the complete compressed block containing the header
1445
1436
 
1446
1437
  igvxhr.loadArrayBuffer(self.bamPath,
1447
1438
  {
@@ -1452,49 +1443,49 @@ var igv = (function (igv) {
1452
1443
  withCredentials: self.config.withCredentials
1453
1444
  }).then(function (compressedBuffer) {
1454
1445
 
1455
- var unc = igv.unbgzf(compressedBuffer, len),
1456
- uncba = new Uint8Array(unc),
1457
- magic = readInt(uncba, 0),
1458
- samHeaderLen = readInt(uncba, 4),
1459
- samHeader = '',
1460
- genome = igv.browser ? igv.browser.genome : null;
1446
+ var unc = igv.unbgzf(compressedBuffer, len),
1447
+ uncba = new Uint8Array(unc),
1448
+ magic = readInt(uncba, 0),
1449
+ samHeaderLen = readInt(uncba, 4),
1450
+ samHeader = '',
1451
+ genome = igv.browser ? igv.browser.genome : null;
1461
1452
 
1462
- for (var i = 0; i < samHeaderLen; ++i) {
1463
- samHeader += String.fromCharCode(uncba[i + 8]);
1464
- }
1453
+ for (var i = 0; i < samHeaderLen; ++i) {
1454
+ samHeader += String.fromCharCode(uncba[i + 8]);
1455
+ }
1465
1456
 
1466
- var nRef = readInt(uncba, samHeaderLen + 8);
1467
- var p = samHeaderLen + 12;
1457
+ var nRef = readInt(uncba, samHeaderLen + 8);
1458
+ var p = samHeaderLen + 12;
1468
1459
 
1469
- self.chrToIndex = {};
1470
- self.indexToChr = [];
1471
- for (var i = 0; i < nRef; ++i) {
1472
- var lName = readInt(uncba, p);
1473
- var name = '';
1474
- for (var j = 0; j < lName - 1; ++j) {
1475
- name += String.fromCharCode(uncba[p + 4 + j]);
1476
- }
1477
- var lRef = readInt(uncba, p + lName + 4);
1478
- //dlog(name + ': ' + lRef);
1460
+ self.chrToIndex = {};
1461
+ self.indexToChr = [];
1462
+ for (var i = 0; i < nRef; ++i) {
1463
+ var lName = readInt(uncba, p);
1464
+ var name = '';
1465
+ for (var j = 0; j < lName - 1; ++j) {
1466
+ name += String.fromCharCode(uncba[p + 4 + j]);
1467
+ }
1468
+ var lRef = readInt(uncba, p + lName + 4);
1469
+ //dlog(name + ': ' + lRef);
1479
1470
 
1480
- if (genome && genome.getChromosomeName) {
1481
- name = genome.getChromosomeName(name);
1482
- }
1471
+ if (genome && genome.getChromosomeName) {
1472
+ name = genome.getChromosomeName(name);
1473
+ }
1483
1474
 
1484
- self.chrToIndex[name] = i;
1485
- self.indexToChr.push(name);
1475
+ self.chrToIndex[name] = i;
1476
+ self.indexToChr.push(name);
1486
1477
 
1487
- p = p + 8 + lName;
1488
- }
1478
+ p = p + 8 + lName;
1479
+ }
1489
1480
 
1490
- fulfill();
1481
+ fulfill();
1491
1482
 
1492
- }).catch(reject);
1483
+ }).catch(reject);
1493
1484
  }).catch(reject);
1494
1485
  });
1495
1486
  }
1496
1487
 
1497
-
1488
+ //
1498
1489
  function getIndex(bam) {
1499
1490
 
1500
1491
  return new Promise(function (fulfill, reject) {
@@ -1506,9 +1497,6 @@ var igv = (function (igv) {
1506
1497
  igv.loadBamIndex(bam.baiPath, bam.config).then(function (index) {
1507
1498
  bam.index = index;
1508
1499
 
1509
- // Content length TODO -- is this exact or approximate?
1510
- bam.contentLength = index.blockMax;
1511
-
1512
1500
  fulfill(bam.index);
1513
1501
  }).catch(reject);
1514
1502
  }
@@ -1833,7 +1821,7 @@ var igv = (function (igv) {
1833
1821
  var alignmentRowYInset = 0;
1834
1822
  var alignmentStartGap = 5;
1835
1823
  var downsampleRowHeight = 5;
1836
-
1824
+ const DEFAULT_COVERAGE_TRACK_HEIGHT = 50;
1837
1825
 
1838
1826
  igv.BAMTrack = function (config) {
1839
1827
 
@@ -1841,6 +1829,10 @@ var igv = (function (igv) {
1841
1829
 
1842
1830
  igv.configTrack(this, config);
1843
1831
 
1832
+ if(config.coverageTrackHeight === undefined) {
1833
+ config.coverageTrackHeight = DEFAULT_COVERAGE_TRACK_HEIGHT;
1834
+ }
1835
+
1844
1836
  this.coverageTrack = new CoverageTrack(config, this);
1845
1837
 
1846
1838
  this.alignmentTrack = new AlignmentTrack(config, this);
@@ -1925,7 +1917,9 @@ var igv = (function (igv) {
1925
1917
 
1926
1918
  igv.BAMTrack.prototype.draw = function (options) {
1927
1919
 
1928
- this.coverageTrack.draw(options);
1920
+ if(this.coverageTrack.height > 0) {
1921
+ this.coverageTrack.draw(options);
1922
+ }
1929
1923
 
1930
1924
  this.alignmentTrack.draw(options);
1931
1925
  };
@@ -2112,7 +2106,9 @@ var igv = (function (igv) {
2112
2106
  this.parent = parent;
2113
2107
  this.featureSource = parent.featureSource;
2114
2108
  this.top = 0;
2115
- this.height = 50;
2109
+
2110
+
2111
+ this.height = config.coverageTrackHeight;
2116
2112
  this.dataRange = {min: 0}; // Leav max undefined
2117
2113
  this.paintAxis = igv.paintAxis;
2118
2114
  }
@@ -2270,7 +2266,7 @@ var igv = (function (igv) {
2270
2266
 
2271
2267
  this.parent = parent;
2272
2268
  this.featureSource = parent.featureSource;
2273
- this.top = config.coverageTrackHeight + 5 || 55;
2269
+ this.top = config.coverageTrackHeight == 0 ? 0 : config.coverageTrackHeight + 5;
2274
2270
  this.alignmentRowHeight = config.alignmentRowHeight || 14;
2275
2271
 
2276
2272
  this.negStrandColor = config.negStrandColor || "rgba(150, 150, 230, 0.75)";
@@ -2709,26 +2705,21 @@ var igv = (function (igv) {
2709
2705
  })
2710
2706
  (igv || {});
2711
2707
 
2712
-
2713
-
2714
-
2715
2708
  var igv = (function (igv) {
2716
2709
 
2717
- /**
2718
- * @param url - url to a bgzipped file
2719
- * @param headers - http headers to include in get requests
2720
- * @constructor
2721
- */
2722
- igv.BGZip = function (url, headers) {
2723
-
2724
- }
2725
-
2710
+ var BLOCK_HEADER_LENGTH = 18;
2711
+ var BLOCK_LENGTH_OFFSET = 16; // Location in the gzip block of the total block size (actually total block size - 1)
2712
+ var BLOCK_FOOTER_LENGTH = 8; // Number of bytes that follow the deflated data
2713
+ var MAX_COMPRESSED_BLOCK_SIZE = 64 * 1024; // We require that a compressed block (including header and footer, be <= this)
2714
+ var GZIP_OVERHEAD = BLOCK_HEADER_LENGTH + BLOCK_FOOTER_LENGTH + 2; // Gzip overhead is the header, the footer, and the block size (encoded as a short).
2715
+ var GZIP_ID1 = 31; // Magic number
2716
+ var GZIP_ID2 = 139; // Magic number
2717
+ var GZIP_FLG = 4; // FEXTRA flag means there are optional fields
2726
2718
 
2727
2719
 
2728
-
2729
- // Uncompress data, assumed to be series of bgzipped blocks
2730
- // Code is based heavily on bam.js, part of the Dalliance Genome Explorer, (c) Thomas Down 2006-2001.
2731
- igv.unbgzf = function(data, lim) {
2720
+ // Uncompress data, assumed to be series of bgzipped blocks
2721
+ // Code is based heavily on bam.js, part of the Dalliance Genome Explorer, (c) Thomas Down 2006-2001.
2722
+ igv.unbgzf = function (data, lim) {
2732
2723
 
2733
2724
  var oBlockList = [],
2734
2725
  ptr = [0],
@@ -2775,6 +2766,57 @@ var igv = (function (igv) {
2775
2766
  }
2776
2767
 
2777
2768
 
2769
+
2770
+ igv.BGZFile = function (config) {
2771
+ this.filePosition = 0;
2772
+ this.config = config;
2773
+ }
2774
+
2775
+ igv.BGZFile.prototype.nextBlock = function () {
2776
+
2777
+ var self = this;
2778
+
2779
+ return new Promise(function (fulfill, reject) {
2780
+
2781
+ igvxhr.loadArrayBuffer(self.path,
2782
+ {
2783
+ headers: self.config.headers,
2784
+ range: {start: self.filePosition, size: BLOCK_HEADER_LENGTH},
2785
+ withCredentials: self.config.withCredentials
2786
+
2787
+ }).then(function (arrayBuffer) {
2788
+
2789
+ var ba = new Uint8Array(arrayBuffer);
2790
+ var xlen = (ba[11] << 8) | (ba[10]);
2791
+ var si1 = ba[12];
2792
+ var si2 = ba[13];
2793
+ var slen = (ba[15] << 8) | (ba[14]);
2794
+ var bsize = (ba[17] << 8) | (ba[16]) + 1;
2795
+
2796
+ self.filePosition += BLOCK_HEADER_LENGTH;
2797
+
2798
+ igvxhr.loadArrayBuffer(self.path, {
2799
+ headers: self.config.headers,
2800
+ range: {start: self.filePosition, size: bsize},
2801
+ withCredentials: self.config.withCredentials
2802
+
2803
+ }).then(function (arrayBuffer) {
2804
+
2805
+ var unc = jszlib_inflate_buffer(arrayBuffer);
2806
+
2807
+ self.filePosition += (bsize + 8); // "8" for CRC-32 and size of uncompressed data
2808
+
2809
+ fulfill(unc);
2810
+
2811
+ }).catch(reject)
2812
+ }).catch(reject);
2813
+ })
2814
+
2815
+ }
2816
+
2817
+
2818
+
2819
+
2778
2820
  return igv;
2779
2821
 
2780
2822
  })(igv || {});
@@ -3015,243 +3057,6 @@ var igv = (function (igv) {
3015
3057
  }
3016
3058
 
3017
3059
 
3018
- return igv;
3019
-
3020
- })(igv || {});
3021
- /*
3022
- * The MIT License (MIT)
3023
- *
3024
- * Copyright (c) 2016 University of California San Diego
3025
- * Author: Jim Robinson
3026
- *
3027
- * Permission is hereby granted, free of charge, to any person obtaining a copy
3028
- * of this software and associated documentation files (the "Software"), to deal
3029
- * in the Software without restriction, including without limitation the rights
3030
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
3031
- * copies of the Software, and to permit persons to whom the Software is
3032
- * furnished to do so, subject to the following conditions:
3033
- *
3034
- * The above copyright notice and this permission notice shall be included in
3035
- * all copies or substantial portions of the Software.
3036
- *
3037
- *
3038
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
3039
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
3040
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
3041
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
3042
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3043
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
3044
- * THE SOFTWARE.
3045
- */
3046
-
3047
- var igv = (function (igv) {
3048
-
3049
-
3050
- igv.BigQueryFeatureReader = function (config) {
3051
-
3052
- // Harcoded for seg features for now
3053
- this.projectId = 'isb-cgc-03-0001';
3054
- this.decode = decodeSeg;
3055
- this.cohort = config.cohort
3056
-
3057
- }
3058
-
3059
- //SELECT ParticipantBarcode FROM [isb-cgc:tcga_201510_alpha.Clinical_data] WHERE Study = \"" + this.study + "\")
3060
-
3061
- igv.BigQueryFeatureReader.prototype.allSamples = function () {
3062
-
3063
- var q = "SELECT UNIQUE(AliquotBarcode) FROM [isb-cgc:tcga_201510_alpha.Copy_Number_segments] WHERE " +
3064
- " ParticipantBarcode IN (" + this.cohort + ")";
3065
-
3066
- return igv.bigQuery(
3067
- {
3068
- projectId: this.projectId,
3069
- queryString: q,
3070
- decode: decodeSample
3071
- });
3072
-
3073
- }
3074
-
3075
- igv.BigQueryFeatureReader.prototype.readFeatures = function (chr, bpStart, bpEnd) {
3076
-
3077
- var c = chr.startsWith("chr") ? chr.substring(3) : chr,
3078
- q = "SELECT * FROM [isb-cgc:tcga_201510_alpha.Copy_Number_segments]" +
3079
- " WHERE " +
3080
- " ParticipantBarcode IN (" + this.cohort + ") " +
3081
- " AND Chromosome = \"" + c + "\" " +
3082
- " AND Start >= " + bpStart + " AND End <= " + bpEnd;
3083
-
3084
- return igv.bigQuery(
3085
- {
3086
- projectId: this.projectId,
3087
- queryString: q,
3088
- decode: decodeSeg
3089
- });
3090
-
3091
- }
3092
-
3093
-
3094
- igv.bigQuery = function (options) {
3095
-
3096
- return new Promise(function (fulfill, reject) {
3097
-
3098
- if (!options.projectId) {
3099
- //todo throw error
3100
- }
3101
-
3102
- var baseURL = options.baseURL || "https://www.googleapis.com/bigquery/v2/",
3103
- url = baseURL + "projects/" + options.projectId + "/queries",
3104
- body = {
3105
- "kind": "bigquery#queryRequest",
3106
- "query": options.queryString,
3107
- "maxResults": 1000,
3108
- "timeoutMs": 5000,
3109
- "dryRun": false,
3110
- "preserveNulls": true,
3111
- "useQueryCache": true
3112
- },
3113
- decode = options.decode,
3114
- apiKey = oauth.google.apiKey,
3115
- jobId,
3116
- paramSeparator = "&";
3117
-
3118
- url = url + "?alt=json";
3119
-
3120
- if (apiKey) {
3121
- url = url + paramSeparator + "key=" + apiKey;
3122
- }
3123
-
3124
- var sendData = JSON.stringify(body);
3125
-
3126
- igvxhr.loadJson(url,
3127
- {
3128
- sendData: sendData,
3129
- contentType: "application/json"
3130
- }).then(function (response) {
3131
-
3132
- var results = [],
3133
- totalRows,
3134
- jobId = response.jobReference.jobId;
3135
-
3136
-
3137
- if (response.jobComplete === true) {
3138
-
3139
- totalRows = parseInt(response.totalRows); // Google convention is to use strings for "long" types
3140
-
3141
- if (totalRows === 0) {
3142
- fulfill(results);
3143
- }
3144
- else {
3145
-
3146
- response.rows.forEach(function (row) {
3147
- results.push(decode(row));
3148
- });
3149
-
3150
- if (results.length < totalRows) {
3151
- getQueryResults(options);
3152
- }
3153
- else {
3154
- fulfill(results);
3155
- }
3156
- }
3157
- }
3158
- else {
3159
- setTimeout(function () {
3160
- getQueryResults(options);
3161
- }, 1000);
3162
- }
3163
-
3164
-
3165
- function getQueryResults(options) {
3166
-
3167
- var url = "https://clients6.google.com/bigquery/v2/projects/" + options.projectId + "/queries/" + jobId,
3168
- decode = options.decode,
3169
- success = options.success,
3170
- apiKey = oauth.google.apiKey,
3171
- paramSeparator = "&";
3172
-
3173
- url = url + "?alt=json"
3174
-
3175
- if (apiKey) {
3176
- url = url + paramSeparator + "key=" + apiKey;
3177
- }
3178
-
3179
- if (options.maxResults) {
3180
- url = url + "&maxResults=" + options.maxResults;
3181
- }
3182
-
3183
- if (results.length > 0) {
3184
- url = url + ("&startIndex=" + results.length);
3185
- }
3186
-
3187
- igvxhr.loadJson(url,
3188
- {
3189
- contentType: "application/json"
3190
- }).then(function (response) {
3191
-
3192
- if (response.jobComplete === true) {
3193
-
3194
- totalRows = response.totalRows;
3195
-
3196
- response.rows.forEach(function (row) {
3197
- results.push(decode(row));
3198
- });
3199
-
3200
- if (results.length < totalRows) {
3201
- getQueryResults(options);
3202
- }
3203
- else {
3204
- fulfill(results);
3205
- }
3206
-
3207
- }
3208
- else {
3209
- setTimeout(function () {
3210
- getQueryResults(options);
3211
- }, 1000);
3212
- }
3213
-
3214
- });
3215
-
3216
- }
3217
-
3218
- }).catch(reject);
3219
- });
3220
- }
3221
-
3222
-
3223
- /*
3224
- sample: tokens[sampleColumn],
3225
- chr: tokens[chrColumn],
3226
- start: parseInt(tokens[startColumn]),
3227
- end: parseInt(tokens[endColumn]),
3228
- value: parseFloat(tokens[dataColumn])
3229
- */
3230
-
3231
- function decodeSeg(row) {
3232
-
3233
- var seg = {};
3234
- seg["sample"] = row.f[3].v;
3235
- seg["Study"] = row.f[4].v;
3236
- seg["chr"] = row.f[6].v;
3237
- seg["start"] = row.f[7].v - 1;
3238
- seg["end"] = row.f[8].v;
3239
- seg["Num_Probes"] = row.f[9].v;
3240
- seg["value"] = row.f[10].v;
3241
- return seg;
3242
- }
3243
-
3244
-
3245
- function decodeStudy(row) {
3246
-
3247
- return row.f[0].v;
3248
- }
3249
-
3250
- function decodeSample(row) {
3251
- return row.f[0].v;
3252
- }
3253
-
3254
-
3255
3060
  return igv;
3256
3061
 
3257
3062
  })(igv || {});
@@ -3388,14 +3193,8 @@ var igv = (function (igv) {
3388
3193
  loadRange = {start: requestedRange.start, size: bufferSize};
3389
3194
  }
3390
3195
 
3391
- igvxhr.loadArrayBuffer(self.path,
3392
- {
3393
- headers: self.config.headers,
3394
- range: loadRange,
3395
- withCredentials: self.config.withCredentials
3396
- }).then(function (arrayBuffer) {
3397
- // TODO -- handle error
3398
-
3196
+ igvxhr.loadArrayBuffer(self.path, Object.assign(self.config, {range: loadRange}))
3197
+ .then(function (arrayBuffer) {
3399
3198
  self.data = arrayBuffer;
3400
3199
  self.range = loadRange;
3401
3200
  subbuffer(self, requestedRange, asUint8);
@@ -3421,6 +3220,7 @@ var igv = (function (igv) {
3421
3220
  return igv;
3422
3221
 
3423
3222
  })(igv || {});
3223
+
3424
3224
  /*
3425
3225
  * The MIT License (MIT)
3426
3226
  *
@@ -3458,11 +3258,11 @@ var igv = (function (igv) {
3458
3258
  var BPTREE_HEADER_SIZE = 32;
3459
3259
 
3460
3260
 
3461
- igv.BPTree = function (binaryParser, treeOffset) {
3261
+ igv.BPTree = function (binaryParser, startOffset) {
3462
3262
 
3463
- var genome = igv.browser ? igv.browser.genome : null;
3263
+ var self = this,
3264
+ genome = igv.browser ? igv.browser.genome : null;
3464
3265
 
3465
- this.treeOffset = treeOffset; // File offset to beginning of tree
3466
3266
  this.header = {};
3467
3267
  this.header.magic = binaryParser.getInt();
3468
3268
  this.header.blockSize = binaryParser.getInt();
@@ -3476,6 +3276,8 @@ var igv = (function (igv) {
3476
3276
  // Recursively walk tree to populate dictionary
3477
3277
  readTreeNode(binaryParser, -1, this.header.keySize, this.dictionary);
3478
3278
 
3279
+ var itemSize = 8 + this.header.keySize;
3280
+ var minSize = 4 + itemSize; // Bytes for a node with 1 item
3479
3281
 
3480
3282
  function readTreeNode(byteBuffer, offset, keySize, dictionary) {
3481
3283
 
@@ -3483,34 +3285,42 @@ var igv = (function (igv) {
3483
3285
 
3484
3286
  var type = byteBuffer.getByte(),
3485
3287
  reserved = byteBuffer.getByte(),
3486
- count = byteBuffer.getShort(),
3288
+ count = byteBuffer.getUShort(),
3487
3289
  i,
3488
3290
  key,
3489
3291
  chromId,
3490
3292
  chromSize,
3491
3293
  childOffset,
3492
- bufferOffset;
3294
+ bufferOffset,
3295
+ currOffset;
3493
3296
 
3494
3297
 
3495
3298
  if (type == 1) {
3496
- for (i = 0; i < count; i++) {
3497
- key = byteBuffer.getFixedLengthString(keySize).trim();
3498
3299
 
3499
- if(genome) key = genome.getChromosomeName(key); // Translate to canonical chr name
3300
+ for (i = 0; i < count; i++) {
3500
3301
 
3302
+ key = byteBuffer.getFixedLengthTrimmedString(keySize);
3501
3303
  chromId = byteBuffer.getInt();
3502
3304
  chromSize = byteBuffer.getInt();
3305
+
3306
+ if(genome) key = genome.getChromosomeName(key); // Translate to canonical chr name
3503
3307
  dictionary[key] = chromId;
3504
3308
 
3505
3309
  }
3506
3310
  }
3507
3311
  else { // non-leaf
3312
+
3508
3313
  for (i = 0; i < count; i++) {
3509
- childOffset = byteBuffer.nextLong();
3510
- bufferOffset = childOffset - self.treeOffset;
3511
- readTreeNode(byteBuffer, offset, keySize, dictionary);
3314
+
3315
+ key = byteBuffer.getFixedLengthTrimmedString(keySize);
3316
+ childOffset = byteBuffer.getLong();
3317
+ bufferOffset = childOffset - startOffset;
3318
+ currOffset = byteBuffer.position;
3319
+ readTreeNode(byteBuffer, bufferOffset, keySize, dictionary);
3320
+ byteBuffer.position = currOffset;
3512
3321
  }
3513
3322
  }
3323
+
3514
3324
  }
3515
3325
  }
3516
3326
 
@@ -3518,6 +3328,7 @@ var igv = (function (igv) {
3518
3328
  return igv;
3519
3329
 
3520
3330
  })(igv || {});
3331
+
3521
3332
  /*
3522
3333
  * The MIT License (MIT)
3523
3334
  *
@@ -3595,7 +3406,7 @@ var igv = (function (igv) {
3595
3406
  var type = binaryParser.getByte();
3596
3407
  var isLeaf = (type === 1) ? true : false;
3597
3408
  var reserved = binaryParser.getByte();
3598
- var count = binaryParser.getShort();
3409
+ var count = binaryParser.getUShort();
3599
3410
 
3600
3411
  filePosition += 4;
3601
3412
 
@@ -3753,6 +3564,7 @@ var igv = (function (igv) {
3753
3564
 
3754
3565
 
3755
3566
  })(igv || {});
3567
+
3756
3568
  /*
3757
3569
  * The MIT License (MIT)
3758
3570
  *
@@ -3822,12 +3634,8 @@ var igv = (function (igv) {
3822
3634
  var self = this;
3823
3635
 
3824
3636
  return new Promise(function (fulfill, reject) {
3825
- igvxhr.loadArrayBuffer(self.path,
3826
- {
3827
- headers: self.config.headers,
3828
- range: {start: 0, size: BBFILE_HEADER_SIZE},
3829
- withCredentials: self.config.withCredentials
3830
- }).then(function (data) {
3637
+ igvxhr.loadArrayBuffer(self.path, Object.assign(self.config, {range: {start: 0, size: BBFILE_HEADER_SIZE}}))
3638
+ .then(function (data) {
3831
3639
 
3832
3640
  if (!data) return;
3833
3641
 
@@ -3865,13 +3673,13 @@ var igv = (function (igv) {
3865
3673
  }
3866
3674
  // Table 5 "Common header for BigWig and BigBed files"
3867
3675
  self.header = {};
3868
- self.header.bwVersion = binaryParser.getShort();
3869
- self.header.nZoomLevels = binaryParser.getShort();
3676
+ self.header.bwVersion = binaryParser.getUShort();
3677
+ self.header.nZoomLevels = binaryParser.getUShort();
3870
3678
  self.header.chromTreeOffset = binaryParser.getLong();
3871
3679
  self.header.fullDataOffset = binaryParser.getLong();
3872
3680
  self.header.fullIndexOffset = binaryParser.getLong();
3873
- self.header.fieldCount = binaryParser.getShort();
3874
- self.header.definedFieldCount = binaryParser.getShort();
3681
+ self.header.fieldCount = binaryParser.getUShort();
3682
+ self.header.definedFieldCount = binaryParser.getUShort();
3875
3683
  self.header.autoSqlOffset = binaryParser.getLong();
3876
3684
  self.header.totalSummaryOffset = binaryParser.getLong();
3877
3685
  self.header.uncompressBuffSize = binaryParser.getInt();
@@ -3893,13 +3701,11 @@ var igv = (function (igv) {
3893
3701
  self = this;
3894
3702
 
3895
3703
  return new Promise(function (fulfill, reject) {
3704
+
3705
+ var range = {start: startOffset, size: (self.header.fullDataOffset - startOffset + 5)};
3896
3706
 
3897
- igvxhr.loadArrayBuffer(self.path,
3898
- {
3899
- headers: self.config.headers,
3900
- range: {start: startOffset, size: (self.header.fullDataOffset - startOffset + 5)},
3901
- withCredentials: self.config.withCredentials
3902
- }).then(function (data) {
3707
+ igvxhr.loadArrayBuffer(self.path, Object.assign(self.config, {range: range}))
3708
+ .then(function (data) {
3903
3709
 
3904
3710
  var nZooms = self.header.nZoomLevels,
3905
3711
  binaryParser = new igv.BinaryParser(new DataView(data)),
@@ -3933,7 +3739,7 @@ var igv = (function (igv) {
3933
3739
  // Chrom data index
3934
3740
  if (self.header.chromTreeOffset > 0) {
3935
3741
  binaryParser.position = self.header.chromTreeOffset - startOffset;
3936
- self.chromTree = new igv.BPTree(binaryParser, 0);
3742
+ self.chromTree = new igv.BPTree(binaryParser, startOffset);
3937
3743
  }
3938
3744
  else {
3939
3745
  // TODO -- this is an error, not expected
@@ -3983,6 +3789,7 @@ var igv = (function (igv) {
3983
3789
 
3984
3790
  })
3985
3791
  (igv || {});
3792
+
3986
3793
  /*
3987
3794
  * The MIT License (MIT)
3988
3795
  *
@@ -4088,13 +3895,13 @@ var igv = (function (igv) {
4088
3895
 
4089
3896
  var i, allFeatures = featureArrays[0];
4090
3897
  if(featureArrays.length > 1) {
4091
- for(i=0; i<featureArrays.length; i++) {
3898
+ for(i=1; i<featureArrays.length; i++) {
4092
3899
  allFeatures = allFeatures.concat(featureArrays[i]);
4093
3900
  }
4094
- allFeatures.sort(function (a, b) {
4095
- return a.start - b.start;
4096
- })
4097
- }
3901
+ }
3902
+ allFeatures.sort(function (a, b) {
3903
+ return a.start - b.start;
3904
+ })
4098
3905
 
4099
3906
  fulfill(allFeatures)
4100
3907
  }).catch(reject);
@@ -4107,6 +3914,18 @@ var igv = (function (igv) {
4107
3914
 
4108
3915
  });
4109
3916
  }
3917
+
3918
+
3919
+ igv.BWSource.prototype.getDefaultRange = function () {
3920
+
3921
+ if(this.reader.totalSummary != undefined) {
3922
+ return this.reader.totalSummary.defaultRange;
3923
+ }
3924
+ else {
3925
+ return undefined;
3926
+ }
3927
+
3928
+ }
4110
3929
 
4111
3930
 
4112
3931
  function zoomLevelForScale(bpPerPixel, zoomLevelHeaders) {
@@ -4141,7 +3960,7 @@ var igv = (function (igv) {
4141
3960
  itemSpan = binaryParser.getInt(),
4142
3961
  type = binaryParser.getByte(),
4143
3962
  reserved = binaryParser.getByte(),
4144
- itemCount = binaryParser.getShort(),
3963
+ itemCount = binaryParser.getUShort(),
4145
3964
  value;
4146
3965
 
4147
3966
  if (chromId === chrIdx) {
@@ -4155,7 +3974,6 @@ var igv = (function (igv) {
4155
3974
  value = binaryParser.getFloat();
4156
3975
  break;
4157
3976
  case 2:
4158
-
4159
3977
  chromStart = binaryParser.getInt();
4160
3978
  value = binaryParser.getFloat();
4161
3979
  chromEnd = chromStart + itemSpan;
@@ -4170,7 +3988,7 @@ var igv = (function (igv) {
4170
3988
 
4171
3989
  if (chromStart >= bpEnd) {
4172
3990
  break; // Out of interval
4173
- } else if (chromEnd > bpStart) {
3991
+ } else if (chromEnd > bpStart && Number.isFinite(value)) {
4174
3992
  featureArray.push({chr: chr, start: chromStart, end: chromEnd, value: value});
4175
3993
  }
4176
3994
 
@@ -4210,7 +4028,7 @@ var igv = (function (igv) {
4210
4028
  if (chromStart >= bpEnd) {
4211
4029
  break; // Out of interval
4212
4030
 
4213
- } else if (chromEnd > bpStart) {
4031
+ } else if (chromEnd > bpStart && Number.isFinite(value)) {
4214
4032
  featureArray.push({chr: chr, start: chromStart, end: chromEnd, value: value});
4215
4033
  }
4216
4034
 
@@ -4355,7 +4173,15 @@ var igv = (function (igv) {
4355
4173
  var n = this.basesCovered;
4356
4174
  if (n > 0) {
4357
4175
  this.mean = this.sumData / n;
4358
- this.stddev = Math.sqrt((this.sumSquares - (this.sumData / n) * this.sumData) / (n - 1));
4176
+ this.stddev = Math.sqrt(this.sumSquares / (n - 1));
4177
+
4178
+ var min = this.minVal < 0 ? this.mean - 2 * this.stddev : 0,
4179
+ max = this.maxVal > 0 ? this.mean + 2 * this.stddev : 0;
4180
+
4181
+ this.defaultRange = {
4182
+ min: 0,
4183
+ max: this.mean + 3 * this.stddev
4184
+ }
4359
4185
  }
4360
4186
  }
4361
4187
 
@@ -4375,6 +4201,7 @@ var igv = (function (igv) {
4375
4201
  return igv;
4376
4202
 
4377
4203
  })(igv || {});
4204
+
4378
4205
  /*
4379
4206
  * The MIT License (MIT)
4380
4207
  *
@@ -4412,7 +4239,11 @@ var igv = (function (igv) {
4412
4239
  this.length = dataView.byteLength;
4413
4240
  }
4414
4241
 
4415
- igv.BinaryParser.prototype.remLength = function() {
4242
+ igv.BinaryParser.prototype.available = function() {
4243
+ return this.length - this.position;
4244
+ }
4245
+
4246
+ igv.BinaryParser.prototype.remLength = function () {
4416
4247
  return this.length - this.position;
4417
4248
  }
4418
4249
 
@@ -4433,6 +4264,19 @@ var igv = (function (igv) {
4433
4264
  return retValue;
4434
4265
  }
4435
4266
 
4267
+ igv.BinaryParser.prototype.getUShort = function () {
4268
+
4269
+ // var byte1 = this.getByte(),
4270
+ // byte2 = this.getByte(),
4271
+ // retValue = ((byte2 << 24 >>> 16) + (byte1 << 24 >>> 24));
4272
+ // return retValue;
4273
+
4274
+ //
4275
+ var retValue = this.view.getUint16 (this.position, this.littleEndian);
4276
+ this.position += 2
4277
+ return retValue;
4278
+ }
4279
+
4436
4280
 
4437
4281
  igv.BinaryParser.prototype.getInt = function () {
4438
4282
 
@@ -4450,23 +4294,32 @@ var igv = (function (igv) {
4450
4294
 
4451
4295
  igv.BinaryParser.prototype.getLong = function () {
4452
4296
 
4453
- // return this.view.getInt32(this.position += 8);
4454
- var byte1 = this.view.getUint8(this.position++) & 0xff;
4455
- var byte2 = this.view.getUint8(this.position++) & 0xff;
4456
- var byte3 = this.view.getUint8(this.position++) & 0xff;
4457
- var byte4 = this.view.getUint8(this.position++) & 0xff;
4458
- var byte5 = this.view.getUint8(this.position++) & 0xff;
4459
- var byte6 = this.view.getUint8(this.position++) & 0xff;
4460
- var byte7 = this.view.getUint8(this.position++) & 0xff;
4461
- var byte8 = this.view.getUint8(this.position++) & 0xff;
4462
- return (byte8 << 56)
4463
- + ((byte7 << 56) >>> 8)
4464
- + ((byte6 << 56) >>> 16)
4465
- + ((byte5 << 56) >>> 24)
4466
- + ((byte4 << 56) >>> 32)
4467
- + ((byte3 << 56) >>> 40)
4468
- + ((byte2 << 56) >>> 48)
4469
- + ((byte1 << 56) >>> 56);
4297
+ // DataView doesn't support long. So we'll try manually
4298
+
4299
+ var b = [];
4300
+ b[0] = this.view.getUint8(this.position);
4301
+ b[1] = this.view.getUint8(this.position + 1);
4302
+ b[2] = this.view.getUint8(this.position + 2);
4303
+ b[3] = this.view.getUint8(this.position + 3);
4304
+ b[4] = this.view.getUint8(this.position + 4);
4305
+ b[5] = this.view.getUint8(this.position + 5);
4306
+ b[6] = this.view.getUint8(this.position + 6);
4307
+ b[7] = this.view.getUint8(this.position + 7);
4308
+
4309
+ var value = 0;
4310
+ if (this.littleEndian) {
4311
+ for (var i = b.length - 1; i >= 0; i--) {
4312
+ value = (value * 256) + b[i];
4313
+ }
4314
+ } else {
4315
+ for (var i = 0; i < b.length; i++) {
4316
+ value = (value * 256) + b[i];
4317
+ }
4318
+ }
4319
+
4320
+
4321
+ this.position += 8;
4322
+ return value;
4470
4323
  }
4471
4324
 
4472
4325
  igv.BinaryParser.prototype.getString = function (len) {
@@ -4485,15 +4338,28 @@ var igv = (function (igv) {
4485
4338
  var s = "";
4486
4339
  var i;
4487
4340
  var c;
4488
- for (i=0; i<len; i++) {
4341
+ for (i = 0; i < len; i++) {
4489
4342
  c = this.view.getUint8(this.position++);
4490
- if(c > 0) {
4343
+ if (c > 0) {
4491
4344
  s += String.fromCharCode(c);
4492
4345
  }
4493
4346
  }
4494
4347
  return s;
4495
4348
  }
4496
4349
 
4350
+ igv.BinaryParser.prototype.getFixedLengthTrimmedString = function (len) {
4351
+
4352
+ var s = "";
4353
+ var i;
4354
+ var c;
4355
+ for (i = 0; i < len; i++) {
4356
+ c = this.view.getUint8(this.position++);
4357
+ if (c > 32) {
4358
+ s += String.fromCharCode(c);
4359
+ }
4360
+ }
4361
+ return s;
4362
+ }
4497
4363
 
4498
4364
  igv.BinaryParser.prototype.getFloat = function () {
4499
4365
 
@@ -4523,7 +4389,7 @@ var igv = (function (igv) {
4523
4389
  * TODO -- why isn't 8th byte used ?
4524
4390
  * @returns {*}
4525
4391
  */
4526
- igv.BinaryParser.prototype. getVPointer = function() {
4392
+ igv.BinaryParser.prototype.getVPointer = function () {
4527
4393
 
4528
4394
  var position = this.position,
4529
4395
  offset = (this.view.getUint8(position + 1) << 8) | (this.view.getUint8(position)),
@@ -4535,11 +4401,11 @@ var igv = (function (igv) {
4535
4401
  block = byte6 + byte5 + byte4 + byte3 + byte2;
4536
4402
  this.position += 8;
4537
4403
 
4538
- if (block == 0 && offset == 0) {
4539
- return null;
4540
- } else {
4541
- return new VPointer(block, offset);
4542
- }
4404
+ // if (block == 0 && offset == 0) {
4405
+ // return null;
4406
+ // } else {
4407
+ return new VPointer(block, offset);
4408
+ // }
4543
4409
  }
4544
4410
 
4545
4411
 
@@ -4548,7 +4414,17 @@ var igv = (function (igv) {
4548
4414
  this.offset = offset;
4549
4415
  }
4550
4416
 
4551
- VPointer.prototype.print = function() {
4417
+ VPointer.prototype.isLessThan = function (vp) {
4418
+ return this.block < vp.block ||
4419
+ (this.block === vp.block && this.offset < vp.offset);
4420
+ }
4421
+
4422
+ VPointer.prototype.isGreaterThan = function (vp) {
4423
+ return this.block > vp.block ||
4424
+ (this.block === vp.block && this.offset > vp.offset);
4425
+ }
4426
+
4427
+ VPointer.prototype.print = function () {
4552
4428
  return "" + this.block + ":" + this.offset;
4553
4429
  }
4554
4430
 
@@ -4556,6 +4432,7 @@ var igv = (function (igv) {
4556
4432
  return igv;
4557
4433
 
4558
4434
  })(igv || {});
4435
+
4559
4436
  /*
4560
4437
  * The MIT License (MIT)
4561
4438
  *
@@ -4583,6 +4460,9 @@ var igv = (function (igv) {
4583
4460
 
4584
4461
  var igv = (function (igv) {
4585
4462
 
4463
+ var knownFileTypes = new Set(["narrowpeak", "broadpeak", "peaks", "bedgraph", "wig", "gff3", "gff",
4464
+ "gtf", "aneu", "fusionjuncspan", "refflat", "seg", "bed", "vcf", "bb", "bigbed", "bw", "bigwig", "bam", "tdf"]);
4465
+
4586
4466
  igv.Browser = function (options, trackContainer) {
4587
4467
 
4588
4468
  igv.browser = this; // Make globally visible (for use in html markup).
@@ -4655,7 +4535,7 @@ var igv = (function (igv) {
4655
4535
  this.searchConfig = {
4656
4536
  // Legacy support -- deprecated
4657
4537
  type: "plain",
4658
- url: "//www.broadinstitute.org/webservices/igv/locus?genome=" + genomeId + "&name=$FEATURE$",
4538
+ url: "https://portals.broadinstitute.org/webservices/igv/locus?genome=" + genomeId + "&name=$FEATURE$",
4659
4539
  coords: 0,
4660
4540
  chromosomeField: "chromosome",
4661
4541
  startField: "start",
@@ -4672,19 +4552,23 @@ var igv = (function (igv) {
4672
4552
 
4673
4553
  igv.Browser.prototype.loadTracksWithConfigList = function (configList) {
4674
4554
 
4675
- var self = this;
4555
+ var self = this,
4556
+ loadedTracks = [];
4557
+
4676
4558
 
4677
4559
  configList.forEach(function (config) {
4678
- self.loadTrack(config);
4560
+ loadedTracks.push(self.loadTrack(config));
4679
4561
  });
4680
4562
 
4681
4563
  // Really we should just resize the new trackViews, but currently there is no way to get a handle on those
4682
4564
  this.trackViews.forEach(function (trackView) {
4683
4565
  trackView.resize();
4684
- })
4566
+ });
4685
4567
 
4568
+ return loadedTracks;
4686
4569
  };
4687
4570
 
4571
+
4688
4572
  igv.Browser.prototype.loadTrack = function (config) {
4689
4573
 
4690
4574
  var self = this,
@@ -4708,13 +4592,14 @@ var igv = (function (igv) {
4708
4592
  }
4709
4593
  }
4710
4594
 
4711
- switch (config.type) {
4595
+ var typeLowerCase = config.type === undefined ? "" : config.type.toLowerCase();
4596
+ switch (typeLowerCase) {
4712
4597
  case "gwas":
4713
4598
  newTrack = new igv.GWASTrack(config);
4714
4599
  break;
4715
4600
  case "annotation":
4716
4601
  case "genes":
4717
- case "FusionJuncSpan":
4602
+ case "fusionjuncspan":
4718
4603
  newTrack = new igv.FeatureTrack(config);
4719
4604
  break;
4720
4605
  case "variant":
@@ -4745,7 +4630,7 @@ var igv = (function (igv) {
4745
4630
  default:
4746
4631
 
4747
4632
  //alert("Unknown file type: " + config.url);
4748
- igv.presentAlert("Unknown file type: " + (config.type || ''));
4633
+ igv.presentAlert("Unknown file type: " + config.url);
4749
4634
 
4750
4635
  return null;
4751
4636
  }
@@ -4769,8 +4654,9 @@ var igv = (function (igv) {
4769
4654
  self.addTrack(newTrack);
4770
4655
  }
4771
4656
 
4772
- };
4657
+ return newTrack;
4773
4658
 
4659
+ };
4774
4660
 
4775
4661
  /**
4776
4662
  * Add a new track. Each track is associated with the following DOM elements
@@ -4816,7 +4702,7 @@ var igv = (function (igv) {
4816
4702
  });
4817
4703
 
4818
4704
  // Reattach the divs to the dom in the correct order
4819
- $(this.trackContainerDiv).children().detach();
4705
+ $(this.trackContainerDiv).children("igv-track-div").detach();
4820
4706
 
4821
4707
  this.trackViews.forEach(function (trackView, index, trackViews) {
4822
4708
 
@@ -4947,6 +4833,10 @@ var igv = (function (igv) {
4947
4833
 
4948
4834
  this.updateLocusSearch(this.referenceFrame);
4949
4835
 
4836
+ if (this.centerGuide) {
4837
+ this.centerGuide.repaint();
4838
+ }
4839
+
4950
4840
  if (this.ideoPanel) {
4951
4841
  this.ideoPanel.repaint();
4952
4842
  }
@@ -5021,14 +4911,14 @@ var igv = (function (igv) {
5021
4911
 
5022
4912
  };
5023
4913
 
5024
- igv.Browser.prototype.pixelPerBasepairThreshold = function () {
5025
- return 14.0;
5026
- };
5027
-
5028
4914
  igv.Browser.prototype.trackViewportWidthBP = function () {
5029
4915
  return this.referenceFrame.bpPerPixel * this.trackViewportWidth();
5030
4916
  };
5031
4917
 
4918
+ igv.Browser.prototype.minimumBasesExtent = function () {
4919
+ return 40;
4920
+ };
4921
+
5032
4922
  igv.Browser.prototype.removeAllTracks = function () {
5033
4923
  var tracks = this.trackViews;
5034
4924
 
@@ -5100,7 +4990,7 @@ var igv = (function (igv) {
5100
4990
 
5101
4991
  };
5102
4992
 
5103
- // Zoom in by a factor of 2, keeping the same center location
4993
+ // Zoom in by a factor of 2, keeping the same center location
5104
4994
  igv.Browser.prototype.zoomIn = function () {
5105
4995
 
5106
4996
  if (this.loadInProgress()) {
@@ -5108,25 +4998,36 @@ var igv = (function (igv) {
5108
4998
  return;
5109
4999
  }
5110
5000
 
5111
- var newScale,
5112
- center,
5113
- viewportWidth;
5001
+ var centerBP;
5114
5002
 
5115
- viewportWidth = this.trackViewportWidth();
5003
+ console.log('browser.zoomIn - src extent ' + basesExtent(this.trackViewportWidth(), this.referenceFrame.bpPerPixel));
5116
5004
 
5117
- newScale = Math.max(1.0 / this.pixelPerBasepairThreshold(), this.referenceFrame.bpPerPixel / 2);
5118
- if (newScale === this.referenceFrame.bpPerPixel) {
5119
- //console.log("zoom in bail bpp " + newScale + " width " + (viewportWidth/14.0));
5005
+ // Have we reached the zoom-in threshold yet? If so, bail.
5006
+ if (this.minimumBasesExtent() > basesExtent(this.trackViewportWidth(), this.referenceFrame.bpPerPixel / 2.0)) {
5007
+ console.log('browser.zoomIn - dst extent ' + basesExtent(this.trackViewportWidth(), this.referenceFrame.bpPerPixel / 2.0) + ' bailing ...');
5120
5008
  return;
5009
+ } else {
5010
+ console.log('browser.zoomIn - dst extent ' + basesExtent(this.trackViewportWidth(), this.referenceFrame.bpPerPixel / 2.0));
5121
5011
  }
5122
5012
 
5123
- center = this.referenceFrame.start + this.referenceFrame.bpPerPixel * viewportWidth / 2;
5124
- this.referenceFrame.start = center - newScale * viewportWidth / 2;
5125
- this.referenceFrame.bpPerPixel = newScale;
5013
+ // window center (base-pair units)
5014
+ centerBP = this.referenceFrame.start + this.referenceFrame.bpPerPixel * (this.trackViewportWidth() / 2);
5015
+
5016
+ // derive scaled (zoomed in) start location (base-pair units) by multiplying half-width by halve'd bases-per-pixel
5017
+ // which results in base-pair units
5018
+ this.referenceFrame.start = centerBP - (this.trackViewportWidth() / 2) * (this.referenceFrame.bpPerPixel / 2.0);
5019
+
5020
+ // halve the bases-per-pixel
5021
+ this.referenceFrame.bpPerPixel /= 2.0;
5022
+
5126
5023
  this.update();
5024
+
5025
+ function basesExtent(width, bpp) {
5026
+ return Math.floor(width * bpp);
5027
+ }
5127
5028
  };
5128
5029
 
5129
- // Zoom out by a factor of 2, keeping the same center location if possible
5030
+ // Zoom out by a factor of 2, keeping the same center location if possible
5130
5031
  igv.Browser.prototype.zoomOut = function () {
5131
5032
 
5132
5033
  if (this.loadInProgress()) {
@@ -5160,67 +5061,46 @@ var igv = (function (igv) {
5160
5061
  this.update();
5161
5062
  };
5162
5063
 
5163
-
5164
5064
  /**
5165
5065
  *
5166
5066
  * @param feature
5167
5067
  * @param callback - function to call
5168
5068
  */
5169
- igv.Browser.prototype.search = function (feature, callback) {
5170
-
5171
- // See if we're ready to respond to a search, if not just queue it up and return
5172
- if (igv.browser === undefined || igv.browser.genome === undefined) {
5173
- igv.browser.initialLocus = feature;
5174
- if (callback) callback();
5175
- return;
5176
- }
5177
-
5178
-
5069
+ igv.Browser.prototype.search = function (feature, callback, force) {
5179
5070
  var type,
5180
5071
  chr,
5181
- posTokens,
5182
5072
  start,
5183
5073
  end,
5184
5074
  searchConfig,
5185
- tokens,
5186
5075
  url,
5187
- chromosome,
5188
5076
  result;
5189
5077
 
5190
- if (feature.contains(":") && feature.contains("-") || this.genome.getChromosome(feature)) {
5078
+ // See if we're ready to respond to a search, if not just queue it up and return
5079
+ if (igv.browser === undefined || igv.browser.genome === undefined) {
5080
+ igv.browser.initialLocus = feature;
5081
+ if (callback) {
5082
+ callback();
5083
+ }
5084
+ return;
5085
+ }
5191
5086
 
5192
- type = "locus";
5193
- tokens = feature.split(":");
5194
- chr = this.genome.getChromosomeName(tokens[0]);
5087
+ if (isLocusFeature(feature, this.genome, force)) {
5195
5088
 
5196
- if (tokens.length == 1) {
5197
- chromosome = this.genome.getChromosome(feature);
5198
- start = 0;
5199
- end = chromosome.bpLength;
5200
- }
5201
- else {
5202
- posTokens = tokens[1].split("-");
5203
- start = parseInt(posTokens[0].replace(/,/g, "")) - 1;
5204
- end = parseInt(posTokens[1].replace(/,/g, ""));
5205
- }
5089
+ var success = gotoLocusFeature(feature, this.genome, this);
5206
5090
 
5207
- if (end > start) {
5208
- this.goto(chr, start, end);
5209
- fireOnsearch.call(igv.browser, feature, type);
5091
+ if ((force || true === success) && callback) {
5092
+ callback();
5210
5093
  }
5211
5094
 
5212
- if (callback) callback();
5213
-
5214
- }
5215
- else {
5095
+ } else {
5216
5096
 
5217
5097
  // Try local feature cache first
5218
5098
  result = this.featureDB[feature.toUpperCase()];
5219
5099
  if (result) {
5100
+
5220
5101
  handleSearchResult(result.name, result.chr, result.start, result.end, "");
5221
- }
5222
5102
 
5223
- else if (this.searchConfig) {
5103
+ } else if (this.searchConfig) {
5224
5104
  url = this.searchConfig.url.replace("$FEATURE$", feature);
5225
5105
  searchConfig = this.searchConfig;
5226
5106
 
@@ -5245,7 +5125,7 @@ var igv = (function (igv) {
5245
5125
  //alert('No feature found with name "' + feature + '"');
5246
5126
  igv.presentAlert('No feature found with name "' + feature + '"');
5247
5127
  }
5248
- else if (results.length == 1) {
5128
+ else {
5249
5129
 
5250
5130
  // Just take the first result for now
5251
5131
  // TODO - merge results, or ask user to choose
@@ -5257,18 +5137,124 @@ var igv = (function (igv) {
5257
5137
  type = r["featureType"] || r["type"];
5258
5138
  handleSearchResult(feature, chr, start, end, type);
5259
5139
  }
5260
- else {
5261
- presentSearchResults(results, searchConfig, feature);
5262
- }
5140
+ //else {
5141
+ // presentSearchResults(results, searchConfig, feature);
5142
+ //}
5263
5143
 
5264
5144
  if (callback) callback();
5265
5145
  });
5266
5146
  }
5267
5147
  }
5268
5148
 
5149
+ function isLocusFeature(f, genome) {
5150
+
5151
+ if (2 === f.split(':').length) {
5152
+ return true;
5153
+ }
5154
+
5155
+ if (genome.getChromosome(f)) {
5156
+ return true;
5157
+ }
5269
5158
 
5159
+ return false;
5160
+ }
5270
5161
  };
5271
5162
 
5163
+ function gotoLocusFeature(locusFeature, genome, browser) {
5164
+
5165
+ var type,
5166
+ tokens,
5167
+ chr,
5168
+ start,
5169
+ end,
5170
+ chrName,
5171
+ startEnd,
5172
+ center,
5173
+ obj;
5174
+
5175
+
5176
+ type = 'locus';
5177
+ tokens = locusFeature.split(":");
5178
+ chrName = genome.getChromosomeName(tokens[0]);
5179
+ if (chrName) {
5180
+ chr = genome.getChromosome(chrName);
5181
+ }
5182
+
5183
+ if (chr) {
5184
+
5185
+ // returning undefined indicates locus is a chromosome name.
5186
+ start = end = undefined;
5187
+ if (1 === tokens.length) {
5188
+ start = 0;
5189
+ end = chr.bpLength;
5190
+ } else {
5191
+ startEnd = tokens[1].split("-");
5192
+ start = Math.max(0, parseInt(startEnd[0].replace(/,/g, "")) - 1);
5193
+ if (2 === startEnd.length) {
5194
+ end = Math.min(chr.bpLength, parseInt(startEnd[1].replace(/,/g, "")));
5195
+ if (end < 0) {
5196
+ // This can happen from integer overflow
5197
+ end = chr.bpLength;
5198
+ }
5199
+ }
5200
+ }
5201
+
5202
+ obj = {start: start, end: end};
5203
+ validateLocusExtent(igv.browser, chr, obj);
5204
+ start = obj.start;
5205
+ end = obj.end;
5206
+
5207
+ }
5208
+
5209
+ if (undefined === chr || isNaN(start) || (start > end)) {
5210
+ igv.presentAlert("Unrecognized feature or locus: " + locusFeature);
5211
+ return false;
5212
+ }
5213
+
5214
+ browser.goto(chrName, start, end);
5215
+ fireOnsearch.call(igv.browser, locusFeature, type);
5216
+
5217
+ function validateLocusExtent(browser, chromosome, extent) {
5218
+
5219
+ var ss = extent.start,
5220
+ ee = extent.end,
5221
+ locusExtent = ee - ss;
5222
+
5223
+ if (undefined === ee) {
5224
+
5225
+ ss -= igv.browser.minimumBasesExtent() / 2;
5226
+ ee = ss + igv.browser.minimumBasesExtent();
5227
+
5228
+ if (ee > chromosome.bpLength) {
5229
+ ee = chromosome.bpLength;
5230
+ ss = ee - igv.browser.minimumBasesExtent();
5231
+ } else if (ss < 0) {
5232
+ ss = 0;
5233
+ ee = igv.browser.minimumBasesExtent();
5234
+ }
5235
+
5236
+ } else if (ee - ss < igv.browser.minimumBasesExtent()) {
5237
+
5238
+ center = (ee + ss) / 2;
5239
+ if (center - igv.browser.minimumBasesExtent() / 2 < 0) {
5240
+ ss = 0;
5241
+ ee = ss + igv.browser.minimumBasesExtent();
5242
+ } else if (center + igv.browser.minimumBasesExtent() / 2 > chromosome.bpLength) {
5243
+ ee = chromosome.bpLength;
5244
+ ss = ee - igv.browser.minimumBasesExtent();
5245
+ } else {
5246
+ ss = center - igv.browser.minimumBasesExtent() / 2;
5247
+ ee = ss + igv.browser.minimumBasesExtent();
5248
+ }
5249
+ }
5250
+
5251
+ extent.start = Math.ceil(ss);
5252
+ extent.end = Math.floor(ee);
5253
+ }
5254
+
5255
+ return true;
5256
+ }
5257
+
5272
5258
  function presentSearchResults(loci, config, feature) {
5273
5259
 
5274
5260
  igv.browser.$searchResultsTable.empty();
@@ -5402,6 +5388,20 @@ var igv = (function (igv) {
5402
5388
  mouseDownX = lastMouseX;
5403
5389
  });
5404
5390
 
5391
+ // Guide line is bound within track area, and offset by 5 pixels so as not to interfere mouse clicks.
5392
+ $(trackContainerDiv).mousemove(function (e) {
5393
+ var xy,
5394
+ _left,
5395
+ $element = igv.browser.$cursorTrackingGuide;
5396
+
5397
+ xy = igv.translateMouseCoordinates(e, trackContainerDiv);
5398
+ _left = Math.max(50, xy.x - 5);
5399
+
5400
+ _left = Math.min(igv.browser.trackContainerDiv.clientWidth - 65, _left);
5401
+ $element.css({left: _left + 'px'});
5402
+ });
5403
+
5404
+
5405
5405
  $(trackContainerDiv).mousemove(igv.throttle(function (e) {
5406
5406
 
5407
5407
  var coords = igv.translateMouseCoordinates(e, trackContainerDiv),
@@ -5430,14 +5430,10 @@ var igv = (function (igv) {
5430
5430
 
5431
5431
  referenceFrame.shiftPixels(lastMouseX - coords.x);
5432
5432
 
5433
- // TODO -- clamping code below is broken for regular IGV => disabled for now, needs fixed
5434
-
5435
-
5436
5433
  // clamp left
5437
5434
  referenceFrame.start = Math.max(0, referenceFrame.start);
5438
5435
 
5439
5436
  // clamp right
5440
-
5441
5437
  var chromosome = igv.browser.genome.getChromosome(referenceFrame.chr);
5442
5438
  maxEnd = chromosome.bpLength;
5443
5439
  maxStart = maxEnd - igv.browser.trackViewportWidth() * referenceFrame.bpPerPixel;
@@ -5462,12 +5458,19 @@ var igv = (function (igv) {
5462
5458
 
5463
5459
  $(trackContainerDiv).mouseleave(mouseUpOrOut);
5464
5460
 
5465
- function mouseUpOrOut() {
5461
+ function mouseUpOrOut(e) {
5462
+
5463
+ var element = igv.browser.$cursorTrackingGuide.get(0);
5466
5464
 
5467
5465
  if (isRulerTrack) {
5468
5466
  return;
5469
5467
  }
5470
5468
 
5469
+ // Don't let vertical line interfere with dragging
5470
+ if (igv.browser.$cursorTrackingGuide && e.toElement === igv.browser.$cursorTrackingGuide.get(0) && e.type === 'mouseleave') {
5471
+ return;
5472
+ }
5473
+
5471
5474
  if (isDragging) {
5472
5475
  igv.browser.fireEvent('trackdragend');
5473
5476
  isDragging = false;
@@ -5486,6 +5489,8 @@ var igv = (function (igv) {
5486
5489
  *
5487
5490
  * @param config
5488
5491
  */
5492
+
5493
+
5489
5494
  function inferTypes(config) {
5490
5495
 
5491
5496
  function translateDeprecatedTypes(config) {
@@ -5496,32 +5501,36 @@ var igv = (function (igv) {
5496
5501
  }
5497
5502
 
5498
5503
  if ("bed" === config.type) {
5499
- config.type = config.type || "annotation";
5504
+ config.type = "annotation";
5500
5505
  config.format = config.format || "bed";
5506
+
5501
5507
  }
5502
5508
 
5503
- if ("bam" === config.type) {
5509
+ else if ("bam" === config.type) {
5504
5510
  config.type = "alignment";
5505
5511
  config.format = "bam"
5506
5512
  }
5507
5513
 
5508
- if ("vcf" === config.type) {
5514
+ else if ("vcf" === config.type) {
5509
5515
  config.type = "variant";
5510
5516
  config.format = "vcf"
5511
5517
  }
5512
5518
 
5513
- if ("t2d" === config.type) {
5519
+ else if ("t2d" === config.type) {
5514
5520
  config.type = "gwas";
5515
5521
  }
5516
5522
 
5517
- if ("FusionJuncSpan" === config.type) {
5518
- config.format = "FusionJuncSpan";
5523
+ else if ("FusionJuncSpan" === config.type) {
5524
+ config.format = "fusionjuncspan";
5519
5525
  }
5520
5526
  }
5521
5527
 
5522
5528
  function inferFileFormat(config) {
5523
5529
 
5524
- if (config.format) return;
5530
+ if (config.format) {
5531
+ config.format = config.format.toLowerCase();
5532
+ return;
5533
+ }
5525
5534
 
5526
5535
  var path = config.url || config.localFile.name,
5527
5536
  fn = path.toLowerCase(),
@@ -5543,18 +5552,20 @@ var igv = (function (igv) {
5543
5552
 
5544
5553
 
5545
5554
  idx = fn.lastIndexOf(".");
5546
- ext = idx < 0 ? fn : fn.substr(idx);
5555
+ ext = idx < 0 ? fn : fn.substr(idx + 1);
5547
5556
 
5548
- switch (ext) {
5557
+ switch (ext.toLowerCase()) {
5549
5558
 
5550
- case ".bw":
5559
+ case "bw":
5551
5560
  config.format = "bigwig";
5552
5561
  break;
5553
- case ".bb":
5562
+ case "bb":
5554
5563
  config.format = "bigbed";
5555
5564
 
5556
5565
  default:
5557
- config.format = ext.substr(1); // Strip leading "."
5566
+ if (knownFileTypes.has(ext)) {
5567
+ config.format = ext;
5568
+ }
5558
5569
  }
5559
5570
  }
5560
5571
 
@@ -5562,25 +5573,27 @@ var igv = (function (igv) {
5562
5573
 
5563
5574
  if (config.type) return;
5564
5575
 
5565
- switch (config.format) {
5566
- case "bw":
5567
- case "bigwig":
5568
- case "wig":
5569
- case "bedgraph":
5570
- config.type = "wig";
5571
- break;
5572
- case "vcf":
5573
- config.type = "variant";
5574
- break;
5575
- case "seg":
5576
- config.type = "seg";
5577
- break;
5578
- case "bam":
5579
- config.type = "alignment";
5580
- break;
5581
- default:
5582
- config.type = "annotation";
5583
-
5576
+ if (config.format !== undefined) {
5577
+ switch (config.format.toLowerCase()) {
5578
+ case "bw":
5579
+ case "bigwig":
5580
+ case "wig":
5581
+ case "bedgraph":
5582
+ case "tdf":
5583
+ config.type = "wig";
5584
+ break;
5585
+ case "vcf":
5586
+ config.type = "variant";
5587
+ break;
5588
+ case "seg":
5589
+ config.type = "seg";
5590
+ break;
5591
+ case "bam":
5592
+ config.type = "alignment";
5593
+ break;
5594
+ default:
5595
+ config.type = "annotation";
5596
+ }
5584
5597
  }
5585
5598
  }
5586
5599
 
@@ -7492,7 +7505,7 @@ var igv = (function (igv) {
7492
7505
  var self = this;
7493
7506
 
7494
7507
  return new Promise(function (fulfill, reject) {
7495
- parser = self.parser,
7508
+ var parser = self.parser,
7496
7509
  options = {
7497
7510
  headers: self.config.headers, // http headers, not file header
7498
7511
  withCredentials: self.config.withCredentials
@@ -7543,7 +7556,7 @@ var igv = (function (igv) {
7543
7556
 
7544
7557
  var startPos = block.minv.block,
7545
7558
  startOffset = block.minv.offset,
7546
- endPos = block.maxv.block + (index.tabix ? MAX_GZIP_BLOCK_SIZE + 100 : 0),
7559
+ endPos = block.maxv.block + (index.tabix ? MAX_GZIP_BLOCK_SIZE : 0),
7547
7560
  options = {
7548
7561
  headers: self.config.headers, // http headers, not file header
7549
7562
  range: {start: startPos, size: endPos - startPos + 1},
@@ -7643,7 +7656,7 @@ var igv = (function (igv) {
7643
7656
  return new Promise(function (fulfill, reject) {
7644
7657
 
7645
7658
 
7646
- if(self.header) {
7659
+ if (self.header) {
7647
7660
  fulfill(self.header);
7648
7661
  }
7649
7662
 
@@ -7776,8 +7789,8 @@ var igv = (function (igv) {
7776
7789
 
7777
7790
 
7778
7791
  switch (format) {
7779
- case "narrowPeak":
7780
- case "broadPeak":
7792
+ case "narrowpeak":
7793
+ case "broadpeak":
7781
7794
  case "peaks":
7782
7795
  this.decode = decodePeak;
7783
7796
  this.delimiter = /\s+/;
@@ -7800,12 +7813,12 @@ var igv = (function (igv) {
7800
7813
  this.decode = decodeAneu;
7801
7814
  this.delimiter = "\t";
7802
7815
  break;
7803
- case "FusionJuncSpan":
7816
+ case "fusionjuncspan":
7804
7817
  // bhaas, needed for FusionInspector view
7805
7818
  this.decode = decodeFusionJuncSpan;
7806
7819
  this.delimiter = /\s+/;
7807
7820
  break;
7808
- case "gtexGWAS":
7821
+ case "gtexgwas":
7809
7822
  this.skipRows = 1;
7810
7823
  this.decode = decodeGtexGWAS;
7811
7824
  this.delimiter = "\t";
@@ -8073,8 +8086,8 @@ var igv = (function (igv) {
8073
8086
  chr: tokens[2],
8074
8087
  start: parseInt(tokens[4]),
8075
8088
  end: parseInt(tokens[5]),
8076
- id: tokens[0],
8077
- name: tokens[1],
8089
+ id: tokens[1],
8090
+ name: tokens[0],
8078
8091
  strand: tokens[3],
8079
8092
  cdStart: parseInt(tokens[6]),
8080
8093
  cdEnd: parseInt(tokens[7])
@@ -8523,7 +8536,13 @@ var igv = (function (igv) {
8523
8536
  if(header) {
8524
8537
  var features = header.features;
8525
8538
  if (features) {
8539
+
8540
+ if ("gtf" === self.config.format || "gff3" === self.config.format || "gff" === self.config.format) {
8541
+ features = (new igv.GFFHelper(self.config.format)).combineFeatures(features);
8542
+ }
8543
+
8526
8544
  // Assign overlapping features to rows
8545
+
8527
8546
  packFeatures(features, maxRows);
8528
8547
  self.featureCache = new igv.FeatureCache(features);
8529
8548
 
@@ -8586,7 +8605,8 @@ var igv = (function (igv) {
8586
8605
  if (self.sourceType === 'file' && (self.visibilityWindow === undefined || self.visibilityWindow <= 0)) {
8587
8606
  // Expand genomic interval to grab entire chromosome
8588
8607
  genomicInterval.start = 0;
8589
- genomicInterval.end = Number.MAX_VALUE;
8608
+ var chromosome = igv.browser.genome.getChromosome(chr);
8609
+ genomicInterval.end = (chromosome === undefined ? Number.MAX_VALUE : chromosome.bpLength);
8590
8610
  }
8591
8611
 
8592
8612
  self.reader.readFeatures(chr, genomicInterval.start, genomicInterval.end).then(
@@ -10321,21 +10341,19 @@ var igv = (function (igv) {
10321
10341
  this.config = config;
10322
10342
  this.url = config.url;
10323
10343
 
10344
+ if (config.color === undefined) config.color = "rgb(150,150,150)"; // Hack -- should set a default color per track type
10345
+
10346
+ igv.configTrack(this, config);
10347
+
10324
10348
  if ("bigwig" === config.format) {
10325
10349
  this.featureSource = new igv.BWSource(config);
10350
+ } else if("tdf" === config.format) {
10351
+ this.featureSource = new igv.TDFSource(config);
10326
10352
  }
10327
10353
  else {
10328
10354
  this.featureSource = new igv.FeatureSource(config);
10329
10355
  }
10330
10356
 
10331
- this.name = config.name;
10332
- this.color = config.color || "rgb(150,150,150)";
10333
- this.autoScale = config.autoScale !== undefined ? config.autoScale :
10334
- (config.max === undefined ? true : false);
10335
-
10336
- this.height = 100;
10337
- this.order = config.order;
10338
-
10339
10357
  // Min and max values. No defaults for these, if they aren't set track will autoscale.
10340
10358
  this.dataRange = {
10341
10359
  min: config.min,
@@ -10508,7 +10526,6 @@ var igv = (function (igv) {
10508
10526
  }
10509
10527
 
10510
10528
 
10511
-
10512
10529
  return igv;
10513
10530
 
10514
10531
  })(igv || {});
@@ -11324,15 +11341,7 @@ var igv = (function (igv) {
11324
11341
  */
11325
11342
  igv.ga4ghGet = function (options) {
11326
11343
 
11327
- var url = options.url + "/" + options.entity + "/" + options.entityId,
11328
- apiKey = oauth.google.apiKey,
11329
- paramSeparator = "?";
11330
-
11331
- if (apiKey) {
11332
- url = url + paramSeparator + "key=" + apiKey;
11333
- }
11334
-
11335
- options.headers = ga4ghHeaders();
11344
+ var url = options.url + "/" + options.entity + "/" + options.entityId;
11336
11345
 
11337
11346
  return igvxhr.loadJson(url, options); // Returns a promise
11338
11347
  }
@@ -11776,24 +11785,55 @@ var igv = (function (igv) {
11776
11785
 
11777
11786
  var igv = (function (igv) {
11778
11787
 
11788
+ igv.Google = {
11789
+
11790
+ // Crude test, this is conservative, nothing bad happens for a false positive
11791
+ isGoogleURL: function (url) {
11792
+ return url.contains("googleapis");
11793
+ },
11779
11794
 
11780
- igv.translateGoogleCloudURL = function(gsUrl) {
11795
+ translateGoogleCloudURL: function (gsUrl) {
11781
11796
 
11782
- var i = gsUrl.indexOf('/', 5);
11783
- if (i < 0) {
11784
- console.log("Invalid gs url: " + gsUrl);
11785
- return gsUrl;
11786
- }
11797
+ var i = gsUrl.indexOf('/', 5);
11798
+ if (i < 0) {
11799
+ console.log("Invalid gs url: " + gsUrl);
11800
+ return gsUrl;
11801
+ }
11787
11802
 
11788
- var bucket = gsUrl.substring(5, i);
11789
- var object = encodeURIComponent(gsUrl.substring(i + 1));
11803
+ var bucket = gsUrl.substring(5, i);
11804
+ var object = encodeURIComponent(gsUrl.substring(i + 1));
11790
11805
 
11791
- return "https://www.googleapis.com/storage/v1/b/" + bucket + "/o/" + object + "?alt=media";
11806
+ return "https://www.googleapis.com/storage/v1/b/" + bucket + "/o/" + object + "?alt=media";
11792
11807
 
11808
+ },
11793
11809
 
11810
+ addGoogleHeaders: function (headers) {
11811
+ {
11812
+ headers["Cache-Control"] = "no-cache";
11794
11813
 
11795
- }
11814
+ var acToken = oauth.google.access_token;
11815
+ if (acToken && !headers.hasOwnProperty("Authorization")) {
11816
+ headers["Authorization"] = "Bearer " + acToken;
11817
+ }
11818
+
11819
+ return headers;
11820
+
11821
+ }
11822
+ },
11823
+
11824
+ addApiKey: function (url) {
11796
11825
 
11826
+ var apiKey = oauth.google.apiKey,
11827
+ paramSeparator = url.contains("?") ? "&" : "?";
11828
+
11829
+ if (apiKey !== undefined && !url.contains("key=")) {
11830
+ if (apiKey) {
11831
+ url = url + paramSeparator + "key=" + apiKey;
11832
+ }
11833
+ }
11834
+ return url;
11835
+ }
11836
+ }
11797
11837
 
11798
11838
  return igv;
11799
11839
 
@@ -14127,7 +14167,7 @@ var igv = (function (igv) {
14127
14167
 
14128
14168
 
14129
14169
  igv.createColorString = function (token) {
14130
- if (token.contains(",")) {
14170
+ if (token.includes(",")) {
14131
14171
  return token.startsWith("rgb") ? token : "rgb(" + token + ")";
14132
14172
  }
14133
14173
  else {
@@ -14336,7 +14376,8 @@ var igv = (function (igv) {
14336
14376
 
14337
14377
  var igv = (function (igv) {
14338
14378
 
14339
- var igvjs_version = "1.0.1";
14379
+ var igvjs_version = "beta";
14380
+ igv.version = igvjs_version;
14340
14381
 
14341
14382
  /**
14342
14383
  * Create an igv.browser instance. This object defines the public API for interacting with the genome browser.
@@ -14436,9 +14477,7 @@ var igv = (function (igv) {
14436
14477
  // controls
14437
14478
 
14438
14479
  if (config.showCommandBar !== false && config.showControls !== false) {
14439
- controlDiv = config.createControls ?
14440
- config.createControls(browser, config) :
14441
- createStandardControls(browser, config);
14480
+ controlDiv = config.createControls ? config.createControls(browser, config) : createStandardControls(browser, config);
14442
14481
  $(rootDiv).append($(controlDiv));
14443
14482
  }
14444
14483
 
@@ -14462,7 +14501,7 @@ var igv = (function (igv) {
14462
14501
  igv.colorPicker.hide();
14463
14502
 
14464
14503
  // alert object -- singleton shared by all components
14465
- igv.alert = new igv.Dialog($(rootDiv), igv.Dialog.alertConstructor, "igv-alert");
14504
+ igv.alert = new igv.AlertDialog($(rootDiv), "igv-alert");
14466
14505
  igv.alert.hide();
14467
14506
 
14468
14507
  // Dialog object -- singleton shared by all components
@@ -14479,8 +14518,12 @@ var igv = (function (igv) {
14479
14518
  }
14480
14519
 
14481
14520
  // ideogram
14482
- browser.ideoPanel = new igv.IdeoPanel(headerDiv);
14483
- browser.ideoPanel.resize();
14521
+ if (config.hideIdeogram && true === config.hideIdeogram) {
14522
+ // do nothing
14523
+ } else {
14524
+ browser.ideoPanel = new igv.IdeoPanel(headerDiv);
14525
+ browser.ideoPanel.resize();
14526
+ }
14484
14527
 
14485
14528
  // phone home -- counts launches. Count is anonymous, needed for our continued funding. Please don't delete
14486
14529
  phoneHome();
@@ -14535,7 +14578,7 @@ var igv = (function (igv) {
14535
14578
 
14536
14579
  }
14537
14580
 
14538
- });
14581
+ }, true);
14539
14582
 
14540
14583
  } else if (config.tracks) {
14541
14584
 
@@ -14562,9 +14605,12 @@ var igv = (function (igv) {
14562
14605
  $searchContainer,
14563
14606
  $faZoom,
14564
14607
  $trackLabelToggle,
14608
+ $cursorTrackingGuideToggle,
14565
14609
  $zoomContainer,
14566
14610
  $faZoomIn,
14567
- $faZoomOut;
14611
+ $faZoomOut,
14612
+ $karyoPanelToggle,
14613
+ display;
14568
14614
 
14569
14615
  $controls = $('<div id="igvControlDiv">');
14570
14616
 
@@ -14627,25 +14673,50 @@ var igv = (function (igv) {
14627
14673
  $zoomContainer.append($faZoomIn[0]);
14628
14674
  $navigation.append($zoomContainer[0]);
14629
14675
 
14630
- // hide/show track labels
14676
+ // toggle track labels
14631
14677
  $trackLabelToggle = $('<div class="igv-toggle-track-labels">');
14632
14678
  $trackLabelToggle.text("hide labels");
14633
-
14634
14679
  $trackLabelToggle.click(function () {
14635
-
14636
14680
  browser.trackLabelsVisible = !browser.trackLabelsVisible;
14637
14681
  $(this).text(true === browser.trackLabelsVisible ? "hide labels" : "show labels");
14638
-
14639
14682
  $(browser.trackContainerDiv).find('.igv-track-label').toggle();
14640
-
14641
14683
  });
14642
14684
 
14643
- $navigation.append($trackLabelToggle[0]);
14685
+ // one base wide center guide
14686
+ browser.centerGuide = new igv.CenterGuide($(browser.trackContainerDiv), config);
14644
14687
 
14645
- }
14688
+ // cursor tracking guide
14689
+ browser.$cursorTrackingGuide = $('<div class="igv-cursor-tracking-guide">');
14690
+ $(browser.trackContainerDiv).append(browser.$cursorTrackingGuide);
14691
+ browser.$cursorTrackingGuide.css("display", (config.showCursorTrackingGuide && true == config.showCursorTrackingGuide) ? "block" : "none");
14646
14692
 
14647
- if (config.showKaryo) {
14648
- contentKaryo = $('#igvKaryoDiv')[0];
14693
+ $cursorTrackingGuideToggle = $('<div class="igv-toggle-track-labels">');
14694
+ display = browser.$cursorTrackingGuide.css("display");
14695
+ $cursorTrackingGuideToggle.text("none" === display ? "show cursor guide" : "hide cursor guide");
14696
+
14697
+ $cursorTrackingGuideToggle.click(function () {
14698
+ display = browser.$cursorTrackingGuide.css("display");
14699
+ if ("none" === display) {
14700
+ browser.$cursorTrackingGuide.css("display", "block");
14701
+ $cursorTrackingGuideToggle.text("hide cursor guide");
14702
+ } else {
14703
+ browser.$cursorTrackingGuide.css("display", "none");
14704
+ $cursorTrackingGuideToggle.text("show cursor guide");
14705
+ }
14706
+ });
14707
+
14708
+ if(undefined === config.showCursorTrackingGuide || false == config.showCursorTrackingGuide) {
14709
+ $cursorTrackingGuideToggle.css("display", "none");
14710
+ }
14711
+
14712
+ $navigation.append($cursorTrackingGuideToggle);
14713
+ $navigation.append(browser.centerGuide.$centerGuideToggle);
14714
+ $navigation.append($trackLabelToggle);
14715
+
14716
+ }
14717
+
14718
+ if (config.showKaryo) {
14719
+ contentKaryo = $('#igvKaryoDiv')[0];
14649
14720
  // if a karyo div already exists in the page, use that one.
14650
14721
  // this allows the placement of the karyo view on the side, for instance
14651
14722
  if (!contentKaryo) {
@@ -14653,8 +14724,29 @@ var igv = (function (igv) {
14653
14724
  $controls.append(contentKaryo);
14654
14725
  }
14655
14726
  browser.karyoPanel = new igv.KaryoPanel(contentKaryo);
14656
- }
14657
14727
 
14728
+ $karyoPanelToggle = $('<div class="igv-toggle-track-labels">');
14729
+
14730
+ if (config.showKaryo === "hide") {
14731
+ $karyoPanelToggle.text("Show Karyotype");
14732
+ $(contentKaryo).addClass("igv-karyo-hide");
14733
+ } else {
14734
+ $karyoPanelToggle.text("Hide Karyotype");
14735
+ }
14736
+
14737
+ $karyoPanelToggle.click(function () {
14738
+ var hidden = $(".igv-karyo-div").hasClass("igv-karyo-hide");
14739
+ if (hidden) {
14740
+ $karyoPanelToggle.text("Hide Karyotype");
14741
+ $(".igv-karyo-div").removeClass("igv-karyo-hide");
14742
+ } else {
14743
+ $karyoPanelToggle.text("Show Karyotype");
14744
+ $(".igv-karyo-div").addClass("igv-karyo-hide");
14745
+ }
14746
+ });
14747
+
14748
+ $navigation.append($karyoPanelToggle[0]);
14749
+ }
14658
14750
 
14659
14751
  return $controls[0];
14660
14752
  }
@@ -14672,15 +14764,15 @@ var igv = (function (igv) {
14672
14764
  switch (genomeId) {
14673
14765
 
14674
14766
  case "hg18":
14675
- reference.fastaURL = "//s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg18/hg18.fasta";
14676
- reference.cytobandURL = "//s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg18/cytoBand.txt.gz";
14767
+ reference.fastaURL = "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg18/hg18.fasta";
14768
+ reference.cytobandURL = "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg18/cytoBand.txt.gz";
14677
14769
  break;
14678
14770
  case "hg19":
14679
14771
  case "GRCh37":
14680
14772
  default:
14681
14773
  {
14682
- reference.fastaURL = "//s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/hg19.fasta";
14683
- reference.cytobandURL = "//s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/cytoBand.txt";
14774
+ reference.fastaURL = "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/hg19.fasta";
14775
+ reference.cytobandURL = "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/cytoBand.txt";
14684
14776
  }
14685
14777
  }
14686
14778
  return reference;
@@ -14896,75 +14988,20 @@ if (typeof String.prototype.contains === "undefined") {
14896
14988
  };
14897
14989
  }
14898
14990
 
14899
- if (typeof String.prototype.splitLines === "undefined") {
14900
- String.prototype.splitLines = function () {
14901
- return this.split(/\r\n|\n|\r/gm);
14902
- }
14903
- }
14904
-
14905
- if (typeof Array.prototype.shuffle === "undefined") {
14906
- // Randomly shuffle contents of an array
14907
- Array.prototype.shuffle = function () {
14908
- for (var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
14909
- return this;
14991
+ if (typeof String.prototype.includes === "undefined") {
14992
+ String.prototype.includes = function (it) {
14993
+ return this.indexOf(it) != -1;
14910
14994
  };
14911
14995
  }
14912
14996
 
14913
- if (typeof Array.prototype.swap === "undefined") {
14914
- Array.prototype.swap = function (a, b) {
14915
- var tmp = this[a];
14916
- this[a] = this[b];
14917
- this[b] = tmp;
14918
- }
14919
- }
14920
-
14921
14997
 
14922
- if (typeof Array.prototype.heapSort === "undefined") {
14923
-
14924
- Array.prototype.heapSort = function (compare) {
14925
-
14926
- var array = this,
14927
- size = this.length,
14928
- temp;
14929
- buildMaxHeap(array);
14930
- for (var i = size - 1; i > 0; i -= 1) {
14931
- temp = array[0];
14932
- array[0] = array[i];
14933
- array[i] = temp;
14934
- size -= 1;
14935
- heapify(array, 0, size);
14936
- }
14937
- return array;
14938
-
14939
- function heapify(array, index, heapSize) {
14940
-
14941
- var left = 2 * index + 1,
14942
- right = 2 * index + 2,
14943
- largest = index;
14944
-
14945
- if (left < heapSize && compare(array[left], array[index]) > 0)
14946
- largest = left;
14947
-
14948
- if (right < heapSize && compare(array[right], array[largest]) > 0)
14949
- largest = right;
14950
-
14951
- if (largest !== index) {
14952
- var temp = array[index];
14953
- array[index] = array[largest];
14954
- array[largest] = temp;
14955
- heapify(array, largest, heapSize);
14956
- }
14957
- }
14958
-
14959
- function buildMaxHeap(array) {
14960
- for (var i = Math.floor(array.length / 2); i >= 0; i -= 1) {
14961
- heapify(array, i, array.length);
14962
- }
14963
- return array;
14964
- }
14998
+ if (typeof String.prototype.splitLines === "undefined") {
14999
+ String.prototype.splitLines = function () {
15000
+ return this.split(/\r\n|\n|\r/gm);
14965
15001
  }
14966
15002
  }
14967
15003
 
15004
+
14968
15005
  if (typeof Uint8Array.prototype.toText === "undefined") {
14969
15006
 
14970
15007
  Uint8Array.prototype.toText = function () {
@@ -15092,10 +15129,9 @@ var igv = (function (igv) {
15092
15129
 
15093
15130
  igv.presentAlert = function (string) {
15094
15131
 
15095
- igv.alert.configure(function () {
15096
- return string;
15097
- }, undefined, undefined);
15132
+ igv.alert.$dialogLabel.text(string);
15098
15133
  igv.alert.show(undefined);
15134
+
15099
15135
  igv.popover.hide();
15100
15136
 
15101
15137
  };
@@ -15248,44 +15284,44 @@ var igv = (function (igv) {
15248
15284
  return {
15249
15285
  object: $('<div class="igv-track-menu-item">' + "Set track color" + '</div>'),
15250
15286
  click: function () {
15251
- igv.colorPicker.trackView = trackView;
15287
+ igv.colorPicker.configure(trackView);
15252
15288
  igv.colorPicker.show();
15253
15289
  popover.hide();
15254
15290
  }
15255
15291
  }
15256
15292
  };
15257
15293
 
15258
- igv.dialogCloseWithParentObject = function (parentObject, closer) {
15294
+ igv.attachDialogCloseHandlerWithParent = function ($parent, closeHandler) {
15259
15295
 
15260
- var closeContainer = $('<div class="igv-dialog-close-container">'),
15261
- close_fa = $('<i class="fa fa-times igv-dialog-close-fa">');
15296
+ var $container = $('<div class="igv-dialog-close-container">'),
15297
+ $fa = $('<i class="fa fa-times igv-dialog-close-fa">');
15262
15298
 
15263
- closeContainer.append(close_fa[0]);
15264
- parentObject.append(closeContainer[0]);
15299
+ $container.append($fa[0]);
15300
+ $parent.append($container[0]);
15265
15301
 
15266
- close_fa.hover(
15302
+ $fa.hover(
15267
15303
  function () {
15268
- close_fa.removeClass("fa-times");
15269
- close_fa.addClass("fa-times-circle");
15304
+ $fa.removeClass("fa-times");
15305
+ $fa.addClass("fa-times-circle");
15270
15306
 
15271
- close_fa.css({
15307
+ $fa.css({
15272
15308
  "color": "#222"
15273
15309
  });
15274
15310
  },
15275
15311
 
15276
15312
  function () {
15277
- close_fa.removeClass("fa-times-circle");
15278
- //close_fa.removeClass("fa-times-circle fa-lg");
15279
- close_fa.addClass("fa-times");
15313
+ $fa.removeClass("fa-times-circle");
15314
+ //$fa.removeClass("fa-times-circle fa-lg");
15315
+ $fa.addClass("fa-times");
15280
15316
 
15281
- close_fa.css({
15317
+ $fa.css({
15282
15318
  "color": "#444"
15283
15319
  });
15284
15320
 
15285
15321
  }
15286
15322
  );
15287
15323
 
15288
- close_fa.click(closer);
15324
+ $fa.click(closeHandler);
15289
15325
 
15290
15326
  };
15291
15327
 
@@ -15651,7 +15687,7 @@ var igvxhr = (function (igvxhr) {
15651
15687
 
15652
15688
  igvxhr.load = function (url, options) {
15653
15689
 
15654
- if(!options) options = {};
15690
+ if (!options) options = {};
15655
15691
 
15656
15692
  return new Promise(function (fulfill, reject) {
15657
15693
 
@@ -15667,11 +15703,22 @@ var igvxhr = (function (igvxhr) {
15667
15703
  withCredentials = options.withCredentials,
15668
15704
  header_keys, key, value, i;
15669
15705
 
15706
+ // Support for GCS paths.
15707
+ url = url.startsWith("gs://") ? igv.Google.translateGoogleCloudURL(url) : url;
15708
+
15709
+ if (igv.Google.isGoogleURL(url)) {
15670
15710
 
15671
- // Hack to prevent caching for google storage files. Get weird net:err-cache errors otherwise
15672
- if (range && url.contains("googleapis")) {
15673
- url += url.contains("?") ? "&" : "?";
15674
- url += "someRandomSeed=" + Math.random().toString(36);
15711
+ url = igv.Google.addApiKey(url);
15712
+
15713
+ // Add google headers (e.g. oAuth)
15714
+ headers = headers || {};
15715
+ igv.Google.addGoogleHeaders(headers);
15716
+
15717
+ // Hack to prevent caching for google storage files. Get weird net:err-cache errors otherwise
15718
+ if (range) {
15719
+ url += url.includes("?") ? "&" : "?";
15720
+ url += "someRandomSeed=" + Math.random().toString(36);
15721
+ }
15675
15722
  }
15676
15723
 
15677
15724
  xhr.open(method, url);
@@ -15699,7 +15746,6 @@ var igvxhr = (function (igvxhr) {
15699
15746
  }
15700
15747
  }
15701
15748
 
15702
- // let cookies go along to get files from any website we are logged in to
15703
15749
  // NOTE: using withCredentials with servers that return "*" for access-allowed-origin will fail
15704
15750
  if (withCredentials === true) {
15705
15751
  xhr.withCredentials = true;
@@ -16511,9 +16557,12 @@ var igv = (function (igv) {
16511
16557
  var g = igv.guichromosomes[i];
16512
16558
  if (g.x < mouseX && g.right > mouseX && g.y < mouseY && g.bottom > mouseY) {
16513
16559
  var dy = mouseY - g.y;
16514
- var bp = Math.round(g.size * dy / g.h);
16515
- log("Going to position " + bp);
16516
- igv.browser.goto(g.name, bp);
16560
+ var center = Math.round(g.size * dy / g.h);
16561
+ log("Going to position " + center);
16562
+
16563
+ // the goto() signature is chr, start, end. We leave end undefined changing
16564
+ // the interpretation of start to the center of the locus extent.
16565
+ igv.browser.goto(g.name, center, undefined);
16517
16566
  break;
16518
16567
  }
16519
16568
  }
@@ -18160,7 +18209,8 @@ var igv = (function (igv) {
18160
18209
  /*
18161
18210
  * The MIT License (MIT)
18162
18211
  *
18163
- * Copyright (c) 2014 Broad Institute
18212
+ * Copyright (c) 2016 University of California San Diego
18213
+ * Author: Jim Robinson
18164
18214
  *
18165
18215
  * Permission is hereby granted, free of charge, to any person obtaining a copy
18166
18216
  * of this software and associated documentation files (the "Software"), to deal
@@ -18182,220 +18232,907 @@ var igv = (function (igv) {
18182
18232
  * THE SOFTWARE.
18183
18233
  */
18184
18234
 
18235
+ /**
18236
+ * Created by jrobinso on 11/22/2016.
18237
+ */
18185
18238
 
18186
- // Generic functions applicable to all track types
18187
18239
 
18188
18240
  var igv = (function (igv) {
18189
18241
 
18190
- /**
18191
- * Set defaults for properties applicable to all tracks.
18192
- * Insure required "config" properties are set.
18193
- * @param track
18194
- * @param config
18195
- */
18196
- igv.configTrack = function (track, config) {
18197
18242
 
18198
- track.config = config;
18199
- track.url = config.url;
18243
+ var GZIP_FLAG = 0x1;
18200
18244
 
18201
- config.name = config.name || config.label; // synonym for name, label is deprecated
18202
- if (config.name) {
18203
- track.name = config.name;
18204
- }
18205
- else {
18206
- if (config.localFile) track.name = config.localFile.name;
18207
- else track.name = config.url;
18208
18245
 
18209
- }
18210
18246
 
18211
- track.id = config.id || track.name; // TODO -- remove this property, not used
18247
+ igv.TDFReader = function (config) {
18248
+ this.config = config || {};
18249
+ this.path = config.url;
18250
+ this.groupCache = {};
18251
+ };
18212
18252
 
18213
- track.order = config.order;
18214
- track.color = config.color || igv.browser.constants.defaultColor;
18215
18253
 
18216
- track.removable = config.removable === undefined ? true : config.removable; // Defaults to true
18254
+ igv.TDFReader.prototype.readHeader = function () {
18217
18255
 
18218
- track.height = config.height || ("annotation" === config.type ? 100 : 50);
18219
- track.autoHeight = config.autoHeight === undefined ? true : config.autoHeight;
18220
- track.minHeight = config.minHeight || Math.min(50, track.height);
18221
- track.maxHeight = config.maxHeight || Math.max(500, track.height);
18256
+ var self = this;
18222
18257
 
18223
- if (config.visibilityWindow) {
18224
- track.visibilityWindow = config.visibilityWindow;
18258
+ if (this.magic !== undefined) {
18259
+ return Promise.resolve(this); // Already read
18225
18260
  }
18226
- };
18227
18261
 
18262
+ return new Promise(function (fulfill, reject) {
18228
18263
 
18229
- igv.setTrackLabel = function (track, label) {
18230
-
18231
- track.name = label;
18232
-
18233
- $(track.trackView.viewportDiv).find('.igv-track-label').text(track.name);
18264
+ igvxhr.loadArrayBuffer(self.path, Object.assign(self.config, {range: {start: 0, size: 64000}}))
18265
+ .then(function (data) {
18234
18266
 
18235
- if (track.trackView) {
18236
- track.trackView.repaint();
18237
- }
18238
- };
18267
+ if (!data) {
18268
+ reject("no data");
18269
+ return;
18270
+ }
18239
18271
 
18240
- igv.setTrackColor = function (track, color) {
18272
+ var binaryParser = new igv.BinaryParser(new DataView(data));
18241
18273
 
18242
- track.color = color;
18274
+ self.magic = binaryParser.getInt();
18275
+ self.version = binaryParser.getInt();
18276
+ self.indexPos = binaryParser.getLong();
18277
+ self.indexSize = binaryParser.getInt();
18278
+ var headerSize = binaryParser.getInt();
18243
18279
 
18244
- if (track.trackView) {
18245
18280
 
18246
- track.trackView.repaint();
18281
+ if (self.version >= 2) {
18282
+ var nWindowFunctions = binaryParser.getInt();
18283
+ self.windowFunctions = [];
18284
+ while (nWindowFunctions-- > 0) {
18285
+ self.windowFunctions.push(binaryParser.getString());
18286
+ }
18287
+ }
18247
18288
 
18248
- }
18289
+ self.trackType = binaryParser.getString();
18290
+ self.trackLine = binaryParser.getString();
18249
18291
 
18250
- };
18292
+ var nTracks = binaryParser.getInt();
18293
+ self.trackNames = [];
18294
+ while (nTracks-- > 0) {
18295
+ self.trackNames.push(binaryParser.getString());
18296
+ }
18251
18297
 
18252
- igv.paintAxis = function (ctx, pixelWidth, pixelHeight) {
18298
+ self.genomeID = binaryParser.getString();
18299
+ self.flags = binaryParser.getInt();
18253
18300
 
18254
- var x1,
18255
- x2,
18256
- y1,
18257
- y2,
18258
- a,
18259
- b,
18260
- reference,
18261
- shim,
18262
- font = {
18263
- 'font': 'normal 10px Arial',
18264
- 'textAlign': 'right',
18265
- 'strokeStyle': "black"
18266
- };
18301
+ self.compressed = (self.flags & GZIP_FLAG) != 0;
18267
18302
 
18268
- if (undefined === this.dataRange || undefined === this.dataRange.max || undefined === this.dataRange.min) {
18269
- return;
18270
- }
18303
+ // Now read index
18304
+ igvxhr.loadArrayBuffer(self.path, Object.assign(self.config, {
18305
+ range: {
18306
+ start: self.indexPos,
18307
+ size: self.indexSize
18308
+ }
18309
+ }))
18310
+ .then(function (data) {
18271
18311
 
18272
- igv.graphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
18273
18312
 
18274
- reference = 0.95 * pixelWidth;
18275
- x1 = reference - 8;
18276
- x2 = reference;
18313
+ if (!data) {
18314
+ reject("no data");
18315
+ return;
18316
+ }
18277
18317
 
18278
- //shim = 0.5 * 0.125;
18279
- shim = .01;
18280
- y1 = y2 = shim * pixelHeight;
18318
+ binaryParser = new igv.BinaryParser(new DataView(data));
18281
18319
 
18282
- a = {x: x2, y: y1};
18320
+ self.datasetIndex = {};
18321
+ var nEntries = binaryParser.getInt();
18322
+ while (nEntries-- > 0) {
18323
+ var name = binaryParser.getString();
18324
+ var pos = binaryParser.getLong();
18325
+ var size = binaryParser.getInt();
18326
+ self.datasetIndex[name] = {position: pos, size: size};
18327
+ }
18283
18328
 
18284
- // tick
18285
- igv.graphics.strokeLine(ctx, x1, y1, x2, y2, font);
18286
- igv.graphics.fillText(ctx, prettyPrint(this.dataRange.max), x1 + 4, y1 + 12, font);
18329
+ self.groupIndex = {};
18330
+ nEntries = binaryParser.getInt();
18331
+ while (nEntries-- > 0) {
18332
+ name = binaryParser.getString();
18333
+ pos = binaryParser.getLong();
18334
+ size = binaryParser.getInt();
18335
+ self.groupIndex[name] = {position: pos, size: size};
18336
+ }
18287
18337
 
18288
- //shim = 0.25 * 0.125;
18289
- y1 = y2 = (1.0 - shim) * pixelHeight;
18338
+ fulfill(self);
18290
18339
 
18291
- b = {x: x2, y: y1};
18340
+ }).catch(reject);
18292
18341
 
18293
- // tick
18294
- igv.graphics.strokeLine(ctx, x1, y1, x2, y2, font);
18295
- igv.graphics.fillText(ctx, prettyPrint(this.dataRange.min), x1 + 4, y1 - 4, font);
18342
+ }).catch(reject)
18296
18343
 
18297
- igv.graphics.strokeLine(ctx, a.x, a.y, b.x, b.y, font);
18344
+ });
18345
+ }
18298
18346
 
18299
- function prettyPrint(number) {
18300
- // if number >= 100, show whole number
18301
- // if >= 1 show 1 significant digits
18302
- // if < 1 show 2 significant digits
18347
+ igv.TDFReader.prototype.readDataset = function (chr, windowFunction, zoom) {
18303
18348
 
18304
- if (number === 0) {
18305
- return "0";
18306
- } else if (Math.abs(number) >= 10) {
18307
- return number.toFixed();
18308
- } else if (Math.abs(number) >= 1) {
18309
- return number.toFixed(1);
18310
- } else {
18311
- return number.toFixed(2);
18312
- }
18313
- }
18349
+ var self = this;
18314
18350
 
18315
- };
18351
+ return new Promise(function (fulfill, reject) {
18316
18352
 
18317
18353
 
18318
- return igv;
18319
- })(igv || {});
18320
- /*
18321
- * The MIT License (MIT)
18322
- *
18323
- * Copyright (c) 2014 Broad Institute
18324
- *
18325
- * Permission is hereby granted, free of charge, to any person obtaining a copy
18326
- * of this software and associated documentation files (the "Software"), to deal
18327
- * in the Software without restriction, including without limitation the rights
18328
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18329
- * copies of the Software, and to permit persons to whom the Software is
18330
- * furnished to do so, subject to the following conditions:
18331
- *
18332
- * The above copyright notice and this permission notice shall be included in
18333
- * all copies or substantial portions of the Software.
18334
- *
18335
- *
18336
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18337
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18338
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18339
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18340
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18341
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18342
- * THE SOFTWARE.
18343
- */
18354
+ self.readHeader().then(function (reader) {
18344
18355
 
18356
+ var wf = (self.version < 2) ? "" : "/" + windowFunction,
18357
+ zoomString = (chr === "all" || zoom === undefined) ? "0" : zoom.toString(),
18358
+ dsName,
18359
+ indexEntry;
18345
18360
 
18346
- var igv = (function (igv) {
18361
+ if (windowFunction === "raw") {
18362
+ dsName = "/" + chr + "/raw";
18363
+ }
18364
+ else {
18365
+ dsName = "/" + chr + "/z" + zoomString + wf;
18366
+ }
18367
+ indexEntry = self.datasetIndex[dsName];
18347
18368
 
18348
- igv.TrackView = function (track, browser) {
18369
+ if (indexEntry === undefined) {
18370
+ fulfill(null);
18371
+ }
18372
+ else {
18349
18373
 
18350
- var self = this,
18351
- element;
18352
18374
 
18353
- this.track = track;
18354
- this.browser = browser;
18375
+ igvxhr.loadArrayBuffer(self.path, Object.assign(self.config, {
18376
+ range: {
18377
+ start: indexEntry.position,
18378
+ size: indexEntry.size
18379
+ }
18380
+ }))
18381
+ .then(function (data) {
18355
18382
 
18356
- this.trackDiv = $('<div class="igv-track-div">')[0];
18357
- $(browser.trackContainerDiv).append(this.trackDiv);
18383
+ if (!data) {
18384
+ reject("no data");
18385
+ return;
18386
+ }
18358
18387
 
18359
- // Optionally override CSS height
18360
- if (track.height) { // Explicit height set, perhaps track.config.height?
18361
- this.trackDiv.style.height = track.height + "px";
18362
- }
18388
+ var binaryParser = new igv.BinaryParser(new DataView(data));
18363
18389
 
18364
- this.appendLeftHandGutterDivToTrackDiv($(this.trackDiv));
18365
- this.appendViewportDivToTrackDiv($(this.trackDiv));
18390
+ var nAttributes = binaryParser.getInt();
18391
+ var attributes = {};
18392
+ while (nAttributes-- > 0) {
18393
+ attributes[binaryParser.getString()] = binaryParser.getString();
18394
+ }
18366
18395
 
18367
- element = this.createRightHandGutter();
18368
- if (element) {
18369
- $(this.trackDiv).append(element);
18370
- }
18396
+ var dataType = binaryParser.getString();
18397
+ var tileWidth = binaryParser.getFloat();
18371
18398
 
18372
- this.trackDiv.appendChild(igv.spinner());
18399
+ var nTiles = binaryParser.getInt();
18400
+ var tiles = [];
18401
+ while (nTiles-- > 0) {
18402
+ tiles.push({position: binaryParser.getLong(), size: binaryParser.getInt()});
18403
+ }
18373
18404
 
18374
- // Track Drag & Drop
18375
- makeTrackDraggable(this.track);
18405
+ var dataset = {
18406
+ name: dsName,
18407
+ attributes: attributes,
18408
+ dataType: dataType,
18409
+ tileWidth: tileWidth,
18410
+ tiles: tiles
18411
+ };
18376
18412
 
18377
- if (this.track instanceof igv.RulerTrack) {
18413
+ fulfill(dataset);
18378
18414
 
18379
- this.trackDiv.dataset.rulerTrack = "rulerTrack";
18415
+ }).catch(reject);
18416
+ }
18417
+ }).catch(reject);
18418
+ });
18419
+ }
18380
18420
 
18381
- // ruler sweeper widget surface
18382
- this.rulerSweeper = $('<div class="igv-ruler-sweeper-div">');
18383
- $(this.contentDiv).append(this.rulerSweeper[0]);
18421
+ igv.TDFReader.prototype.readRootGroup = function () {
18384
18422
 
18385
- addRulerTrackHandlers(this);
18423
+ var self = this,
18424
+ rootGroup = this.groupCache["/"];
18386
18425
 
18387
- } else {
18388
- addTrackHandlers(this);
18426
+ if (rootGroup) {
18427
+ return Promise.resolve(rootGroup);
18389
18428
  }
18429
+ else {
18430
+ return new Promise(function (fulfill, reject) {
18390
18431
 
18391
- $('.igv-ideogram-content-div').addClass('igv-ideogram-gutter-shim');
18392
- $('.igv-viewport-div').addClass('igv-gutter-shim');
18432
+ self.readGroup("/").then(function (group) {
18393
18433
 
18394
- function makeTrackDraggable(track) {
18434
+ var genome = igv.browser.genome,
18435
+ names = group["chromosomes"],
18436
+ maxZoomString = group["maxZoom"];
18395
18437
 
18396
- self.igvTrackDragScrim = $('<div class="igv-track-drag-scrim">')[0];
18397
- $(self.viewportDiv).append(self.igvTrackDragScrim);
18398
- $(self.igvTrackDragScrim).hide();
18438
+ // Now parse out interesting attributes. This is a side effect, and bad bad bad, but the alternative is messy as well.
18439
+ if (maxZoomString) {
18440
+ self.maxZoom = Number(maxZoomString);
18441
+ }
18442
+
18443
+ // Chromosome names
18444
+ self.chrNameMap = {};
18445
+ if (names) {
18446
+ names.split(",").forEach( function (chr) {
18447
+ var canonicalName = genome.getChromosomeName(chr);
18448
+ self.chrNameMap[canonicalName] = chr;
18449
+ })
18450
+ }
18451
+
18452
+ fulfill(group);
18453
+
18454
+
18455
+ }).catch(reject);
18456
+ });
18457
+
18458
+ }
18459
+ }
18460
+
18461
+ igv.TDFReader.prototype.readGroup = function (name) {
18462
+
18463
+ var self = this;
18464
+
18465
+ return new Promise(function (fulfill, reject) {
18466
+
18467
+
18468
+ self.readHeader().then(function (reader) {
18469
+
18470
+ var group = self.groupCache[name],
18471
+ indexEntry = self.groupIndex[name];
18472
+
18473
+ if (group) {
18474
+ fulfill(group);
18475
+ }
18476
+ else if (indexEntry === undefined) {
18477
+ return fulfill(null);
18478
+ }
18479
+ else {
18480
+
18481
+
18482
+ igvxhr.loadArrayBuffer(self.path, Object.assign(self.config, {
18483
+ range: {
18484
+ start: indexEntry.position,
18485
+ size: indexEntry.size
18486
+ }
18487
+ }))
18488
+ .then(function (data) {
18489
+
18490
+ if (!data) {
18491
+ reject("no data");
18492
+ return;
18493
+ }
18494
+
18495
+ var binaryParser = new igv.BinaryParser(new DataView(data));
18496
+
18497
+ var nAttributes = binaryParser.getInt();
18498
+ var group = {name: name};
18499
+ while (nAttributes-- > 0) {
18500
+ group[binaryParser.getString()] = binaryParser.getString();
18501
+ }
18502
+
18503
+ self.groupCache[name] = group;
18504
+
18505
+ fulfill(group);
18506
+
18507
+ }).catch(reject);
18508
+ }
18509
+ }).catch(reject);
18510
+ });
18511
+ }
18512
+
18513
+
18514
+ function createFixedStep(binaryParser, nTracks) {
18515
+ var nPositions = binaryParser.getInt(),
18516
+ start = binaryParser.getInt(),
18517
+ span = binaryParser.getFloat(),
18518
+ np = nPositions,
18519
+ nt = nTracks,
18520
+ data,
18521
+ dtrack;
18522
+
18523
+
18524
+ data = [];
18525
+ while (nt-- > 0) {
18526
+ np = nPositions;
18527
+ dtrack = [];
18528
+ while (np-- > 0) {
18529
+ dtrack.push(binaryParser.getFloat());
18530
+ }
18531
+ data.push(dtrack);
18532
+ }
18533
+
18534
+ return {
18535
+ type: "fixedStep",
18536
+ start: start,
18537
+ span: span,
18538
+ data: data,
18539
+ nTracks: nTracks,
18540
+ nPositions: nPositions
18541
+ }
18542
+ }
18543
+
18544
+ function createVariableStep(binaryParser, nTracks) {
18545
+
18546
+ var tileStart = binaryParser.getInt(),
18547
+ span = binaryParser.getFloat(),
18548
+ nPositions = binaryParser.getInt(),
18549
+ np = nPositions,
18550
+ nt = nTracks,
18551
+ start = [],
18552
+ data,
18553
+ dtrack;
18554
+
18555
+ while (np-- > 0) {
18556
+ start.push(binaryParser.getInt());
18557
+ }
18558
+
18559
+ var nS = binaryParser.getInt(); // # of samples, ignored but should === nTracks
18560
+
18561
+ data = [];
18562
+ while (nt-- > 0) {
18563
+ np = nPositions;
18564
+ dtrack = [];
18565
+ while (np-- > 0) {
18566
+ dtrack.push(binaryParser.getFloat());
18567
+ }
18568
+ data.push(dtrack);
18569
+ }
18570
+
18571
+ return {
18572
+ type: "variableStep",
18573
+ tileStart: tileStart,
18574
+ span: span,
18575
+ start: start,
18576
+ data: data,
18577
+ nTracks: nTracks,
18578
+ nPositions: nPositions
18579
+ }
18580
+ }
18581
+
18582
+ function createBed(binaryParser, nTracks, type) {
18583
+ var nPositions, start, end, nS, data, name, n, nt;
18584
+
18585
+ nPositions = binaryParser.getInt();
18586
+
18587
+ n = nPositions;
18588
+ start = [];
18589
+ while (n-- > 0) {
18590
+ start.push(binaryParser.getInt());
18591
+ }
18592
+
18593
+ n = nPositions;
18594
+ end = [];
18595
+ while (n-- > 0) {
18596
+ end.push(binaryParser.getInt());
18597
+ }
18598
+
18599
+ var nS = binaryParser.getInt(); // # of samples, ignored but should === nTracks
18600
+
18601
+ data = [];
18602
+ nt = nTracks;
18603
+ while (nt-- > 0) {
18604
+ np = nPositions;
18605
+ dtrack = [];
18606
+ while (np-- > 0) {
18607
+ dtrack.push(binaryParser.getFloat());
18608
+ }
18609
+ data.push(dtrack);
18610
+ }
18611
+
18612
+ if (type === "bedWithName") {
18613
+ n = nPositions;
18614
+ name = [];
18615
+ while (n-- > 0) {
18616
+ name.push(binaryParser.getString());
18617
+ }
18618
+ }
18619
+
18620
+ return {
18621
+ type: type,
18622
+ start: start,
18623
+ end: end,
18624
+ data: data,
18625
+ name: name,
18626
+ nTracks: nTracks,
18627
+ nPositions: nPositions
18628
+ }
18629
+
18630
+ }
18631
+
18632
+
18633
+ igv.TDFReader.prototype.readTile = function (indexEntry, nTracks) {
18634
+
18635
+ var self = this;
18636
+
18637
+ return new Promise(function (fulfill, reject) {
18638
+
18639
+ igvxhr.loadArrayBuffer(self.path, Object.assign(self.config, {
18640
+ range: {
18641
+ start: indexEntry.position,
18642
+ size: indexEntry.size
18643
+ }
18644
+ }))
18645
+ .then(function (data) {
18646
+
18647
+ if (!data) {
18648
+ reject("no data");
18649
+ return;
18650
+ }
18651
+
18652
+ if (self.compressed) {
18653
+ var inflate = new Zlib.Inflate(new Uint8Array(data));
18654
+ var plain = inflate.decompress();
18655
+ data = plain.buffer;
18656
+ }
18657
+
18658
+ var binaryParser = new igv.BinaryParser(new DataView(data));
18659
+
18660
+ var type = binaryParser.getString();
18661
+
18662
+ switch (type) {
18663
+ case "fixedStep":
18664
+ fulfill(createFixedStep(binaryParser, nTracks));
18665
+ break;
18666
+ case "variableStep":
18667
+ fulfill(createVariableStep(binaryParser, nTracks));
18668
+ break;
18669
+ case "bed":
18670
+ case "bedWithName":
18671
+ fulfill(createBed(binaryParser, nTracks, type));
18672
+ break;
18673
+ default:
18674
+ reject("Unknown tile type: " + type);
18675
+ }
18676
+
18677
+
18678
+ }).catch(reject);
18679
+
18680
+ });
18681
+
18682
+ }
18683
+
18684
+ return igv;
18685
+
18686
+ })
18687
+ (igv || {});
18688
+
18689
+ /*
18690
+ * The MIT License (MIT)
18691
+ *
18692
+ * Copyright (c) 2016 University of California San Diego
18693
+ * Author: Jim Robinson
18694
+ *
18695
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
18696
+ * of this software and associated documentation files (the "Software"), to deal
18697
+ * in the Software without restriction, including without limitation the rights
18698
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18699
+ * copies of the Software, and to permit persons to whom the Software is
18700
+ * furnished to do so, subject to the following conditions:
18701
+ *
18702
+ * The above copyright notice and this permission notice shall be included in
18703
+ * all copies or substantial portions of the Software.
18704
+ *
18705
+ *
18706
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18707
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18708
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18709
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18710
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18711
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18712
+ * THE SOFTWARE.
18713
+ */
18714
+
18715
+ /**
18716
+ * Created by jrobinso on 11/27/16.
18717
+ */
18718
+
18719
+
18720
+ var igv = (function (igv) {
18721
+
18722
+ igv.TDFSource = function (config) {
18723
+
18724
+ this.windowFunction = config.windowFunction || "mean";
18725
+ this.reader = new igv.TDFReader(config);
18726
+ };
18727
+
18728
+ igv.TDFSource.prototype.getFeatures = function (chr, bpStart, bpEnd) {
18729
+
18730
+ var self = this,
18731
+ bpPerPixel = igv.browser.referenceFrame.bpPerPixel;
18732
+
18733
+ return new Promise(function (fulfill, reject) {
18734
+
18735
+ self.reader.readRootGroup().then(function (group) {
18736
+
18737
+ var zoom = zoomLevelForScale(chr, bpPerPixel),
18738
+ queryChr = self.reader.chrNameMap[chr],
18739
+ maxZoom = self.reader.maxZoom,
18740
+ wf,
18741
+ dataset;
18742
+
18743
+ if (queryChr === undefined) queryChr = chr;
18744
+ if (maxZoom === undefined) maxZoom = -1;
18745
+
18746
+ wf = zoom > maxZoom ? "raw" : self.windowFunction;
18747
+
18748
+ self.reader.readDataset(queryChr, wf, zoom).then(function (dataset) {
18749
+
18750
+ if(dataset == null) {
18751
+ fulfill(null);
18752
+ return;
18753
+ }
18754
+
18755
+ var tileWidth = dataset.tileWidth,
18756
+ startTile = Math.floor(bpStart / tileWidth),
18757
+ endTile = Math.floor(bpEnd / tileWidth),
18758
+ i,
18759
+ p = [],
18760
+ NTRACKS = 1; // TODO read this
18761
+
18762
+ for (i = startTile; i <= endTile; i++) {
18763
+ if(dataset.tiles[i] !== undefined) {
18764
+ p.push(self.reader.readTile(dataset.tiles[i], NTRACKS));
18765
+ }
18766
+ }
18767
+
18768
+ Promise.all(p).then(function (tiles) {
18769
+ var features = [];
18770
+ tiles.forEach(function (tile) {
18771
+ switch (tile.type) {
18772
+ case "bed":
18773
+ decodeBedTile(tile, chr, bpStart, bpEnd, bpPerPixel, features);
18774
+ break;
18775
+ case "variableStep":
18776
+ decodeVaryTile(tile, chr, bpStart, bpEnd, bpPerPixel, features);
18777
+ break;
18778
+ case "fixedStep":
18779
+ decodeFixedTile(tile, chr, bpStart, bpEnd, bpPerPixel, features);
18780
+ break;
18781
+ default:
18782
+ reject("Unknown tile type: " + tile.type);
18783
+ return;
18784
+ }
18785
+ })
18786
+ fulfill(features);
18787
+
18788
+ }).catch(reject)
18789
+
18790
+
18791
+ }).catch(reject)
18792
+ })
18793
+ });
18794
+ }
18795
+
18796
+ function decodeBedTile(tile, chr, bpStart, bpEnd, bpPerPixel, features) {
18797
+
18798
+ var nPositions = tile.nPositions,
18799
+ starts = tile.start,
18800
+ ends = tile.end,
18801
+ data = tile.data[0], // Single track for now
18802
+ i;
18803
+
18804
+ for (i = 0; i < nPositions; i++) {
18805
+
18806
+ var s = starts[i];
18807
+ var e = ends[i];
18808
+
18809
+ if (e < bpStart) continue;
18810
+ if (s > bpEnd) break;
18811
+
18812
+ features.push({
18813
+ start: s,
18814
+ end: e,
18815
+ value: data[i]
18816
+ });
18817
+ }
18818
+ }
18819
+
18820
+ function decodeVaryTile(tile, chr, bpStart, bpEnd, bpPerPixel, features) {
18821
+
18822
+ var nPositions = tile.nPositions,
18823
+ starts = tile.start,
18824
+ span = tile.span,
18825
+ data = tile.data[0], // Single track for now
18826
+ i;
18827
+
18828
+ for (i = 0; i < nPositions; i++) {
18829
+
18830
+ var s = starts[i];
18831
+ var e = s + span;
18832
+
18833
+ if (e < bpStart) continue;
18834
+ if (s > bpEnd) break;
18835
+
18836
+ features.push({
18837
+ start: s,
18838
+ end: e,
18839
+ value: data[i]
18840
+ });
18841
+ }
18842
+ }
18843
+
18844
+ function decodeFixedTile(tile, chr, bpStart, bpEnd, bpPerPixel, features) {
18845
+
18846
+ var nPositions = tile.nPositions,
18847
+ s = tile.start,
18848
+ span = tile.span,
18849
+ data = tile.data[0], // Single track for now
18850
+ i;
18851
+
18852
+ for (i = 0; i < nPositions; i++) {
18853
+
18854
+ var e = s + span;
18855
+
18856
+ if (e < bpStart) continue;
18857
+ if (s > bpEnd) break;
18858
+
18859
+ if(!Number.isNaN(data[i])) {
18860
+ features.push({
18861
+ start: s,
18862
+ end: e,
18863
+ value: data[i]
18864
+ });
18865
+ }
18866
+
18867
+ s = e;
18868
+ }
18869
+ }
18870
+
18871
+
18872
+ var log2 = Math.log(2);
18873
+
18874
+ function zoomLevelForScale(chr, bpPerPixel) {
18875
+
18876
+ // Convert bpPerPixel to IGV "zoom" level. This is a bit convoluted, IGV computes zoom levels assuming
18877
+ // display in a 700 pixel window. The fully zoomed out view of a chromosome is zoom level "0".
18878
+ // Zoom level 1 is magnified 2X, and so forth
18879
+
18880
+ var chrSize = igv.browser.genome.getChromosome(chr).bpLength;
18881
+
18882
+ return Math.ceil(Math.log(Math.max(0, (chrSize / (bpPerPixel * 700)))) / log2);
18883
+ }
18884
+
18885
+
18886
+ return igv;
18887
+
18888
+
18889
+ })
18890
+ (igv || {});
18891
+
18892
+ /*
18893
+ * The MIT License (MIT)
18894
+ *
18895
+ * Copyright (c) 2014 Broad Institute
18896
+ *
18897
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
18898
+ * of this software and associated documentation files (the "Software"), to deal
18899
+ * in the Software without restriction, including without limitation the rights
18900
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18901
+ * copies of the Software, and to permit persons to whom the Software is
18902
+ * furnished to do so, subject to the following conditions:
18903
+ *
18904
+ * The above copyright notice and this permission notice shall be included in
18905
+ * all copies or substantial portions of the Software.
18906
+ *
18907
+ *
18908
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18909
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18910
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18911
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18912
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18913
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
18914
+ * THE SOFTWARE.
18915
+ */
18916
+
18917
+
18918
+ // Generic functions applicable to all track types
18919
+
18920
+ var igv = (function (igv) {
18921
+
18922
+ /**
18923
+ * Set defaults for properties applicable to all tracks.
18924
+ * Insure required "config" properties are set.
18925
+ * @param track
18926
+ * @param config
18927
+ */
18928
+ igv.configTrack = function (track, config) {
18929
+
18930
+ track.config = config;
18931
+ track.url = config.url;
18932
+
18933
+ config.name = config.name || config.label; // synonym for name, label is deprecated
18934
+ if (config.name) {
18935
+ track.name = config.name;
18936
+ }
18937
+ else {
18938
+ if (config.localFile) track.name = config.localFile.name;
18939
+ else track.name = config.url;
18940
+
18941
+ }
18942
+
18943
+ track.id = config.id || track.name; // TODO -- remove this property, not used
18944
+
18945
+ track.order = config.order;
18946
+ track.color = config.color || igv.browser.constants.defaultColor;
18947
+
18948
+ track.removable = config.removable === undefined ? true : config.removable; // Defaults to true
18949
+
18950
+ track.height = config.height || ('wig' === config.type ? 50 : 100);
18951
+
18952
+ if(config.autoHeight === undefined) config.autoHeight = config.autoheight; // Some case confusion in the initial releasae
18953
+
18954
+ track.autoHeight = config.autoHeight === undefined ?
18955
+ (config.height === undefined ? true : false) :
18956
+ config.autoHeight;
18957
+ track.minHeight = config.minHeight || Math.min(50, track.height);
18958
+ track.maxHeight = config.maxHeight || Math.max(500, track.height);
18959
+
18960
+ if (config.visibilityWindow) {
18961
+ track.visibilityWindow = config.visibilityWindow;
18962
+ }
18963
+ };
18964
+
18965
+
18966
+ igv.setTrackLabel = function (track, label) {
18967
+
18968
+ track.name = label;
18969
+
18970
+ $(track.trackView.viewportDiv).find('.igv-track-label').html(track.name);
18971
+
18972
+ if (track.trackView) {
18973
+ track.trackView.repaint();
18974
+ }
18975
+ };
18976
+
18977
+ igv.setTrackColor = function (track, color) {
18978
+
18979
+ track.color = color;
18980
+
18981
+ if (track.trackView) {
18982
+
18983
+ track.trackView.repaint();
18984
+
18985
+ }
18986
+
18987
+ };
18988
+
18989
+ igv.paintAxis = function (ctx, pixelWidth, pixelHeight) {
18990
+
18991
+ var x1,
18992
+ x2,
18993
+ y1,
18994
+ y2,
18995
+ a,
18996
+ b,
18997
+ reference,
18998
+ shim,
18999
+ font = {
19000
+ 'font': 'normal 10px Arial',
19001
+ 'textAlign': 'right',
19002
+ 'strokeStyle': "black"
19003
+ };
19004
+
19005
+ if (undefined === this.dataRange || undefined === this.dataRange.max || undefined === this.dataRange.min) {
19006
+ return;
19007
+ }
19008
+
19009
+ igv.graphics.fillRect(ctx, 0, 0, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"});
19010
+
19011
+ reference = 0.95 * pixelWidth;
19012
+ x1 = reference - 8;
19013
+ x2 = reference;
19014
+
19015
+ //shim = 0.5 * 0.125;
19016
+ shim = .01;
19017
+ y1 = y2 = shim * pixelHeight;
19018
+
19019
+ a = {x: x2, y: y1};
19020
+
19021
+ // tick
19022
+ igv.graphics.strokeLine(ctx, x1, y1, x2, y2, font);
19023
+ igv.graphics.fillText(ctx, prettyPrint(this.dataRange.max), x1 + 4, y1 + 12, font);
19024
+
19025
+ //shim = 0.25 * 0.125;
19026
+ y1 = y2 = (1.0 - shim) * pixelHeight;
19027
+
19028
+ b = {x: x2, y: y1};
19029
+
19030
+ // tick
19031
+ igv.graphics.strokeLine(ctx, x1, y1, x2, y2, font);
19032
+ igv.graphics.fillText(ctx, prettyPrint(this.dataRange.min), x1 + 4, y1 - 4, font);
19033
+
19034
+ igv.graphics.strokeLine(ctx, a.x, a.y, b.x, b.y, font);
19035
+
19036
+ function prettyPrint(number) {
19037
+ // if number >= 100, show whole number
19038
+ // if >= 1 show 1 significant digits
19039
+ // if < 1 show 2 significant digits
19040
+
19041
+ if (number === 0) {
19042
+ return "0";
19043
+ } else if (Math.abs(number) >= 10) {
19044
+ return number.toFixed();
19045
+ } else if (Math.abs(number) >= 1) {
19046
+ return number.toFixed(1);
19047
+ } else {
19048
+ return number.toFixed(2);
19049
+ }
19050
+ }
19051
+
19052
+ };
19053
+
19054
+
19055
+ return igv;
19056
+ })(igv || {});
19057
+ /*
19058
+ * The MIT License (MIT)
19059
+ *
19060
+ * Copyright (c) 2014 Broad Institute
19061
+ *
19062
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
19063
+ * of this software and associated documentation files (the "Software"), to deal
19064
+ * in the Software without restriction, including without limitation the rights
19065
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19066
+ * copies of the Software, and to permit persons to whom the Software is
19067
+ * furnished to do so, subject to the following conditions:
19068
+ *
19069
+ * The above copyright notice and this permission notice shall be included in
19070
+ * all copies or substantial portions of the Software.
19071
+ *
19072
+ *
19073
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19074
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19075
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19076
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19077
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19078
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19079
+ * THE SOFTWARE.
19080
+ */
19081
+
19082
+
19083
+ var igv = (function (igv) {
19084
+
19085
+ igv.TrackView = function (track, browser) {
19086
+
19087
+ var self = this,
19088
+ element;
19089
+
19090
+ this.track = track;
19091
+ this.browser = browser;
19092
+
19093
+ this.trackDiv = $('<div class="igv-track-div">')[0];
19094
+ $(browser.trackContainerDiv).append(this.trackDiv);
19095
+
19096
+ // Optionally override CSS height
19097
+ if (track.height) { // Explicit height set, perhaps track.config.height?
19098
+ this.trackDiv.style.height = track.height + "px";
19099
+ }
19100
+
19101
+ this.appendLeftHandGutterDivToTrackDiv($(this.trackDiv));
19102
+ this.appendViewportDivToTrackDiv($(this.trackDiv));
19103
+
19104
+ element = this.createRightHandGutter();
19105
+ if (element) {
19106
+ $(this.trackDiv).append(element);
19107
+ }
19108
+
19109
+ this.trackDiv.appendChild(igv.spinner());
19110
+
19111
+ // Track Drag & Drop
19112
+ makeTrackDraggable(this.track);
19113
+
19114
+ if (this.track instanceof igv.RulerTrack) {
19115
+
19116
+ this.trackDiv.dataset.rulerTrack = "rulerTrack";
19117
+
19118
+ // ruler sweeper widget surface
19119
+ this.rulerSweeper = $('<div class="igv-ruler-sweeper-div">');
19120
+ $(this.contentDiv).append(this.rulerSweeper[0]);
19121
+
19122
+ addRulerTrackHandlers(this);
19123
+
19124
+ } else {
19125
+ addTrackHandlers(this);
19126
+ }
19127
+
19128
+ $('.igv-ideogram-content-div').addClass('igv-ideogram-gutter-shim');
19129
+ $('.igv-viewport-div').addClass('igv-gutter-shim');
19130
+
19131
+ function makeTrackDraggable(track) {
19132
+
19133
+ self.igvTrackDragScrim = $('<div class="igv-track-drag-scrim">')[0];
19134
+ $(self.viewportDiv).append(self.igvTrackDragScrim);
19135
+ $(self.igvTrackDragScrim).hide();
18399
19136
 
18400
19137
  self.igvTrackManipulationHandle = $('<div class="igv-track-manipulation-handle">')[0];
18401
19138
  $(self.trackDiv).append(self.igvTrackManipulationHandle);
@@ -18510,7 +19247,7 @@ var igv = (function (igv) {
18510
19247
  description = this.track.description || this.track.name;
18511
19248
  $trackLabel = $('<div class="igv-track-label">');
18512
19249
 
18513
- $trackLabel.text(this.track.name);
19250
+ $trackLabel.html(this.track.name);
18514
19251
 
18515
19252
  $trackLabel.click(function (e) {
18516
19253
  igv.popover.presentTrackPopup(e.pageX, e.pageY, description, false);
@@ -18612,6 +19349,9 @@ var igv = (function (igv) {
18612
19349
  */
18613
19350
  igv.TrackView.prototype.setContentHeight = function (newHeight) {
18614
19351
 
19352
+ // Maximum height of a canvas is ~32,000 pixels on Chrome, possibly smaller on other platforms
19353
+ newHeight = Math.min(newHeight, 32000);
19354
+
18615
19355
  if (this.track.minHeight) newHeight = Math.max(this.track.minHeight, newHeight);
18616
19356
 
18617
19357
  var contentHeightStr = newHeight + "px";
@@ -19126,6 +19866,253 @@ var igv = (function (igv) {
19126
19866
 
19127
19867
  })(igv || {});
19128
19868
 
19869
+ /*
19870
+ * The MIT License (MIT)
19871
+ *
19872
+ * Copyright (c) 2014 Broad Institute
19873
+ *
19874
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
19875
+ * of this software and associated documentation files (the "Software"), to deal
19876
+ * in the Software without restriction, including without limitation the rights
19877
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
19878
+ * copies of the Software, and to permit persons to whom the Software is
19879
+ * furnished to do so, subject to the following conditions:
19880
+ *
19881
+ * The above copyright notice and this permission notice shall be included in
19882
+ * all copies or substantial portions of the Software.
19883
+ *
19884
+ *
19885
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19886
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19887
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19888
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19889
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19890
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19891
+ * THE SOFTWARE.
19892
+ */
19893
+
19894
+ /**
19895
+ * Created by turner on 4/29/15.
19896
+ */
19897
+ var igv = (function (igv) {
19898
+
19899
+ igv.AlertDialog = function ($parent, id) {
19900
+
19901
+ var self = this,
19902
+ $header,
19903
+ $headerBlurb;
19904
+
19905
+ this.$container = $('<div>', { "id": id, "class": "igv-grid-container-alert-dialog" });
19906
+ $parent.append(this.$container);
19907
+
19908
+ $header = $('<div class="igv-grid-header">');
19909
+ $headerBlurb = $('<div class="igv-grid-header-blurb">');
19910
+ $header.append($headerBlurb);
19911
+ igv.attachDialogCloseHandlerWithParent($header, function () {
19912
+ self.hide();
19913
+ });
19914
+ this.$container.append($header);
19915
+
19916
+ this.$container.append(this.alertTextContainer());
19917
+
19918
+ this.$container.append(this.rowOfOk());
19919
+
19920
+ };
19921
+
19922
+ igv.AlertDialog.prototype.alertTextContainer = function() {
19923
+
19924
+ var $rowContainer,
19925
+ $col;
19926
+
19927
+ $rowContainer = $('<div class="igv-grid-rect">');
19928
+
19929
+ this.$dialogLabel = $('<div>', { "class": "igv-col igv-col-4-4 igv-alert-dialog-text" });
19930
+
19931
+ // $col = $('<div class="igv-col igv-col-4-4">');
19932
+ // $col.append(this.$dialogLabel);
19933
+ // $rowContainer.append($col);
19934
+
19935
+ $rowContainer.append(this.$dialogLabel);
19936
+
19937
+ return $rowContainer;
19938
+
19939
+ };
19940
+
19941
+ igv.AlertDialog.prototype.rowOfOk = function() {
19942
+
19943
+ var self = this,
19944
+ $rowContainer,
19945
+ $col;
19946
+
19947
+ $rowContainer = $('<div class="igv-grid-rect">');
19948
+
19949
+ // shim
19950
+ $col = $('<div class="igv-col igv-col-1-4">');
19951
+ $rowContainer.append( $col );
19952
+
19953
+ // ok button
19954
+ $col = $('<div class="igv-col igv-col-2-4">');
19955
+ this.$ok = $('<div class="igv-col-filler-ok-button">');
19956
+ this.$ok.text("OK");
19957
+
19958
+ this.$ok.unbind();
19959
+ this.$ok.click(function() {
19960
+ self.hide();
19961
+ });
19962
+
19963
+ $col.append( this.$ok );
19964
+ $rowContainer.append( $col );
19965
+
19966
+ return $rowContainer;
19967
+
19968
+ };
19969
+
19970
+ igv.AlertDialog.prototype.hide = function () {
19971
+
19972
+ if (this.$container.hasClass('igv-grid-container-dialog')) {
19973
+ this.$container.offset( { left: 0, top: 0 } );
19974
+ }
19975
+ this.$container.hide();
19976
+ };
19977
+
19978
+ igv.AlertDialog.prototype.show = function ($host) {
19979
+
19980
+ var body_scrolltop,
19981
+ track_origin,
19982
+ track_size,
19983
+ offset,
19984
+ _top,
19985
+ _left;
19986
+
19987
+ body_scrolltop = $('body').scrollTop();
19988
+
19989
+ if (this.$container.hasClass('igv-grid-container-dialog')) {
19990
+
19991
+ offset = $host.offset();
19992
+
19993
+ _top = offset.top + body_scrolltop;
19994
+ _left = $host.outerWidth() - 300;
19995
+
19996
+ this.$container.offset( { left: _left, top: _top } );
19997
+
19998
+ //track_origin = $host.offset();
19999
+ //track_size =
20000
+ //{
20001
+ // width: $host.outerWidth(),
20002
+ // height: $host.outerHeight()
20003
+ //};
20004
+ //this.$container.offset( { left: (track_size.width - 300), top: (track_origin.top + body_scrolltop) } );
20005
+ //this.$container.offset( igv.constrainBBox(this.$container, $(igv.browser.trackContainerDiv)) );
20006
+ }
20007
+
20008
+ this.$container.show();
20009
+
20010
+ };
20011
+
20012
+ return igv;
20013
+
20014
+ })(igv || {});
20015
+
20016
+ /*
20017
+ * The MIT License (MIT)
20018
+ *
20019
+ * Copyright (c) 2016 University of California San Diego
20020
+ * Author: Jim Robinson
20021
+ *
20022
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
20023
+ * of this software and associated documentation files (the "Software"), to deal
20024
+ * in the Software without restriction, including without limitation the rights
20025
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20026
+ * copies of the Software, and to permit persons to whom the Software is
20027
+ * furnished to do so, subject to the following conditions:
20028
+ *
20029
+ * The above copyright notice and this permission notice shall be included in
20030
+ * all copies or substantial portions of the Software.
20031
+ *
20032
+ *
20033
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20034
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20035
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20036
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20037
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20038
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20039
+ * THE SOFTWARE.
20040
+ */
20041
+
20042
+ /**
20043
+ * Created by dat on 9/1/16.
20044
+ */
20045
+ var igv = (function (igv) {
20046
+
20047
+ igv.CenterGuide = function ($parent, config) {
20048
+ var self = this,
20049
+ cssDisplay;
20050
+
20051
+ this.$container = $('<div class="igv-center-guide igv-center-guide-thin">');
20052
+ $parent.append(this.$container);
20053
+ this.$container.css("display", (config.showCenterGuide && true == config.showCenterGuide) ? "block" : "none");
20054
+
20055
+ cssDisplay = this.$container.css("display");
20056
+ this.$centerGuideToggle = $('<div class="igv-toggle-track-labels">');
20057
+ this.$centerGuideToggle.text(("none" === cssDisplay) ? "show center guide" : "hide center guide");
20058
+
20059
+ this.$centerGuideToggle.click(function () {
20060
+ cssDisplay = self.$container.css("display");
20061
+ if ("none" === cssDisplay) {
20062
+ self.$container.css("display", "block");
20063
+ self.$centerGuideToggle.text("hide center guide");
20064
+ } else {
20065
+ self.$container.css("display", "none");
20066
+ self.$centerGuideToggle.text("show center guide");
20067
+ }
20068
+ });
20069
+
20070
+ // Hide toggle unless property is set (for now, prior to official release)
20071
+ if(undefined === config.showCenterGuide || false == config.showCenterGuide) {
20072
+ this.$centerGuideToggle.css("display", "none");
20073
+ }
20074
+
20075
+
20076
+ };
20077
+
20078
+ igv.CenterGuide.prototype.repaint = function () {
20079
+
20080
+ var left,
20081
+ ls,
20082
+ ws,
20083
+ center,
20084
+ ppb = Math.floor(1.0/igv.browser.referenceFrame.bpPerPixel),
20085
+ x = this.$container.position.x;
20086
+
20087
+ center = x + this.$container.outerWidth()/2;
20088
+
20089
+ if (ppb > 1) {
20090
+
20091
+ left = center - ppb/2;
20092
+ ls = left.toString() + 'px';
20093
+ ws = ppb.toString() + 'px';
20094
+ this.$container.css({ left:ls, width:ws });
20095
+
20096
+ this.$container.removeClass('igv-center-guide-thin');
20097
+ this.$container.addClass('igv-center-guide-wide');
20098
+ } else {
20099
+
20100
+ // ls = center.toString() + 'px';
20101
+ ls = '50%';
20102
+ ws = '1px';
20103
+ this.$container.css({ left:ls, width:ws });
20104
+
20105
+ this.$container.removeClass('igv-center-guide-wide');
20106
+ this.$container.addClass('igv-center-guide-thin');
20107
+ }
20108
+
20109
+ // console.log('CenterGuide - repaint. PPB ' + ppb);
20110
+ };
20111
+
20112
+ return igv;
20113
+
20114
+ }) (igv || {});
20115
+
19129
20116
  /*
19130
20117
  * The MIT License (MIT)
19131
20118
  *
@@ -19173,44 +20160,44 @@ var igv = (function (igv) {
19173
20160
  if (id) {
19174
20161
  this.$container.attr("id", id);
19175
20162
  }
19176
- $parent.append(this.$container[0]);
20163
+ $parent.append(this.$container);
19177
20164
 
19178
20165
  this.$container.draggable();
19179
20166
 
19180
20167
  this.$header = $('<div class="igv-grid-header">');
19181
20168
  this.$headerBlurb = $('<div class="igv-grid-header-blurb">');
19182
20169
 
19183
- this.$header.append(this.$headerBlurb[0]);
20170
+ this.$header.append(this.$headerBlurb);
19184
20171
 
19185
- igv.dialogCloseWithParentObject(this.$header, function () {
20172
+ igv.attachDialogCloseHandlerWithParent(this.$header, function () {
19186
20173
  self.hide();
19187
20174
  });
19188
20175
 
19189
- this.$container.append(this.$header[0]);
20176
+ this.$container.append(this.$header);
19190
20177
 
19191
20178
 
19192
20179
  // color palette
19193
20180
  for (rowIndex = 0; rowIndex < rowCount; rowIndex++) {
19194
- self.$container.append(makeRow(palette.slice(rowIndex * columnCount))[0]);
20181
+ self.$container.append(makeRow(palette.slice(rowIndex * columnCount)));
19195
20182
  }
19196
20183
 
19197
20184
  // dividing line
19198
- self.$container.append($('<hr class="igv-grid-dividing-line">')[0]);
20185
+ self.$container.append($('<hr class="igv-grid-dividing-line">'));
19199
20186
 
19200
20187
  // user colors
19201
- self.$container.append(rowOfUserColors()[0]);
20188
+ self.$container.append(rowOfUserColors());
19202
20189
 
19203
20190
  //// dividing line
19204
20191
  //self.$container.append($('<hr class="igv-grid-dividing-line">')[ 0 ]);
19205
20192
 
19206
20193
  // initial track color
19207
- self.$container.append(rowOfPreviousColor()[0]);
20194
+ self.$container.append(rowOfPreviousColor());
19208
20195
 
19209
20196
  //// dividing line
19210
20197
  //self.$container.append($('<hr class="igv-grid-dividing-line">')[ 0 ]);
19211
20198
 
19212
20199
  // initial track color
19213
- self.$container.append(rowOfDefaultColor()[0]);
20200
+ self.$container.append(rowOfDefaultColor());
19214
20201
 
19215
20202
  function rowOfUserColors() {
19216
20203
 
@@ -19230,8 +20217,6 @@ var igv = (function (igv) {
19230
20217
  self.$container.append( $row[ 0 ] );
19231
20218
 
19232
20219
  $row.find('.igv-col-filler-no-color').addClass("igv-grid-rect-hidden");
19233
-
19234
- //self.$container.append(self.userColors[ digit ][0]);
19235
20220
  }
19236
20221
 
19237
20222
  self.userColorsIndex = undefined;
@@ -19289,8 +20274,8 @@ var igv = (function (igv) {
19289
20274
 
19290
20275
  });
19291
20276
 
19292
- $column.append($userColorInput[0]);
19293
- $row.append($column[0]);
20277
+ $column.append($userColorInput);
20278
+ $row.append($column);
19294
20279
 
19295
20280
 
19296
20281
  // color feedback chip
@@ -19300,7 +20285,7 @@ var igv = (function (igv) {
19300
20285
  self.$userColorFeeback.hide();
19301
20286
 
19302
20287
  $rowContainer = $('<div class="igv-grid-rect">');
19303
- $rowContainer.append($row[0]);
20288
+ $rowContainer.append($row);
19304
20289
 
19305
20290
 
19306
20291
 
@@ -19310,7 +20295,7 @@ var igv = (function (igv) {
19310
20295
  self.$userError.hide();
19311
20296
 
19312
20297
  $row = $('<div class="igv-grid-colorpicker-user-error">');
19313
- $row.append(self.$userError[0]);
20298
+ $row.append(self.$userError);
19314
20299
  $rowContainer.append($row);
19315
20300
 
19316
20301
  function parseColor(value) {
@@ -19392,28 +20377,28 @@ var igv = (function (igv) {
19392
20377
  $row = $('<div class="igv-grid-colorpicker">');
19393
20378
 
19394
20379
  // initial color tile
19395
- self.defaultTrackColorTile = $('<div class="igv-col-filler">');
19396
- self.defaultTrackColorTile.css("background-color", "#eee");
20380
+ self.$defaultColor = $('<div class="igv-col-filler">');
20381
+ self.$defaultColor.css("background-color", "#eee");
19397
20382
 
19398
20383
  $column = $('<div class="igv-col igv-col-1-8">');
19399
- $column.append(self.defaultTrackColorTile[0]);
20384
+ $column.append(self.$defaultColor);
19400
20385
 
19401
20386
  $column.click(function () {
19402
20387
  igv.setTrackColor(self.trackView.track, $(this).find(".igv-col-filler").css("background-color"));
19403
20388
  self.trackView.update();
19404
20389
  });
19405
20390
 
19406
- $row.append($column[0]);
20391
+ $row.append($column);
19407
20392
 
19408
20393
 
19409
20394
  // default color label
19410
20395
  $column = $('<div class="igv-col igv-col-7-8 igv-col-label">');
19411
20396
  $column.text("Default Color");
19412
- $row.append($column[0]);
20397
+ $row.append($column);
19413
20398
 
19414
20399
 
19415
20400
  $rowContainer = $('<div class="igv-grid-rect">');
19416
- $rowContainer.append($row[0]);
20401
+ $rowContainer.append($row);
19417
20402
 
19418
20403
  return $rowContainer;
19419
20404
  }
@@ -19427,28 +20412,28 @@ var igv = (function (igv) {
19427
20412
  $row = $('<div class="igv-grid-colorpicker">');
19428
20413
 
19429
20414
  // initial color tile
19430
- self.previousTrackColorTile = $('<div class="igv-col-filler">');
19431
- self.previousTrackColorTile.css("background-color", "#eee");
20415
+ self.$previousColor = $('<div class="igv-col-filler">');
20416
+ self.$previousColor.css("background-color", "#eee");
19432
20417
 
19433
20418
  $column = $('<div class="igv-col igv-col-1-8">');
19434
- $column.append(self.previousTrackColorTile[0]);
20419
+ $column.append(self.$previousColor);
19435
20420
 
19436
20421
  $column.click(function () {
19437
20422
  igv.setTrackColor(self.trackView.track, $(this).find(".igv-col-filler").css("background-color"));
19438
20423
  self.trackView.update();
19439
20424
  });
19440
20425
 
19441
- $row.append($column[0]);
20426
+ $row.append($column);
19442
20427
 
19443
20428
 
19444
20429
  // initial color label
19445
20430
  $column = $('<div class="igv-col igv-col-7-8 igv-col-label">');
19446
20431
  $column.text("Previous Color");
19447
- $row.append($column[0]);
20432
+ $row.append($column);
19448
20433
 
19449
20434
 
19450
20435
  $rowContainer = $('<div class="igv-grid-rect">');
19451
- $rowContainer.append($row[0]);
20436
+ $rowContainer.append($row);
19452
20437
 
19453
20438
  return $rowContainer;
19454
20439
  }
@@ -19460,7 +20445,7 @@ var igv = (function (igv) {
19460
20445
  columnIndex;
19461
20446
 
19462
20447
  for (columnIndex = 0; columnIndex < columnCount; columnIndex++) {
19463
- $row.append(makeColumn(null)[0]);
20448
+ $row.append(makeColumn(null));
19464
20449
  }
19465
20450
 
19466
20451
  $rowContainer.append($row);
@@ -19474,7 +20459,7 @@ var igv = (function (igv) {
19474
20459
  i;
19475
20460
 
19476
20461
  for (i = 0; i < Math.min(columnCount, colors.length); i++) {
19477
- $row.append(makeColumn(colors[i])[0]);
20462
+ $row.append(makeColumn(colors[i]));
19478
20463
  }
19479
20464
 
19480
20465
  $rowContainer.append($row);
@@ -19486,7 +20471,7 @@ var igv = (function (igv) {
19486
20471
  var $column = $('<div class="igv-col igv-col-1-8">'),
19487
20472
  $filler = $('<div>');
19488
20473
 
19489
- $column.append($filler[0]);
20474
+ $column.append($filler);
19490
20475
 
19491
20476
  if (null !== colorOrNull) {
19492
20477
 
@@ -19510,6 +20495,15 @@ var igv = (function (igv) {
19510
20495
 
19511
20496
  };
19512
20497
 
20498
+ igv.ColorPicker.prototype.configure = function (trackView) {
20499
+
20500
+ this.trackView = trackView;
20501
+
20502
+ this.$defaultColor.css("background-color", trackView.track.config.color || igv.browser.constants.defaultColor);
20503
+ this.$previousColor.css("background-color", trackView.track.color);
20504
+
20505
+ };
20506
+
19513
20507
  igv.ColorPicker.prototype.hide = function () {
19514
20508
  $(this.$container).offset({left: 0, top: 0});
19515
20509
  this.$container.hide();
@@ -19526,13 +20520,8 @@ var igv = (function (igv) {
19526
20520
  size = {width: $(this.$container).outerWidth(), height: $(this.$container).outerHeight()},
19527
20521
  obj;
19528
20522
 
19529
- //$(this.$container).offset( { left: (track_size.width - size.width)/2, top: track_origin.top } );
19530
-
19531
20523
  $(this.$container).offset({left: (track_size.width - 300), top: (track_origin.top + body_scrolltop)});
19532
20524
 
19533
- this.previousTrackColorTile.css("background-color", this.trackView.track.color);
19534
-
19535
- this.defaultTrackColorTile.css("background-color", (this.trackView.track.defaultColor || igv.browser.constants.defaultColor));
19536
20525
 
19537
20526
  obj = $(".igv-user-input-color");
19538
20527
  obj.val("");
@@ -19596,7 +20585,7 @@ var igv = (function (igv) {
19596
20585
 
19597
20586
  this.header.append(this.headerBlurb[ 0 ]);
19598
20587
 
19599
- igv.dialogCloseWithParentObject(this.header, function () {
20588
+ igv.attachDialogCloseHandlerWithParent(this.header, function () {
19600
20589
  self.hide();
19601
20590
  });
19602
20591
 
@@ -19852,7 +20841,7 @@ var igv = (function (igv) {
19852
20841
 
19853
20842
  constructorHelper(this);
19854
20843
 
19855
- igv.dialogCloseWithParentObject($header, function () {
20844
+ igv.attachDialogCloseHandlerWithParent($header, function () {
19856
20845
  self.hide();
19857
20846
  });
19858
20847
 
@@ -19870,19 +20859,6 @@ var igv = (function (igv) {
19870
20859
 
19871
20860
  };
19872
20861
 
19873
- igv.Dialog.alertConstructor = function (dialog) {
19874
-
19875
- dialog.$container.removeClass("igv-grid-container-dialog");
19876
- dialog.$container.addClass("igv-grid-container-alert-dialog");
19877
-
19878
- dialog.$container.append(dialog.rowOfLabel()[ 0 ]);
19879
-
19880
- dialog.$container.append(dialog.rowOfInput()[ 0 ]);
19881
-
19882
- dialog.$container.append(dialog.rowOfOk()[ 0 ]);
19883
-
19884
- };
19885
-
19886
20862
  igv.Dialog.prototype.rowOfOk = function() {
19887
20863
 
19888
20864
  var $rowContainer,
@@ -20030,7 +21006,14 @@ var igv = (function (igv) {
20030
21006
  self.$dialogInput.val(inputValue);
20031
21007
 
20032
21008
  self.$dialogInput.unbind();
20033
- self.$dialogInput.change(clickFunction);
21009
+ self.$dialogInput.change(function(){
21010
+
21011
+ if (clickFunction) {
21012
+ clickFunction();
21013
+ }
21014
+
21015
+ self.hide();
21016
+ });
20034
21017
 
20035
21018
  self.$dialogInput.show();
20036
21019
  } else {
@@ -20156,7 +21139,7 @@ var igv = (function (igv) {
20156
21139
  popoverHeader = $('<div class="igv-popoverHeader">');
20157
21140
  this.popover.append(popoverHeader[ 0 ]);
20158
21141
 
20159
- igv.dialogCloseWithParentObject(popoverHeader, function () {
21142
+ igv.attachDialogCloseHandlerWithParent(popoverHeader, function () {
20160
21143
  self.hide();
20161
21144
  });
20162
21145
 
@@ -20191,35 +21174,26 @@ var igv = (function (igv) {
20191
21174
  var $container = $('<div class="igv-track-menu-container">'),
20192
21175
  trackMenuItems = igv.trackMenuItems(this, trackView);
20193
21176
 
20194
- trackMenuItems.forEach(function (trackMenuItem, index, tmi) {
20195
- if (trackMenuItem.object) {
20196
- var ob = trackMenuItem.object;
20197
- $container.append(ob[ 0 ]);
20198
- } else {
20199
- $container.append(trackMenuItem)
20200
- }
21177
+ trackMenuItems.forEach(function (item) {
21178
+ $container.append(item.object || item)
20201
21179
  });
20202
21180
 
20203
21181
  this.$popoverContent.empty();
20204
21182
 
20205
21183
  this.$popoverContent.removeClass("igv-popoverTrackPopupContent");
20206
- this.$popoverContent.append($container[ 0 ]);
21184
+ this.$popoverContent.append($container);
20207
21185
 
20208
21186
  // Attach click handler AFTER inserting markup in DOM.
20209
21187
  // Insertion beforehand will cause it to have NO effect
20210
21188
  // when clicked.
20211
- trackMenuItems.forEach(function (trackMenuItem) {
20212
-
20213
- var ob = trackMenuItem.object,
20214
- cl = trackMenuItem.click,
20215
- init = trackMenuItem.init;
21189
+ trackMenuItems.forEach(function (item) {
20216
21190
 
20217
- if (cl) {
20218
- ob.click(cl);
21191
+ if (item.object && item.click) {
21192
+ item.object.click( item.click );
20219
21193
  }
20220
21194
 
20221
- if (init) {
20222
- init();
21195
+ if (item.init) {
21196
+ item.init();
20223
21197
  }
20224
21198
 
20225
21199
  });
@@ -20621,6 +21595,8 @@ var igv = (function (igv) {
20621
21595
  self = this;
20622
21596
 
20623
21597
  fields = [
21598
+ {name: "Chr", value: this.chr},
21599
+ {name: "Pos", value: (this.pos + 1)},
20624
21600
  {name: "Names", value: this.names ? this.names : ""},
20625
21601
  {name: "Ref", value: this.referenceBases},
20626
21602
  {name: "Alt", value: this.alternateBases},