icn3d 3.26.9 → 3.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/icn3d.module.js CHANGED
@@ -5357,23 +5357,23 @@ class ParasCls {
5357
5357
  //this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * ( + 0.81)/(1.14 + 0.81)),
5358
5358
  // hydrophobic
5359
5359
  // https://en.m.wikipedia.org/wiki/Hydrophobicity_scales#Wimley%E2%80%93White_whole_residue_hydrophobicity_scales
5360
- 'TRP': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.85 + 1.85)/(0 + 1.85)),
5361
- 'PHE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.13 + 1.85)/(0 + 1.85)),
5362
- 'TYR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.94 + 1.85)/(0 + 1.85)),
5363
- 'LEU': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.56 + 1.85)/(0 + 1.85)),
5364
- 'ILE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.31 + 1.85)/(0 + 1.85)),
5365
- 'CYS': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.24 + 1.85)/(0 + 1.85)),
5366
- 'MET': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.23 + 1.85)/(0 + 1.85)),
5360
+ 'TRP': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-2.09 + 2.09) / (0 + 2.09)),
5361
+ 'PHE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.71 + 2.09) / (0 + 2.09)),
5362
+ 'LEU': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.25 + 2.09) / (0 + 2.09)),
5363
+ 'ILE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.12 + 2.09) / (0 + 2.09)),
5364
+ 'TYR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.71 + 2.09) / (0 + 2.09)),
5365
+ 'MET': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.67 + 2.09) / (0 + 2.09)),
5366
+ 'VAL': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.46 + 2.09) / (0 + 2.09)),
5367
+ 'CYS': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.02 + 2.09) / (0 + 2.09)),
5367
5368
 
5368
5369
  // polar
5369
- 'GLY': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.01 + 0.58)/(0 + 0.58)),
5370
- 'VAL': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.07 + 0.58)/(0 + 0.58)),
5371
- 'SER': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.13 + 0.58)/(0 + 0.58)),
5372
- 'THR': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.14 + 0.58)/(0 + 0.58)),
5373
- 'ALA': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.17 + 0.58)/(0 + 0.58)),
5374
- 'ASN': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.42 + 0.58)/(0 + 0.58)),
5375
- 'PRO': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.45 + 0.58)/(0 + 0.58)),
5376
- 'GLN': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.58 + 0.58)/(0 + 0.58))
5370
+ 'PRO': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.14 + 1.15) / (0 + 1.15)),
5371
+ 'THR': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.25 + 1.15) / (0 + 1.15)),
5372
+ 'SER': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.46 + 1.15) / (0 + 1.15)),
5373
+ 'ALA': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.50 + 1.15) / (0 + 1.15)),
5374
+ 'GLN': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.77 + 1.15) / (0 + 1.15)),
5375
+ 'ASN': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.85 + 1.15) / (0 + 1.15)),
5376
+ 'GLY': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-1.15 + 1.15) / (0 + 1.15))
5377
5377
  };
5378
5378
 
5379
5379
  this.normalizedHPColors = {
@@ -5391,59 +5391,58 @@ class ParasCls {
5391
5391
  //this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * ( + 0.81)/(1.14 + 0.81)),
5392
5392
  // hydrophobic
5393
5393
  // https://en.m.wikipedia.org/wiki/Hydrophobicity_scales#Wimley%E2%80%93White_whole_residue_hydrophobicity_scales
5394
- // 0.65 ~ -1.85: white ~ green
5395
- 'TRP': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.85 + 1.85)/2.5),
5396
- 'PHE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.13 + 1.85)/2.5),
5397
- 'TYR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.94 + 1.85)/2.5),
5398
- 'LEU': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.56 + 1.85)/2.5),
5399
- 'ILE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.31 + 1.85)/2.5),
5400
- 'CYS': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.24 + 1.85)/2.5),
5401
- 'MET': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.23 + 1.85)/2.5),
5394
+ // 1.15 ~ -2.09: white ~ green
5395
+ 'TRP': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-2.09 + 2.09) / 3.24),
5396
+ 'PHE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.71 + 2.09) / 3.24),
5397
+ 'LEU': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.25 + 2.09) / 3.24),
5398
+ 'ILE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.12 + 2.09) / 3.24),
5399
+ 'TYR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.71 + 2.09) / 3.24),
5400
+ 'MET': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.67 + 2.09) / 3.24),
5401
+ 'VAL': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.46 + 2.09) / 3.24),
5402
+ 'CYS': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.02 + 2.09) / 3.24),
5402
5403
 
5403
5404
  // polar
5404
- 'GLY': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.01 + 1.85)/2.5),
5405
- 'VAL': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.07 + 1.85)/2.5),
5406
- 'SER': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.13 + 1.85)/2.5),
5407
- 'THR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.14 + 1.85)/2.5),
5408
- 'ALA': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.17 + 1.85)/2.5),
5409
- 'ASN': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.42 + 1.85)/2.5),
5410
- 'PRO': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.45 + 1.85)/2.5),
5411
- 'GLN': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.58 + 1.85)/2.5)
5405
+ 'PRO': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.14 + 2.09) / 3.24),
5406
+ 'THR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.25 + 2.09) / 3.24),
5407
+ 'SER': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.46 + 2.09) / 3.24),
5408
+ 'ALA': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.50 + 2.09) / 3.24),
5409
+ 'GLN': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.77 + 2.09) / 3.24),
5410
+ 'ASN': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.85 + 2.09) / 3.24),
5411
+ 'GLY': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (1.15 + 2.09) / 3.24)
5412
5412
  };
5413
5413
 
5414
5414
  this.hydrophobicValues = {
5415
- // charged residues
5415
+ // charged residues, larger than max polar (1.15)
5416
5416
  ' G': 3, ' A': 3, ' T': 3,
5417
5417
  ' C': 3, ' U': 3, ' DG': 3,
5418
5418
  ' DA': 3, ' DT': 3, ' DC': 3,
5419
5419
  ' DU': 3, 'G': 3, 'A': 3,
5420
5420
  'T': 3, 'C': 3, 'U': 3,
5421
5421
  'DG': 3, 'DA': 3, 'DT': 3,
5422
- 'DC': 3, 'DU': 3, 'ARG': 1,
5423
- 'LYS': 1, 'ASP': 3, 'GLU': 3,
5422
+ 'DC': 3, 'DU': 3, 'ARG': 1.5,
5423
+ 'LYS': 1.5, 'ASP': 3, 'GLU': 3,
5424
5424
  'HIS': 2,
5425
5425
 
5426
- // + 0.81)/(1.14 + 0.81)),
5427
5426
  // hydrophobic
5428
5427
  // https://en.m.wikipedia.org/wiki/Hydrophobicity_scales#Wimley%E2%80%93White_whole_residue_hydrophobicity_scales
5429
- // 0.65 ~ -1.85: white ~ green
5430
- 'TRP': -1.85,
5431
- 'PHE': -1.13,
5432
- 'TYR': -0.94,
5433
- 'LEU': -0.56,
5434
- 'ILE': -0.31,
5435
- 'CYS': -0.24,
5436
- 'MET': -0.23,
5428
+ // 1.15 ~ -2.09: white ~ green
5429
+ 'TRP': -2.09,
5430
+ 'PHE': -1.71,
5431
+ 'LEU': -1.25,
5432
+ 'ILE': -1.12,
5433
+ 'TYR': -0.71,
5434
+ 'MET': -0.67,
5435
+ 'VAL': -0.46,
5436
+ 'CYS': -0.02,
5437
5437
 
5438
5438
  // polar
5439
- 'GLY': 0.01,
5440
- 'VAL': 0.07,
5441
- 'SER': 0.13,
5442
- 'THR': 0.14,
5443
- 'ALA': 0.17,
5444
- 'ASN': 0.42,
5445
- 'PRO': 0.45,
5446
- 'GLN': 0.58
5439
+ 'PRO': 0.14,
5440
+ 'THR': 0.25,
5441
+ 'SER': 0.46,
5442
+ 'ALA': 0.50,
5443
+ 'GLN': 0.77,
5444
+ 'ASN': 0.85,
5445
+ 'GLY': 1.15
5447
5446
  };
5448
5447
 
5449
5448
  this.residueAbbrev = {
@@ -6829,8 +6828,8 @@ class ClickMenu {
6829
6828
  me.htmlCls.dialogCls.openDlg('dl_esmfold', 'Sequence to structure prediction with ESMFold');
6830
6829
  });
6831
6830
 
6832
- me.myEventCls.onIds("#" + me.pre + "mn1_gi", "click", function(e) { me.icn3d; //e.preventDefault();
6833
- me.htmlCls.dialogCls.openDlg('dl_gi', 'Please input protein gi');
6831
+ me.myEventCls.onIds("#" + me.pre + "mn1_proteinname", "click", function(e) { me.icn3d; //e.preventDefault();
6832
+ me.htmlCls.dialogCls.openDlg('dl_proteinname', 'Please input protein or gene name');
6834
6833
  });
6835
6834
 
6836
6835
  me.myEventCls.onIds("#" + me.pre + "mn1_cid", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -9355,10 +9354,16 @@ class SetMenu {
9355
9354
  let html = "";
9356
9355
 
9357
9356
  html += "<ul class='icn3d-mn-item'>";
9358
- //html += "<li><a href='https://www.ncbi.nlm.nih.gov/structure' target='_blank'>Search Structure " + me.htmlCls.wifiStr + "</a></li>";
9359
- html += this.getMenuUrl('mn1_searchstru', "https://www.ncbi.nlm.nih.gov/structure", "Search Structure " + me.htmlCls.wifiStr, 1, 1);
9357
+
9358
+ html += this.getMenuText('mn1_searchgrooup', 'Search Structure ' + me.htmlCls.wifiStr, undefined, 1, 1);
9359
+ html += "<ul>";
9360
+ html += this.getMenuUrl('mn1_searchstru', 'https://www.ncbi.nlm.nih.gov/structure', 'PDB Structures ' + me.htmlCls.wifiStr, undefined, 2);
9361
+ html += this.getLink('mn1_proteinname', 'AlphaFold Structures ' + me.htmlCls.wifiStr, undefined, 2);
9362
+ html += this.getMenuUrl('mn1_afdatabase', 'https://alphafold.ebi.ac.uk', 'AlphaFold UniProt Database ' + me.htmlCls.wifiStr, undefined, 2);
9363
+ html += "</ul>";
9364
+ html += "</li>";
9360
9365
 
9361
- html += this.getMenuText('mn1_searchsimilar', 'Search Similar', undefined, undefined, 1);
9366
+ html += this.getMenuText('mn1_searchsimilar', 'Search Similar' + me.htmlCls.wifiStr, undefined, undefined, 1);
9362
9367
  html += "<ul>";
9363
9368
  html += this.getLink('mn1_vastplus', 'NCBI VAST+ (PDB Complex)' + me.htmlCls.wifiStr, undefined, 2);
9364
9369
  html += this.getLink('mn1_vast', 'NCBI VAST (PDB Chain)' + me.htmlCls.wifiStr, undefined, 2);
@@ -9379,7 +9384,6 @@ class SetMenu {
9379
9384
 
9380
9385
  html += this.getLink('mn1_afid', 'UniProt ID ' + me.htmlCls.wifiStr, undefined, 3);
9381
9386
  html += this.getLink('mn1_refseqid', 'NCBI Protein Accession ' + me.htmlCls.wifiStr, undefined, 3);
9382
- // html += this.getLink('mn1_proteinname', 'Protein Name ' + me.htmlCls.wifiStr, undefined, 3);
9383
9387
  html += "</ul>";
9384
9388
 
9385
9389
 
@@ -9421,10 +9425,11 @@ class SetMenu {
9421
9425
  html += "</ul>";
9422
9426
  html += "</li>";
9423
9427
 
9424
- html += this.getMenuText('mn1_fold', 'AlphaFold/ESM', undefined, undefined, 1);
9428
+ //html += this.getMenuText('mn1_fold', 'AlphaFold/ESM', undefined, undefined, 1);
9429
+ html += this.getMenuText('mn1_fold', 'Predict by Seq.', undefined, undefined, 1);
9425
9430
  html += "<ul>";
9426
- html += this.getLink('mn1_alphafold', 'AlphaFold2 via ColabFold', undefined, 2);
9427
9431
  html += this.getLink('mn1_esmfold', 'ESMFold', undefined, 2);
9432
+ html += this.getLink('mn1_alphafold', 'AlphaFold2 via ColabFold', undefined, 2);
9428
9433
  html += "</ul>";
9429
9434
 
9430
9435
 
@@ -9730,9 +9735,9 @@ class SetMenu {
9730
9735
 
9731
9736
  html += this.getMenuText('mn2_rotate90', 'Rotate 90&deg;', undefined, undefined, 2);
9732
9737
  html += "<ul>";
9733
- html += this.getRadio('mn6_rotate90', 'mn6_rotatex', 'X-axis(Shift + Key M)', undefined, undefined, 2);
9734
- html += this.getRadio('mn6_rotate90', 'mn6_rotatey', 'Y-axis(Shift + Key J)', undefined, undefined, 2);
9735
- html += this.getRadio('mn6_rotate90', 'mn6_rotatez', 'Z-axis', undefined, undefined, 2);
9738
+ html += this.getRadio('mn6_rotate90', 'mn6_rotatex', 'rotate x', undefined, undefined, 2);
9739
+ html += this.getRadio('mn6_rotate90', 'mn6_rotatey', 'rotate y', undefined, undefined, 2);
9740
+ html += this.getRadio('mn6_rotate90', 'mn6_rotatez', 'rotate z', undefined, undefined, 2);
9736
9741
  html += "</ul>";
9737
9742
  html += "</li>";
9738
9743
  html += this.getMenuText('mn2_rotateauto', 'Auto Rotation', undefined, 1, 2);
@@ -11242,6 +11247,9 @@ class Dialog {
11242
11247
  if(me.cfg.align) {
11243
11248
  position ={ my: "left top", at: "left top+90", of: "#" + me.pre + "canvas", collision: "none" };
11244
11249
  }
11250
+ else if(id === me.pre + 'dl_mmdbafid') {
11251
+ position ={ my: "left top", at: "left top+130", of: "#" + me.pre + "canvas", collision: "none" };
11252
+ }
11245
11253
  else {
11246
11254
  position ={ my: "left top", at: "left top+50", of: "#" + me.pre + "canvas", collision: "none" };
11247
11255
  }
@@ -11775,7 +11783,7 @@ class SetDialog {
11775
11783
 
11776
11784
  html += me.htmlCls.divStr + "dl_esmfold' style='max-width:600px;' class='" + dialogClass + "'>";
11777
11785
  html += this.addNotebookTitle('dl_esmfold', 'Sequence to structure prediction with ESMFold');
11778
- html += "The sequence to structure prediction is done via <a href='https://esmatlas.com/resources?action=fold' target='_blank'>ESM Metagenomic Atlas</a>. Generally the sequence should be less than 1024 characters. For any seqeunce longer than 1024, please see the discussion <a href='https://github.com/facebookresearch/esm/issues/21' target='_blank'>here</a>.<br><br> ";
11786
+ html += "The sequence to structure prediction is done via <a href='https://esmatlas.com/resources?action=fold' target='_blank'>ESM Metagenomic Atlas</a>. The sequence should be less than 400 characters. For any sequence longer than 400, please see the discussion <a href='https://github.com/facebookresearch/esm/issues/21' target='_blank'>here</a>.<br><br> ";
11779
11787
  html += "FASTA sequence: <br><textarea id='" + me.pre + "esmfold_fasta' rows='5' style='width: 100%; height: " +(me.htmlCls.LOG_HEIGHT) + "px; padding: 0px; border: 0px;'></textarea><br><br>";
11780
11788
  html += me.htmlCls.buttonStr + "run_esmfold'>ESMFold</button> ";
11781
11789
  html += "</div>";
@@ -11787,10 +11795,10 @@ class SetDialog {
11787
11795
  html += me.htmlCls.buttonStr + "applyyournote'>Save</button>";
11788
11796
  html += "</div>";
11789
11797
 
11790
- html += me.htmlCls.divStr + "dl_gi' class='" + dialogClass + "'>";
11791
- html += this.addNotebookTitle('dl_gi', 'Please input an NCBI gi');
11792
- html += "Protein gi: " + me.htmlCls.inputTextStr + "id='" + me.pre + "gi' value='1310960' size=8> ";
11793
- html += me.htmlCls.buttonStr + "reload_gi'>Load</button>";
11798
+ html += me.htmlCls.divStr + "dl_proteinname' class='" + dialogClass + "'>";
11799
+ html += this.addNotebookTitle('dl_proteinname', 'Please input a protein/gene name');
11800
+ html += "Protein/Gene name: " + me.htmlCls.inputTextStr + "id='" + me.pre + "proteinname' value='TP53' size=8> ";
11801
+ html += me.htmlCls.buttonStr + "reload_proteinname'>Search</button>";
11794
11802
  html += "</div>";
11795
11803
 
11796
11804
  html += me.htmlCls.divStr + "dl_cid' class='" + dialogClass + "'>";
@@ -12460,9 +12468,10 @@ class SetDialog {
12460
12468
 
12461
12469
  html += me.htmlCls.divStr + "dl_addtrack_tabs' style='border:0px;'>";
12462
12470
  html += "<ul>";
12471
+ html += "<li><a href='#" + me.pre + "tracktab2c'>Isoforms & Exons</a></li>";
12472
+ html += "<li><a href='#" + me.pre + "tracktab2b'>MSA</a></li>";
12463
12473
  html += "<li><a href='#" + me.pre + "tracktab1'>NCBI gi/Accession</a></li>";
12464
12474
  html += "<li><a href='#" + me.pre + "tracktab2'>FASTA</a></li>";
12465
- html += "<li><a href='#" + me.pre + "tracktab2b'>FASTA Alignment</a></li>";
12466
12475
  html += "<li><a href='#" + me.pre + "tracktab3'>BED File</a></li>";
12467
12476
  html += "<li><a href='#" + me.pre + "tracktab4'>Custom</a></li>";
12468
12477
  html += "<li><a href='#" + me.pre + "tracktab5'>Current Selection</a></li>";
@@ -12478,10 +12487,16 @@ class SetDialog {
12478
12487
  html += "</div>";
12479
12488
 
12480
12489
  html += me.htmlCls.divStr + "tracktab2b'>";
12481
- html += "<div style='width:600px'>The full protein sequences with gaps are listed one by one. The sequence of the structure is listed at the top. If there are non-gap residues(e.g., from RefSeq) outside of the sequence of the structure, please remove them. Each sequence has a title line starting with \">\".</div><br>";
12482
- html += "<b>FASTA alignment sequences</b>:<br>";
12490
+ // html += "<div style='width:600px'>The full protein sequences with gaps are listed one by one. The sequence of the structure is listed at the top. If there are non-gap residues(e.g., from RefSeq) outside of the sequence of the structure, please remove them. Each sequence has a title line starting with \">\".</div><br>";
12491
+ html += "<div style='width:600px'>Note: The full protein sequences with gaps in MSA are listed one by one. The sequence of the structure is listed at the top. Each sequence has a title line starting with \">\".</div><br>";
12492
+
12493
+ html += "<b>Precalculated Multiple Sequence Alignment (MSA)</b>:<br>";
12483
12494
  html += "<textarea id='" + me.pre + "track_fastaalign' rows='5' style='width: 100%; height: " +(2*me.htmlCls.LOG_HEIGHT) + "px; padding: 0px; border: 0px;'></textarea><br><br>";
12484
- html += "Position of the first residue in Sequences & Annotations window: " + me.htmlCls.inputTextStr + "id='" + me.pre + "fasta_startpos' value='1' size=2> <br><br>";
12495
+
12496
+ // html += "<b>Opion 1. Precalculated Multiple Sequence Alignment (MSA)</b>:<br>";
12497
+ // html += "<textarea id='" + me.pre + "track_fastaalign' rows='5' style='width: 100%; height: " +(2*me.htmlCls.LOG_HEIGHT) + "px; padding: 0px; border: 0px;'></textarea><br><br>";
12498
+ // html += "<b>Opion 2. NCBI Protein Accessions</b>: "+ me.htmlCls.inputTextStr + "id='" + me.pre + "track_acclist' size=60> <br><br>";
12499
+ html += "<b>Position of the first residue in Sequences & Annotations window</b>: " + me.htmlCls.inputTextStr + "id='" + me.pre + "fasta_startpos' value='1' size=2> <br><br>";
12485
12500
 
12486
12501
  html += "Color Sequence by: <select id='" + me.pre + "colorseqby'>";
12487
12502
  html += me.htmlCls.optionStr + "'identity' selected>Identity</option>";
@@ -12491,6 +12506,22 @@ class SetDialog {
12491
12506
  html += me.htmlCls.buttonStr + "addtrack_button2b'>Add Track(s)</button>";
12492
12507
  html += "</div>";
12493
12508
 
12509
+ html += me.htmlCls.divStr + "tracktab2c'>";
12510
+ html += "<div style='width:500px'>Note: Show exons for all isoforms of the protein in the same gene as specified below.</div><br>";
12511
+
12512
+ html += "<b><a href='https://www.ncbi.nlm.nih.gov/gene' target='_blank'>NCBI Gene</a> ID</b>: "+ me.htmlCls.inputTextStr + "id='" + me.pre + "track_geneid' size=20>" + me.htmlCls.space3 + me.htmlCls.buttonStr + "exons_table'>Exons & Introns in Gene Table</button><br><br>";
12513
+
12514
+ html += "<b>Position of the first residue in Sequences & Annotations window</b>: " + me.htmlCls.inputTextStr + "id='" + me.pre + "fasta_startpos2' value='1' size=2> <br><br>";
12515
+
12516
+ html += "Color Sequence by: <select id='" + me.pre + "colorseqby2'>";
12517
+ html += me.htmlCls.optionStr + "'identity' selected>Identity</option>";
12518
+ html += me.htmlCls.optionStr + "'conservation'>Conservation</option>";
12519
+ html += "</select> <br><br>";
12520
+
12521
+ html += me.htmlCls.buttonStr + "addtrack_button2c'>Show Isoforms & Exons</button>";
12522
+ html += "</div>";
12523
+
12524
+
12494
12525
  html += me.htmlCls.divStr + "tracktab3'>";
12495
12526
  html += "BED file: " + me.htmlCls.inputFileStr + "id='" + me.pre + "track_bed' size=16> <br><br>";
12496
12527
  html += me.htmlCls.buttonStr + "addtrack_button3'>Add Track</button>";
@@ -13780,12 +13811,19 @@ class Events {
13780
13811
  }
13781
13812
 
13782
13813
  let esmfold_fasta = $("#" + me.pre + "esmfold_fasta").val();
13783
- let pdbid;
13814
+ let pdbid = 'stru--';
13784
13815
 
13785
13816
  if(esmfold_fasta.indexOf('>') != -1) { //FASTA with header
13786
13817
  let pos = esmfold_fasta.indexOf('\n');
13787
13818
  ic.esmTitle = esmfold_fasta.substr(1, pos - 1).trim();
13788
- pdbid = (ic.esmTitle.indexOf(' ') != -1) ? ic.esmTitle.substr(0, ic.esmTitle.indexOf(' ')) : ic.esmTitle;
13819
+ if(ic.esmTitle.indexOf('|') != -1) { // uniprot
13820
+ let idArray = ic.esmTitle.split('|');
13821
+ pdbid = (idArray.length > 2) ? idArray[1] : ic.esmTitle;
13822
+ }
13823
+ else { // NCBI
13824
+ pdbid = (ic.esmTitle.indexOf(' ') != -1) ? ic.esmTitle.substr(0, ic.esmTitle.indexOf(' ')) : ic.esmTitle;
13825
+ }
13826
+
13789
13827
  if(pdbid.length < 6) pdbid = pdbid.padEnd(6, '-');
13790
13828
 
13791
13829
  esmfold_fasta = esmfold_fasta.substr(pos + 1);
@@ -13794,8 +13832,8 @@ class Events {
13794
13832
  // remove new lines
13795
13833
  esmfold_fasta = esmfold_fasta.replace(/\s/g, '');
13796
13834
 
13797
- if(esmfold_fasta.length > 1024) {
13798
- alert("Your seqeunce is larger than 1024 characters. Please consider to split it as described at https://github.com/facebookresearch/esm/issues/21.");
13835
+ if(esmfold_fasta.length > 400) {
13836
+ alert("Your sequence is larger than 400 characters. Please consider to split it as described at https://github.com/facebookresearch/esm/issues/21.");
13799
13837
  return;
13800
13838
  }
13801
13839
 
@@ -13804,6 +13842,13 @@ class Events {
13804
13842
  thisClass.setLogCmd("Run ESMFold with the sequence " + esmfold_fasta, false);
13805
13843
 
13806
13844
  let esmData = await me.getAjaxPostPromise(esmUrl, esmfold_fasta, true, alertMess, undefined, true, 'text');
13845
+
13846
+ ic.bResetAnno = true;
13847
+
13848
+ ic.bInputfile = true;
13849
+ ic.InputfileType = 'pdb';
13850
+ ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + esmData : esmData;
13851
+
13807
13852
  ic.bEsmfold = true;
13808
13853
  let bAppend = true;
13809
13854
  await ic.pdbParserCls.loadPdbData(esmData, pdbid, undefined, bAppend, undefined, undefined, undefined, ic.bEsmfold);
@@ -13842,12 +13887,12 @@ class Events {
13842
13887
  });
13843
13888
 
13844
13889
 
13845
- me.myEventCls.onIds("#" + me.pre + "reload_gi", "click", function(e) { let ic = me.icn3d;
13890
+ me.myEventCls.onIds("#" + me.pre + "reload_proteinname", "click", function(e) { let ic = me.icn3d;
13846
13891
  e.preventDefault();
13847
13892
  if(!me.cfg.notebook) dialog.dialog( "close" );
13848
- thisClass.setLogCmd("load gi " + $("#" + me.pre + "gi").val(), false);
13893
+ thisClass.setLogCmd("load protein " + $("#" + me.pre + "proteinname").val(), false);
13849
13894
  let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
13850
- window.open(hostUrl + '?gi=' + $("#" + me.pre + "gi").val(), urlTarget);
13895
+ window.open(hostUrl + '?protein=' + $("#" + me.pre + "proteinname").val(), urlTarget);
13851
13896
  });
13852
13897
 
13853
13898
  me.myEventCls.onIds("#" + me.pre + "reload_refseq", "click", function(e) { let ic = me.icn3d;
@@ -15208,13 +15253,15 @@ class Events {
15208
15253
  });
15209
15254
 
15210
15255
 
15211
- $(document).on("click", ".icn3d-addtrack", function(e) { me.icn3d;
15256
+ $(document).on("click", ".icn3d-addtrack", function(e) { let ic = me.icn3d;
15212
15257
  e.stopImmediatePropagation();
15213
15258
  $("#" + me.pre + "anno_custom")[0].checked = true;
15214
15259
  $("[id^=" + me.pre + "custom]").show();
15215
15260
  //e.preventDefault();
15216
15261
  let chainid = $(this).attr('chainid');
15262
+ let geneid = ic.chainsGene[chainid].geneId;
15217
15263
  $("#" + me.pre + "track_chainid").val(chainid);
15264
+ $("#" + me.pre + "track_geneid").val(geneid);
15218
15265
  me.htmlCls.dialogCls.openDlg('dl_addtrack', 'Add track for Chain: ' + chainid);
15219
15266
  $( "#" + me.pre + "track_gi" ).focus();
15220
15267
  });
@@ -15429,8 +15476,17 @@ class AlignSeq {
15429
15476
 
15430
15477
  let chainHash = {};
15431
15478
  if (alignChainArray !== undefined) {
15479
+
15432
15480
  for (let i = 0, il = alignChainArray.length; i < il; ++i) {
15433
- chainHash[alignChainArray[i]] = 1;
15481
+ let chainid = alignChainArray[i];
15482
+
15483
+ // make sure some residues are aligned
15484
+ if(ic.alnChainsSeq[chainid] && ic.alnChainsSeq[chainid].length > 0) {
15485
+ chainHash[chainid] = 1;
15486
+ }
15487
+ else {
15488
+ return { "sequencesHtml": sequencesHtml, "maxSeqCnt": maxSeqCnt };
15489
+ }
15434
15490
  }
15435
15491
  }
15436
15492
 
@@ -15622,7 +15678,7 @@ class AlignSeq {
15622
15678
  //sequencesHtml += "<div class='icn3d-residueLine' style='white-space:nowrap;'><div class='icn3d-seqTitle' chain='" + i + "' anno='" + j + "'>" + annotitle + "</div>" + resiHtmlArray[j] + "<br/></div>";
15623
15679
  sequencesHtml += "<div class='icn3d-residueLine' style='white-space:nowrap;'><div class='icn3d-seqTitle' anno='" + j + "'>" + annotitle + "</div>" + resiHtmlArray[j] + "<br/></div>";
15624
15680
  }
15625
-
15681
+
15626
15682
  sequencesHtml += '<div class="icn3d-seqTitle icn3d-link icn3d-blue" chain="' + i + '" anno="sequence" title="' + title + '">' + chainidTmp + ' </div><span class="icn3d-seqLine">' + seqHtml + '</span><br/>';
15627
15683
 
15628
15684
  if (index > 0) prevResCnt2nd += seqLength;
@@ -33161,6 +33217,8 @@ class Alternate {
33161
33217
  // change the display atom when alternating
33162
33218
  //Show structures one by one.
33163
33219
  alternateStructures() { let ic = this.icn3d, me = ic.icn3dui;
33220
+ ic.bAlernate = true;
33221
+
33164
33222
  //ic.transformCls.zoominSelection();
33165
33223
 
33166
33224
  // default ic.ALTERNATE_STRUCTURE = -1
@@ -33275,11 +33333,11 @@ class Alternate {
33275
33333
 
33276
33334
  //ic.glycanCls.showGlycans();
33277
33335
 
33336
+ ic.opts['rotationcenter'] = 'highlight center';
33337
+
33278
33338
  ic.drawCls.draw();
33279
33339
 
33280
33340
  ic.bShowHighlight = true;
33281
- //ic.opts['rotationcenter'] = 'molecule center';
33282
- ic.opts['rotationcenter'] = 'highlight center';
33283
33341
  }
33284
33342
 
33285
33343
  alternateWrapper() { let ic = this.icn3d; ic.icn3dui;
@@ -36461,13 +36519,13 @@ class SetOption {
36461
36519
  html += "<div>";
36462
36520
 
36463
36521
  if(colorType == 'normalized hydrophobic') {
36464
- html += "Dark green (W, F, Y, L, I, C, M): Hydrophobic<br>";
36465
- html += "Light green (G, V, S, T, A, N, P, Q): Polar<br>";
36522
+ html += "Dark green (W, F, L, I, Y, M, V, C): Hydrophobic<br>";
36523
+ html += "Light green (P, T, S, A, Q, N, G): Polar<br>";
36466
36524
  html += "Grey: Charged, not hydrophobic<br><br>";
36467
36525
  }
36468
36526
  else {
36469
- html += "Green (W, F, Y, L, I, C, M): Hydrophobic<br>";
36470
- html += "Yellow (G, V, S, T, A, N, P, Q): Polar<br>";
36527
+ html += "Green (W, F, L, I, Y, M, V, C): Hydrophobic<br>";
36528
+ html += "Yellow (P, T, S, A, Q, N, G): Polar<br>";
36471
36529
  html += "Red: Negatively Charged<br>";
36472
36530
  html += "Blue: Positively Charged<br><br>";
36473
36531
  }
@@ -36905,6 +36963,10 @@ class AnnoCddSite {
36905
36963
  let prevEmptyWidth = 0;
36906
36964
  let prevLineWidth = 0;
36907
36965
  let widthPerRes = 1;
36966
+
36967
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
36968
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
36969
+
36908
36970
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
36909
36971
  html += ic.showSeqCls.insertGap(chnid, i, '-');
36910
36972
  if(resPosArray.indexOf(i) != -1) {
@@ -36937,6 +36999,9 @@ class AnnoCddSite {
36937
36999
  html += '<span>-</span>'; //'<span>-</span>';
36938
37000
  }
36939
37001
  }
37002
+
37003
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
37004
+
36940
37005
  htmlTmp = '<span class="icn3d-residueNum" title="residue count">&nbsp;' + resCnt.toString() + ' Residues</span>';
36941
37006
  htmlTmp += '</span>';
36942
37007
  htmlTmp += '<br>';
@@ -37094,6 +37159,9 @@ class AnnoCddSite {
37094
37159
  html2 += '<div style="width:' + titleSpace + 'px!important;" class="icn3d-seqTitle ' + linkStr + '" ' + type + '="' + acc + '" from="' + fromArray + '" to="' + toArray + '" shorttitle="' + title + '" index="' + index + '" setname="' + setname + '" anno="sequence" chain="' + chnid + '" title="' + fulltitle + '">' + title + ' </div>';
37095
37160
  html2 += htmlTmp3 + htmlTmp;
37096
37161
  let pre = type + index.toString();
37162
+
37163
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
37164
+
37097
37165
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
37098
37166
  html += ic.showSeqCls.insertGap(chnid, i, '-');
37099
37167
 
@@ -37121,9 +37189,15 @@ class AnnoCddSite {
37121
37189
  html += '<span>-</span>'; //'<span>-</span>';
37122
37190
  }
37123
37191
  }
37192
+
37193
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
37194
+
37124
37195
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chnid]);
37125
37196
  let colorStr =(atom.color === undefined || atom.color.getHexString() === 'FFFFFF') ? 'DDDDDD' : atom.color.getHexString();
37126
37197
  let color =(atom.color !== undefined) ? colorStr : "CCCCCC";
37198
+
37199
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
37200
+
37127
37201
  if(me.cfg.blast_rep_id != chnid) { // regular
37128
37202
  for(let i = 0, il = fromArray.length; i < il; ++i) {
37129
37203
  let emptyWidth =(i == 0) ? Math.round(ic.seqAnnWidth *(fromArray[i] - ic.baseResi[chnid] - 1) / ic.maxAnnoLength) : Math.round(ic.seqAnnWidth *(fromArray[i] - toArray[i-1] - 1) / ic.maxAnnoLength);
@@ -37200,6 +37274,10 @@ class AnnoCddSite {
37200
37274
  let prevEmptyWidth = 0;
37201
37275
  let prevLineWidth = 0;
37202
37276
  let widthPerRes = 1;
37277
+
37278
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
37279
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
37280
+
37203
37281
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
37204
37282
  html += ic.showSeqCls.insertGap(chnid, i, '-');
37205
37283
  let resi = ic.ParserUtilsCls.getResi(chnid, i);
@@ -37275,6 +37353,9 @@ class AnnoCddSite {
37275
37353
  html += '<span>-</span>'; //'<span>-</span>';
37276
37354
  }
37277
37355
  }
37356
+
37357
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
37358
+
37278
37359
  htmlTmp = '<span class="icn3d-residueNum" title="residue count">&nbsp;' + resCnt.toString() + ' Residues</span>';
37279
37360
  htmlTmp += '</span>';
37280
37361
  htmlTmp += '<br>';
@@ -37439,6 +37520,9 @@ class AnnoContact {
37439
37520
  let prevLineWidth = 0;
37440
37521
  let widthPerRes = 1;
37441
37522
 
37523
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
37524
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
37525
+
37442
37526
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
37443
37527
  html += ic.showSeqCls.insertGap(chnid, i, '-');
37444
37528
  let resi = ic.ParserUtilsCls.getResi(chnid, i);
@@ -37474,6 +37558,9 @@ class AnnoContact {
37474
37558
  html += '<span>-</span>'; //'<span>-</span>';
37475
37559
  }
37476
37560
  }
37561
+
37562
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
37563
+
37477
37564
  htmlTmp = '<span class="icn3d-residueNum" title="residue count">&nbsp;' + resCnt.toString() + ' Residues</span>';
37478
37565
  htmlTmp += '</span>';
37479
37566
  htmlTmp += '<br>';
@@ -37726,6 +37813,10 @@ class AnnoPTM {
37726
37813
  let prevEmptyWidth = 0;
37727
37814
  let prevLineWidth = 0;
37728
37815
  let widthPerRes = 1;
37816
+
37817
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
37818
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
37819
+
37729
37820
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
37730
37821
  html += ic.showSeqCls.insertGap(chnid, i, '-');
37731
37822
  if(resPosArray.indexOf(i) != -1) {
@@ -37758,6 +37849,9 @@ class AnnoPTM {
37758
37849
  html += '<span>-</span>'; //'<span>-</span>';
37759
37850
  }
37760
37851
  }
37852
+
37853
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
37854
+
37761
37855
  htmlTmp = '<span class="icn3d-residueNum" title="residue count">&nbsp;' + resCnt.toString() + ' Residues</span>';
37762
37856
  htmlTmp += '</span>';
37763
37857
  htmlTmp += '<br>';
@@ -38037,6 +38131,9 @@ class AnnoDomain {
38037
38131
  html += htmlTmp2 + htmlTmp3 + htmlTmp;
38038
38132
  html2 += htmlTmp2 + htmlTmp3 + htmlTmp;
38039
38133
  let pre = 'domain3d' + index.toString();
38134
+
38135
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
38136
+
38040
38137
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
38041
38138
  html += ic.showSeqCls.insertGap(chnid, i, '-');
38042
38139
  //if(i >= domainFrom && i <= domainTo) {
@@ -38056,9 +38153,15 @@ class AnnoDomain {
38056
38153
  html += '<span>-</span>'; //'<span>-</span>';
38057
38154
  }
38058
38155
  }
38156
+
38157
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
38158
+
38059
38159
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chnid]);
38060
38160
  let colorStr =(atom.color === undefined || atom.color.getHexString() === 'FFFFFF') ? 'DDDDDD' : atom.color.getHexString();
38061
38161
  let color =(atom.color !== undefined) ? colorStr : "CCCCCC";
38162
+
38163
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
38164
+
38062
38165
  if(me.cfg.blast_rep_id != chnid) { // regular
38063
38166
  for(let i = 0, il = fromArray.length; i < il; ++i) {
38064
38167
  let emptyWidth =(i == 0) ? Math.round(ic.seqAnnWidth *(fromArray[i] - ic.baseResi[chnid] - 1) / ic.maxAnnoLength) : Math.round(ic.seqAnnWidth *(fromArray[i] - toArray[i-1] - 1) / ic.maxAnnoLength);
@@ -38326,9 +38429,18 @@ class AnnoSnpClinVar {
38326
38429
  let prevEmptyWidth = 0;
38327
38430
  let prevLineWidth = 0;
38328
38431
  let widthPerRes = 1;
38432
+
38433
+ if(bOverview) {
38434
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
38435
+ }
38436
+ else {
38437
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
38438
+ }
38439
+
38329
38440
  for(let i = 1, il = ic.giSeq[chnid].length; i <= il; ++i) {
38330
38441
  if(bOverview) {
38331
38442
  if(resi2index[i] !== undefined) {
38443
+
38332
38444
  // get the mouse over text
38333
38445
  let cFull = ic.giSeq[chnid][i-1];
38334
38446
  let c = cFull;
@@ -38353,7 +38465,8 @@ class AnnoSnpClinVar {
38353
38465
  }
38354
38466
  }
38355
38467
  html += ic.showSeqCls.insertGapOverview(chnid, i-1);
38356
- let emptyWidth =(me.cfg.blast_rep_id == chnid) ? Math.round(ic.seqAnnWidth *(i-1) /(ic.maxAnnoLength + ic.nTotalGap) - prevEmptyWidth - prevLineWidth) : Math.round(ic.seqAnnWidth *(i-1) / ic.maxAnnoLength - prevEmptyWidth - prevLineWidth);
38468
+ let emptyWidth = Math.round(ic.seqAnnWidth *(i-1) /(ic.maxAnnoLength + ic.nTotalGap) - prevEmptyWidth - prevLineWidth);
38469
+ //let emptyWidth =(me.cfg.blast_rep_id == chnid) ? Math.round(ic.seqAnnWidth *(i-1) /(ic.maxAnnoLength + ic.nTotalGap) - prevEmptyWidth - prevLineWidth) : Math.round(ic.seqAnnWidth *(i-1) / ic.maxAnnoLength - prevEmptyWidth - prevLineWidth);
38357
38470
  //if(emptyWidth < 0) emptyWidth = 0;
38358
38471
  if(bClinvar) {
38359
38472
  if(snpTypeHash[i] == 'icn3d-clinvar' || snpTypeHash[i] == 'icn3d-clinvar-path') {
@@ -38582,6 +38695,10 @@ class AnnoSnpClinVar {
38582
38695
  }
38583
38696
  } // if(bOverview) {
38584
38697
  } // for
38698
+
38699
+ if(!bOverview) {
38700
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
38701
+ }
38585
38702
 
38586
38703
  //var end = bStartEndRes ? ic.chainsSeq[chnid][ic.giSeq[chnid].length - 1 - ic.matchedPos[chnid] ].resi : '';
38587
38704
  if(line == 1) {
@@ -40026,7 +40143,7 @@ class Domain3d {
40026
40143
  return {subdomains: subdomains, substruct: substruct, pos2resi: pos2resi };
40027
40144
  } // end c2b_NewSplitChain
40028
40145
 
40029
- getDomainJsonForAlign(atoms) { let ic = this.icn3d, me = ic.icn3dui;
40146
+ getDomainJsonForAlign(atoms, bForceOneDomain) { let ic = this.icn3d, me = ic.icn3dui;
40030
40147
  let result = this.c2b_NewSplitChain(atoms);
40031
40148
 
40032
40149
  let subdomains = result.subdomains;
@@ -40037,6 +40154,8 @@ class Domain3d {
40037
40154
  let residueArray = Object.keys(residueHash);
40038
40155
  let chnid = residueArray[0].substr(0, residueArray[0].lastIndexOf('_'));
40039
40156
 
40157
+ if(bForceOneDomain) subdomains = [];
40158
+
40040
40159
  //the whole structure is also considered as a large domain
40041
40160
  //if(subdomains.length == 0) {
40042
40161
  //subdomains.push([parseInt(ic.chainsSeq[chnid][0].resi), parseInt(ic.chainsSeq[chnid][ic.chainsSeq[chnid].length - 1].resi)]);
@@ -40193,7 +40312,7 @@ class AddTrack {
40193
40312
  thisClass.alignSequenceToStructure(chainid, data, title);
40194
40313
  });
40195
40314
 
40196
- // FASTA Alignment
40315
+ // MSA
40197
40316
  me.myEventCls.onIds("#" + ic.pre + "addtrack_button2b", "click", async function(e) { let ic = thisClass.icn3d;
40198
40317
  e.stopImmediatePropagation();
40199
40318
  //e.preventDefault();
@@ -40201,159 +40320,47 @@ class AddTrack {
40201
40320
 
40202
40321
  let chainid = $("#" + ic.pre + "track_chainid").val();
40203
40322
  let startpos = $("#" + ic.pre + "fasta_startpos").val();
40323
+ if(!startpos) startpos = 1;
40324
+
40204
40325
  let colorseqby = $("#" + ic.pre + "colorseqby").val();
40205
40326
  let type =(colorseqby == 'identity') ? 'identity' : 'custom';
40206
40327
 
40207
40328
  let fastaList = $("#" + ic.pre + "track_fastaalign").val();
40208
- let fastaArray = fastaList.split('>');
40209
-
40210
- // the first array item is empty
40211
- // the second array item is the sequence of the structure, start with i = 2
40212
- let posFirst = fastaArray[1].indexOf('\n');
40213
- fastaArray[1].substr(0, posFirst);
40214
- let seqFirst = fastaArray[1].substr(posFirst + 1).replace(/\n/g, '');
40215
-
40216
- let trackTitleArray = [];
40217
- let trackSeqArray = [];
40218
- for(let i = 2, il = fastaArray.length; i < il; ++i) {
40219
- let pos = fastaArray[i].indexOf('\n');
40220
- let title = fastaArray[i].substr(0, pos);
40221
- trackTitleArray.push(title);
40222
- let seq = fastaArray[i].substr(pos + 1).replace(/\n/g, '');
40223
- trackSeqArray.push(seq);
40224
- }
40225
-
40226
- let startposGiSeq = undefined;
40227
- for(let i = 0, il = ic.giSeq[chainid].length; i < il; ++i) {
40228
- //let pos =(i >= ic.matchedPos[chainid] && i - ic.matchedPos[chainid] < ic.chainsSeq[chainid].length) ? ic.chainsSeq[chainid][i - ic.matchedPos[chainid]].resi : ic.baseResi[chainid] + 1 + i;
40229
- let pos = ic.ParserUtilsCls.getResi(chainid, i);
40230
-
40231
- if(pos != startpos) {
40232
- continue;
40233
- }
40234
- else {
40235
- startposGiSeq = i;
40236
- }
40237
- }
40238
-
40239
- if(startposGiSeq === undefined) alert("Please double check the start position before clicking \"Add Track\"");
40240
-
40241
-
40242
- // set up gap for the master seq
40243
- // don't count gaps in both ends
40244
- ic.targetGapHash = {};
40245
- let prevSeq = '-', prevPos = 0, from, to, cnt = 0, dashCnt = 0;
40246
- let bFound = false, seqStart = 0, seqEnd = 0;
40247
- for(let i = 0, il = seqFirst.length; i < il; ++i) {
40248
- if(seqFirst[i] == '-' && seqFirst[i] != prevSeq) { // start of gap
40249
- from = cnt;
40250
- dashCnt = 0;
40251
- }
40252
-
40253
- if(prevSeq == '-' && seqFirst[i] != prevSeq && cnt > 0) { // end of gap
40254
- to = prevPos;
40255
- ic.targetGapHash[from + startposGiSeq] = {'from': from + startposGiSeq, 'to': to + dashCnt - 1 + startposGiSeq};
40256
- }
40257
-
40258
- prevSeq = seqFirst[i];
40259
- prevPos = cnt;
40260
-
40261
- if(seqFirst[i] != '-') {
40262
- ++cnt;
40263
- seqEnd = i;
40264
-
40265
- if(!bFound) {
40266
- seqStart = i;
40267
- bFound = true;
40268
- }
40269
- }
40270
- else {
40271
- ++dashCnt;
40272
- }
40273
- }
40274
-
40275
- await ic.annotationCls.resetAnnoAll();
40276
-
40277
- let targetGapHashStr = '';
40278
- let cntTmp = 0;
40279
- for(let i in ic.targetGapHash) {
40280
- if(cntTmp > 0) targetGapHashStr += ' ';
40281
- targetGapHashStr += i + '_' + ic.targetGapHash[i].from + '_' + ic.targetGapHash[i].to;
40282
- ++cntTmp;
40283
- }
40284
-
40285
- me.htmlCls.clickMenuCls.setLogCmd("msa | " + targetGapHashStr, true);
40286
-
40287
- // add tracks
40288
- let resi2cntSameRes = {}; // count of same residue at each position
40289
- for(let j = 0, jl = trackSeqArray.length; j < jl; ++j) {
40290
- let resi = startpos; //startposGiSeq + 1;
40291
- let text = '';
40292
- for(let k = 0; k < startposGiSeq; ++k) {
40293
- if(ic.targetGapHash.hasOwnProperty(k)) {
40294
- for(let m = 0; m < ic.targetGapHash[k].to - ic.targetGapHash[k].from + 1; ++m) {
40295
- text += '-';
40296
- }
40297
- }
40298
-
40299
- text += '-';
40300
- }
40301
-
40302
- for(let k = seqStart; k <= seqEnd; ++k) {
40303
- //if(seqFirst[k] == '-') continue;
40304
-
40305
- if(j == 0) resi2cntSameRes[resi] = 0;
40306
-
40307
- text += trackSeqArray[j][k]; //ic.giSeq[chainid][i];
40308
-
40309
- if(seqFirst[k] != '-') {
40310
- if(seqFirst[k] == trackSeqArray[j][k]) ++resi2cntSameRes[resi];
40311
- ++resi;
40312
- }
40313
- }
40314
-
40315
- let title =(trackTitleArray[j].length < 20) ? trackTitleArray[j] : trackTitleArray[j].substr(0, 20) + '...';
40316
- let bMsa = true;
40317
- thisClass.showNewTrack(chainid, title, text, undefined, undefined, type, undefined, bMsa);
40318
-
40319
- me.htmlCls.clickMenuCls.setLogCmd("add track | chainid " + chainid + " | title " + title + " | text " + thisClass.simplifyText(text)
40320
- + " | type " + type + " | color 0 | msa 1", true);
40321
- }
40322
40329
 
40323
- // set colot for the master seq
40324
- if(trackSeqArray.length > 0) {
40325
- if(ic.queryresi2score === undefined) ic.queryresi2score = {};
40326
- if(ic.queryresi2score[chainid] === undefined) ic.queryresi2score[chainid] = {};
40327
-
40328
- let nSeq = trackSeqArray.length;
40329
- for(let resi in resi2cntSameRes) {
40330
- let score = parseInt(resi2cntSameRes[resi] / nSeq * 100);
40331
- ic.queryresi2score[chainid][resi] = score;
40332
- }
40330
+ if(fastaList) {
40331
+ await thisClass.addMsaTracks(chainid, startpos, type, fastaList);
40332
+ }
40333
+ });
40333
40334
 
40334
- let resiArray = Object.keys(resi2cntSameRes);
40335
- let start = Math.min.apply(null, resiArray);
40336
- let end = Math.max.apply(null, resiArray);
40335
+ // Gene table
40336
+ me.myEventCls.onIds("#" + ic.pre + "exons_table", "click", async function(e) { let ic = thisClass.icn3d;
40337
+ e.stopImmediatePropagation();
40338
+ //dialog.dialog( "close" );
40337
40339
 
40338
- let resiScoreStr = '';
40339
- for(let resi = start; resi <= end; ++resi) {
40340
- if(resi2cntSameRes.hasOwnProperty(resi)) {
40341
- resiScoreStr += Math.round(resi2cntSameRes[resi] / nSeq * 9); // max 9
40342
- }
40343
- else {
40344
- resiScoreStr += '_';
40345
- }
40346
- }
40340
+ let geneid = $("#" + ic.pre + "track_geneid").val().trim();
40341
+ window.open('https://www.ncbi.nlm.nih.gov/gene/' + geneid + '?report=gene_table', '_blank');
40342
+ });
40347
40343
 
40348
- ic.opts['color'] = 'align custom';
40349
- ic.setColorCls.setColorByOptions(ic.opts, ic.hAtoms);
40344
+ // Isoform Alignment
40345
+ me.myEventCls.onIds("#" + ic.pre + "addtrack_button2c", "click", async function(e) { let ic = thisClass.icn3d;
40346
+ e.stopImmediatePropagation();
40347
+ //e.preventDefault();
40348
+ dialog.dialog( "close" );
40350
40349
 
40351
- ic.hlUpdateCls.updateHlAll();
40350
+ let chainid = $("#" + ic.pre + "track_chainid").val();
40351
+ let geneid = $("#" + ic.pre + "track_geneid").val();
40352
+ if(!geneid) {
40353
+ alert("Please fill in the Gene ID...");
40354
+ return;
40355
+ }
40352
40356
 
40353
- ic.drawCls.draw();
40357
+ let startpos = $("#" + ic.pre + "fasta_startpos2").val();
40358
+ if(!startpos) startpos = 1;
40354
40359
 
40355
- me.htmlCls.clickMenuCls.setLogCmd('color align custom | ' + chainid + ' | range ' + start + '_' + end + ' | ' + resiScoreStr, true);
40356
- }
40360
+ let colorseqby = $("#" + ic.pre + "colorseqby2").val();
40361
+ let type =(colorseqby == 'identity') ? 'identity' : 'custom';
40362
+
40363
+ await thisClass.addExonTracks(chainid, geneid, startpos, type);
40357
40364
  });
40358
40365
 
40359
40366
  // BED file
@@ -40539,7 +40546,7 @@ class AddTrack {
40539
40546
 
40540
40547
  }
40541
40548
 
40542
- showNewTrack(chnid, title, text, cssColorArray, inTarget2queryHash, type, color, bMsa, fromArray, toArray) { let ic = this.icn3d, me = ic.icn3dui;
40549
+ showNewTrack(chnid, title, text, cssColorArray, inTarget2queryHash, type, color, bMsa, fromArray, toArray, seqStartLen, exonArray) { let ic = this.icn3d, me = ic.icn3dui;
40543
40550
  //if(ic.customTracks[chnid] === undefined) {
40544
40551
  // ic.customTracks[chnid] = {}
40545
40552
  //}
@@ -40588,22 +40595,28 @@ class AddTrack {
40588
40595
  $("#" + ic.pre + "tt_custom_" + chnid + "_" + simpTitle).width(divLength);
40589
40596
 
40590
40597
  let html = '<div id="' + ic.pre + 'giseq_sequence" class="icn3d-dl_sequence">';
40598
+ let htmlExon = html;
40591
40599
  let html2 = html;
40592
40600
  let html3 = html;
40601
+ let html3Exon = html;
40593
40602
 
40594
40603
  //var htmlTmp2 = '<div class="icn3d-seqTitle icn3d-link icn3d-blue" gi="' + chnid + '" anno="sequence" chain="' + chnid + '"><span style="white-space:nowrap;">' + title + '</span></div>';
40595
40604
  //var htmlTmp2 = '<div class="icn3d-seqTitle" gi="' + chnid + '" anno="sequence" chain="' + chnid + '"><span style="white-space:nowrap;">' + title + '</span></div>';
40596
40605
  let index = parseInt(Math.random()*10);
40597
40606
  let htmlTmp2 = '<div class="icn3d-seqTitle icn3d-link icn3d-blue" custom="' +(index+1).toString() + '" from="' + fromArray + '" to="' + toArray + '" shorttitle="' + simpTitle + '" index="' + index + '" setname="' + chnid + '_custom_' +(index+1).toString() + '" anno="sequence" chain="' + chnid + '" title="' + title + '">' + simpTitle + ' </div>';
40607
+ let htmlTmp2Exon = '<div class="icn3d-seqTitle" chain="' + chnid + '" title="Exons of ' + title + '">Exons </div>';
40608
+
40598
40609
  let htmlTmp3 = '<span class="icn3d-residueNum" title="residue count">' + resCnt.toString() + ' Pos</span>';
40599
40610
 
40600
40611
  html3 += htmlTmp2 + htmlTmp3 + '<br>';
40612
+ html3Exon += htmlTmp2Exon + htmlTmp3 + '<br>';
40601
40613
 
40602
40614
  let htmlTmp = '<span class="icn3d-seqLine">';
40603
40615
 
40604
40616
  html += htmlTmp2 + htmlTmp3 + htmlTmp;
40617
+ htmlExon += htmlTmp2Exon + htmlTmp3 + htmlTmp;
40605
40618
  html2 += htmlTmp2 + htmlTmp3 + htmlTmp;
40606
-
40619
+
40607
40620
  //var pre ='cst' + ic.customTracks[chnid].length;
40608
40621
  let posTmp = chnid.indexOf('_');
40609
40622
  //var pre ='cst' + chnid.substr(posTmp);
@@ -40618,10 +40631,34 @@ class AddTrack {
40618
40631
  let bIdentityColor =(type === 'identity') && text.indexOf('cannot-be-aligned') == -1 && text.indexOf('cannot be aligned') == -1 ? true : false;
40619
40632
 
40620
40633
  let parsedResn = {};
40621
- let gapCnt = 0, currResi = 1;
40634
+ let gapCnt = 0;
40622
40635
  htmlTmp2 = '';
40636
+
40637
+ // if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
40638
+ // if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
40639
+
40640
+ let pos2exonColor = {}, pos2genome = {}, pos2exonIndex = {};
40641
+ let cnt = 0;
40642
+ if(exonArray) {
40643
+ for(let j = 0, jl = exonArray.length; j < jl; ++j) {
40644
+ let start = exonArray[j].resStart, end = exonArray[j].resEnd;
40645
+ let genStart = exonArray[j].genomeRange.split('-')[0];
40646
+
40647
+ for(let k = 0, kl = end - start + 1; k < kl; ++k) {
40648
+ let colorStr = this.getExonColor(start, end, cnt);
40649
+
40650
+ pos2exonColor[cnt] = colorStr;
40651
+ pos2genome[cnt] = (genStart + ic.exonOrder * k*3) + '-' + (genStart + ic.exonOrder * k*3 + ic.exonOrder * 2); // reverse order from large to small
40652
+ pos2exonIndex[cnt] = j;
40653
+
40654
+ ++cnt;
40655
+ }
40656
+ }
40657
+ }
40658
+
40659
+ cnt = 0;
40623
40660
  for(let i = 0, il = text.length; i < il; ++i) {
40624
- let resNum = i-gapCnt;
40661
+ let resNum = i - gapCnt - ((ic.seqStartLen && ic.seqStartLen[chnid]) ? ic.seqStartLen[chnid] : 0);
40625
40662
 
40626
40663
  if(!bMsa) {
40627
40664
  html += ic.showSeqCls.insertGap(chnid, i, '-');
@@ -40642,7 +40679,8 @@ class AddTrack {
40642
40679
  let identityColorStr =(c == resName) ? 'FF0000' : '0000FF';
40643
40680
 
40644
40681
  //var pos =(resNum >= ic.matchedPos[chnid] && resNum - ic.matchedPos[chnid] < ic.chainsSeq[chnid].length) ? ic.chainsSeq[chnid][resNum - ic.matchedPos[chnid]].resi : ic.baseResi[chnid] + 1 + resNum;
40645
- let pos = ic.baseResi[chnid] + currResi;
40682
+ // let pos = ic.baseResi[chnid] + currResi;
40683
+ let pos = ic.baseResi[chnid] + (i+1) - ((ic.seqStartLen && ic.seqStartLen[chnid]) ? ic.seqStartLen[chnid] : 0);
40646
40684
 
40647
40685
  if(inTarget2queryHash !== undefined) pos = ic.baseResi[chnid] + inTarget2queryHash[i] + 1; // 0-based
40648
40686
 
@@ -40673,9 +40711,13 @@ class AddTrack {
40673
40711
 
40674
40712
  html += '<span id="' + pre + '_' + ic.pre + chnid + '_' + pos + '" title="' + c + pos + '" class="icn3d-residue" ' + tmpStr + '>' + c + '</span>';
40675
40713
 
40714
+ let tmpStrExon = 'style="background-color:' + pos2exonColor[cnt] + '"';
40715
+ htmlExon += '<span id="' + pre + '_' + ic.pre + chnid + '_' + pos + '" title="' + c + pos + ', Exon ' + (pos2exonIndex[cnt] + 1) + ': ' + pos2genome[cnt] + '" class="icn3d-residue" ' + tmpStrExon + '>&nbsp;</span>';
40716
+
40676
40717
  htmlTmp2 += ic.showSeqCls.insertGapOverview(chnid, i);
40677
40718
 
40678
- let emptyWidth =(me.cfg.blast_rep_id == chnid) ? Math.round(ic.seqAnnWidth * i /(ic.maxAnnoLength + ic.nTotalGap) - prevEmptyWidth - prevLineWidth) : Math.round(ic.seqAnnWidth * i / ic.maxAnnoLength - prevEmptyWidth - prevLineWidth);
40719
+ // let emptyWidth =(me.cfg.blast_rep_id == chnid) ? Math.round(ic.seqAnnWidth * i /(ic.maxAnnoLength + ic.nTotalGap) - prevEmptyWidth - prevLineWidth) : Math.round(ic.seqAnnWidth * i / ic.maxAnnoLength - prevEmptyWidth - prevLineWidth);
40720
+ let emptyWidth = Math.round(ic.seqAnnWidth * i /(ic.maxAnnoLength + ic.nTotalGap) - prevEmptyWidth - prevLineWidth);
40679
40721
  if(emptyWidth < 0) emptyWidth = 0;
40680
40722
 
40681
40723
  htmlTmp2 += '<div style="display:inline-block; width:' + emptyWidth + 'px;">&nbsp;</div>';
@@ -40696,19 +40738,21 @@ class AddTrack {
40696
40738
 
40697
40739
  prevEmptyWidth += emptyWidth;
40698
40740
  prevLineWidth += widthPerRes;
40699
-
40700
- ++currResi;
40741
+ ++cnt;
40701
40742
  }
40702
40743
  else {
40703
40744
  if(bErrorMess) {
40704
- html += '<span>' + c + '</span>';
40745
+ html += '<span>' + c + '</span>';
40705
40746
  }
40706
40747
  else {
40707
40748
  html += '<span>-</span>';
40749
+ htmlExon += '<span></span>';
40708
40750
  }
40709
40751
  }
40710
40752
  }
40711
40753
 
40754
+ // if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
40755
+
40712
40756
  if(fromArray !== undefined) {
40713
40757
  htmlTmp2 = '';
40714
40758
  let fromArray2 = [], toArray2 = [];
@@ -40734,13 +40778,77 @@ class AddTrack {
40734
40778
  let colorStr =(atom.color === undefined || atom.color.getHexString() === 'FFFFFF') ? 'DDDDDD' : atom.color.getHexString();
40735
40779
  let color =(atom.color !== undefined) ? colorStr : "CCCCCC";
40736
40780
 
40781
+ let cnt, prevCntTotal = 0;
40737
40782
  for(let i = 0, il = fromArray2.length; i < il; ++i) {
40738
40783
  htmlTmp2 += ic.showSeqCls.insertGapOverview(chnid, fromArray2[i]);
40739
40784
 
40740
- let emptyWidth =(i == 0) ? Math.round(ic.seqAnnWidth *(fromArray2[i] - ic.baseResi[chnid] - 1) /(ic.maxAnnoLength + ic.nTotalGap)) : Math.round(ic.seqAnnWidth *(fromArray2[i] - toArray2[i-1] - 1) /(ic.maxAnnoLength + ic.nTotalGap));
40785
+ let initialPos = (seqStartLen) ? fromArray2[i] : fromArray2[i] - ic.baseResi[chnid] - 1;
40786
+
40787
+ let emptyWidth =(i == 0) ? Math.round(ic.seqAnnWidth * initialPos /(ic.maxAnnoLength + ic.nTotalGap)) : Math.round(ic.seqAnnWidth *(fromArray2[i] - toArray2[i-1] - 1) /(ic.maxAnnoLength + ic.nTotalGap));
40788
+ if(emptyWidth < 0) emptyWidth = 0;
40789
+
40741
40790
  htmlTmp2 += '<div style="display:inline-block; width:' + emptyWidth + 'px;">&nbsp;</div>';
40742
40791
 
40743
- htmlTmp2 += '<div style="display:inline-block; color:white!important; font-weight:bold; background-color:#' + color + '; width:' + Math.round(ic.seqAnnWidth *(toArray2[i] - fromArray2[i] + 1) /(ic.maxAnnoLength + ic.nTotalGap)) + 'px;" class="icn3d-seqTitle icn3d-link icn3d-blue" custom="' +(index+1).toString() + '" from="' + fromArray2 + '" to="' + toArray2 + '" shorttitle="' + simpTitle + '" index="' + index + '" setname="' + chnid + '_custom_' +(index+1).toString() + '" id="' + chnid + '_custom_' + index + '" anno="sequence" chain="' + chnid + '" title="' + title + '">' + title + '</div>';
40792
+ if(!exonArray) {
40793
+ htmlTmp2 += '<div style="display:inline-block; color:white!important; font-weight:bold; background-color:#' + color + '; width:' + Math.round(ic.seqAnnWidth *(toArray2[i] - fromArray2[i] + 1) /(ic.maxAnnoLength + ic.nTotalGap)) + 'px;" class="icn3d-seqTitle icn3d-link icn3d-blue" custom="' +(index+1).toString() + '" from="' + fromArray2 + '" to="' + toArray2 + '" shorttitle="' + simpTitle + '" index="' + index + '" setname="' + chnid + '_custom_' +(index+1).toString() + '" id="' + chnid + '_custom_' + index + '" anno="sequence" chain="' + chnid + '" title="' + title + '">' + title + '</div>';
40794
+ }
40795
+ else {
40796
+ // determine how this range sits in the exon ranges in exonArray
40797
+ let startExon, endExon;
40798
+
40799
+ cnt = toArray[i] - fromArray[i] + 1;
40800
+ let from = prevCntTotal, to = prevCntTotal + cnt - 1;
40801
+
40802
+ prevCntTotal += cnt;
40803
+
40804
+ // fromArray2 was adjusted with gaps, no gaps in this case
40805
+ // let offset = fromArray2[i] - fromArray[i];
40806
+ // let emptyWidth = Math.round(ic.seqAnnWidth * offset /(ic.maxAnnoLength + ic.nTotalGap));
40807
+ // htmlTmp2 += '<div style="display:inline-block; width:' + emptyWidth + 'px;">&nbsp;</div>';
40808
+
40809
+ for(let j = 0, jl = exonArray.length; j < jl; ++j) {
40810
+ let start = exonArray[j].resStart, end = exonArray[j].resEnd;
40811
+
40812
+ if(from >= start && from <= end) {
40813
+ startExon = {exonIndex: j, rangeStart: start, rangeEnd: end, from: from, genomeRange: exonArray[j].genomeRange};
40814
+ }
40815
+
40816
+ if(to >= start && to <= end) {
40817
+ endExon = {exonIndex: j, rangeStart: start, rangeEnd: end, to: to, genomeRange: exonArray[j].genomeRange};
40818
+ }
40819
+ }
40820
+
40821
+ let startColorStr, endColorStr, colorGradient;
40822
+ if(startExon && endExon && startExon.exonIndex == endExon.exonIndex) { //
40823
+ startColorStr = this.getExonColor(startExon.rangeStart, startExon.rangeEnd, from);
40824
+ endColorStr = this.getExonColor(startExon.rangeStart, startExon.rangeEnd, to);
40825
+
40826
+ colorGradient = startColorStr + ' 0%, #FFF 50%, ' + endColorStr + ' 100%';
40827
+ htmlTmp2 += this.getExonHtml(startExon.exonIndex, colorGradient, startExon.from, endExon.to, startExon.genomeRange);
40828
+ }
40829
+ else {
40830
+ if(startExon) {
40831
+ startColorStr = this.getExonColor(startExon.rangeStart, startExon.rangeEnd, from);
40832
+
40833
+ colorGradient = startColorStr + ' 0%, #FFF 50%, #00F 100%';
40834
+ htmlTmp2 += this.getExonHtml(startExon.exonIndex, colorGradient, startExon.from, startExon.rangeEnd, startExon.genomeRange);
40835
+ }
40836
+
40837
+ if(startExon && endExon) {
40838
+ for(let j = startExon.exonIndex + 1; j < endExon.exonIndex; ++j) {
40839
+ colorGradient = '#F00 0%, #FFF 50%, #00F 100%';
40840
+ htmlTmp2 += this.getExonHtml(j, colorGradient, exonArray[j].resStart, exonArray[j].resEnd, exonArray[j].genomeRange);
40841
+ }
40842
+
40843
+ endColorStr = this.getExonColor(endExon.rangeStart, endExon.rangeEnd, to);
40844
+
40845
+ colorGradient = '#F00 0%, #FFF 50%, ' + endColorStr + ' 100%';
40846
+ htmlTmp2 += this.getExonHtml(endExon.exonIndex, colorGradient, endExon.rangeStart, endExon.to, endExon.genomeRange);
40847
+ }
40848
+ }
40849
+
40850
+ //htmlTmp2 += '<div style="display:inline-block; color:white!important; font-weight:bold; background-color:#' + color + '; width:' + Math.round(ic.seqAnnWidth *(toArray2[i] - fromArray2[i] + 1) /(ic.maxAnnoLength + ic.nTotalGap)) + 'px;" class="icn3d-seqTitle icn3d-link icn3d-blue" custom="' +(index+1).toString() + '" from="' + fromArray2 + '" to="' + toArray2 + '" shorttitle="' + simpTitle + '" index="' + index + '" setname="' + chnid + '_custom_' +(index+1).toString() + '" id="' + chnid + '_custom_' + index + '" anno="sequence" chain="' + chnid + '" title="' + title + '">' + title + '</div>';
40851
+ }
40744
40852
  }
40745
40853
  }
40746
40854
 
@@ -40752,12 +40860,37 @@ class AddTrack {
40752
40860
 
40753
40861
  html += htmlTmp;
40754
40862
  html2 += htmlTmp2 + htmlTmp;
40863
+ htmlExon += htmlTmp;
40755
40864
 
40756
40865
  html3 += '</div>';
40866
+ html3Exon += '</div>';
40757
40867
 
40758
- $("#" + ic.pre + "dt_custom_" + chnid + "_" + simpTitle).html(html);
40759
- $("#" + ic.pre + "ov_custom_" + chnid + "_" + simpTitle).html(html2);
40760
- $("#" + ic.pre + "tt_custom_" + chnid + "_" + simpTitle).html(html3);
40868
+ if(!exonArray) {
40869
+ $("#" + ic.pre + "dt_custom_" + chnid + "_" + simpTitle).html(html);
40870
+ $("#" + ic.pre + "ov_custom_" + chnid + "_" + simpTitle).html(html2);
40871
+ $("#" + ic.pre + "tt_custom_" + chnid + "_" + simpTitle).html(html3);
40872
+ }
40873
+ else {
40874
+ $("#" + ic.pre + "dt_custom_" + chnid + "_" + simpTitle).html(htmlExon + html);
40875
+ $("#" + ic.pre + "ov_custom_" + chnid + "_" + simpTitle).html(html2);
40876
+ $("#" + ic.pre + "tt_custom_" + chnid + "_" + simpTitle).html(html3Exon + html3);
40877
+ }
40878
+ }
40879
+
40880
+ getExonHtml(exonIndex, colorGradient, from, to, genomeRange) { let ic = this.icn3d; ic.icn3dui;
40881
+ return '<div style="display:inline-block; color:white!important; width:' + Math.round(ic.seqAnnWidth *(to - from + 1) /(ic.maxAnnoLength + ic.nTotalGap)) + 'px;" class="icn3d-seqTitle icn3d-link icn3d-blue" title="Exon ' + (exonIndex + 1) + ': ' + genomeRange + ' genomic interval" anno="sequence" title="' + (exonIndex + 1) + '"><div style="height: 12px; border: 1px solid #000; background: linear-gradient(to right, ' + colorGradient + ');"></div></div>';
40882
+ }
40883
+
40884
+ getExonColor(start, end, pos) { let ic = this.icn3d; ic.icn3dui;
40885
+ let middle = ( start + end) * 0.5;
40886
+ if(pos < middle) {
40887
+ let gb = parseInt((pos - start) / (middle - start) * 255);
40888
+ return "rgb(255, " + gb + ", " + gb + ")";
40889
+ }
40890
+ else {
40891
+ let rg = parseInt((end - pos) / (end - middle) * 255);
40892
+ return "rgb(" + rg + ", " + rg + ", 255)";
40893
+ }
40761
40894
  }
40762
40895
 
40763
40896
  alignSequenceToStructure(chainid, data, title) { let ic = this.icn3d, me = ic.icn3dui;
@@ -41065,6 +41198,7 @@ class AddTrack {
41065
41198
  let result = this.getFullText(text);
41066
41199
  text = result.text;
41067
41200
  this.showNewTrack(chainid, title, text, undefined, undefined, type, color, bMsa);
41201
+
41068
41202
  return false;
41069
41203
  }
41070
41204
 
@@ -41187,6 +41321,722 @@ class AddTrack {
41187
41321
  }
41188
41322
  }
41189
41323
 
41324
+ async getMsa(acclist, firstAcc, chainSeq) { let ic = this.icn3d, me = ic.icn3dui;
41325
+ let trackTitleArray = [firstAcc], trackSeqArray = [];
41326
+ // get all seq
41327
+ let url = me.htmlCls.baseUrl + "/vastdyn/vastdyn.cgi?chainlist=" + acclist;
41328
+ let data = await me.getAjaxPromise(url, 'jsonp');
41329
+ let maxLen = 0, maxIndex = 0, index = 0;
41330
+ //let seqArray = [];
41331
+ for(let acc in data) {
41332
+ let seq = data[acc];
41333
+ //seqArray.push(seq);
41334
+
41335
+ let pos = acc.indexOf('.');
41336
+ if(pos != -1) {
41337
+ acc = acc.substr(0, pos);
41338
+ }
41339
+ trackTitleArray.push(acc);
41340
+
41341
+ if(seq.length > maxLen) {
41342
+ maxLen = seq.length;
41343
+ maxIndex = index;
41344
+ }
41345
+ ++index;
41346
+ }
41347
+
41348
+ // pairwise align each seq to the one with maxIndex
41349
+ url = me.htmlCls.baseUrl + 'pwaln/pwaln.fcgi?from=msa';
41350
+
41351
+ let accArray = acclist.split(',');
41352
+ // oroginal index, chain as the first one
41353
+ let acc2index = {};
41354
+ acc2index[firstAcc] = 0;
41355
+ for(let i = 0, il = accArray.length; i < il; ++i) {
41356
+ acc2index[accArray[i]] = i + 1;
41357
+ }
41358
+ let targetId = accArray[maxIndex];
41359
+ accArray.splice(maxIndex, 1);
41360
+
41361
+ let queries = (chainSeq) ? chainSeq : firstAcc;
41362
+ if(accArray.length > 0) queries += ',' + accArray.join(',');
41363
+
41364
+ let dataObj = {'targets': targetId, 'queries': queries};
41365
+ let alignData = await me.getAjaxPostPromise(url, dataObj);
41366
+
41367
+ if(!alignData.data) {
41368
+ console.log("The protein accessions " + targetId + "," + queries + " can not be aligned...");
41369
+ return;
41370
+ }
41371
+
41372
+ // get aligned length for each pair
41373
+ let index_alignLen = [];
41374
+ ic.qt_start_end = {};
41375
+ // target: targetId
41376
+ // queries: accArray
41377
+ let accArrayFound = [], querySeqArray = [];
41378
+ let firstKey = Object.keys(alignData.targets)[0];
41379
+ let targetSeq = alignData.targets[firstKey].seqdata;
41380
+
41381
+ //add firstAcc to accArray
41382
+ accArray.splice(0, 0, firstAcc);
41383
+
41384
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41385
+ let query, target;
41386
+
41387
+ if(!alignData.data[index]) {
41388
+ continue;
41389
+ }
41390
+
41391
+ query = alignData.data[index].query;
41392
+ let acc;
41393
+ if(query.acc.length <= 5) { // PDB
41394
+ acc = query.acc.substr(0, 4) + '_' + query.acc.substr(4, 1);
41395
+ }
41396
+ else {
41397
+ acc = query.acc;
41398
+ }
41399
+
41400
+ if(index == 0) acc = firstAcc;
41401
+
41402
+ accArrayFound.push(acc);
41403
+
41404
+ firstKey = Object.keys(alignData.data[index].targets)[0];
41405
+ target = alignData.data[index].targets[firstKey];
41406
+
41407
+ target = target.hsps[0];
41408
+
41409
+ querySeqArray.push(query.seqdata);
41410
+ let alignLen = target.scores.num_ident * 100 + query.sz; // order by aligned seq length, then seq length
41411
+
41412
+ ic.qt_start_end[index] = [];
41413
+
41414
+ let segArray = target.segs;
41415
+ for(let i = 0, il = segArray.length; i < il; ++i) {
41416
+ let seg = segArray[i];
41417
+ let qt_start_end = {t_start: seg.orifrom, t_end: seg.orito, q_start: seg.from, q_end: seg.to};
41418
+ ic.qt_start_end[index].push(qt_start_end);
41419
+ }
41420
+
41421
+ index_alignLen.push({index: index, alignLen: alignLen});
41422
+ }
41423
+
41424
+ accArray = accArrayFound;
41425
+
41426
+ index_alignLen.sort(function(a,b){
41427
+ return b.alignLen - a.alignLen;
41428
+ });
41429
+
41430
+ // start and end of MSA
41431
+ let start_t = 9999, end_t = -1;
41432
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41433
+ if(!ic.qt_start_end[index]) continue;
41434
+
41435
+ for(let i = 0, il = ic.qt_start_end[index].length; i < il; ++i) {
41436
+ let start1, end1;
41437
+
41438
+ start1 = ic.qt_start_end[index][i].t_start;
41439
+ end1 = ic.qt_start_end[index][i].t_end;
41440
+
41441
+ for(let j = start1; j <= end1; ++j) {
41442
+ if(j < start_t) start_t = j;
41443
+ if(j > end_t) end_t = j;
41444
+ }
41445
+ }
41446
+ }
41447
+
41448
+ // N- and C-terminal residues
41449
+ let maxNtermLen = start_t, maxCtermLen = targetSeq.length - (end_t + 1);
41450
+ let startArray = [], endArray = [];
41451
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41452
+ if(!ic.qt_start_end[index]) continue;
41453
+
41454
+ let qPos = ic.qt_start_end[index][0].q_start;
41455
+ startArray.push(qPos);
41456
+ if(maxNtermLen < qPos) maxNtermLen = qPos;
41457
+
41458
+ let lastIndex = ic.qt_start_end[index].length - 1;
41459
+ qPos = ic.qt_start_end[index][lastIndex].q_end;
41460
+ endArray.push(qPos);
41461
+ let dist = querySeqArray[index].length - (qPos + 1);
41462
+ if(maxCtermLen < dist) maxCtermLen = dist;
41463
+ }
41464
+
41465
+ ic.msaSeq = {};
41466
+ // assign the template
41467
+ ic.msaSeq[targetId] = '';
41468
+
41469
+ for(let i = start_t; i <= end_t; ++i) {
41470
+ ic.msaSeq[targetId] += targetSeq[i];
41471
+ }
41472
+
41473
+ // progressively merge sequences, starting from most similar to least similar
41474
+ let alignedChainIndice = [0];
41475
+ for(let arrayIndex = 0, arrayIndexl = index_alignLen.length; arrayIndex < arrayIndexl; ++arrayIndex) {
41476
+ let index = index_alignLen[arrayIndex].index;
41477
+ alignedChainIndice.push(index);
41478
+
41479
+ ic.msaSeq[accArray[index]] = '';
41480
+
41481
+ // some proteins may not be aligned
41482
+ if(!querySeqArray[index]) continue;
41483
+
41484
+ ic.setSeqAlignCls.mergeTwoSeqForAllSimple(targetId, accArray, index, alignedChainIndice, start_t, end_t, querySeqArray);
41485
+ }
41486
+
41487
+ // add N-terminal seq
41488
+ let seqN = '', cnt;
41489
+ for(let i = 0; i < maxNtermLen - start_t; ++i) {
41490
+ seqN += '-';
41491
+ }
41492
+ for(let i = 0; i < start_t; ++i) {
41493
+ seqN += targetSeq[i];
41494
+ }
41495
+ ic.msaSeq[targetId] = seqN + ic.msaSeq[targetId];
41496
+
41497
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41498
+ seqN = '';
41499
+ for(let i = 0; i < maxNtermLen - startArray[index]; ++i) {
41500
+ seqN += '-';
41501
+ }
41502
+ for(let i = 0; i < startArray[index]; ++i) {
41503
+ seqN += querySeqArray[index][i];
41504
+ }
41505
+
41506
+ ic.msaSeq[accArray[index]] = seqN + ic.msaSeq[accArray[index]];
41507
+ }
41508
+
41509
+ // add C-terminal seq
41510
+ for(let i = end_t + 1; i < targetSeq.length; ++i) {
41511
+ ic.msaSeq[targetId] += targetSeq[i];
41512
+ }
41513
+
41514
+ cnt = targetSeq.length - (end_t + 1);
41515
+ for(let i = 0; i < maxCtermLen - cnt; ++i) {
41516
+ ic.msaSeq[targetId] += '-';
41517
+ }
41518
+
41519
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41520
+ for(let i = endArray[index] + 1; i < querySeqArray[index].length; ++i) {
41521
+ ic.msaSeq[accArray[index]] += querySeqArray[index][i];
41522
+ }
41523
+
41524
+ cnt = querySeqArray[index].length - (endArray[index] + 1);
41525
+ for(let i = 0; i < maxCtermLen - cnt; ++i) {
41526
+ ic.msaSeq[accArray[index]] += '-';
41527
+ }
41528
+ }
41529
+
41530
+ for(let acc in ic.msaSeq) {
41531
+ let index = acc2index[acc];
41532
+ trackSeqArray[index] = ic.msaSeq[acc];
41533
+ trackTitleArray[index] = acc;
41534
+ }
41535
+
41536
+ // some of the protein may not be aligned
41537
+ let trackTitleArrayFinal = [], trackSeqArrayFinal = [];
41538
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
41539
+ if(trackSeqArray[i]) {
41540
+ trackSeqArrayFinal.push(trackSeqArray[i]);
41541
+ trackTitleArrayFinal.push(trackTitleArray[i]);
41542
+ }
41543
+ }
41544
+
41545
+ let seqFirst = trackSeqArrayFinal[0];
41546
+
41547
+ trackSeqArrayFinal.splice(0, 1);
41548
+ trackTitleArrayFinal.splice(0, 1);
41549
+
41550
+ return {trackTitleArray: trackTitleArrayFinal, trackSeqArray: trackSeqArrayFinal, seqFirst: seqFirst};
41551
+ }
41552
+
41553
+ async getIsoformMsa(acclist, acc2exons) { let ic = this.icn3d, me = ic.icn3dui;
41554
+ let trackTitleArray = [], trackSeqArray = [];
41555
+ // get all seq
41556
+ let url = me.htmlCls.baseUrl + "/vastdyn/vastdyn.cgi?chainlist=" + acclist;
41557
+ let data = await me.getAjaxPromise(url, 'jsonp');
41558
+ let maxLen = 0, maxIndex = 0, index = 0;
41559
+ let accArray = [], querySeqArray = [];
41560
+ for(let acc in data) {
41561
+ let seq = data[acc];
41562
+ querySeqArray.push(seq);
41563
+
41564
+ let pos = acc.indexOf('.');
41565
+ if(pos != -1) {
41566
+ acc = acc.substr(0, pos);
41567
+ }
41568
+ accArray.push(acc);
41569
+
41570
+ if(seq.length > maxLen) {
41571
+ maxLen = seq.length;
41572
+ maxIndex = index;
41573
+ }
41574
+ ++index;
41575
+ }
41576
+
41577
+ // get aligned length for each pair
41578
+ ic.qt_start_end = {};
41579
+
41580
+ // use the genomic interval as the alignment template
41581
+ let targetId = 'genomeRes';
41582
+
41583
+ let acc2index = {};
41584
+
41585
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41586
+ let acc = accArray[index];
41587
+
41588
+ acc2index[acc] = index;
41589
+
41590
+ ic.qt_start_end[index] = [];
41591
+
41592
+ let segArray = acc2exons[acc];
41593
+
41594
+ for(let i = 0, il = segArray.length; i < il; ++i) {
41595
+ let seg = segArray[i];
41596
+
41597
+ // mRNA has the reverse order, use negative to make the order right, then minus the offset
41598
+ let qt_start_end = {t_start: ic.exonOrder * seg.genResStart, t_end: ic.exonOrder * seg.genResEnd, q_start: seg.resStart, q_end: seg.resEnd};
41599
+ ic.qt_start_end[index].push(qt_start_end);
41600
+ }
41601
+ }
41602
+
41603
+ // start and end of MSA
41604
+ let start_t = 999999999, end_t = -999999999;
41605
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41606
+ if(!ic.qt_start_end[index]) continue;
41607
+
41608
+ for(let i = 0, il = ic.qt_start_end[index].length; i < il; ++i) {
41609
+ let start1, end1;
41610
+
41611
+ start1 = ic.qt_start_end[index][i].t_start;
41612
+ end1 = ic.qt_start_end[index][i].t_end;
41613
+
41614
+ for(let j = start1; j <= end1; ++j) {
41615
+ if(j < start_t) start_t = j;
41616
+ if(j > end_t) end_t = j;
41617
+ }
41618
+ }
41619
+ }
41620
+
41621
+ // minus the offset start_t
41622
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41623
+ let segArray = ic.qt_start_end[index];
41624
+ for(let i = 0, il = segArray.length; i < il; ++i) {
41625
+ let seg = segArray[i];
41626
+ seg.t_start -= start_t;
41627
+ seg.t_end -= start_t;
41628
+ }
41629
+ }
41630
+
41631
+ ic.msaSeq = {};
41632
+ // assign the template
41633
+ ic.msaSeq[targetId] = '';
41634
+
41635
+ let start_tFinal = 0;
41636
+ let end_tFinal = end_t - start_t;
41637
+
41638
+ for(let i = start_tFinal; i <= end_tFinal; ++i) {
41639
+ ic.msaSeq[targetId] += 'X'; // fake seq
41640
+ }
41641
+
41642
+ // progressively merge sequences, starting from most similar to least similar
41643
+ let alignedChainIndice = [0];
41644
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
41645
+ alignedChainIndice.push(index);
41646
+
41647
+ ic.msaSeq[accArray[index]] = '';
41648
+
41649
+ // some proteins may not be aligned
41650
+ if(!querySeqArray[index]) continue;
41651
+ ic.setSeqAlignCls.mergeTwoSeqForAllSimple(targetId, accArray, index, alignedChainIndice, start_tFinal, end_tFinal, querySeqArray);
41652
+ }
41653
+
41654
+ for(let acc in ic.msaSeq) {
41655
+ let index = acc2index[acc];
41656
+
41657
+ if(index !== undefined) {
41658
+ trackSeqArray[index] = ic.msaSeq[acc];
41659
+ trackTitleArray[index] = acc;
41660
+ }
41661
+ }
41662
+
41663
+ // remove introns in trackSeqArray
41664
+ let trackSeqArrayFinal = [];
41665
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
41666
+ trackSeqArrayFinal[i] = '';
41667
+ }
41668
+
41669
+ for(let j = 0, jl = trackSeqArray[maxIndex].length; j < jl; ++j) {
41670
+ let seq = trackSeqArray[maxIndex][j];
41671
+
41672
+ let bExon = (seq != '-') ? true : false;
41673
+ if(!bExon) {
41674
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
41675
+ if(trackSeqArray[i][j] != '-') {
41676
+ bExon = true;
41677
+ break;
41678
+ }
41679
+ }
41680
+ }
41681
+
41682
+ if(bExon) {
41683
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
41684
+ trackSeqArrayFinal[i] += trackSeqArray[i][j];
41685
+ }
41686
+ }
41687
+ }
41688
+
41689
+ return {trackTitleArray: trackTitleArray, trackSeqArray: trackSeqArrayFinal, maxIndex: maxIndex};
41690
+ }
41691
+
41692
+ async showMsaTracks(chainid, seqFirst, trackTitleArray, trackSeqArray, startpos, type, acc2exons) { let ic = this.icn3d; ic.icn3dui;
41693
+ //ic.startposGiSeq = undefined;
41694
+ for(let i = 0, il = ic.giSeq[chainid].length; i < il; ++i) {
41695
+ //let pos =(i >= ic.matchedPos[chainid] && i - ic.matchedPos[chainid] < ic.chainsSeq, [chainid].length) ? ic.chainsSeq[chainid][i - ic.matchedPos[chainid]].resi : ic.baseResi[chainid] + 1 + i;
41696
+ let pos = ic.ParserUtilsCls.getResi(chainid, i);
41697
+
41698
+ if(pos != startpos) {
41699
+ continue;
41700
+ }
41701
+ else {
41702
+ ic.startposGiSeq = i;
41703
+ }
41704
+ }
41705
+
41706
+ if(ic.startposGiSeq === undefined) {
41707
+ alert("Please double check the start position before clicking \"Add Track\"");
41708
+ return;
41709
+ }
41710
+
41711
+ // set up gap for the master seq
41712
+ // don't count gaps in both ends
41713
+ ic.targetGapHash = {};
41714
+ let prevSeq = '-', prevPos = 0, from, to, cnt = 0, dashCnt = 0;
41715
+ let bFound = false, seqStart = 0, seqEnd = 0, seqLength = seqFirst.length;
41716
+ // add gaps to the N- and C-terminal
41717
+ if(!ic.seqStartLen) ic.seqStartLen = {};
41718
+ if(!ic.seqEndLen) ic.seqEndLen = {};
41719
+ for(let i = 0, il = seqFirst.length; i < il; ++i) {
41720
+ if(seqFirst[i] == '-' && seqFirst[i] != prevSeq) { // start of gap
41721
+ from = cnt;
41722
+ dashCnt = 0;
41723
+ }
41724
+
41725
+ if(prevSeq == '-' && seqFirst[i] != prevSeq && cnt > 0) { // end of gap
41726
+ to = prevPos;
41727
+ ic.targetGapHash[from + ic.startposGiSeq] = {'from': from + ic.startposGiSeq, 'to': to + dashCnt - 1 + ic.startposGiSeq};
41728
+ }
41729
+
41730
+ prevSeq = seqFirst[i];
41731
+ prevPos = cnt;
41732
+
41733
+ if(seqFirst[i] != '-') {
41734
+ ++cnt;
41735
+ seqEnd = i;
41736
+ ic.seqEndLen[chainid] = seqLength - 1 - seqEnd;
41737
+
41738
+ if(!bFound) {
41739
+ seqStart = i;
41740
+ ic.seqStartLen[chainid] = seqStart;
41741
+
41742
+ bFound = true;
41743
+ }
41744
+ }
41745
+ else {
41746
+ ++dashCnt;
41747
+ }
41748
+ }
41749
+
41750
+ // adjust the total length
41751
+ if(ic.maxAnnoLength < ic.maxAnnoLengthOri + ic.seqStartLen[chainid] + ic.seqEndLen[chainid]) {
41752
+ ic.maxAnnoLength = ic.maxAnnoLengthOri + ic.seqStartLen[chainid] + ic.seqEndLen[chainid];
41753
+ }
41754
+
41755
+ await ic.annotationCls.resetAnnoAll();
41756
+
41757
+ let targetGapHashStr = '';
41758
+ let cntTmp = 0;
41759
+ for(let i in ic.targetGapHash) {
41760
+ if(cntTmp > 0) targetGapHashStr += ' ';
41761
+ targetGapHashStr += i + '_' + ic.targetGapHash[i].from + '_' + ic.targetGapHash[i].to;
41762
+ ++cntTmp;
41763
+ }
41764
+
41765
+ //me.htmlCls.clickMenuCls.setLogCmd("msa | " + targetGapHashStr, true);
41766
+
41767
+ // add tracks
41768
+ let resi2cntSameRes = {}; // count of same residue at each position
41769
+ for(let j = 0, jl = trackSeqArray.length; j < jl; ++j) {
41770
+ let resi = startpos;
41771
+ let text = '';
41772
+ for(let k = 0; k < ic.startposGiSeq; ++k) {
41773
+ if(ic.targetGapHash.hasOwnProperty(k)) {
41774
+ for(let m = 0; m < ic.targetGapHash[k].to - ic.targetGapHash[k].from + 1; ++m) {
41775
+ text += '-';
41776
+ }
41777
+ }
41778
+
41779
+ text += '-';
41780
+ }
41781
+
41782
+ let resn, prevResn = '-';
41783
+ let fromArray = [], toArray = [];
41784
+ let bFound = false;
41785
+ let seqStartLen = 0;
41786
+ // for(let k = seqStart; k <= seqEnd; ++k) {
41787
+ for(let k = 0; k < seqLength; ++k) {
41788
+ //if(seqFirst[k] == '-') continue;
41789
+
41790
+ if(j == 0) resi2cntSameRes[resi] = 0;
41791
+
41792
+ resn = trackSeqArray[j][k];
41793
+
41794
+ if(prevResn == '-' && resn != '-') {
41795
+ fromArray.push(k);
41796
+ }
41797
+
41798
+ if(prevResn != '-' && resn == '-') {
41799
+ toArray.push(k - 1);
41800
+ }
41801
+
41802
+ if(resn != '-') {
41803
+ if(!bFound) {
41804
+ seqStartLen = k;
41805
+ bFound = true;
41806
+ }
41807
+ }
41808
+
41809
+ text += resn; //ic.giSeq[chainid][i];
41810
+
41811
+ if(seqFirst[k] != '-') {
41812
+ if(seqFirst[k] == trackSeqArray[j][k]) ++resi2cntSameRes[resi];
41813
+ ++resi;
41814
+ }
41815
+
41816
+ prevResn = resn;
41817
+ }
41818
+
41819
+ // last one
41820
+ if(prevResn != '-') {
41821
+ toArray.push(seqLength - 1);
41822
+ }
41823
+
41824
+ let title =(trackTitleArray[j].length < 20) ? trackTitleArray[j] : trackTitleArray[j].substr(0, 20) + '...';
41825
+ let bMsa = true;
41826
+ let exonArray = (acc2exons) ? acc2exons[trackTitleArray[j]] : undefined;
41827
+ this.showNewTrack(chainid, title, text, undefined, undefined, type, undefined, bMsa, fromArray, toArray, seqStartLen, exonArray);
41828
+ }
41829
+
41830
+ // set color for the master seq
41831
+ if(trackSeqArray.length > 0) {
41832
+ if(ic.queryresi2score === undefined) ic.queryresi2score = {};
41833
+ if(ic.queryresi2score[chainid] === undefined) ic.queryresi2score[chainid] = {};
41834
+
41835
+ let nSeq = trackSeqArray.length;
41836
+ for(let resi in resi2cntSameRes) {
41837
+ let score = parseInt(resi2cntSameRes[resi] / nSeq * 100);
41838
+ ic.queryresi2score[chainid][resi] = score;
41839
+ }
41840
+
41841
+ let resiArray = Object.keys(resi2cntSameRes);
41842
+ let start = Math.min.apply(null, resiArray);
41843
+ let end = Math.max.apply(null, resiArray);
41844
+
41845
+ let resiScoreStr = '';
41846
+ for(let resi = start; resi <= end; ++resi) {
41847
+ if(resi2cntSameRes.hasOwnProperty(resi)) {
41848
+ resiScoreStr += Math.round(resi2cntSameRes[resi] / nSeq * 9); // max 9
41849
+ }
41850
+ else {
41851
+ resiScoreStr += '_';
41852
+ }
41853
+ }
41854
+
41855
+ ic.opts['color'] = 'align custom';
41856
+ ic.setColorCls.setColorByOptions(ic.opts, ic.hAtoms);
41857
+
41858
+ ic.hlUpdateCls.updateHlAll();
41859
+
41860
+ ic.drawCls.draw();
41861
+
41862
+ //me.htmlCls.clickMenuCls.setLogCmd('color align custom | ' + chainid + ' | range ' + start + '_' + end + ' | ' + resiScoreStr, true);
41863
+ }
41864
+ }
41865
+
41866
+ processAccList(acclist) { let ic = this.icn3d; ic.icn3dui;
41867
+ // remove version from acc
41868
+ let accArray = acclist.split(',');
41869
+ let accHash = {};
41870
+ let acclistTmp = '';
41871
+ for(let i = 0, il = accArray.length; i < il; ++i) {
41872
+ let acc = accArray[i];
41873
+
41874
+ if(accHash.hasOwnProperty(acc)) {
41875
+ continue;
41876
+ }
41877
+ else {
41878
+ accHash[acc] = 1;
41879
+ }
41880
+
41881
+ let pos = acc.indexOf('.');
41882
+ if(pos != -1) {
41883
+ acclistTmp += acc.substr(0, pos);
41884
+ }
41885
+ else {
41886
+ acclistTmp += acc;
41887
+ }
41888
+
41889
+ if(i < accArray.length - 1) {
41890
+ acclistTmp += ',';
41891
+ }
41892
+ }
41893
+
41894
+ return acclistTmp;
41895
+ }
41896
+
41897
+ async addExonTracks(chainid, geneid, startpos, type) { let ic = this.icn3d, me = ic.icn3dui;
41898
+ let seqFirst, trackTitleArray = [], trackSeqArray = [];
41899
+
41900
+ // get acclist from geneid
41901
+ let url = me.htmlCls.baseUrl + "/vastdyn/vastdyn.cgi?geneid2isoforms=" + geneid;
41902
+ let data = await me.getAjaxPromise(url, 'jsonp');
41903
+ let accArray = data.acclist;
41904
+ let exons = data.exons;
41905
+ let acc2exons = {};
41906
+
41907
+ let acclist = '';
41908
+ ic.exonOrder = 1; // 1: increasing bp order; -1 decreasing bp order
41909
+ for(let i = 0, il = accArray.length; i < il; ++i) {
41910
+ let accOri = accArray[i];
41911
+ let pos = accOri.indexOf('.');
41912
+ let acc = (pos != -1) ? accOri.substr(0, pos) : accOri;
41913
+
41914
+ let cntTotal = 0, prevCntTotal = 0, rangeArray = [];
41915
+ for(let j = 0, jl = exons[accOri].length; j < jl; ++j) {
41916
+ let itemArray = exons[accOri][j].split('-');
41917
+ itemArray[0] = parseInt(itemArray[0]);
41918
+ itemArray[1] = parseInt(itemArray[1]);
41919
+ itemArray[2] = parseInt(itemArray[2]);
41920
+
41921
+ ic.exonOrder = (itemArray[0] < itemArray[1]) ? 1 : -1;
41922
+
41923
+ let genomeRange = itemArray[0] + '-' + itemArray[1];
41924
+ let cnt = (j == jl - 1) ? itemArray[2] - 3 : itemArray[2]; // The last one is stop codeon
41925
+ cntTotal += cnt;
41926
+
41927
+ let resStart = parseInt(prevCntTotal/3.0 + 0.5); // 0-based
41928
+ let resEnd = parseInt(cntTotal/3.0 + 0.5) - 1; // 0-based
41929
+
41930
+ let genResStart = parseInt(itemArray[0] / 3.0 + 0.5);
41931
+
41932
+ //let genResEnd = parseInt(itemArray[1] / 3.0 + 0.5); // some difference due to round
41933
+ let genResEnd = genResStart + ic.exonOrder * (resEnd - resStart);
41934
+
41935
+ rangeArray.push({genomeRange: genomeRange, genResStart: genResStart, genResEnd: genResEnd, resStart: resStart, resEnd: resEnd});
41936
+
41937
+ prevCntTotal = cntTotal;
41938
+ }
41939
+ acc2exons[acc] = rangeArray;
41940
+
41941
+ acclist += acc;
41942
+ if(i < il - 1) {
41943
+ acclist += ',';
41944
+ }
41945
+ }
41946
+
41947
+ let result = await this.getIsoformMsa(acclist, acc2exons);
41948
+ trackTitleArray = result.trackTitleArray;
41949
+ trackSeqArray = result.trackSeqArray;
41950
+ //seqFirst = result.seqFirst;
41951
+ let maxIndex = result.maxIndex;
41952
+
41953
+ let acclist2 = trackTitleArray[maxIndex];
41954
+ let structure = chainid.substr(0, chainid.indexOf('_'));
41955
+ let firstAcc;
41956
+ if(structure.length > 5) {
41957
+ if(ic.uniprot2acc && ic.uniprot2acc[structure]) structure = ic.uniprot2acc[structure];
41958
+ firstAcc = structure;
41959
+ }
41960
+ else {
41961
+ firstAcc = chainid;
41962
+ }
41963
+
41964
+ // get the sequence from iCn3D because a uniProt ID can not be retrieved in pwaln.fcgi
41965
+ if(structure.length > 5) {
41966
+ let chainSeq = '';
41967
+ for(let i = 0, il = ic.chainsSeq.length; i < il; ++i) {
41968
+ chainSeq += ic.chainsSeq[i].resn;
41969
+ }
41970
+
41971
+ result = await this.getMsa(acclist2, firstAcc, chainSeq);
41972
+ }
41973
+ else {
41974
+ result = await this.getMsa(acclist2, firstAcc);
41975
+ }
41976
+
41977
+ result.trackTitleArray;
41978
+ let trackSeqArray2 = result.trackSeqArray;
41979
+ seqFirst = result.seqFirst;
41980
+
41981
+ // merge trackTitleArray2[0] with trackSeqArray[maxIndex]
41982
+ let A = trackSeqArray[maxIndex], B = trackSeqArray2[0];
41983
+ let i = 0, j = 0;
41984
+
41985
+ let ALen = trackSeqArray.length;
41986
+
41987
+ while (i < A.length && j < B.length) {
41988
+ if(A[i] != B[j]) {
41989
+ if(A[i] == '-') {
41990
+ // inser "-" in B
41991
+ B = B.substr(0, j) + '-' + B.substr(j);
41992
+ seqFirst = seqFirst.substr(0, j) + '-' + seqFirst.substr(j);
41993
+ }
41994
+ else { //if(B[j] == '-') {
41995
+ // inser "-" in A
41996
+ for(let k = 0; k < ALen; ++k) {
41997
+ trackSeqArray[k] = trackSeqArray[k].substr(0, i) + '-' + trackSeqArray[k].substr(i);
41998
+ }
41999
+ }
42000
+ }
42001
+
42002
+ ++i;
42003
+ ++j;
42004
+ }
42005
+
42006
+ await this.showMsaTracks(chainid, seqFirst, trackTitleArray, trackSeqArray, startpos, type, acc2exons);
42007
+
42008
+ me.htmlCls.clickMenuCls.setLogCmd("add exon track | chainid " + chainid + " | geneid " + geneid + " | startpos " + startpos + " | type " + type, true);
42009
+ }
42010
+
42011
+ async addMsaTracks(chainid, startpos, type, fastaList) { let ic = this.icn3d, me = ic.icn3dui;
42012
+ let seqFirst, trackTitleArray = [], trackSeqArray = [];
42013
+
42014
+ let fastaArray = fastaList.split('>');
42015
+
42016
+ // the first array item is empty
42017
+ // the second array item is the sequence of the structure, start with i = 2
42018
+ let posFirst = fastaArray[1].indexOf('\n');
42019
+ //let titleFirst = fastaArray[1].substr(0, posFirst);
42020
+ seqFirst = fastaArray[1].substr(posFirst + 1).replace(/\n/g, '');
42021
+
42022
+ for(let i = 2, il = fastaArray.length; i < il; ++i) {
42023
+ let pos = fastaArray[i].indexOf('\n');
42024
+ let title = fastaArray[i].substr(0, pos);
42025
+ if(title.indexOf('|') != -1) {
42026
+ title = title.split('|')[1];
42027
+ // if(title.indexOf('.') != -1) {
42028
+ // title = title.split('.')[0];
42029
+ // }
42030
+ }
42031
+ trackTitleArray.push(title);
42032
+ let seq = fastaArray[i].substr(pos + 1).replace(/\n/g, '');
42033
+ trackSeqArray.push(seq);
42034
+ }
42035
+
42036
+ await this.showMsaTracks(chainid, seqFirst, trackTitleArray, trackSeqArray, startpos, type);
42037
+
42038
+ me.htmlCls.clickMenuCls.setLogCmd("add msa track | chainid " + chainid + " | startpos " + startpos + " | type " + type + " | fastaList " + fastaList , true);
42039
+ }
41190
42040
  }
41191
42041
 
41192
42042
  /**
@@ -41837,13 +42687,14 @@ class ShowAnno {
41837
42687
  } // if(me.cfg.mmdbid
41838
42688
  } // for(let i = 0
41839
42689
 
41840
- ic.maxAnnoLength = 1;
42690
+ ic.maxAnnoLengthOri = 1;
41841
42691
  for(let chainid in ic.chainsSeq) {
41842
42692
  // use protein or nucleotide as the max length
41843
- if(ic.chainsSeq[chainid].length > ic.maxAnnoLength && (ic.protein_chainid.hasOwnProperty(chainid) || nucleotide_chainid.hasOwnProperty(chainid)) ) {
41844
- ic.maxAnnoLength = ic.chainsSeq[chainid].length;
42693
+ if(ic.chainsSeq[chainid].length > ic.maxAnnoLengthOri && (ic.protein_chainid.hasOwnProperty(chainid) || nucleotide_chainid.hasOwnProperty(chainid)) ) {
42694
+ ic.maxAnnoLengthOri = ic.chainsSeq[chainid].length;
41845
42695
  }
41846
42696
  }
42697
+ ic.maxAnnoLength = ic.maxAnnoLengthOri;
41847
42698
  }
41848
42699
 
41849
42700
  return {'nucleotide_chainid': nucleotide_chainid, 'chemical_chainid': chemical_chainid, 'chemical_set': chemical_set};
@@ -41858,7 +42709,7 @@ class ShowAnno {
41858
42709
  let chemical_chainid = result.chemical_chainid;
41859
42710
  let chemical_set = result.chemical_set;
41860
42711
 
41861
- if(ic.bAnnoShown === undefined || !ic.bAnnoShown || ic.bResetAnno) { // ic.bResetAnno when loading another structure
42712
+ if(!ic.bAnnoShown || ic.bResetAnno) { // ic.bResetAnno when loading another structure
41862
42713
  // assign early to avoid load annotations twice
41863
42714
  ic.bAnnoShown = true;
41864
42715
 
@@ -41894,7 +42745,7 @@ class ShowAnno {
41894
42745
  dataObj['targets'] = me.cfg.blast_rep_id + ':' + target_from_to_array.join(':');
41895
42746
  }
41896
42747
 
41897
- // get seqeunce
42748
+ // get sequence
41898
42749
  if(ic.blastAcxn) {
41899
42750
  let chainid = me.cfg.afid + '_A';
41900
42751
  let seq = '';
@@ -41925,7 +42776,7 @@ class ShowAnno {
41925
42776
  idArray.push(me.cfg.query_id);
41926
42777
  }
41927
42778
 
41928
- // get seqeunce
42779
+ // get sequence
41929
42780
  if(ic.blastAcxn) {
41930
42781
  let chainid = me.cfg.afid + '_A';
41931
42782
  let seq = '';
@@ -41999,13 +42850,52 @@ class ShowAnno {
41999
42850
  let thisClass = this;
42000
42851
  let chnidBaseArray = $.map(ic.protein_chainid, function(v) { return v; });
42001
42852
  let index = 0;
42853
+
42854
+ // get geneid
42855
+ if(!ic.chainsGene) ic.chainsGene = {};
42856
+ for(let chnid in ic.protein_chainid) {
42857
+ let structure = chnid.substr(0, chnid.indexOf('_'));
42858
+ // UniProt or NCBI protein accession
42859
+ if(structure.length > 5) {
42860
+ let refseqid, url;
42861
+ if(ic.uniprot2acc && ic.uniprot2acc[structure]) {
42862
+ refseqid = ic.uniprot2acc[structure];
42863
+ }
42864
+ else {
42865
+ try {
42866
+ if(!ic.uniprot2acc) ic.uniprot2acc = {};
42867
+ url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?uniprot2refseq=" + structure;
42868
+ let result = await me.getAjaxPromise(url, 'jsonp');
42869
+ refseqid = (result && result.refseq) ? result.refseq : structure;
42870
+
42871
+ ic.uniprot2acc[structure] = refseqid;
42872
+ }
42873
+ catch {
42874
+ console.log("Problem in getting protein accession from UniProt ID...");
42875
+ refseqid = structure;
42876
+ }
42877
+ }
42878
+
42879
+ // get Gene info from protein name
42880
+ // url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?protein2gene=" + refseqid;
42881
+ // ic.chainsGene[chnid] = await me.getAjaxPromise(url, 'jsonp');
42882
+
42883
+ // get Gene info from uniprot
42884
+ url = "https://rest.uniprot.org/uniprotkb/search?format=json&fields=xref_geneid,gene_names&query=" + structure;
42885
+ let geneData = await me.getAjaxPromise(url, 'json');
42886
+ let geneId = (geneData.results[0] && geneData.results[0].uniProtKBCrossReferences[0]) ? geneData.results[0].uniProtKBCrossReferences[0].id : undefined;
42887
+ let geneSymbol = (geneData.results[0] && geneData.results[0].genes[0] && geneData.results[0].genes[0].geneName) ? geneData.results[0].genes[0].geneName.value : undefined;
42888
+ ic.chainsGene[chnid] = {geneId: geneId, geneSymbol: geneSymbol};
42889
+ }
42890
+ }
42891
+
42002
42892
  for(let chnid in ic.protein_chainid) {
42003
42893
  let buttonStyle = me.utilsCls.isMobile() ? 'none' : 'button';
42004
42894
  let fullProteinName = ic.showSeqCls.getProteinName(chnid);
42005
42895
  let proteinName = fullProteinName;
42006
42896
  //if(proteinName.length > 40) proteinName = proteinName.substr(0, 40) + "...";
42007
42897
  let categoryStr =(index == 0) ? "<span class='icn3d-annoLargeTitle'><b>Proteins</b>: </span><br><br>" : "";
42008
- let geneLink =(ic.chainsGene[chnid] && ic.chainsGene[chnid].geneId) ? "(Gene: <a href='https://www.ncbi.nlm.nih.gov/gene/" + ic.chainsGene[chnid].geneId + "' target='_blank' title='" + ic.chainsGene[chnid].geneDesc + "'>" + ic.chainsGene[chnid].geneSymbol + "</a>)" : '';
42898
+ let geneLink =(ic.chainsGene[chnid] && ic.chainsGene[chnid].geneId) ? "(Gene: <a href='https://www.ncbi.nlm.nih.gov/gene/" + ic.chainsGene[chnid].geneId + "?report=gene_table' target='_blank' title='" + ic.chainsGene[chnid].geneDesc + "'>" + ic.chainsGene[chnid].geneSymbol + "</a>)" : '';
42009
42899
  let structure = chnid.substr(0, chnid.indexOf('_'));
42010
42900
  let chainLink = (structure.length > 5) ? '<a href="https://alphafold.ebi.ac.uk/entry/' + structure + '" target="_blank">' + chnid + '</a>' : chnid;
42011
42901
  let chainHtml = "<div id='" + ic.pre + "anno_" + chnid + "' class='icn3d-annotation'>" + categoryStr
@@ -42252,7 +43142,7 @@ class ShowAnno {
42252
43142
  let data = ic.seqStructAlignData;
42253
43143
  if(data.data !== undefined) {
42254
43144
  query = data.data[0].query;
42255
- // if target is seqeunce, the key is not chnid
43145
+ // if target is sequence, the key is not chnid
42256
43146
  //target = data.data[0].targets[chnid];
42257
43147
  let keys = Object.keys(data.data[0].targets);
42258
43148
  target = data.data[0].targets[keys[0]];
@@ -42264,7 +43154,7 @@ class ShowAnno {
42264
43154
  evalue = target.scores.e_value.toPrecision(2);
42265
43155
  if(evalue > 1e-200) evalue = parseFloat(evalue).toExponential();
42266
43156
  target.scores.bit_score;
42267
- // if target is seqeunce, the key is not chnid
43157
+ // if target is sequence, the key is not chnid
42268
43158
  // targetSeq = data.targets[chnid].seqdata;
42269
43159
  let keys = Object.keys(data.targets);
42270
43160
  targetSeq = data.targets[keys[0]].seqdata;
@@ -42556,6 +43446,9 @@ class ShowSeq {
42556
43446
  html += htmlTmp + '<span class="icn3d-seqLine">';
42557
43447
  let helixCnt = 0, sheetCnt = 0;
42558
43448
  let savedSsName = '';
43449
+
43450
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqStartLen[chnid], ' ');
43451
+
42559
43452
  for(let i = 0, il = giSeq.length; i < il; ++i) {
42560
43453
  html += this.insertGap(chnid, i, '-');
42561
43454
  let currResi;
@@ -42613,18 +43506,25 @@ class ShowSeq {
42613
43506
  }
42614
43507
  html += '</span>';
42615
43508
  }
43509
+
43510
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqEndLen[chnid], ' ');
43511
+
42616
43512
  html += '<span class="icn3d-residueNum"></span>';
42617
43513
  html += '</span>';
42618
43514
  html += '<br>';
42619
43515
  html += '</div>';
42620
43516
  html3 += '</div>';
42621
43517
  }
43518
+
42622
43519
  // html to display secondary structures
42623
43520
  htmlTmp = '<div class="icn3d-residueLine" style="white-space:nowrap;">';
42624
43521
  htmlTmp += '<div class="icn3d-annoTitle" anno="0"></div>';
42625
43522
  htmlTmp += '<span class="icn3d-residueNum"></span>';
42626
43523
  html3 += htmlTmp + '<br>';
42627
43524
  html += htmlTmp + '<span class="icn3d-seqLine">';
43525
+
43526
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqStartLen[chnid], '-');
43527
+
42628
43528
  for(let i = 0, il = giSeq.length; i < il; ++i) {
42629
43529
  html += this.insertGap(chnid, i, '-');
42630
43530
  // let resi =(i >= ic.matchedPos[chnid] && i - ic.matchedPos[chnid] < ic.chainsSeq[chnid].length) ? ic.chainsSeq[chnid][i - ic.matchedPos[chnid]].resi : ic.baseResi[chnid] + 1 + i;
@@ -42672,6 +43572,9 @@ class ShowSeq {
42672
43572
  html += '<span>-</span>'; //'<span>-</span>';
42673
43573
  }
42674
43574
  }
43575
+
43576
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqEndLen[chnid], '-');
43577
+
42675
43578
  html += '<span class="icn3d-residueNum"></span>';
42676
43579
  html += '</span>';
42677
43580
  html += '<br>';
@@ -42703,6 +43606,9 @@ class ShowSeq {
42703
43606
  html += htmlTmp + htmlTmp2;
42704
43607
  html2 += htmlTmp + htmlTmp2;
42705
43608
  let pos, nGap = 0;
43609
+
43610
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqStartLen[chnid], '-');
43611
+
42706
43612
  for(let i = 0, il = giSeq.length; i < il; ++i) {
42707
43613
  html += this.insertGap(chnid, i, '-');
42708
43614
  if(ic.targetGapHash !== undefined && ic.targetGapHash.hasOwnProperty(i)) nGap += ic.targetGapHash[i].to - ic.targetGapHash[i].from + 1;
@@ -42732,6 +43638,9 @@ class ShowSeq {
42732
43638
  html += '<span id="giseq_' + ic.pre + chnid + '_' + pos + '" title="' + cFull + pos + '" class="icn3d-residue" style="color:#' + color + '">' + c + '</span>';
42733
43639
  }
42734
43640
  }
43641
+
43642
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqEndLen[chnid], '-');
43643
+
42735
43644
  if(me.cfg.blast_rep_id == chnid) {
42736
43645
  // change color in 3D
42737
43646
  ic.opts['color'] = (ic.blastAcxn) ? 'confidence' : 'conservation';
@@ -42742,8 +43651,11 @@ class ShowSeq {
42742
43651
  // sequence, overview
42743
43652
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chnid]);
42744
43653
  let color =(atom.color) ? atom.color.getHexString() : "CCCCCC";
42745
- let width = Math.round(ic.seqAnnWidth * giSeq.length / ic.maxAnnoLength);
43654
+ let width = Math.round(ic.seqAnnWidth * giSeq.length / (ic.maxAnnoLength + ic.nTotalGap));
42746
43655
  if(width < 1) width = 1;
43656
+
43657
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += this.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
43658
+
42747
43659
  if(me.cfg.blast_rep_id != chnid) { // regular
42748
43660
  html2 += '<div id="giseq_summary_' + ic.pre + chnid + '" class="icn3d-seqTitle icn3d-link" gi chain="' + chnid + '" style="display:inline-block; color:white; font-weight:bold; background-color:#' + color + '; width:' + width + 'px;">' + chnid + '</div>';
42749
43661
  }
@@ -42757,7 +43669,9 @@ class ShowSeq {
42757
43669
  }
42758
43670
  }
42759
43671
  toArray2.push(giSeq.length - 1);
43672
+
42760
43673
  html2 += '<div id="giseq_summary_' + ic.pre + chnid + '" class="icn3d-seqTitle icn3d-link" gi chain="' + chnid + '" style="width:' + width + 'px;">';
43674
+
42761
43675
  for(let i = 0, il = fromArray2.length; i < il; ++i) {
42762
43676
  html2 += this.insertGapOverview(chnid, fromArray2[i]);
42763
43677
  html2 += '<div style="display:inline-block; color:white!important; font-weight:bold; background-color:#' + color + '; width:' + Math.round(ic.seqAnnWidth *(toArray2[i] - fromArray2[i] + 1) /(ic.maxAnnoLength + ic.nTotalGap)) + 'px;" class="icn3d-seqTitle icn3d-link icn3d-blue" anno="sequence" gi chain="' + chnid + '" title="' + chnid + '">' + chnid + '</div>';
@@ -42889,6 +43803,9 @@ class ShowSeq {
42889
43803
  htmlTmp += '<span class="icn3d-residueNum"></span>';
42890
43804
  html3 += htmlTmp + '<br>';
42891
43805
  html += htmlTmp + '<span class="icn3d-seqLine">';
43806
+
43807
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqStartLen[chnid], '-');
43808
+
42892
43809
  for(let i = 0, il = giSeq.length; i < il; ++i) {
42893
43810
  html += this.insertGap(chnid, i, '-');
42894
43811
  //if(i >= ic.matchedPos[chnid] && i - ic.matchedPos[chnid] < ic.chainsSeq[chnid].length) {
@@ -42912,6 +43829,9 @@ class ShowSeq {
42912
43829
  // html += '<span></span>';
42913
43830
  // }
42914
43831
  }
43832
+
43833
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqEndLen[chnid], '-');
43834
+
42915
43835
  html += '<span class="icn3d-residueNum"></span>';
42916
43836
  html += '</span>';
42917
43837
  html += '<br>';
@@ -43559,26 +44479,43 @@ class ShowSeq {
43559
44479
  let html = '';
43560
44480
  //if(me.cfg.blast_rep_id == chnid && ic.targetGapHash!== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
43561
44481
  if(ic.targetGapHash!== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
43562
- for(let j = 0; j <(ic.targetGapHash[seqIndex].to - ic.targetGapHash[seqIndex].from + 1); ++j) {
43563
- if(bNohtml) {
43564
- html += text;
43565
- }
43566
- else {
43567
- html += '<span>' + text + '</span>';
43568
- }
43569
- }
44482
+ html += this.insertMulGap(ic.targetGapHash[seqIndex].to - ic.targetGapHash[seqIndex].from + 1, text, bNohtml);
43570
44483
  }
43571
44484
  return html;
43572
44485
  }
43573
- insertGapOverview(chnid, seqIndex) { let ic = this.icn3d, me = ic.icn3dui;
44486
+
44487
+ insertMulGap(n, text, bNohtml) { let ic = this.icn3d; ic.icn3dui;
44488
+ let html = '';
44489
+ for(let j = 0; j < n; ++j) {
44490
+ if(bNohtml) {
44491
+ html += text;
44492
+ }
44493
+ else {
44494
+ html += '<span>' + text + '</span>';
44495
+ }
44496
+ }
44497
+ return html;
44498
+ }
44499
+
44500
+ insertGapOverview(chnid, seqIndex) { let ic = this.icn3d; ic.icn3dui;
43574
44501
  let html2 = '';
43575
- if(me.cfg.blast_rep_id == chnid && ic.targetGapHash!== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
43576
- let width = ic.seqAnnWidth *(ic.targetGapHash[seqIndex].to - ic.targetGapHash[seqIndex].from + 1) /(ic.maxAnnoLength + ic.nTotalGap);
43577
- html2 += '<div style="display:inline-block; background-color:#333; width:' + width + 'px; height:3px;">&nbsp;</div>';
44502
+ // if(me.cfg.blast_rep_id == chnid && ic.targetGapHash !== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
44503
+ if(ic.targetGapHash !== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
44504
+ html2 += this.insertMulGapOverview(chnid, ic.targetGapHash[seqIndex].to - ic.targetGapHash[seqIndex].from + 1);
43578
44505
  }
43579
44506
  return html2;
43580
44507
  }
43581
44508
 
44509
+ insertMulGapOverview(chnid, n) { let ic = this.icn3d; ic.icn3dui;
44510
+ let html2 = '';
44511
+ let width = ic.seqAnnWidth * n /(ic.maxAnnoLength + ic.nTotalGap);
44512
+ width = parseInt(width);
44513
+
44514
+ // html2 += '<div style="display:inline-block; background-color:#333; width:' + width + 'px; height:3px;">&nbsp;</div>';
44515
+ html2 += '<div style="display:inline-block; width:' + width + 'px;">&nbsp;</div>';
44516
+ return html2;
44517
+ }
44518
+
43582
44519
  setAlternativeSeq(chnid, chnidBase) { let ic = this.icn3d; ic.icn3dui;
43583
44520
  //if(ic.chainsSeq[chnid] !== undefined) {
43584
44521
  let resArray = ic.chainsSeq[chnid];
@@ -43708,7 +44645,7 @@ class HlSeq {
43708
44645
  //});
43709
44646
 
43710
44647
  // remove possible text selection
43711
- // the following code caused the scroll of seqeunce window to the top, remove it for now
44648
+ // the following code caused the scroll of sequence window to the top, remove it for now
43712
44649
  /*
43713
44650
  if(window.getSelection) {
43714
44651
  if(window.getSelection().empty) { // Chrome
@@ -45296,26 +46233,22 @@ class LineGraph {
45296
46233
 
45297
46234
  let pdbAjaxArray = [];
45298
46235
  for(let k = 0, kl = ic.refpdbArray.length; k < kl; ++k) {
45299
- //let urlpdb = me.htmlCls.baseUrl + "icn3d/refpdb/" + ic.refpdbArray[k] + ".pdb";
45300
- let urlpdb = me.htmlCls.baseUrl + "mmcifparser/mmcifparser.cgi?refpdbid=" + ic.refpdbArray[k];
46236
+ //let urlpdb = me.htmlCls.baseUrl + "mmcifparser/mmcifparser.cgi?refpdbid=" + ic.refpdbArray[k];
46237
+ let urlpdb = me.htmlCls.baseUrl + "mmcifparser/mmcifparser.cgi?refjsonid=" + ic.refpdbArray[k];
45301
46238
 
45302
46239
  let pdbAjax = me.getAjaxPromise(urlpdb, 'text');
45303
46240
 
45304
46241
  pdbAjaxArray.push(pdbAjax);
45305
46242
  }
45306
46243
 
45307
- try {
46244
+ // try {
45308
46245
  let allPromise = Promise.allSettled(pdbAjaxArray);
45309
46246
  ic.pdbDataArray = await allPromise;
45310
46247
  await thisClass.parseRefPdbData(ic.pdbDataArray);
45311
- }
45312
- catch(err) {
45313
- if(!me.bNode) alert("Error in retrieveing reference PDB data...");
45314
- //alert("Error in retrieveing reference PDB data...");
45315
- return;
45316
- }
45317
-
45318
46248
  // }
46249
+ // catch(err) {
46250
+ // if(!me.bNode) alert("Error in retrieveing reference PDB data...");
46251
+ // return;
45319
46252
  // }
45320
46253
  }
45321
46254
 
@@ -45327,7 +46260,8 @@ class LineGraph {
45327
46260
  let ajaxArray = [];
45328
46261
  let domainidpairArray = [];
45329
46262
 
45330
- let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
46263
+ me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
46264
+ let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
45331
46265
 
45332
46266
  if(!ic.resid2domainid) ic.resid2domainid = {};
45333
46267
  //ic.resid2domainid = {};
@@ -45407,6 +46341,9 @@ class LineGraph {
45407
46341
 
45408
46342
  for(let k = 0, kl = domainAtomsArray.length; k < kl; ++k) {
45409
46343
  let pdb_target = ic.saveFileCls.getAtomPDB(domainAtomsArray[k], undefined, undefined, undefined, undefined, struct);
46344
+ let bForceOneDomain = true;
46345
+ let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(domainAtomsArray[k], bForceOneDomain);
46346
+
45410
46347
  // ig strand for any subset will have the same k, use the number of residue to separate them
45411
46348
  let atomFirst = ic.firstAtomObjCls.getFirstAtomObj(domainAtomsArray[k]);
45412
46349
  let atomLast = ic.firstAtomObjCls.getLastAtomObj(domainAtomsArray[k]);
@@ -45416,14 +46353,19 @@ class LineGraph {
45416
46353
  ic.domainid2pdb[domainid] = pdb_target;
45417
46354
 
45418
46355
  for(let index = 0, indexl = dataArray.length; index < indexl; ++index) {
45419
- let struct2 = ic.defaultPdbId + index;
45420
- //let pdb_query = (me.bNode) ? dataArray[index] : dataArray[index].value; //[0];
45421
- let pdb_query = dataArray[index].value; //[0];
45422
- let header = 'HEADER ' + struct2 + '\n';
45423
- pdb_query = header + pdb_query;
45424
-
45425
- let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target, "queryid": ic.refpdbArray[index]};
45426
- let alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
46356
+ // let struct2 = ic.defaultPdbId + index;
46357
+ // let pdb_query = dataArray[index].value; //[0];
46358
+ // let header = 'HEADER ' + struct2 + '\n';
46359
+ // pdb_query = header + pdb_query;
46360
+ let jsonStr_q = dataArray[index].value; //[0];
46361
+
46362
+ // TM-align is not good when you align a full structure with the strand-only structure. VAST is better in this case.
46363
+ // let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target, "queryid": ic.refpdbArray[index]};
46364
+ // let alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
46365
+
46366
+ let dataObj = {'domains1': jsonStr_q, 'domains2': jsonStr_t};
46367
+ let alignAjax = me.getAjaxPostPromise(urlalign, dataObj);
46368
+
45427
46369
  ajaxArray.push(alignAjax);
45428
46370
 
45429
46371
  domainidpairArray.push(domainid + "|" + ic.refpdbArray[index]);
@@ -45502,6 +46444,7 @@ class LineGraph {
45502
46444
  let thisClass = this;
45503
46445
 
45504
46446
  let tmscoreThreshold = 0.4; // 0.4; //0.5;
46447
+ let rmsdThreshold = 10;
45505
46448
 
45506
46449
  // find the best alignment for each chain
45507
46450
  let domainid2score = {}, domainid2segs = {}, chainid2segs = {};
@@ -45529,8 +46472,15 @@ class LineGraph {
45529
46472
 
45530
46473
  if(queryData.length == 0) continue;
45531
46474
 
45532
- if(queryData[0].score < tmscoreThreshold || queryData[0].num_res < minResidues) {
45533
- continue;
46475
+ if(!bRound1) {
46476
+ if(queryData[0].score < tmscoreThreshold || queryData[0].num_res < minResidues) {
46477
+ continue;
46478
+ }
46479
+ }
46480
+ else {
46481
+ if(queryData[0].super_rmsd > rmsdThreshold || queryData[0].num_res < minResidues) {
46482
+ continue;
46483
+ }
45534
46484
  }
45535
46485
 
45536
46486
  //let domainid_index = domainidpairArray[i].split(',');
@@ -45539,44 +46489,63 @@ class LineGraph {
45539
46489
  let refpdbname = domainidpairArray[i].substr(domainidpairArray[i].indexOf('|') + 1);
45540
46490
  //let chainid = domainid.split('-')[0];
45541
46491
 
45542
- if(!me.bNode) console.log("refpdbname " + refpdbname + " TM-score: " + queryData[0].score);
46492
+ if(!bRound1) {
46493
+ if(!me.bNode) console.log("refpdbname " + refpdbname + " TM-score: " + queryData[0].score);
46494
+ }
46495
+ else {
46496
+ if(!me.bNode) console.log("refpdbname " + refpdbname + " RMSD: " + queryData[0].super_rmsd);
46497
+ }
45543
46498
 
45544
46499
  // Ig-like domains: B (2150, 2150a, 2150b), C (3150, 3250), E (7150, 7250), F (8150, 8250) strands
45545
46500
  // Ig domain may require G (7050). But we'll leave that out for now.
45546
- let bBstrand = false, bCstrand = false, bEstrand = false, bFstrand = false;
45547
- for(let i = 0, il = queryData[0].segs.length; i < il; ++i) {
45548
- let seg = queryData[0].segs[i];
46501
+ if(!bRound1) {
46502
+ let bBstrand = false, bCstrand = false, bEstrand = false, bFstrand = false;
46503
+ for(let i = 0, il = queryData[0].segs.length; i < il; ++i) {
46504
+ let seg = queryData[0].segs[i];
45549
46505
 
45550
- if(seg.q_start.indexOf('2150') != -1 || seg.q_start.indexOf('2250') != -1) {
45551
- bBstrand = true;
45552
- }
45553
- else if(seg.q_start.indexOf('3150') != -1 || seg.q_start.indexOf('3250') != -1) {
45554
- bCstrand = true;
45555
- }
45556
- else if(seg.q_start.indexOf('7150') != -1 || seg.q_start.indexOf('7250') != -1) {
45557
- bEstrand = true;
45558
- }
45559
- else if(seg.q_start.indexOf('8150') != -1 || seg.q_start.indexOf('8250') != -1) {
45560
- bFstrand = true;
46506
+ if(seg.q_start.indexOf('2150') != -1 || seg.q_start.indexOf('2250') != -1) {
46507
+ bBstrand = true;
46508
+ }
46509
+ else if(seg.q_start.indexOf('3150') != -1 || seg.q_start.indexOf('3250') != -1) {
46510
+ bCstrand = true;
46511
+ }
46512
+ else if(seg.q_start.indexOf('7150') != -1 || seg.q_start.indexOf('7250') != -1) {
46513
+ bEstrand = true;
46514
+ }
46515
+ else if(seg.q_start.indexOf('8150') != -1 || seg.q_start.indexOf('8250') != -1) {
46516
+ bFstrand = true;
46517
+ }
46518
+
46519
+ //if(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand) break;
46520
+ if(bBstrand && bCstrand && bEstrand && bFstrand) break;
45561
46521
  }
45562
46522
 
45563
- //if(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand) break;
45564
- if(bBstrand && bCstrand && bEstrand && bFstrand) break;
46523
+ //if(!(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand)) continue;
46524
+ if(!(bBstrand && bCstrand && bEstrand && bFstrand)) {
46525
+ if(!me.bNode) console.log("Some of the Ig strands B, C, E, F are missing in the domain " + domainid + "...");
46526
+ continue;
46527
+ }
45565
46528
  }
45566
46529
 
45567
- //if(!(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand)) continue;
45568
- if(!(bBstrand && bCstrand && bEstrand && bFstrand)) {
45569
- if(!me.bNode) console.log("Some of the Ig strands B, C, E, F are missing in the domain " + domainid + "...");
45570
- continue;
46530
+ if(!bRound1) {
46531
+ if(!domainid2score.hasOwnProperty(domainid) || queryData[0].score > domainid2score[domainid]) {
46532
+ domainid2score[domainid] = queryData[0].score;
46533
+
46534
+ ic.domainid2refpdbname[domainid] = refpdbname;
46535
+ domainid2segs[domainid] = queryData[0].segs;
46536
+ ic.domainid2ig2kabat[domainid] = queryData[0].ig2kabat;
46537
+ ic.domainid2ig2imgt[domainid] = queryData[0].ig2imgt;
46538
+ }
45571
46539
  }
45572
-
45573
- if(!domainid2score.hasOwnProperty(domainid) || queryData[0].score > domainid2score[domainid]) {
45574
- domainid2score[domainid] = queryData[0].score;
45575
-
45576
- ic.domainid2refpdbname[domainid] = refpdbname;
45577
- domainid2segs[domainid] = queryData[0].segs;
45578
- ic.domainid2ig2kabat[domainid] = queryData[0].ig2kabat;
45579
- ic.domainid2ig2imgt[domainid] = queryData[0].ig2imgt;
46540
+ else {
46541
+ if(!domainid2score.hasOwnProperty(domainid) || queryData[0].super_rmsd < domainid2score[domainid]) {
46542
+ domainid2score[domainid] = queryData[0].super_rmsd;
46543
+
46544
+ ic.domainid2refpdbname[domainid] = refpdbname;
46545
+ domainid2segs[domainid] = queryData[0].segs;
46546
+ ic.domainid2ig2kabat[domainid] = queryData[0].ig2kabat;
46547
+ ic.domainid2ig2imgt[domainid] = queryData[0].ig2imgt;
46548
+ }
45580
46549
  }
45581
46550
  }
45582
46551
 
@@ -48993,7 +49962,7 @@ class ChainalignParser {
48993
49962
  let hAtomsAll = {};
48994
49963
 
48995
49964
  if(ic.bFullUi && ic.q_rotation !== undefined && !me.cfg.resnum && !me.cfg.resdef) {
48996
- // set multiple seqeunce alignment from ic.qt_start_end
49965
+ // set multiple sequence alignment from ic.qt_start_end
48997
49966
  hAtomsAll = this.setMsa(chainidArray);
48998
49967
  }
48999
49968
 
@@ -49053,7 +50022,7 @@ class ChainalignParser {
49053
50022
  ic.qt_start_end = [];
49054
50023
 
49055
50024
  let mmdbid2cnt = {}, mmdbidpairHash = {};
49056
-
50025
+
49057
50026
  let bFoundAlignment = false;
49058
50027
  for(let i = 0, il = dataArray.length; i < il; ++i) {
49059
50028
  // let align = (me.bNode) ? dataArray[i] : dataArray[i].value;//[0];
@@ -49533,6 +50502,7 @@ class ChainalignParser {
49533
50502
 
49534
50503
  processAlign(align, index, queryData, bEqualMmdbid, bEqualChain, bNoAlert) { let ic = this.icn3d, me = ic.icn3dui;
49535
50504
  let bAligned = false;
50505
+
49536
50506
  if((!align || align.length == 0) && !bNoAlert) {
49537
50507
  let serverName = (me.cfg.aligntool == 'tmalign') ? 'TM-align' : 'VAST';
49538
50508
 
@@ -49717,14 +50687,14 @@ class ChainalignParser {
49717
50687
  ic.ParserUtilsCls.showLoading();
49718
50688
 
49719
50689
  let allPromise = Promise.allSettled(ajaxArray);
49720
- try {
50690
+ // try {
49721
50691
  let dataArray = await allPromise;
49722
50692
  await thisClass.parseMMdbAfData(dataArray, structArray, bQuery, vastplusAtype);
49723
50693
  if(vastplusAtype === undefined) ic.ParserUtilsCls.hideLoading();
49724
- }
49725
- catch(err) {
49726
- alert("There are some problems in retrieving the coordinates...");
49727
- }
50694
+ // }
50695
+ // catch(err) {
50696
+ // alert("There are some problems in retrieving the coordinates...");
50697
+ // }
49728
50698
  // });
49729
50699
 
49730
50700
  // return ic.deferredMmdbaf.promise();
@@ -50346,6 +51316,8 @@ class MmdbParser {
50346
51316
 
50347
51317
  if(data && data.uniprot) {
50348
51318
  me.cfg.afid = data.uniprot;
51319
+ if(!ic.uniprot2acc) ic.uniprot2acc = {};
51320
+ ic.uniprot2acc[data.uniprot] = refseqid;
50349
51321
  }
50350
51322
  else {
50351
51323
  alert('The accession ' + refseqid + ' can not be mapped to AlphaFold UniProt ID. It will be treated as a UniProt ID instead.');
@@ -50363,6 +51335,73 @@ class MmdbParser {
50363
51335
  //await ic.loadScriptCls.loadScript(me.cfg.command, undefined, true);
50364
51336
  }
50365
51337
 
51338
+ async downloadProteinname(protein) { let ic = this.icn3d, me = ic.icn3dui;
51339
+ me.icn3d.bCid = undefined;
51340
+
51341
+ // get RefSeq ID from protein name
51342
+ let url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?protein2acc=" + protein;
51343
+
51344
+ let accJson = await me.getAjaxPromise(url, 'jsonp');
51345
+
51346
+ let accArray = accJson.acc;
51347
+
51348
+ if(accArray.length == 0) {
51349
+ if(!me.bNode) alert('The protein/gene name ' + protein + ' can not be mapped to RefSeq proteins...');
51350
+ return;
51351
+ }
51352
+
51353
+ let ajaxArray = [];
51354
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
51355
+ let refseqid = accArray[index];
51356
+ url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?refseq2uniprot=" + refseqid;
51357
+
51358
+ let ajax = me.getAjaxPromise(url, 'jsonp');
51359
+
51360
+ ajaxArray.push(ajax);
51361
+ }
51362
+
51363
+ let allPromise = Promise.allSettled(ajaxArray);
51364
+ let dataArray = await allPromise;
51365
+
51366
+ ajaxArray = [];
51367
+ let afidArray = [];
51368
+ for(let i = 0, il = dataArray.length; i < il; ++i) {
51369
+ let data = dataArray[i].value;
51370
+
51371
+ if(data && data.uniprot) {
51372
+ let afid = data.uniprot;
51373
+ url = "https://alphafold.ebi.ac.uk/files/AF-" + afid + "-F1-model_" + ic.AFUniprotVersion + ".pdb";
51374
+ ic.ParserUtilsCls.setYourNote(me.cfg.protein + '(NCBI Protein/Gene) in iCn3D');
51375
+
51376
+ let ajax = me.getAjaxPromise(url, 'text', true);
51377
+ ajaxArray.push(ajax);
51378
+ afidArray.push(afid);
51379
+ }
51380
+ }
51381
+
51382
+ allPromise = Promise.allSettled(ajaxArray);
51383
+ dataArray = await allPromise;
51384
+
51385
+ for(let i = 0, il = dataArray.length; i < il; ++i) {
51386
+ let data = dataArray[i].value;
51387
+ me.cfg.afid = afidArray[i];
51388
+
51389
+ if(data) {
51390
+ // add UniProt ID into the header
51391
+ let header = 'HEADER ' + me.cfg.afid + '\n';
51392
+ data = header + data;
51393
+ await ic.opmParserCls.parseAtomData(data, me.cfg.afid, undefined, 'pdb', undefined);
51394
+
51395
+ break;
51396
+ }
51397
+ }
51398
+
51399
+ if(!me.cfg.afid) {
51400
+ if(!me.bNode) alert('The protein/gene name ' + protein + ' can not be mapped to AlphaFold structures...');
51401
+ return;
51402
+ }
51403
+ }
51404
+
50366
51405
  getNoData(mmdbid, bGi) { let ic = this.icn3d, me = ic.icn3dui;
50367
51406
  if(bGi) {
50368
51407
  alert("This gi " + mmdbid + " has no corresponding 3D structure...");
@@ -51439,6 +52478,9 @@ class PdbParser {
51439
52478
  if(me.cfg.refseqid) {
51440
52479
  ic.ParserUtilsCls.setYourNote(me.cfg.refseqid.toUpperCase() + '(NCBI Protein Acc.) in iCn3D');
51441
52480
  }
52481
+ else if(me.cfg.protein) {
52482
+ ic.ParserUtilsCls.setYourNote(me.cfg.protein + '(NCBI Protein/Gene) in iCn3D');
52483
+ }
51442
52484
  else {
51443
52485
  ic.ParserUtilsCls.setYourNote(pdbid.toUpperCase() + '(AlphaFold) in iCn3D');
51444
52486
  }
@@ -52374,6 +53416,7 @@ class RealignParser {
52374
53416
  async realignOnStructAlign(bReverse) { let ic = this.icn3d, me = ic.icn3dui;
52375
53417
  // each 3D domain should have at least 3 secondary structures
52376
53418
  let minSseCnt = (me.cfg.aligntool != 'tmalign') ? 3 : 0;
53419
+
52377
53420
  let struct2domain = {};
52378
53421
  for(let struct in ic.structures) {
52379
53422
  struct2domain[struct] = {};
@@ -52384,7 +53427,7 @@ class RealignParser {
52384
53427
  let sseCnt = 0;
52385
53428
  for(let serial in atoms) {
52386
53429
  if(ic.atoms[serial].ssbegin) ++sseCnt;
52387
- if(sseCnt == minSseCnt) {
53430
+ if(sseCnt > minSseCnt) {
52388
53431
  struct2domain[struct][chainid] = atoms;
52389
53432
  break;
52390
53433
  }
@@ -52416,7 +53459,6 @@ class RealignParser {
52416
53459
  let chainid2 = chainidArray2[j];
52417
53460
 
52418
53461
  let alignAjax;
52419
-
52420
53462
  if(me.cfg.aligntool != 'tmalign') {
52421
53463
  let jsonStr_q = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct2][chainid2]);
52422
53464
 
@@ -52455,7 +53497,7 @@ class RealignParser {
52455
53497
 
52456
53498
  async realignOnStructAlignMsa(nameArray) { let ic = this.icn3d, me = ic.icn3dui;
52457
53499
  // each 3D domain should have at least 3 secondary structures
52458
- let minSseCnt = 3;
53500
+ let minSseCnt = (me.cfg.aligntool != 'tmalign') ? 3 : 0;
52459
53501
  let chainid2domain = {};
52460
53502
 
52461
53503
  for(let i = 0, il = nameArray.length; i < il; ++i) {
@@ -52464,7 +53506,7 @@ class RealignParser {
52464
53506
  let sseCnt = 0;
52465
53507
  for(let serial in atoms) {
52466
53508
  if(ic.atoms[serial].ssbegin) ++sseCnt;
52467
- if(sseCnt == minSseCnt) {
53509
+ if(sseCnt > minSseCnt) {
52468
53510
  chainid2domain[chainid] = atoms;
52469
53511
  break;
52470
53512
  }
@@ -54585,7 +55627,7 @@ class ParserUtils {
54585
55627
  if(ic.bAnnoShown) await ic.showAnnoCls.showAnnotations();
54586
55628
  }
54587
55629
 
54588
- // Realign by seqeunce alignment with the residues in "segment", i.e., transmembrane helix
55630
+ // Realign by sequence alignment with the residues in "segment", i.e., transmembrane helix
54589
55631
  let segment = data.segment; // e.g., " 361- 379 ( 359- 384)", the first range is trnasmembrane range,
54590
55632
  //the second range is the range of the helix
54591
55633
  let range = segment.replace(/ /gi, '').split('(')[0]; //361-379
@@ -56399,7 +57441,7 @@ class SetSeqAlign {
56399
57441
 
56400
57442
  //mmdbid1 = ic.mmdbid_t;
56401
57443
  mmdbid1 = chainidArray[0].substr(0, pos1); //.toUpperCase();
56402
- mmdbid2 = chainid.substr(0, pos2); //.toUpperCase();
57444
+ mmdbid2 = chainid.substr(0, pos2); //.toUpperCase()mergeTwoSeqForAll;
56403
57445
 
56404
57446
  chain1 = chainidArray[0].substr(pos1 + 1);
56405
57447
  chain2 = chainid.substr(pos2 + 1);
@@ -56558,14 +57600,121 @@ class SetSeqAlign {
56558
57600
  result = this.getTemplatePosFromOriPos(chainid1, prevIndex1, end_t, bRealign);
56559
57601
  pos1 = result.pos1;
56560
57602
  pos2 = result.pos2;
56561
- //for(let i = pos1; i < pos2; ++i) {
56562
- for(let i = pos1; i <= pos2; ++i) {
57603
+ for(let i = pos1; i < pos2; ++i) {
57604
+ //for(let i = pos1; i <= pos2; ++i) {
56563
57605
  ic.alnChainsSeq[chainid2].push(gapResObject2);
56564
57606
  }
56565
57607
 
56566
57608
  return hAtoms;
56567
57609
  }
56568
57610
 
57611
+ // used for seq MSA
57612
+ mergeTwoSeqForAllSimple(targetId, chainidArray, index, alignedChainIndice, start_t, end_t, querySeqArray) { let ic = this.icn3d; ic.icn3dui;
57613
+ let chainid1 = targetId;
57614
+ let chainid2 = chainidArray[index];
57615
+
57616
+ let pos1, pos2, prevIndex1, prevIndex2;
57617
+
57618
+ for(let i = 0, il = ic.qt_start_end[index].length; i < il; ++i) {
57619
+ let start1, start2, end1, end2, resiStart1, start1Pos, end1Pos;
57620
+
57621
+ start1 = ic.qt_start_end[index][i].t_start;
57622
+ start2 = ic.qt_start_end[index][i].q_start;
57623
+ end1 = ic.qt_start_end[index][i].t_end;
57624
+ end2 = ic.qt_start_end[index][i].q_end;
57625
+
57626
+ // 1. before the mapped residues
57627
+ //resiStart1 = ic.ParserUtilsCls.getResi(chainid1, start1);
57628
+ resiStart1 = start1;
57629
+ start1Pos = start1;
57630
+ end1Pos = end1;
57631
+
57632
+ // if the mapping does not start from start_t, add gaps to the query seq
57633
+ if(i == 0) {
57634
+ pos1 = start_t;
57635
+ pos2 = start1Pos;
57636
+
57637
+ if(start1Pos > start_t) {
57638
+ for(let j = 0, jl = pos2 - pos1; j < jl; ++j) {
57639
+ ic.msaSeq[chainid2] += '-';
57640
+ }
57641
+ }
57642
+ }
57643
+ else {
57644
+ pos1 = prevIndex1;
57645
+ pos2 = start1;
57646
+ let notAlnLen1 = pos2 - (pos1 + 1);
57647
+ let notAlnLen2 = start2 - (prevIndex2 + 1);
57648
+
57649
+ // insert non-aligned residues in query seq
57650
+ // this.insertNotAlignRes(chainid2, prevIndex2+1, notAlnLen2, bRealign);
57651
+
57652
+ for(let j = 0, jl = notAlnLen2; j < jl; ++j) {
57653
+ let resn = querySeqArray[index][prevIndex2+1 + j];
57654
+ ic.msaSeq[chainid2] += resn;
57655
+ }
57656
+
57657
+ if(notAlnLen1 >= notAlnLen2) {
57658
+ // add gaps before the query sequence
57659
+ for(let j = 0, jl = notAlnLen1 - notAlnLen2; j < jl; ++j) {
57660
+ ic.msaSeq[chainid2] += '-';
57661
+ }
57662
+ }
57663
+ else {
57664
+ // check the number of gaps before resiStart1 (n), and insert 'notAlnLen2 - notAlnLen1 - n' gaps
57665
+ // this.addGapAllAlnChains(chainidArray, alignedChainIndice, chainid1, resiStart1, notAlnLen2 - notAlnLen1);
57666
+
57667
+ // let result = this.getResiPosInTemplate(chainid1, resi_t);
57668
+ // let nGap = result.ngap, pos_t = result.pos;
57669
+
57670
+ let pos_t = resiStart1; // position to add gap
57671
+
57672
+ // add gaps for all previously aligned sequences, not the current sequence, which is the last one
57673
+ for(let j = 0, jl = alignedChainIndice.length - 1; j < jl; ++j) {
57674
+ let chainidTmp = (j == 0) ? chainid1 : chainidArray[alignedChainIndice[j]];
57675
+
57676
+ for(let k = 0, kl = notAlnLen2 - notAlnLen1; k < kl; ++k) {
57677
+ //ic.msaSeq[chainidTmp].splice(pos_t, 0, '-');
57678
+ ic.msaSeq[chainidTmp] = ic.msaSeq[chainidTmp].substr(0, pos_t) + '-' + ic.msaSeq[chainidTmp].substr(pos_t);
57679
+ }
57680
+ }
57681
+ }
57682
+ }
57683
+
57684
+ // 2. In the mapped residues
57685
+ pos1 = start1Pos;
57686
+ pos2 = end1Pos;
57687
+
57688
+ let k = 0;
57689
+ for(let j = pos1; j <= pos2; ++j) {
57690
+ // inherit the gaps from the template
57691
+ if(ic.msaSeq[chainid1][j] == '-') {
57692
+ ic.msaSeq[chainid2] += '-';
57693
+ }
57694
+ else {
57695
+ //let resn1 = targetSeq[start1 + k];
57696
+ let resn2 = querySeqArray[index][start2 + k];
57697
+ //let resn2 = (querySeqArray[index]) ? querySeqArray[index][start2 + k] : '?';
57698
+
57699
+ ic.msaSeq[chainid2] += resn2;
57700
+
57701
+ ++k;
57702
+ }
57703
+ }
57704
+
57705
+ prevIndex1 = end1;
57706
+ prevIndex2 = end2;
57707
+ }
57708
+
57709
+ // add gaps at the end
57710
+ pos1 = prevIndex1;
57711
+ pos2 = end_t;
57712
+ for(let i = pos1; i < pos2; ++i) {
57713
+ //for(let i = pos1; i <= pos2; ++i) {
57714
+ ic.msaSeq[chainid2] += '-';
57715
+ }
57716
+ }
57717
+
56569
57718
  setSeqAlignForRealign(chainid_t, chainid, chainIndex) { let ic = this.icn3d, me = ic.icn3dui;
56570
57719
  //var chainid_t = ic.chainidArray[0];
56571
57720
 
@@ -56794,7 +57943,7 @@ class LoadPDB {
56794
57943
  getStructureId(id, moleculeNum, bMutation) { let ic = this.icn3d; ic.icn3dui;
56795
57944
  let structure = id;
56796
57945
 
56797
- if(id == ic.defaultPdbId || bMutation) { // bMutation: side chain prediction
57946
+ if(id == ic.defaultPdbId || bMutation || ic.structures.hasOwnProperty(id)) { // bMutation: side chain prediction
56798
57947
  structure = (moleculeNum === 1) ? id : id + moleculeNum.toString();
56799
57948
  }
56800
57949
 
@@ -56862,7 +58011,7 @@ class LoadPDB {
56862
58011
  let prevMissingChain = '';
56863
58012
  let CSerial, prevCSerial, OSerial, prevOSerial;
56864
58013
 
56865
- let bHeader = false;
58014
+ let bHeader = false, bFirstAtom = true;
56866
58015
 
56867
58016
  for (let i in lines) {
56868
58017
  let line = lines[i];
@@ -57023,7 +58172,11 @@ class LoadPDB {
57023
58172
  ic.pmid = line.substr(19).trim();
57024
58173
  }
57025
58174
  } else if (record === 'ATOM ' || record === 'HETATM') {
57026
- structure = this.getStructureId(id, moleculeNum, bMutation);
58175
+ if(bFirstAtom) {
58176
+ structure = this.getStructureId(id, moleculeNum, bMutation);
58177
+
58178
+ bFirstAtom = false;
58179
+ }
57027
58180
 
57028
58181
  let alt = line.substr(16, 1);
57029
58182
  //if (alt !== " " && alt !== "A") continue;
@@ -57914,7 +59067,7 @@ class Vastplus {
57914
59067
 
57915
59068
  // reinitialize the alignment
57916
59069
  $("#" + ic.pre + "dl_sequence2").html('');
57917
-
59070
+
57918
59071
  for(let j = 0, jl = nodeArray.length; j < jl; ++j) {
57919
59072
  let node = parseInt(nodeArray[j]);
57920
59073
  let segs = queryDataArray[node][0].segs;
@@ -57991,7 +59144,7 @@ class Vastplus {
57991
59144
  for(let j = 0, jl = nodeArray.length; j < jl; ++j) {
57992
59145
  chainpairStr += chainidpairArray[parseInt(nodeArray[j])] + '; ';
57993
59146
  }
57994
- console.log("Selected the alignment: " + chainpairStr);
59147
+ if(!me.bNode) console.log("Selected the alignment: " + chainpairStr);
57995
59148
 
57996
59149
  break;
57997
59150
  }
@@ -58000,7 +59153,7 @@ class Vastplus {
58000
59153
  for(let j = 0, jl = nodeArray.length; j < jl; ++j) {
58001
59154
  chainpairStr += chainidpairArray[parseInt(nodeArray[j])] + '; ';
58002
59155
  }
58003
- console.log("skipped the alignment: " + chainpairStr);
59156
+ if(!me.bNode) console.log("skipped the alignment: " + chainpairStr);
58004
59157
  }
58005
59158
  }
58006
59159
  }
@@ -61139,6 +62292,38 @@ class LoadScript {
61139
62292
 
61140
62293
  await ic.cartoon2dCls.draw2Dcartoon(type);
61141
62294
  }
62295
+ else if(command.indexOf('add msa track') == 0) {
62296
+ //add msa track | chainid " + chainid + " | startpos " + startpos + " | type " + type + " | fastaList " + fastaList
62297
+ let paraArray = command.split(' | ');
62298
+
62299
+ let chainid = paraArray[1].substr(8);
62300
+ let startpos = paraArray[2].substr(9);
62301
+ let type = paraArray[3].substr(5);
62302
+ let fastaList = paraArray[4].substr(10);
62303
+
62304
+ if($("#" + ic.pre + "anno_custom")[0]) {
62305
+ $("#" + ic.pre + "anno_custom")[0].checked = true;
62306
+ }
62307
+ $("[id^=" + ic.pre + "custom]").show();
62308
+
62309
+ await ic.addTrackCls.addMsaTracks(chainid, startpos, type, fastaList);
62310
+ }
62311
+ else if(command.indexOf('add exon track') == 0) {
62312
+ //add exon track | chainid " + chainid + " | geneid " + geneid + " | startpos " + startpos + " | type " + type
62313
+ let paraArray = command.split(' | ');
62314
+
62315
+ let chainid = paraArray[1].substr(8);
62316
+ let geneid = paraArray[2].substr(7);
62317
+ let startpos = paraArray[3].substr(9);
62318
+ let type = paraArray[4].substr(5);
62319
+
62320
+ if($("#" + ic.pre + "anno_custom")[0]) {
62321
+ $("#" + ic.pre + "anno_custom")[0].checked = true;
62322
+ }
62323
+ $("[id^=" + ic.pre + "custom]").show();
62324
+
62325
+ await ic.addTrackCls.addExonTracks(chainid, geneid, startpos, type);
62326
+ }
61142
62327
  else {
61143
62328
  await ic.applyCommandCls.applyCommand(ic.commands[i]);
61144
62329
  }
@@ -61385,6 +62570,10 @@ class LoadScript {
61385
62570
  me.cfg.refseqid = id;
61386
62571
  await ic.mmdbParserCls.downloadRefseq(id);
61387
62572
  }
62573
+ else if(command.indexOf('load protein') !== -1) {
62574
+ me.cfg.protein = id;
62575
+ await ic.mmdbParserCls.downloadProteinname(id);
62576
+ }
61388
62577
  else if(command.indexOf('load seq_struct_ids ') !== -1) {
61389
62578
  ic.bSmithwm = false;
61390
62579
  ic.bLocalSmithwm = false;
@@ -61847,12 +63036,18 @@ class SelectByCommand {
61847
63036
  residueStr = "*";
61848
63037
  }
61849
63038
  else if(colonPos2 != -1) {
61850
- refResStr = testStr.substr(colonPos2 + 5);
61851
- testStr = testStr.substr(0, colonPos2);
63039
+ refResStr = testStr.substr(colonPos2 + 5);
63040
+ testStr = testStr.substr(0, colonPos2);
63041
+
63042
+ // somehow sometimes refResStr or residueStr is rmpty
63043
+ if(!refResStr) continue;
61852
63044
  }
61853
63045
  else if(colonPos != -1) {
61854
- residueStr = testStr.substr(colonPos + 1);
61855
- testStr = testStr.substr(0, colonPos);
63046
+ residueStr = testStr.substr(colonPos + 1);
63047
+ testStr = testStr.substr(0, colonPos);
63048
+
63049
+ // somehow sometimes refResStr or residueStr is rmpty
63050
+ if(!residueStr) continue;
61856
63051
  }
61857
63052
 
61858
63053
  if(periodPos === -1) {
@@ -62480,6 +63675,8 @@ class Selection {
62480
63675
  ic.graphStr = this.getGraphDataForDisplayed();
62481
63676
  }
62482
63677
 
63678
+ ic.saveFileCls.showTitle();
63679
+
62483
63680
  // don not redraw graphs after the selection changes
62484
63681
  /*
62485
63682
  if(ic.bGraph) ic.drawGraphCls.drawGraph(ic.graphStr, ic.pre + 'dl_graph');
@@ -67719,7 +68916,7 @@ class ResizeCanvas {
67719
68916
  //let itemArray = ['dl_selectannotations', 'dl_alignment', 'dl_2ddgm', 'dl_definedsets', 'dl_graph',
67720
68917
  // 'dl_linegraph', 'dl_scatterplot', 'dl_contactmap', 'dl_allinteraction', 'dl_copyurl',
67721
68918
  // 'dl_symmetry', 'dl_symd', 'dl_rmsd', 'dl_legend', 'dl_disttable'];
67722
- let itemArray = ['dl_2ddgm', 'dl_2dctn', 'dl_alignment', 'dl_sequence2', 'dl_definedsets', 'dl_setsmenu', 'dl_command', 'dl_setoperations', 'dl_vast', 'dl_foldseek', 'dl_mmtfid', 'dl_pdbid', 'dl_afid', 'dl_opmid', 'dl_pdbfile', 'dl_pdbfile_app', 'dl_rescolorfile', 'dl_customcolor', 'dl_align', 'dl_alignaf', 'dl_chainalign', 'dl_chainalign2', 'dl_chainalign3', 'dl_mutation', 'dl_mol2file', 'dl_sdffile', 'dl_xyzfile', 'dl_afmapfile', 'dl_urlfile', 'dl_mmciffile', 'dl_mmcifid', 'dl_mmdbid', 'dl_mmdbafid', 'dl_blast_rep_id', 'dl_yournote', 'dl_gi', 'dl_refseqid', 'dl_cid', 'dl_pngimage', 'dl_state', 'dl_fixedversion', 'dl_selection', 'dl_dsn6', 'dl_dsn6url', 'dl_clr', 'dl_symmetry', 'dl_symd', 'dl_contact', 'dl_hbonds', 'dl_realign', 'dl_realignbystruct', 'dl_allinteracton', 'dl_interactionsorted', 'dl_linegraph', 'dl_linegraphcolor', 'dl_scatterplot', 'dl_scatterploitcolor', 'dl_contactmap', 'dl_alignerrormap', 'dl_elecmap2fofc', 'dl_elecmapfofc', 'dl_emmap', 'dl_aroundsphere', 'dl_adjustmem', 'dl_selectplane', 'dl_addlabel', 'dl_addlabelselection', 'dl_labelColor', 'dl_distance', 'dl_stabilizer', 'dl_disttwosets', 'dl_distmanysets', 'dl_stabilizer_rm', 'dl_thickness', 'dl_thickness2', 'dl_addtrack', 'dl_addtrack_tabs', 'dl_saveselection', 'dl_copyurl', 'dl_selectannotations', 'dl_annotations_tabs', 'dl_anno_view_tabs', 'dl_annotations', 'dl_graph', 'dl_svgcolor', 'dl_area', 'dl_colorbyarea', 'dl_rmsd', 'dl_buriedarea', 'dl_propbypercentout', 'dl_propbybfactor', 'dl_legend', 'dl_disttable'];
68919
+ let itemArray = ['dl_2ddgm', 'dl_2dctn', 'dl_alignment', 'dl_sequence2', 'dl_definedsets', 'dl_setsmenu', 'dl_command', 'dl_setoperations', 'dl_vast', 'dl_foldseek', 'dl_mmtfid', 'dl_pdbid', 'dl_afid', 'dl_opmid', 'dl_pdbfile', 'dl_pdbfile_app', 'dl_rescolorfile', 'dl_customcolor', 'dl_align', 'dl_alignaf', 'dl_chainalign', 'dl_chainalign2', 'dl_chainalign3', 'dl_mutation', 'dl_mol2file', 'dl_sdffile', 'dl_xyzfile', 'dl_afmapfile', 'dl_urlfile', 'dl_mmciffile', 'dl_mmcifid', 'dl_mmdbid', 'dl_mmdbafid', 'dl_blast_rep_id', 'dl_yournote', 'dl_proteinname', 'dl_refseqid', 'dl_cid', 'dl_pngimage', 'dl_state', 'dl_fixedversion', 'dl_selection', 'dl_dsn6', 'dl_dsn6url', 'dl_clr', 'dl_symmetry', 'dl_symd', 'dl_contact', 'dl_hbonds', 'dl_realign', 'dl_realignbystruct', 'dl_allinteracton', 'dl_interactionsorted', 'dl_linegraph', 'dl_linegraphcolor', 'dl_scatterplot', 'dl_scatterploitcolor', 'dl_contactmap', 'dl_alignerrormap', 'dl_elecmap2fofc', 'dl_elecmapfofc', 'dl_emmap', 'dl_aroundsphere', 'dl_adjustmem', 'dl_selectplane', 'dl_addlabel', 'dl_addlabelselection', 'dl_labelColor', 'dl_distance', 'dl_stabilizer', 'dl_disttwosets', 'dl_distmanysets', 'dl_stabilizer_rm', 'dl_thickness', 'dl_thickness2', 'dl_addtrack', 'dl_addtrack_tabs', 'dl_saveselection', 'dl_copyurl', 'dl_selectannotations', 'dl_annotations_tabs', 'dl_anno_view_tabs', 'dl_annotations', 'dl_graph', 'dl_svgcolor', 'dl_area', 'dl_colorbyarea', 'dl_rmsd', 'dl_buriedarea', 'dl_propbypercentout', 'dl_propbybfactor', 'dl_legend', 'dl_disttable'];
67723
68920
 
67724
68921
  for(let i in itemArray) {
67725
68922
  let item = itemArray[i];
@@ -68853,13 +70050,13 @@ class SaveFile {
68853
70050
 
68854
70051
  //Show the title and PDB ID of the PDB structure at the beginning of the viewer.
68855
70052
  showTitle() {var ic = this.icn3d, me = ic.icn3dui;
68856
- if(ic.molTitle !== undefined && ic.molTitle !== '') {
68857
- let title = ic.molTitle;
70053
+ // if(ic.molTitle !== undefined && ic.molTitle !== '') {
70054
+ let title = (ic.molTitle) ? ic.molTitle : '';
68858
70055
 
68859
70056
  let titlelinkColor =(ic.opts['background'] == 'black') ? me.htmlCls.GREYD : 'black';
68860
70057
 
68861
70058
  if(ic.inputid === undefined) {
68862
- if(ic.molTitle.length > 40) title = ic.molTitle.substr(0, 40) + "...";
70059
+ if(title.length > 40) title = title.substr(0, 40) + "...";
68863
70060
 
68864
70061
  $("#" + ic.pre + "title").html(title);
68865
70062
  }
@@ -68879,31 +70076,38 @@ class SaveFile {
68879
70076
 
68880
70077
  $("#" + ic.pre + "title").html(title);
68881
70078
  }
68882
- else if(me.cfg.mmdbafid !== undefined) {
68883
- let structureArray = Object.keys(ic.structures); //me.cfg.mmdbafid.split(',');
70079
+ else { //if(me.cfg.mmdbafid !== undefined) {
70080
+ //let structureArray = Object.keys(ic.structures); //me.cfg.mmdbafid.split(',');
70081
+ let structureArray = Object.keys(me.utilsCls.getStructures(ic.dAtoms));
70082
+
68884
70083
  if(structureArray.length > 1) {
68885
- title = 'Multiple structures: ' + structureArray;
70084
+ title = 'Multiple structures: ';
70085
+ for(let i = 0, il = structureArray.length; i < il; ++i) {
70086
+ let url = (isNaN(structureArray[i]) && structureArray[i].length > 5) ? 'https://alphafold.ebi.ac.uk/entry/' + structureArray[i] : 'https://www.ncbi.nlm.nih.gov/structure/?term=' + structureArray[i];
70087
+ title += '<a href="' + url + '" style="color:' + titlelinkColor + '" target="_blank">' + structureArray[i] + '</a>';
70088
+ if(i < il - 1) title += ', ';
70089
+ }
68886
70090
  $("#" + ic.pre + "title").html(title);
68887
70091
  }
68888
70092
  else if(structureArray.length == 1) {
68889
70093
  //let url = this.getLinkToStructureSummary();
68890
- let url = (isNaN(ic.inputid) && ic.inputid.length > 5) ? 'https://alphafold.ebi.ac.uk/entry/' + ic.inputid : 'https://www.ncbi.nlm.nih.gov/structure/?term=' + ic.inputid;
70094
+ let url = (isNaN(structureArray[0]) && structureArray[0].length > 5) ? 'https://alphafold.ebi.ac.uk/entry/' + structureArray[0] : 'https://www.ncbi.nlm.nih.gov/structure/?term=' + structureArray[0];
68891
70095
 
68892
70096
  this.setStructureTitle(url, title, titlelinkColor);
68893
70097
  }
68894
70098
  }
68895
- else {
68896
- let url = this.getLinkToStructureSummary();
68897
- this.setStructureTitle(url, title, titlelinkColor);
68898
- }
68899
- }
68900
- else {
68901
- $("#" + ic.pre + "title").html("");
68902
- }
70099
+ // else {
70100
+ // let url = this.getLinkToStructureSummary();
70101
+ // this.setStructureTitle(url, title, titlelinkColor);
70102
+ // }
70103
+ // }
70104
+ // else {
70105
+ // $("#" + ic.pre + "title").html("");
70106
+ // }
68903
70107
  }
68904
70108
 
68905
70109
  setStructureTitle(url, title, titlelinkColor) {var ic = this.icn3d, me = ic.icn3dui;
68906
- if(ic.molTitle.length > 40) title = ic.molTitle.substr(0, 40) + "...";
70110
+ if(title.length > 40) title = title.substr(0, 40) + "...";
68907
70111
 
68908
70112
  let inputid = ic.inputid;
68909
70113
 
@@ -68929,7 +70133,7 @@ class SaveFile {
68929
70133
  let structureidArray = Object.keys(idHash);
68930
70134
  inputid = structureidArray.join(',');
68931
70135
 
68932
- text = (me.cfg.refseqid) ? ic.inputid : inputid.toUpperCase();
70136
+ text = (me.cfg.refseqid || me.cfg.protein) ? ic.inputid : inputid.toUpperCase();
68933
70137
 
68934
70138
  //idName = (isNaN(inputid) && inputid.length > 5) ? "AlphaFold ID" : "PDB ID";
68935
70139
  if(bPdb && bAlphaFold) {
@@ -68955,7 +70159,12 @@ class SaveFile {
68955
70159
  }
68956
70160
  }
68957
70161
 
68958
- if(me.cfg.refseqid) idName = 'NCBI Protein Acc.';
70162
+ if(me.cfg.refseqid) {
70163
+ idName = 'NCBI Protein Acc.';
70164
+ }
70165
+ else if(me.cfg.protein) {
70166
+ idName = 'Protein/Gene Name';
70167
+ }
68959
70168
 
68960
70169
  if(!inputid || inputid.substr(0, 4) == ic.defaultPdbId) {
68961
70170
  $("#" + ic.pre + "title").html(title);
@@ -72227,7 +73436,7 @@ class iCn3DUI {
72227
73436
  //even when multiple iCn3D viewers are shown together.
72228
73437
  this.pre = this.cfg.divid + "_";
72229
73438
 
72230
- this.REVISION = '3.26.0';
73439
+ this.REVISION = '3.28.0';
72231
73440
 
72232
73441
  // In nodejs, iCn3D defines "window = {navigator: {}}"
72233
73442
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -72520,6 +73729,14 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
72520
73729
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
72521
73730
  await ic.mmdbParserCls.downloadRefseq(me.cfg.refseqid);
72522
73731
  }
73732
+ else if(me.cfg.protein !== undefined) {
73733
+ ic.inputid = me.cfg.protein;
73734
+
73735
+ // ic.bNCBI = true;
73736
+ ic.loadCmd = 'load protein ' + me.cfg.protein;
73737
+ me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
73738
+ await ic.mmdbParserCls.downloadProteinname(me.cfg.protein);
73739
+ }
72523
73740
  else if(me.cfg.blast_rep_id !== undefined) {
72524
73741
  // ic.bNCBI = true;
72525
73742
  ic.inputid = me.cfg.query_id + ',' + me.cfg.blast_rep_id;
@@ -72527,7 +73744,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
72527
73744
  me.cfg.oriQuery_id = me.cfg.query_id;
72528
73745
  me.cfg.oriBlast_rep_id = me.cfg.blast_rep_id;
72529
73746
 
72530
- // custom seqeunce has query_id such as "Query_78989" in BLAST
73747
+ // custom sequence has query_id such as "Query_78989" in BLAST
72531
73748
  if(me.cfg.query_id.substr(0,5) !== 'Query' && me.cfg.rid === undefined) {
72532
73749
  // make it backward compatible for figure 2 in iCn3D paper: https://academic.oup.com/bioinformatics/article/36/1/131/5520951
72533
73750
  if(me.cfg.from == 'icn3d' && me.cfg.blast_rep_id == '1TSR_A' && me.cfg.query_id == 'NP_001108451.1') {