igv-rails 1.0.1.1 → 1.0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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},