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.js CHANGED
@@ -4456,23 +4456,23 @@ class ParasCls {
4456
4456
  //this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * ( + 0.81)/(1.14 + 0.81)),
4457
4457
  // hydrophobic
4458
4458
  // https://en.m.wikipedia.org/wiki/Hydrophobicity_scales#Wimley%E2%80%93White_whole_residue_hydrophobicity_scales
4459
- 'TRP': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.85 + 1.85)/(0 + 1.85)),
4460
- 'PHE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.13 + 1.85)/(0 + 1.85)),
4461
- 'TYR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.94 + 1.85)/(0 + 1.85)),
4462
- 'LEU': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.56 + 1.85)/(0 + 1.85)),
4463
- 'ILE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.31 + 1.85)/(0 + 1.85)),
4464
- 'CYS': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.24 + 1.85)/(0 + 1.85)),
4465
- 'MET': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.23 + 1.85)/(0 + 1.85)),
4459
+ 'TRP': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-2.09 + 2.09) / (0 + 2.09)),
4460
+ 'PHE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.71 + 2.09) / (0 + 2.09)),
4461
+ 'LEU': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.25 + 2.09) / (0 + 2.09)),
4462
+ 'ILE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.12 + 2.09) / (0 + 2.09)),
4463
+ 'TYR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.71 + 2.09) / (0 + 2.09)),
4464
+ 'MET': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.67 + 2.09) / (0 + 2.09)),
4465
+ 'VAL': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.46 + 2.09) / (0 + 2.09)),
4466
+ 'CYS': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.02 + 2.09) / (0 + 2.09)),
4466
4467
 
4467
4468
  // polar
4468
- 'GLY': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.01 + 0.58)/(0 + 0.58)),
4469
- 'VAL': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.07 + 0.58)/(0 + 0.58)),
4470
- 'SER': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.13 + 0.58)/(0 + 0.58)),
4471
- 'THR': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.14 + 0.58)/(0 + 0.58)),
4472
- 'ALA': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.17 + 0.58)/(0 + 0.58)),
4473
- 'ASN': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.42 + 0.58)/(0 + 0.58)),
4474
- 'PRO': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.45 + 0.58)/(0 + 0.58)),
4475
- 'GLN': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.58 + 0.58)/(0 + 0.58))
4469
+ 'PRO': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.14 + 1.15) / (0 + 1.15)),
4470
+ 'THR': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.25 + 1.15) / (0 + 1.15)),
4471
+ 'SER': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.46 + 1.15) / (0 + 1.15)),
4472
+ 'ALA': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.50 + 1.15) / (0 + 1.15)),
4473
+ 'GLN': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.77 + 1.15) / (0 + 1.15)),
4474
+ 'ASN': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-0.85 + 1.15) / (0 + 1.15)),
4475
+ 'GLY': this.thr().setHSL(1/6.0, 1, 0.5 + 0.5 * (-1.15 + 1.15) / (0 + 1.15))
4476
4476
  };
4477
4477
 
4478
4478
  this.normalizedHPColors = {
@@ -4490,59 +4490,58 @@ class ParasCls {
4490
4490
  //this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * ( + 0.81)/(1.14 + 0.81)),
4491
4491
  // hydrophobic
4492
4492
  // https://en.m.wikipedia.org/wiki/Hydrophobicity_scales#Wimley%E2%80%93White_whole_residue_hydrophobicity_scales
4493
- // 0.65 ~ -1.85: white ~ green
4494
- 'TRP': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.85 + 1.85)/2.5),
4495
- 'PHE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.13 + 1.85)/2.5),
4496
- 'TYR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.94 + 1.85)/2.5),
4497
- 'LEU': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.56 + 1.85)/2.5),
4498
- 'ILE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.31 + 1.85)/2.5),
4499
- 'CYS': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.24 + 1.85)/2.5),
4500
- 'MET': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.23 + 1.85)/2.5),
4493
+ // 1.15 ~ -2.09: white ~ green
4494
+ 'TRP': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-2.09 + 2.09) / 3.24),
4495
+ 'PHE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.71 + 2.09) / 3.24),
4496
+ 'LEU': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.25 + 2.09) / 3.24),
4497
+ 'ILE': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-1.12 + 2.09) / 3.24),
4498
+ 'TYR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.71 + 2.09) / 3.24),
4499
+ 'MET': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.67 + 2.09) / 3.24),
4500
+ 'VAL': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.46 + 2.09) / 3.24),
4501
+ 'CYS': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (-0.02 + 2.09) / 3.24),
4501
4502
 
4502
4503
  // polar
4503
- 'GLY': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.01 + 1.85)/2.5),
4504
- 'VAL': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.07 + 1.85)/2.5),
4505
- 'SER': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.13 + 1.85)/2.5),
4506
- 'THR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.14 + 1.85)/2.5),
4507
- 'ALA': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.17 + 1.85)/2.5),
4508
- 'ASN': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.42 + 1.85)/2.5),
4509
- 'PRO': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.45 + 1.85)/2.5),
4510
- 'GLN': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.58 + 1.85)/2.5)
4504
+ 'PRO': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.14 + 2.09) / 3.24),
4505
+ 'THR': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.25 + 2.09) / 3.24),
4506
+ 'SER': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.46 + 2.09) / 3.24),
4507
+ 'ALA': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.50 + 2.09) / 3.24),
4508
+ 'GLN': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.77 + 2.09) / 3.24),
4509
+ 'ASN': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (0.85 + 2.09) / 3.24),
4510
+ 'GLY': this.thr().setHSL(1/3.0, 1, 0.5 + 0.5 * (1.15 + 2.09) / 3.24)
4511
4511
  };
4512
4512
 
4513
4513
  this.hydrophobicValues = {
4514
- // charged residues
4514
+ // charged residues, larger than max polar (1.15)
4515
4515
  ' G': 3, ' A': 3, ' T': 3,
4516
4516
  ' C': 3, ' U': 3, ' DG': 3,
4517
4517
  ' DA': 3, ' DT': 3, ' DC': 3,
4518
4518
  ' DU': 3, 'G': 3, 'A': 3,
4519
4519
  'T': 3, 'C': 3, 'U': 3,
4520
4520
  'DG': 3, 'DA': 3, 'DT': 3,
4521
- 'DC': 3, 'DU': 3, 'ARG': 1,
4522
- 'LYS': 1, 'ASP': 3, 'GLU': 3,
4521
+ 'DC': 3, 'DU': 3, 'ARG': 1.5,
4522
+ 'LYS': 1.5, 'ASP': 3, 'GLU': 3,
4523
4523
  'HIS': 2,
4524
4524
 
4525
- // + 0.81)/(1.14 + 0.81)),
4526
4525
  // hydrophobic
4527
4526
  // https://en.m.wikipedia.org/wiki/Hydrophobicity_scales#Wimley%E2%80%93White_whole_residue_hydrophobicity_scales
4528
- // 0.65 ~ -1.85: white ~ green
4529
- 'TRP': -1.85,
4530
- 'PHE': -1.13,
4531
- 'TYR': -0.94,
4532
- 'LEU': -0.56,
4533
- 'ILE': -0.31,
4534
- 'CYS': -0.24,
4535
- 'MET': -0.23,
4527
+ // 1.15 ~ -2.09: white ~ green
4528
+ 'TRP': -2.09,
4529
+ 'PHE': -1.71,
4530
+ 'LEU': -1.25,
4531
+ 'ILE': -1.12,
4532
+ 'TYR': -0.71,
4533
+ 'MET': -0.67,
4534
+ 'VAL': -0.46,
4535
+ 'CYS': -0.02,
4536
4536
 
4537
4537
  // polar
4538
- 'GLY': 0.01,
4539
- 'VAL': 0.07,
4540
- 'SER': 0.13,
4541
- 'THR': 0.14,
4542
- 'ALA': 0.17,
4543
- 'ASN': 0.42,
4544
- 'PRO': 0.45,
4545
- 'GLN': 0.58
4538
+ 'PRO': 0.14,
4539
+ 'THR': 0.25,
4540
+ 'SER': 0.46,
4541
+ 'ALA': 0.50,
4542
+ 'GLN': 0.77,
4543
+ 'ASN': 0.85,
4544
+ 'GLY': 1.15
4546
4545
  };
4547
4546
 
4548
4547
  this.residueAbbrev = {
@@ -5928,8 +5927,8 @@ class ClickMenu {
5928
5927
  me.htmlCls.dialogCls.openDlg('dl_esmfold', 'Sequence to structure prediction with ESMFold');
5929
5928
  });
5930
5929
 
5931
- me.myEventCls.onIds("#" + me.pre + "mn1_gi", "click", function(e) { me.icn3d; //e.preventDefault();
5932
- me.htmlCls.dialogCls.openDlg('dl_gi', 'Please input protein gi');
5930
+ me.myEventCls.onIds("#" + me.pre + "mn1_proteinname", "click", function(e) { me.icn3d; //e.preventDefault();
5931
+ me.htmlCls.dialogCls.openDlg('dl_proteinname', 'Please input protein or gene name');
5933
5932
  });
5934
5933
 
5935
5934
  me.myEventCls.onIds("#" + me.pre + "mn1_cid", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -8454,10 +8453,16 @@ class SetMenu {
8454
8453
  let html = "";
8455
8454
 
8456
8455
  html += "<ul class='icn3d-mn-item'>";
8457
- //html += "<li><a href='https://www.ncbi.nlm.nih.gov/structure' target='_blank'>Search Structure " + me.htmlCls.wifiStr + "</a></li>";
8458
- html += this.getMenuUrl('mn1_searchstru', "https://www.ncbi.nlm.nih.gov/structure", "Search Structure " + me.htmlCls.wifiStr, 1, 1);
8456
+
8457
+ html += this.getMenuText('mn1_searchgrooup', 'Search Structure ' + me.htmlCls.wifiStr, undefined, 1, 1);
8458
+ html += "<ul>";
8459
+ html += this.getMenuUrl('mn1_searchstru', 'https://www.ncbi.nlm.nih.gov/structure', 'PDB Structures ' + me.htmlCls.wifiStr, undefined, 2);
8460
+ html += this.getLink('mn1_proteinname', 'AlphaFold Structures ' + me.htmlCls.wifiStr, undefined, 2);
8461
+ html += this.getMenuUrl('mn1_afdatabase', 'https://alphafold.ebi.ac.uk', 'AlphaFold UniProt Database ' + me.htmlCls.wifiStr, undefined, 2);
8462
+ html += "</ul>";
8463
+ html += "</li>";
8459
8464
 
8460
- html += this.getMenuText('mn1_searchsimilar', 'Search Similar', undefined, undefined, 1);
8465
+ html += this.getMenuText('mn1_searchsimilar', 'Search Similar' + me.htmlCls.wifiStr, undefined, undefined, 1);
8461
8466
  html += "<ul>";
8462
8467
  html += this.getLink('mn1_vastplus', 'NCBI VAST+ (PDB Complex)' + me.htmlCls.wifiStr, undefined, 2);
8463
8468
  html += this.getLink('mn1_vast', 'NCBI VAST (PDB Chain)' + me.htmlCls.wifiStr, undefined, 2);
@@ -8478,7 +8483,6 @@ class SetMenu {
8478
8483
 
8479
8484
  html += this.getLink('mn1_afid', 'UniProt ID ' + me.htmlCls.wifiStr, undefined, 3);
8480
8485
  html += this.getLink('mn1_refseqid', 'NCBI Protein Accession ' + me.htmlCls.wifiStr, undefined, 3);
8481
- // html += this.getLink('mn1_proteinname', 'Protein Name ' + me.htmlCls.wifiStr, undefined, 3);
8482
8486
  html += "</ul>";
8483
8487
 
8484
8488
 
@@ -8520,10 +8524,11 @@ class SetMenu {
8520
8524
  html += "</ul>";
8521
8525
  html += "</li>";
8522
8526
 
8523
- html += this.getMenuText('mn1_fold', 'AlphaFold/ESM', undefined, undefined, 1);
8527
+ //html += this.getMenuText('mn1_fold', 'AlphaFold/ESM', undefined, undefined, 1);
8528
+ html += this.getMenuText('mn1_fold', 'Predict by Seq.', undefined, undefined, 1);
8524
8529
  html += "<ul>";
8525
- html += this.getLink('mn1_alphafold', 'AlphaFold2 via ColabFold', undefined, 2);
8526
8530
  html += this.getLink('mn1_esmfold', 'ESMFold', undefined, 2);
8531
+ html += this.getLink('mn1_alphafold', 'AlphaFold2 via ColabFold', undefined, 2);
8527
8532
  html += "</ul>";
8528
8533
 
8529
8534
 
@@ -8829,9 +8834,9 @@ class SetMenu {
8829
8834
 
8830
8835
  html += this.getMenuText('mn2_rotate90', 'Rotate 90&deg;', undefined, undefined, 2);
8831
8836
  html += "<ul>";
8832
- html += this.getRadio('mn6_rotate90', 'mn6_rotatex', 'X-axis(Shift + Key M)', undefined, undefined, 2);
8833
- html += this.getRadio('mn6_rotate90', 'mn6_rotatey', 'Y-axis(Shift + Key J)', undefined, undefined, 2);
8834
- html += this.getRadio('mn6_rotate90', 'mn6_rotatez', 'Z-axis', undefined, undefined, 2);
8837
+ html += this.getRadio('mn6_rotate90', 'mn6_rotatex', 'rotate x', undefined, undefined, 2);
8838
+ html += this.getRadio('mn6_rotate90', 'mn6_rotatey', 'rotate y', undefined, undefined, 2);
8839
+ html += this.getRadio('mn6_rotate90', 'mn6_rotatez', 'rotate z', undefined, undefined, 2);
8835
8840
  html += "</ul>";
8836
8841
  html += "</li>";
8837
8842
  html += this.getMenuText('mn2_rotateauto', 'Auto Rotation', undefined, 1, 2);
@@ -10341,6 +10346,9 @@ class Dialog {
10341
10346
  if(me.cfg.align) {
10342
10347
  position ={ my: "left top", at: "left top+90", of: "#" + me.pre + "canvas", collision: "none" };
10343
10348
  }
10349
+ else if(id === me.pre + 'dl_mmdbafid') {
10350
+ position ={ my: "left top", at: "left top+130", of: "#" + me.pre + "canvas", collision: "none" };
10351
+ }
10344
10352
  else {
10345
10353
  position ={ my: "left top", at: "left top+50", of: "#" + me.pre + "canvas", collision: "none" };
10346
10354
  }
@@ -10874,7 +10882,7 @@ class SetDialog {
10874
10882
 
10875
10883
  html += me.htmlCls.divStr + "dl_esmfold' style='max-width:600px;' class='" + dialogClass + "'>";
10876
10884
  html += this.addNotebookTitle('dl_esmfold', 'Sequence to structure prediction with ESMFold');
10877
- 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> ";
10885
+ 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> ";
10878
10886
  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>";
10879
10887
  html += me.htmlCls.buttonStr + "run_esmfold'>ESMFold</button> ";
10880
10888
  html += "</div>";
@@ -10886,10 +10894,10 @@ class SetDialog {
10886
10894
  html += me.htmlCls.buttonStr + "applyyournote'>Save</button>";
10887
10895
  html += "</div>";
10888
10896
 
10889
- html += me.htmlCls.divStr + "dl_gi' class='" + dialogClass + "'>";
10890
- html += this.addNotebookTitle('dl_gi', 'Please input an NCBI gi');
10891
- html += "Protein gi: " + me.htmlCls.inputTextStr + "id='" + me.pre + "gi' value='1310960' size=8> ";
10892
- html += me.htmlCls.buttonStr + "reload_gi'>Load</button>";
10897
+ html += me.htmlCls.divStr + "dl_proteinname' class='" + dialogClass + "'>";
10898
+ html += this.addNotebookTitle('dl_proteinname', 'Please input a protein/gene name');
10899
+ html += "Protein/Gene name: " + me.htmlCls.inputTextStr + "id='" + me.pre + "proteinname' value='TP53' size=8> ";
10900
+ html += me.htmlCls.buttonStr + "reload_proteinname'>Search</button>";
10893
10901
  html += "</div>";
10894
10902
 
10895
10903
  html += me.htmlCls.divStr + "dl_cid' class='" + dialogClass + "'>";
@@ -11559,9 +11567,10 @@ class SetDialog {
11559
11567
 
11560
11568
  html += me.htmlCls.divStr + "dl_addtrack_tabs' style='border:0px;'>";
11561
11569
  html += "<ul>";
11570
+ html += "<li><a href='#" + me.pre + "tracktab2c'>Isoforms & Exons</a></li>";
11571
+ html += "<li><a href='#" + me.pre + "tracktab2b'>MSA</a></li>";
11562
11572
  html += "<li><a href='#" + me.pre + "tracktab1'>NCBI gi/Accession</a></li>";
11563
11573
  html += "<li><a href='#" + me.pre + "tracktab2'>FASTA</a></li>";
11564
- html += "<li><a href='#" + me.pre + "tracktab2b'>FASTA Alignment</a></li>";
11565
11574
  html += "<li><a href='#" + me.pre + "tracktab3'>BED File</a></li>";
11566
11575
  html += "<li><a href='#" + me.pre + "tracktab4'>Custom</a></li>";
11567
11576
  html += "<li><a href='#" + me.pre + "tracktab5'>Current Selection</a></li>";
@@ -11577,10 +11586,16 @@ class SetDialog {
11577
11586
  html += "</div>";
11578
11587
 
11579
11588
  html += me.htmlCls.divStr + "tracktab2b'>";
11580
- 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>";
11581
- html += "<b>FASTA alignment sequences</b>:<br>";
11589
+ // 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>";
11590
+ 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>";
11591
+
11592
+ html += "<b>Precalculated Multiple Sequence Alignment (MSA)</b>:<br>";
11582
11593
  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>";
11583
- html += "Position of the first residue in Sequences & Annotations window: " + me.htmlCls.inputTextStr + "id='" + me.pre + "fasta_startpos' value='1' size=2> <br><br>";
11594
+
11595
+ // html += "<b>Opion 1. Precalculated Multiple Sequence Alignment (MSA)</b>:<br>";
11596
+ // 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>";
11597
+ // html += "<b>Opion 2. NCBI Protein Accessions</b>: "+ me.htmlCls.inputTextStr + "id='" + me.pre + "track_acclist' size=60> <br><br>";
11598
+ 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>";
11584
11599
 
11585
11600
  html += "Color Sequence by: <select id='" + me.pre + "colorseqby'>";
11586
11601
  html += me.htmlCls.optionStr + "'identity' selected>Identity</option>";
@@ -11590,6 +11605,22 @@ class SetDialog {
11590
11605
  html += me.htmlCls.buttonStr + "addtrack_button2b'>Add Track(s)</button>";
11591
11606
  html += "</div>";
11592
11607
 
11608
+ html += me.htmlCls.divStr + "tracktab2c'>";
11609
+ html += "<div style='width:500px'>Note: Show exons for all isoforms of the protein in the same gene as specified below.</div><br>";
11610
+
11611
+ 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>";
11612
+
11613
+ 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>";
11614
+
11615
+ html += "Color Sequence by: <select id='" + me.pre + "colorseqby2'>";
11616
+ html += me.htmlCls.optionStr + "'identity' selected>Identity</option>";
11617
+ html += me.htmlCls.optionStr + "'conservation'>Conservation</option>";
11618
+ html += "</select> <br><br>";
11619
+
11620
+ html += me.htmlCls.buttonStr + "addtrack_button2c'>Show Isoforms & Exons</button>";
11621
+ html += "</div>";
11622
+
11623
+
11593
11624
  html += me.htmlCls.divStr + "tracktab3'>";
11594
11625
  html += "BED file: " + me.htmlCls.inputFileStr + "id='" + me.pre + "track_bed' size=16> <br><br>";
11595
11626
  html += me.htmlCls.buttonStr + "addtrack_button3'>Add Track</button>";
@@ -12879,12 +12910,19 @@ class Events {
12879
12910
  }
12880
12911
 
12881
12912
  let esmfold_fasta = $("#" + me.pre + "esmfold_fasta").val();
12882
- let pdbid;
12913
+ let pdbid = 'stru--';
12883
12914
 
12884
12915
  if(esmfold_fasta.indexOf('>') != -1) { //FASTA with header
12885
12916
  let pos = esmfold_fasta.indexOf('\n');
12886
12917
  ic.esmTitle = esmfold_fasta.substr(1, pos - 1).trim();
12887
- pdbid = (ic.esmTitle.indexOf(' ') != -1) ? ic.esmTitle.substr(0, ic.esmTitle.indexOf(' ')) : ic.esmTitle;
12918
+ if(ic.esmTitle.indexOf('|') != -1) { // uniprot
12919
+ let idArray = ic.esmTitle.split('|');
12920
+ pdbid = (idArray.length > 2) ? idArray[1] : ic.esmTitle;
12921
+ }
12922
+ else { // NCBI
12923
+ pdbid = (ic.esmTitle.indexOf(' ') != -1) ? ic.esmTitle.substr(0, ic.esmTitle.indexOf(' ')) : ic.esmTitle;
12924
+ }
12925
+
12888
12926
  if(pdbid.length < 6) pdbid = pdbid.padEnd(6, '-');
12889
12927
 
12890
12928
  esmfold_fasta = esmfold_fasta.substr(pos + 1);
@@ -12893,8 +12931,8 @@ class Events {
12893
12931
  // remove new lines
12894
12932
  esmfold_fasta = esmfold_fasta.replace(/\s/g, '');
12895
12933
 
12896
- if(esmfold_fasta.length > 1024) {
12897
- var aaa = 1; //alert("Your seqeunce is larger than 1024 characters. Please consider to split it as described at https://github.com/facebookresearch/esm/issues/21.");
12934
+ if(esmfold_fasta.length > 400) {
12935
+ var aaa = 1; //alert("Your sequence is larger than 400 characters. Please consider to split it as described at https://github.com/facebookresearch/esm/issues/21.");
12898
12936
  return;
12899
12937
  }
12900
12938
 
@@ -12903,6 +12941,13 @@ class Events {
12903
12941
  thisClass.setLogCmd("Run ESMFold with the sequence " + esmfold_fasta, false);
12904
12942
 
12905
12943
  let esmData = await me.getAjaxPostPromise(esmUrl, esmfold_fasta, true, alertMess, undefined, true, 'text');
12944
+
12945
+ ic.bResetAnno = true;
12946
+
12947
+ ic.bInputfile = true;
12948
+ ic.InputfileType = 'pdb';
12949
+ ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + esmData : esmData;
12950
+
12906
12951
  ic.bEsmfold = true;
12907
12952
  let bAppend = true;
12908
12953
  await ic.pdbParserCls.loadPdbData(esmData, pdbid, undefined, bAppend, undefined, undefined, undefined, ic.bEsmfold);
@@ -12941,12 +12986,12 @@ class Events {
12941
12986
  });
12942
12987
 
12943
12988
 
12944
- me.myEventCls.onIds("#" + me.pre + "reload_gi", "click", function(e) { let ic = me.icn3d;
12989
+ me.myEventCls.onIds("#" + me.pre + "reload_proteinname", "click", function(e) { let ic = me.icn3d;
12945
12990
  e.preventDefault();
12946
12991
  if(!me.cfg.notebook) dialog.dialog( "close" );
12947
- thisClass.setLogCmd("load gi " + $("#" + me.pre + "gi").val(), false);
12992
+ thisClass.setLogCmd("load protein " + $("#" + me.pre + "proteinname").val(), false);
12948
12993
  let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
12949
- window.open(hostUrl + '?gi=' + $("#" + me.pre + "gi").val(), urlTarget);
12994
+ window.open(hostUrl + '?protein=' + $("#" + me.pre + "proteinname").val(), urlTarget);
12950
12995
  });
12951
12996
 
12952
12997
  me.myEventCls.onIds("#" + me.pre + "reload_refseq", "click", function(e) { let ic = me.icn3d;
@@ -14307,13 +14352,15 @@ class Events {
14307
14352
  });
14308
14353
 
14309
14354
 
14310
- $(document).on("click", ".icn3d-addtrack", function(e) { me.icn3d;
14355
+ $(document).on("click", ".icn3d-addtrack", function(e) { let ic = me.icn3d;
14311
14356
  e.stopImmediatePropagation();
14312
14357
  $("#" + me.pre + "anno_custom")[0].checked = true;
14313
14358
  $("[id^=" + me.pre + "custom]").show();
14314
14359
  //e.preventDefault();
14315
14360
  let chainid = $(this).attr('chainid');
14361
+ let geneid = ic.chainsGene[chainid].geneId;
14316
14362
  $("#" + me.pre + "track_chainid").val(chainid);
14363
+ $("#" + me.pre + "track_geneid").val(geneid);
14317
14364
  me.htmlCls.dialogCls.openDlg('dl_addtrack', 'Add track for Chain: ' + chainid);
14318
14365
  $( "#" + me.pre + "track_gi" ).focus();
14319
14366
  });
@@ -14528,8 +14575,17 @@ class AlignSeq {
14528
14575
 
14529
14576
  let chainHash = {};
14530
14577
  if (alignChainArray !== undefined) {
14578
+
14531
14579
  for (let i = 0, il = alignChainArray.length; i < il; ++i) {
14532
- chainHash[alignChainArray[i]] = 1;
14580
+ let chainid = alignChainArray[i];
14581
+
14582
+ // make sure some residues are aligned
14583
+ if(ic.alnChainsSeq[chainid] && ic.alnChainsSeq[chainid].length > 0) {
14584
+ chainHash[chainid] = 1;
14585
+ }
14586
+ else {
14587
+ return { "sequencesHtml": sequencesHtml, "maxSeqCnt": maxSeqCnt };
14588
+ }
14533
14589
  }
14534
14590
  }
14535
14591
 
@@ -14721,7 +14777,7 @@ class AlignSeq {
14721
14777
  //sequencesHtml += "<div class='icn3d-residueLine' style='white-space:nowrap;'><div class='icn3d-seqTitle' chain='" + i + "' anno='" + j + "'>" + annotitle + "</div>" + resiHtmlArray[j] + "<br/></div>";
14722
14778
  sequencesHtml += "<div class='icn3d-residueLine' style='white-space:nowrap;'><div class='icn3d-seqTitle' anno='" + j + "'>" + annotitle + "</div>" + resiHtmlArray[j] + "<br/></div>";
14723
14779
  }
14724
-
14780
+
14725
14781
  sequencesHtml += '<div class="icn3d-seqTitle icn3d-link icn3d-blue" chain="' + i + '" anno="sequence" title="' + title + '">' + chainidTmp + ' </div><span class="icn3d-seqLine">' + seqHtml + '</span><br/>';
14726
14782
 
14727
14783
  if (index > 0) prevResCnt2nd += seqLength;
@@ -32260,6 +32316,8 @@ class Alternate {
32260
32316
  // change the display atom when alternating
32261
32317
  //Show structures one by one.
32262
32318
  alternateStructures() { let ic = this.icn3d, me = ic.icn3dui;
32319
+ ic.bAlernate = true;
32320
+
32263
32321
  //ic.transformCls.zoominSelection();
32264
32322
 
32265
32323
  // default ic.ALTERNATE_STRUCTURE = -1
@@ -32374,11 +32432,11 @@ class Alternate {
32374
32432
 
32375
32433
  //ic.glycanCls.showGlycans();
32376
32434
 
32435
+ ic.opts['rotationcenter'] = 'highlight center';
32436
+
32377
32437
  ic.drawCls.draw();
32378
32438
 
32379
32439
  ic.bShowHighlight = true;
32380
- //ic.opts['rotationcenter'] = 'molecule center';
32381
- ic.opts['rotationcenter'] = 'highlight center';
32382
32440
  }
32383
32441
 
32384
32442
  alternateWrapper() { let ic = this.icn3d; ic.icn3dui;
@@ -35560,13 +35618,13 @@ class SetOption {
35560
35618
  html += "<div>";
35561
35619
 
35562
35620
  if(colorType == 'normalized hydrophobic') {
35563
- html += "Dark green (W, F, Y, L, I, C, M): Hydrophobic<br>";
35564
- html += "Light green (G, V, S, T, A, N, P, Q): Polar<br>";
35621
+ html += "Dark green (W, F, L, I, Y, M, V, C): Hydrophobic<br>";
35622
+ html += "Light green (P, T, S, A, Q, N, G): Polar<br>";
35565
35623
  html += "Grey: Charged, not hydrophobic<br><br>";
35566
35624
  }
35567
35625
  else {
35568
- html += "Green (W, F, Y, L, I, C, M): Hydrophobic<br>";
35569
- html += "Yellow (G, V, S, T, A, N, P, Q): Polar<br>";
35626
+ html += "Green (W, F, L, I, Y, M, V, C): Hydrophobic<br>";
35627
+ html += "Yellow (P, T, S, A, Q, N, G): Polar<br>";
35570
35628
  html += "Red: Negatively Charged<br>";
35571
35629
  html += "Blue: Positively Charged<br><br>";
35572
35630
  }
@@ -36004,6 +36062,10 @@ class AnnoCddSite {
36004
36062
  let prevEmptyWidth = 0;
36005
36063
  let prevLineWidth = 0;
36006
36064
  let widthPerRes = 1;
36065
+
36066
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
36067
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
36068
+
36007
36069
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
36008
36070
  html += ic.showSeqCls.insertGap(chnid, i, '-');
36009
36071
  if(resPosArray.indexOf(i) != -1) {
@@ -36036,6 +36098,9 @@ class AnnoCddSite {
36036
36098
  html += '<span>-</span>'; //'<span>-</span>';
36037
36099
  }
36038
36100
  }
36101
+
36102
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
36103
+
36039
36104
  htmlTmp = '<span class="icn3d-residueNum" title="residue count">&nbsp;' + resCnt.toString() + ' Residues</span>';
36040
36105
  htmlTmp += '</span>';
36041
36106
  htmlTmp += '<br>';
@@ -36193,6 +36258,9 @@ class AnnoCddSite {
36193
36258
  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>';
36194
36259
  html2 += htmlTmp3 + htmlTmp;
36195
36260
  let pre = type + index.toString();
36261
+
36262
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
36263
+
36196
36264
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
36197
36265
  html += ic.showSeqCls.insertGap(chnid, i, '-');
36198
36266
 
@@ -36220,9 +36288,15 @@ class AnnoCddSite {
36220
36288
  html += '<span>-</span>'; //'<span>-</span>';
36221
36289
  }
36222
36290
  }
36291
+
36292
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
36293
+
36223
36294
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chnid]);
36224
36295
  let colorStr =(atom.color === undefined || atom.color.getHexString() === 'FFFFFF') ? 'DDDDDD' : atom.color.getHexString();
36225
36296
  let color =(atom.color !== undefined) ? colorStr : "CCCCCC";
36297
+
36298
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
36299
+
36226
36300
  if(me.cfg.blast_rep_id != chnid) { // regular
36227
36301
  for(let i = 0, il = fromArray.length; i < il; ++i) {
36228
36302
  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);
@@ -36299,6 +36373,10 @@ class AnnoCddSite {
36299
36373
  let prevEmptyWidth = 0;
36300
36374
  let prevLineWidth = 0;
36301
36375
  let widthPerRes = 1;
36376
+
36377
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
36378
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
36379
+
36302
36380
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
36303
36381
  html += ic.showSeqCls.insertGap(chnid, i, '-');
36304
36382
  let resi = ic.ParserUtilsCls.getResi(chnid, i);
@@ -36374,6 +36452,9 @@ class AnnoCddSite {
36374
36452
  html += '<span>-</span>'; //'<span>-</span>';
36375
36453
  }
36376
36454
  }
36455
+
36456
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
36457
+
36377
36458
  htmlTmp = '<span class="icn3d-residueNum" title="residue count">&nbsp;' + resCnt.toString() + ' Residues</span>';
36378
36459
  htmlTmp += '</span>';
36379
36460
  htmlTmp += '<br>';
@@ -36538,6 +36619,9 @@ class AnnoContact {
36538
36619
  let prevLineWidth = 0;
36539
36620
  let widthPerRes = 1;
36540
36621
 
36622
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
36623
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
36624
+
36541
36625
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
36542
36626
  html += ic.showSeqCls.insertGap(chnid, i, '-');
36543
36627
  let resi = ic.ParserUtilsCls.getResi(chnid, i);
@@ -36573,6 +36657,9 @@ class AnnoContact {
36573
36657
  html += '<span>-</span>'; //'<span>-</span>';
36574
36658
  }
36575
36659
  }
36660
+
36661
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
36662
+
36576
36663
  htmlTmp = '<span class="icn3d-residueNum" title="residue count">&nbsp;' + resCnt.toString() + ' Residues</span>';
36577
36664
  htmlTmp += '</span>';
36578
36665
  htmlTmp += '<br>';
@@ -36825,6 +36912,10 @@ class AnnoPTM {
36825
36912
  let prevEmptyWidth = 0;
36826
36913
  let prevLineWidth = 0;
36827
36914
  let widthPerRes = 1;
36915
+
36916
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
36917
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
36918
+
36828
36919
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
36829
36920
  html += ic.showSeqCls.insertGap(chnid, i, '-');
36830
36921
  if(resPosArray.indexOf(i) != -1) {
@@ -36857,6 +36948,9 @@ class AnnoPTM {
36857
36948
  html += '<span>-</span>'; //'<span>-</span>';
36858
36949
  }
36859
36950
  }
36951
+
36952
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
36953
+
36860
36954
  htmlTmp = '<span class="icn3d-residueNum" title="residue count">&nbsp;' + resCnt.toString() + ' Residues</span>';
36861
36955
  htmlTmp += '</span>';
36862
36956
  htmlTmp += '<br>';
@@ -37136,6 +37230,9 @@ class AnnoDomain {
37136
37230
  html += htmlTmp2 + htmlTmp3 + htmlTmp;
37137
37231
  html2 += htmlTmp2 + htmlTmp3 + htmlTmp;
37138
37232
  let pre = 'domain3d' + index.toString();
37233
+
37234
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
37235
+
37139
37236
  for(let i = 0, il = ic.giSeq[chnid].length; i < il; ++i) {
37140
37237
  html += ic.showSeqCls.insertGap(chnid, i, '-');
37141
37238
  //if(i >= domainFrom && i <= domainTo) {
@@ -37155,9 +37252,15 @@ class AnnoDomain {
37155
37252
  html += '<span>-</span>'; //'<span>-</span>';
37156
37253
  }
37157
37254
  }
37255
+
37256
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
37257
+
37158
37258
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chnid]);
37159
37259
  let colorStr =(atom.color === undefined || atom.color.getHexString() === 'FFFFFF') ? 'DDDDDD' : atom.color.getHexString();
37160
37260
  let color =(atom.color !== undefined) ? colorStr : "CCCCCC";
37261
+
37262
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
37263
+
37161
37264
  if(me.cfg.blast_rep_id != chnid) { // regular
37162
37265
  for(let i = 0, il = fromArray.length; i < il; ++i) {
37163
37266
  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);
@@ -37425,9 +37528,18 @@ class AnnoSnpClinVar {
37425
37528
  let prevEmptyWidth = 0;
37426
37529
  let prevLineWidth = 0;
37427
37530
  let widthPerRes = 1;
37531
+
37532
+ if(bOverview) {
37533
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
37534
+ }
37535
+ else {
37536
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
37537
+ }
37538
+
37428
37539
  for(let i = 1, il = ic.giSeq[chnid].length; i <= il; ++i) {
37429
37540
  if(bOverview) {
37430
37541
  if(resi2index[i] !== undefined) {
37542
+
37431
37543
  // get the mouse over text
37432
37544
  let cFull = ic.giSeq[chnid][i-1];
37433
37545
  let c = cFull;
@@ -37452,7 +37564,8 @@ class AnnoSnpClinVar {
37452
37564
  }
37453
37565
  }
37454
37566
  html += ic.showSeqCls.insertGapOverview(chnid, i-1);
37455
- 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);
37567
+ let emptyWidth = Math.round(ic.seqAnnWidth *(i-1) /(ic.maxAnnoLength + ic.nTotalGap) - prevEmptyWidth - prevLineWidth);
37568
+ //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);
37456
37569
  //if(emptyWidth < 0) emptyWidth = 0;
37457
37570
  if(bClinvar) {
37458
37571
  if(snpTypeHash[i] == 'icn3d-clinvar' || snpTypeHash[i] == 'icn3d-clinvar-path') {
@@ -37681,6 +37794,10 @@ class AnnoSnpClinVar {
37681
37794
  }
37682
37795
  } // if(bOverview) {
37683
37796
  } // for
37797
+
37798
+ if(!bOverview) {
37799
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
37800
+ }
37684
37801
 
37685
37802
  //var end = bStartEndRes ? ic.chainsSeq[chnid][ic.giSeq[chnid].length - 1 - ic.matchedPos[chnid] ].resi : '';
37686
37803
  if(line == 1) {
@@ -39125,7 +39242,7 @@ class Domain3d {
39125
39242
  return {subdomains: subdomains, substruct: substruct, pos2resi: pos2resi };
39126
39243
  } // end c2b_NewSplitChain
39127
39244
 
39128
- getDomainJsonForAlign(atoms) { let ic = this.icn3d, me = ic.icn3dui;
39245
+ getDomainJsonForAlign(atoms, bForceOneDomain) { let ic = this.icn3d, me = ic.icn3dui;
39129
39246
  let result = this.c2b_NewSplitChain(atoms);
39130
39247
 
39131
39248
  let subdomains = result.subdomains;
@@ -39136,6 +39253,8 @@ class Domain3d {
39136
39253
  let residueArray = Object.keys(residueHash);
39137
39254
  let chnid = residueArray[0].substr(0, residueArray[0].lastIndexOf('_'));
39138
39255
 
39256
+ if(bForceOneDomain) subdomains = [];
39257
+
39139
39258
  //the whole structure is also considered as a large domain
39140
39259
  //if(subdomains.length == 0) {
39141
39260
  //subdomains.push([parseInt(ic.chainsSeq[chnid][0].resi), parseInt(ic.chainsSeq[chnid][ic.chainsSeq[chnid].length - 1].resi)]);
@@ -39292,7 +39411,7 @@ class AddTrack {
39292
39411
  thisClass.alignSequenceToStructure(chainid, data, title);
39293
39412
  });
39294
39413
 
39295
- // FASTA Alignment
39414
+ // MSA
39296
39415
  me.myEventCls.onIds("#" + ic.pre + "addtrack_button2b", "click", async function(e) { let ic = thisClass.icn3d;
39297
39416
  e.stopImmediatePropagation();
39298
39417
  //e.preventDefault();
@@ -39300,159 +39419,47 @@ class AddTrack {
39300
39419
 
39301
39420
  let chainid = $("#" + ic.pre + "track_chainid").val();
39302
39421
  let startpos = $("#" + ic.pre + "fasta_startpos").val();
39422
+ if(!startpos) startpos = 1;
39423
+
39303
39424
  let colorseqby = $("#" + ic.pre + "colorseqby").val();
39304
39425
  let type =(colorseqby == 'identity') ? 'identity' : 'custom';
39305
39426
 
39306
39427
  let fastaList = $("#" + ic.pre + "track_fastaalign").val();
39307
- let fastaArray = fastaList.split('>');
39308
-
39309
- // the first array item is empty
39310
- // the second array item is the sequence of the structure, start with i = 2
39311
- let posFirst = fastaArray[1].indexOf('\n');
39312
- fastaArray[1].substr(0, posFirst);
39313
- let seqFirst = fastaArray[1].substr(posFirst + 1).replace(/\n/g, '');
39314
-
39315
- let trackTitleArray = [];
39316
- let trackSeqArray = [];
39317
- for(let i = 2, il = fastaArray.length; i < il; ++i) {
39318
- let pos = fastaArray[i].indexOf('\n');
39319
- let title = fastaArray[i].substr(0, pos);
39320
- trackTitleArray.push(title);
39321
- let seq = fastaArray[i].substr(pos + 1).replace(/\n/g, '');
39322
- trackSeqArray.push(seq);
39323
- }
39324
-
39325
- let startposGiSeq = undefined;
39326
- for(let i = 0, il = ic.giSeq[chainid].length; i < il; ++i) {
39327
- //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;
39328
- let pos = ic.ParserUtilsCls.getResi(chainid, i);
39329
-
39330
- if(pos != startpos) {
39331
- continue;
39332
- }
39333
- else {
39334
- startposGiSeq = i;
39335
- }
39336
- }
39337
-
39338
- if(startposGiSeq === undefined) var aaa = 1; //alert("Please double check the start position before clicking \"Add Track\"");
39339
-
39340
-
39341
- // set up gap for the master seq
39342
- // don't count gaps in both ends
39343
- ic.targetGapHash = {};
39344
- let prevSeq = '-', prevPos = 0, from, to, cnt = 0, dashCnt = 0;
39345
- let bFound = false, seqStart = 0, seqEnd = 0;
39346
- for(let i = 0, il = seqFirst.length; i < il; ++i) {
39347
- if(seqFirst[i] == '-' && seqFirst[i] != prevSeq) { // start of gap
39348
- from = cnt;
39349
- dashCnt = 0;
39350
- }
39351
-
39352
- if(prevSeq == '-' && seqFirst[i] != prevSeq && cnt > 0) { // end of gap
39353
- to = prevPos;
39354
- ic.targetGapHash[from + startposGiSeq] = {'from': from + startposGiSeq, 'to': to + dashCnt - 1 + startposGiSeq};
39355
- }
39356
-
39357
- prevSeq = seqFirst[i];
39358
- prevPos = cnt;
39359
-
39360
- if(seqFirst[i] != '-') {
39361
- ++cnt;
39362
- seqEnd = i;
39363
-
39364
- if(!bFound) {
39365
- seqStart = i;
39366
- bFound = true;
39367
- }
39368
- }
39369
- else {
39370
- ++dashCnt;
39371
- }
39372
- }
39373
-
39374
- await ic.annotationCls.resetAnnoAll();
39375
-
39376
- let targetGapHashStr = '';
39377
- let cntTmp = 0;
39378
- for(let i in ic.targetGapHash) {
39379
- if(cntTmp > 0) targetGapHashStr += ' ';
39380
- targetGapHashStr += i + '_' + ic.targetGapHash[i].from + '_' + ic.targetGapHash[i].to;
39381
- ++cntTmp;
39382
- }
39383
-
39384
- me.htmlCls.clickMenuCls.setLogCmd("msa | " + targetGapHashStr, true);
39385
-
39386
- // add tracks
39387
- let resi2cntSameRes = {}; // count of same residue at each position
39388
- for(let j = 0, jl = trackSeqArray.length; j < jl; ++j) {
39389
- let resi = startpos; //startposGiSeq + 1;
39390
- let text = '';
39391
- for(let k = 0; k < startposGiSeq; ++k) {
39392
- if(ic.targetGapHash.hasOwnProperty(k)) {
39393
- for(let m = 0; m < ic.targetGapHash[k].to - ic.targetGapHash[k].from + 1; ++m) {
39394
- text += '-';
39395
- }
39396
- }
39397
-
39398
- text += '-';
39399
- }
39400
-
39401
- for(let k = seqStart; k <= seqEnd; ++k) {
39402
- //if(seqFirst[k] == '-') continue;
39403
-
39404
- if(j == 0) resi2cntSameRes[resi] = 0;
39405
-
39406
- text += trackSeqArray[j][k]; //ic.giSeq[chainid][i];
39407
-
39408
- if(seqFirst[k] != '-') {
39409
- if(seqFirst[k] == trackSeqArray[j][k]) ++resi2cntSameRes[resi];
39410
- ++resi;
39411
- }
39412
- }
39413
-
39414
- let title =(trackTitleArray[j].length < 20) ? trackTitleArray[j] : trackTitleArray[j].substr(0, 20) + '...';
39415
- let bMsa = true;
39416
- thisClass.showNewTrack(chainid, title, text, undefined, undefined, type, undefined, bMsa);
39417
-
39418
- me.htmlCls.clickMenuCls.setLogCmd("add track | chainid " + chainid + " | title " + title + " | text " + thisClass.simplifyText(text)
39419
- + " | type " + type + " | color 0 | msa 1", true);
39420
- }
39421
39428
 
39422
- // set colot for the master seq
39423
- if(trackSeqArray.length > 0) {
39424
- if(ic.queryresi2score === undefined) ic.queryresi2score = {};
39425
- if(ic.queryresi2score[chainid] === undefined) ic.queryresi2score[chainid] = {};
39426
-
39427
- let nSeq = trackSeqArray.length;
39428
- for(let resi in resi2cntSameRes) {
39429
- let score = parseInt(resi2cntSameRes[resi] / nSeq * 100);
39430
- ic.queryresi2score[chainid][resi] = score;
39431
- }
39429
+ if(fastaList) {
39430
+ await thisClass.addMsaTracks(chainid, startpos, type, fastaList);
39431
+ }
39432
+ });
39432
39433
 
39433
- let resiArray = Object.keys(resi2cntSameRes);
39434
- let start = Math.min.apply(null, resiArray);
39435
- let end = Math.max.apply(null, resiArray);
39434
+ // Gene table
39435
+ me.myEventCls.onIds("#" + ic.pre + "exons_table", "click", async function(e) { let ic = thisClass.icn3d;
39436
+ e.stopImmediatePropagation();
39437
+ //dialog.dialog( "close" );
39436
39438
 
39437
- let resiScoreStr = '';
39438
- for(let resi = start; resi <= end; ++resi) {
39439
- if(resi2cntSameRes.hasOwnProperty(resi)) {
39440
- resiScoreStr += Math.round(resi2cntSameRes[resi] / nSeq * 9); // max 9
39441
- }
39442
- else {
39443
- resiScoreStr += '_';
39444
- }
39445
- }
39439
+ let geneid = $("#" + ic.pre + "track_geneid").val().trim();
39440
+ window.open('https://www.ncbi.nlm.nih.gov/gene/' + geneid + '?report=gene_table', '_blank');
39441
+ });
39446
39442
 
39447
- ic.opts['color'] = 'align custom';
39448
- ic.setColorCls.setColorByOptions(ic.opts, ic.hAtoms);
39443
+ // Isoform Alignment
39444
+ me.myEventCls.onIds("#" + ic.pre + "addtrack_button2c", "click", async function(e) { let ic = thisClass.icn3d;
39445
+ e.stopImmediatePropagation();
39446
+ //e.preventDefault();
39447
+ dialog.dialog( "close" );
39449
39448
 
39450
- ic.hlUpdateCls.updateHlAll();
39449
+ let chainid = $("#" + ic.pre + "track_chainid").val();
39450
+ let geneid = $("#" + ic.pre + "track_geneid").val();
39451
+ if(!geneid) {
39452
+ var aaa = 1; //alert("Please fill in the Gene ID...");
39453
+ return;
39454
+ }
39451
39455
 
39452
- ic.drawCls.draw();
39456
+ let startpos = $("#" + ic.pre + "fasta_startpos2").val();
39457
+ if(!startpos) startpos = 1;
39453
39458
 
39454
- me.htmlCls.clickMenuCls.setLogCmd('color align custom | ' + chainid + ' | range ' + start + '_' + end + ' | ' + resiScoreStr, true);
39455
- }
39459
+ let colorseqby = $("#" + ic.pre + "colorseqby2").val();
39460
+ let type =(colorseqby == 'identity') ? 'identity' : 'custom';
39461
+
39462
+ await thisClass.addExonTracks(chainid, geneid, startpos, type);
39456
39463
  });
39457
39464
 
39458
39465
  // BED file
@@ -39638,7 +39645,7 @@ class AddTrack {
39638
39645
 
39639
39646
  }
39640
39647
 
39641
- showNewTrack(chnid, title, text, cssColorArray, inTarget2queryHash, type, color, bMsa, fromArray, toArray) { let ic = this.icn3d, me = ic.icn3dui;
39648
+ showNewTrack(chnid, title, text, cssColorArray, inTarget2queryHash, type, color, bMsa, fromArray, toArray, seqStartLen, exonArray) { let ic = this.icn3d, me = ic.icn3dui;
39642
39649
  //if(ic.customTracks[chnid] === undefined) {
39643
39650
  // ic.customTracks[chnid] = {}
39644
39651
  //}
@@ -39687,22 +39694,28 @@ class AddTrack {
39687
39694
  $("#" + ic.pre + "tt_custom_" + chnid + "_" + simpTitle).width(divLength);
39688
39695
 
39689
39696
  let html = '<div id="' + ic.pre + 'giseq_sequence" class="icn3d-dl_sequence">';
39697
+ let htmlExon = html;
39690
39698
  let html2 = html;
39691
39699
  let html3 = html;
39700
+ let html3Exon = html;
39692
39701
 
39693
39702
  //var htmlTmp2 = '<div class="icn3d-seqTitle icn3d-link icn3d-blue" gi="' + chnid + '" anno="sequence" chain="' + chnid + '"><span style="white-space:nowrap;">' + title + '</span></div>';
39694
39703
  //var htmlTmp2 = '<div class="icn3d-seqTitle" gi="' + chnid + '" anno="sequence" chain="' + chnid + '"><span style="white-space:nowrap;">' + title + '</span></div>';
39695
39704
  let index = parseInt(Math.random()*10);
39696
39705
  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>';
39706
+ let htmlTmp2Exon = '<div class="icn3d-seqTitle" chain="' + chnid + '" title="Exons of ' + title + '">Exons </div>';
39707
+
39697
39708
  let htmlTmp3 = '<span class="icn3d-residueNum" title="residue count">' + resCnt.toString() + ' Pos</span>';
39698
39709
 
39699
39710
  html3 += htmlTmp2 + htmlTmp3 + '<br>';
39711
+ html3Exon += htmlTmp2Exon + htmlTmp3 + '<br>';
39700
39712
 
39701
39713
  let htmlTmp = '<span class="icn3d-seqLine">';
39702
39714
 
39703
39715
  html += htmlTmp2 + htmlTmp3 + htmlTmp;
39716
+ htmlExon += htmlTmp2Exon + htmlTmp3 + htmlTmp;
39704
39717
  html2 += htmlTmp2 + htmlTmp3 + htmlTmp;
39705
-
39718
+
39706
39719
  //var pre ='cst' + ic.customTracks[chnid].length;
39707
39720
  let posTmp = chnid.indexOf('_');
39708
39721
  //var pre ='cst' + chnid.substr(posTmp);
@@ -39717,10 +39730,34 @@ class AddTrack {
39717
39730
  let bIdentityColor =(type === 'identity') && text.indexOf('cannot-be-aligned') == -1 && text.indexOf('cannot be aligned') == -1 ? true : false;
39718
39731
 
39719
39732
  let parsedResn = {};
39720
- let gapCnt = 0, currResi = 1;
39733
+ let gapCnt = 0;
39721
39734
  htmlTmp2 = '';
39735
+
39736
+ // if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += ic.showSeqCls.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
39737
+ // if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqStartLen[chnid], '-');
39738
+
39739
+ let pos2exonColor = {}, pos2genome = {}, pos2exonIndex = {};
39740
+ let cnt = 0;
39741
+ if(exonArray) {
39742
+ for(let j = 0, jl = exonArray.length; j < jl; ++j) {
39743
+ let start = exonArray[j].resStart, end = exonArray[j].resEnd;
39744
+ let genStart = exonArray[j].genomeRange.split('-')[0];
39745
+
39746
+ for(let k = 0, kl = end - start + 1; k < kl; ++k) {
39747
+ let colorStr = this.getExonColor(start, end, cnt);
39748
+
39749
+ pos2exonColor[cnt] = colorStr;
39750
+ pos2genome[cnt] = (genStart + ic.exonOrder * k*3) + '-' + (genStart + ic.exonOrder * k*3 + ic.exonOrder * 2); // reverse order from large to small
39751
+ pos2exonIndex[cnt] = j;
39752
+
39753
+ ++cnt;
39754
+ }
39755
+ }
39756
+ }
39757
+
39758
+ cnt = 0;
39722
39759
  for(let i = 0, il = text.length; i < il; ++i) {
39723
- let resNum = i-gapCnt;
39760
+ let resNum = i - gapCnt - ((ic.seqStartLen && ic.seqStartLen[chnid]) ? ic.seqStartLen[chnid] : 0);
39724
39761
 
39725
39762
  if(!bMsa) {
39726
39763
  html += ic.showSeqCls.insertGap(chnid, i, '-');
@@ -39741,7 +39778,8 @@ class AddTrack {
39741
39778
  let identityColorStr =(c == resName) ? 'FF0000' : '0000FF';
39742
39779
 
39743
39780
  //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;
39744
- let pos = ic.baseResi[chnid] + currResi;
39781
+ // let pos = ic.baseResi[chnid] + currResi;
39782
+ let pos = ic.baseResi[chnid] + (i+1) - ((ic.seqStartLen && ic.seqStartLen[chnid]) ? ic.seqStartLen[chnid] : 0);
39745
39783
 
39746
39784
  if(inTarget2queryHash !== undefined) pos = ic.baseResi[chnid] + inTarget2queryHash[i] + 1; // 0-based
39747
39785
 
@@ -39772,9 +39810,13 @@ class AddTrack {
39772
39810
 
39773
39811
  html += '<span id="' + pre + '_' + ic.pre + chnid + '_' + pos + '" title="' + c + pos + '" class="icn3d-residue" ' + tmpStr + '>' + c + '</span>';
39774
39812
 
39813
+ let tmpStrExon = 'style="background-color:' + pos2exonColor[cnt] + '"';
39814
+ htmlExon += '<span id="' + pre + '_' + ic.pre + chnid + '_' + pos + '" title="' + c + pos + ', Exon ' + (pos2exonIndex[cnt] + 1) + ': ' + pos2genome[cnt] + '" class="icn3d-residue" ' + tmpStrExon + '>&nbsp;</span>';
39815
+
39775
39816
  htmlTmp2 += ic.showSeqCls.insertGapOverview(chnid, i);
39776
39817
 
39777
- 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);
39818
+ // 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);
39819
+ let emptyWidth = Math.round(ic.seqAnnWidth * i /(ic.maxAnnoLength + ic.nTotalGap) - prevEmptyWidth - prevLineWidth);
39778
39820
  if(emptyWidth < 0) emptyWidth = 0;
39779
39821
 
39780
39822
  htmlTmp2 += '<div style="display:inline-block; width:' + emptyWidth + 'px;">&nbsp;</div>';
@@ -39795,19 +39837,21 @@ class AddTrack {
39795
39837
 
39796
39838
  prevEmptyWidth += emptyWidth;
39797
39839
  prevLineWidth += widthPerRes;
39798
-
39799
- ++currResi;
39840
+ ++cnt;
39800
39841
  }
39801
39842
  else {
39802
39843
  if(bErrorMess) {
39803
- html += '<span>' + c + '</span>';
39844
+ html += '<span>' + c + '</span>';
39804
39845
  }
39805
39846
  else {
39806
39847
  html += '<span>-</span>';
39848
+ htmlExon += '<span></span>';
39807
39849
  }
39808
39850
  }
39809
39851
  }
39810
39852
 
39853
+ // if(ic.seqStartLen && ic.seqStartLen[chnid]) html += ic.showSeqCls.insertMulGap(ic.seqEndLen[chnid], '-');
39854
+
39811
39855
  if(fromArray !== undefined) {
39812
39856
  htmlTmp2 = '';
39813
39857
  let fromArray2 = [], toArray2 = [];
@@ -39833,13 +39877,77 @@ class AddTrack {
39833
39877
  let colorStr =(atom.color === undefined || atom.color.getHexString() === 'FFFFFF') ? 'DDDDDD' : atom.color.getHexString();
39834
39878
  let color =(atom.color !== undefined) ? colorStr : "CCCCCC";
39835
39879
 
39880
+ let cnt, prevCntTotal = 0;
39836
39881
  for(let i = 0, il = fromArray2.length; i < il; ++i) {
39837
39882
  htmlTmp2 += ic.showSeqCls.insertGapOverview(chnid, fromArray2[i]);
39838
39883
 
39839
- 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));
39884
+ let initialPos = (seqStartLen) ? fromArray2[i] : fromArray2[i] - ic.baseResi[chnid] - 1;
39885
+
39886
+ 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));
39887
+ if(emptyWidth < 0) emptyWidth = 0;
39888
+
39840
39889
  htmlTmp2 += '<div style="display:inline-block; width:' + emptyWidth + 'px;">&nbsp;</div>';
39841
39890
 
39842
- 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>';
39891
+ if(!exonArray) {
39892
+ 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>';
39893
+ }
39894
+ else {
39895
+ // determine how this range sits in the exon ranges in exonArray
39896
+ let startExon, endExon;
39897
+
39898
+ cnt = toArray[i] - fromArray[i] + 1;
39899
+ let from = prevCntTotal, to = prevCntTotal + cnt - 1;
39900
+
39901
+ prevCntTotal += cnt;
39902
+
39903
+ // fromArray2 was adjusted with gaps, no gaps in this case
39904
+ // let offset = fromArray2[i] - fromArray[i];
39905
+ // let emptyWidth = Math.round(ic.seqAnnWidth * offset /(ic.maxAnnoLength + ic.nTotalGap));
39906
+ // htmlTmp2 += '<div style="display:inline-block; width:' + emptyWidth + 'px;">&nbsp;</div>';
39907
+
39908
+ for(let j = 0, jl = exonArray.length; j < jl; ++j) {
39909
+ let start = exonArray[j].resStart, end = exonArray[j].resEnd;
39910
+
39911
+ if(from >= start && from <= end) {
39912
+ startExon = {exonIndex: j, rangeStart: start, rangeEnd: end, from: from, genomeRange: exonArray[j].genomeRange};
39913
+ }
39914
+
39915
+ if(to >= start && to <= end) {
39916
+ endExon = {exonIndex: j, rangeStart: start, rangeEnd: end, to: to, genomeRange: exonArray[j].genomeRange};
39917
+ }
39918
+ }
39919
+
39920
+ let startColorStr, endColorStr, colorGradient;
39921
+ if(startExon && endExon && startExon.exonIndex == endExon.exonIndex) { //
39922
+ startColorStr = this.getExonColor(startExon.rangeStart, startExon.rangeEnd, from);
39923
+ endColorStr = this.getExonColor(startExon.rangeStart, startExon.rangeEnd, to);
39924
+
39925
+ colorGradient = startColorStr + ' 0%, #FFF 50%, ' + endColorStr + ' 100%';
39926
+ htmlTmp2 += this.getExonHtml(startExon.exonIndex, colorGradient, startExon.from, endExon.to, startExon.genomeRange);
39927
+ }
39928
+ else {
39929
+ if(startExon) {
39930
+ startColorStr = this.getExonColor(startExon.rangeStart, startExon.rangeEnd, from);
39931
+
39932
+ colorGradient = startColorStr + ' 0%, #FFF 50%, #00F 100%';
39933
+ htmlTmp2 += this.getExonHtml(startExon.exonIndex, colorGradient, startExon.from, startExon.rangeEnd, startExon.genomeRange);
39934
+ }
39935
+
39936
+ if(startExon && endExon) {
39937
+ for(let j = startExon.exonIndex + 1; j < endExon.exonIndex; ++j) {
39938
+ colorGradient = '#F00 0%, #FFF 50%, #00F 100%';
39939
+ htmlTmp2 += this.getExonHtml(j, colorGradient, exonArray[j].resStart, exonArray[j].resEnd, exonArray[j].genomeRange);
39940
+ }
39941
+
39942
+ endColorStr = this.getExonColor(endExon.rangeStart, endExon.rangeEnd, to);
39943
+
39944
+ colorGradient = '#F00 0%, #FFF 50%, ' + endColorStr + ' 100%';
39945
+ htmlTmp2 += this.getExonHtml(endExon.exonIndex, colorGradient, endExon.rangeStart, endExon.to, endExon.genomeRange);
39946
+ }
39947
+ }
39948
+
39949
+ //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>';
39950
+ }
39843
39951
  }
39844
39952
  }
39845
39953
 
@@ -39851,12 +39959,37 @@ class AddTrack {
39851
39959
 
39852
39960
  html += htmlTmp;
39853
39961
  html2 += htmlTmp2 + htmlTmp;
39962
+ htmlExon += htmlTmp;
39854
39963
 
39855
39964
  html3 += '</div>';
39965
+ html3Exon += '</div>';
39856
39966
 
39857
- $("#" + ic.pre + "dt_custom_" + chnid + "_" + simpTitle).html(html);
39858
- $("#" + ic.pre + "ov_custom_" + chnid + "_" + simpTitle).html(html2);
39859
- $("#" + ic.pre + "tt_custom_" + chnid + "_" + simpTitle).html(html3);
39967
+ if(!exonArray) {
39968
+ $("#" + ic.pre + "dt_custom_" + chnid + "_" + simpTitle).html(html);
39969
+ $("#" + ic.pre + "ov_custom_" + chnid + "_" + simpTitle).html(html2);
39970
+ $("#" + ic.pre + "tt_custom_" + chnid + "_" + simpTitle).html(html3);
39971
+ }
39972
+ else {
39973
+ $("#" + ic.pre + "dt_custom_" + chnid + "_" + simpTitle).html(htmlExon + html);
39974
+ $("#" + ic.pre + "ov_custom_" + chnid + "_" + simpTitle).html(html2);
39975
+ $("#" + ic.pre + "tt_custom_" + chnid + "_" + simpTitle).html(html3Exon + html3);
39976
+ }
39977
+ }
39978
+
39979
+ getExonHtml(exonIndex, colorGradient, from, to, genomeRange) { let ic = this.icn3d; ic.icn3dui;
39980
+ 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>';
39981
+ }
39982
+
39983
+ getExonColor(start, end, pos) { let ic = this.icn3d; ic.icn3dui;
39984
+ let middle = ( start + end) * 0.5;
39985
+ if(pos < middle) {
39986
+ let gb = parseInt((pos - start) / (middle - start) * 255);
39987
+ return "rgb(255, " + gb + ", " + gb + ")";
39988
+ }
39989
+ else {
39990
+ let rg = parseInt((end - pos) / (end - middle) * 255);
39991
+ return "rgb(" + rg + ", " + rg + ", 255)";
39992
+ }
39860
39993
  }
39861
39994
 
39862
39995
  alignSequenceToStructure(chainid, data, title) { let ic = this.icn3d, me = ic.icn3dui;
@@ -40164,6 +40297,7 @@ class AddTrack {
40164
40297
  let result = this.getFullText(text);
40165
40298
  text = result.text;
40166
40299
  this.showNewTrack(chainid, title, text, undefined, undefined, type, color, bMsa);
40300
+
40167
40301
  return false;
40168
40302
  }
40169
40303
 
@@ -40286,6 +40420,722 @@ class AddTrack {
40286
40420
  }
40287
40421
  }
40288
40422
 
40423
+ async getMsa(acclist, firstAcc, chainSeq) { let ic = this.icn3d, me = ic.icn3dui;
40424
+ let trackTitleArray = [firstAcc], trackSeqArray = [];
40425
+ // get all seq
40426
+ let url = me.htmlCls.baseUrl + "/vastdyn/vastdyn.cgi?chainlist=" + acclist;
40427
+ let data = await me.getAjaxPromise(url, 'jsonp');
40428
+ let maxLen = 0, maxIndex = 0, index = 0;
40429
+ //let seqArray = [];
40430
+ for(let acc in data) {
40431
+ let seq = data[acc];
40432
+ //seqArray.push(seq);
40433
+
40434
+ let pos = acc.indexOf('.');
40435
+ if(pos != -1) {
40436
+ acc = acc.substr(0, pos);
40437
+ }
40438
+ trackTitleArray.push(acc);
40439
+
40440
+ if(seq.length > maxLen) {
40441
+ maxLen = seq.length;
40442
+ maxIndex = index;
40443
+ }
40444
+ ++index;
40445
+ }
40446
+
40447
+ // pairwise align each seq to the one with maxIndex
40448
+ url = me.htmlCls.baseUrl + 'pwaln/pwaln.fcgi?from=msa';
40449
+
40450
+ let accArray = acclist.split(',');
40451
+ // oroginal index, chain as the first one
40452
+ let acc2index = {};
40453
+ acc2index[firstAcc] = 0;
40454
+ for(let i = 0, il = accArray.length; i < il; ++i) {
40455
+ acc2index[accArray[i]] = i + 1;
40456
+ }
40457
+ let targetId = accArray[maxIndex];
40458
+ accArray.splice(maxIndex, 1);
40459
+
40460
+ let queries = (chainSeq) ? chainSeq : firstAcc;
40461
+ if(accArray.length > 0) queries += ',' + accArray.join(',');
40462
+
40463
+ let dataObj = {'targets': targetId, 'queries': queries};
40464
+ let alignData = await me.getAjaxPostPromise(url, dataObj);
40465
+
40466
+ if(!alignData.data) {
40467
+ console.log("The protein accessions " + targetId + "," + queries + " can not be aligned...");
40468
+ return;
40469
+ }
40470
+
40471
+ // get aligned length for each pair
40472
+ let index_alignLen = [];
40473
+ ic.qt_start_end = {};
40474
+ // target: targetId
40475
+ // queries: accArray
40476
+ let accArrayFound = [], querySeqArray = [];
40477
+ let firstKey = Object.keys(alignData.targets)[0];
40478
+ let targetSeq = alignData.targets[firstKey].seqdata;
40479
+
40480
+ //add firstAcc to accArray
40481
+ accArray.splice(0, 0, firstAcc);
40482
+
40483
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40484
+ let query, target;
40485
+
40486
+ if(!alignData.data[index]) {
40487
+ continue;
40488
+ }
40489
+
40490
+ query = alignData.data[index].query;
40491
+ let acc;
40492
+ if(query.acc.length <= 5) { // PDB
40493
+ acc = query.acc.substr(0, 4) + '_' + query.acc.substr(4, 1);
40494
+ }
40495
+ else {
40496
+ acc = query.acc;
40497
+ }
40498
+
40499
+ if(index == 0) acc = firstAcc;
40500
+
40501
+ accArrayFound.push(acc);
40502
+
40503
+ firstKey = Object.keys(alignData.data[index].targets)[0];
40504
+ target = alignData.data[index].targets[firstKey];
40505
+
40506
+ target = target.hsps[0];
40507
+
40508
+ querySeqArray.push(query.seqdata);
40509
+ let alignLen = target.scores.num_ident * 100 + query.sz; // order by aligned seq length, then seq length
40510
+
40511
+ ic.qt_start_end[index] = [];
40512
+
40513
+ let segArray = target.segs;
40514
+ for(let i = 0, il = segArray.length; i < il; ++i) {
40515
+ let seg = segArray[i];
40516
+ let qt_start_end = {t_start: seg.orifrom, t_end: seg.orito, q_start: seg.from, q_end: seg.to};
40517
+ ic.qt_start_end[index].push(qt_start_end);
40518
+ }
40519
+
40520
+ index_alignLen.push({index: index, alignLen: alignLen});
40521
+ }
40522
+
40523
+ accArray = accArrayFound;
40524
+
40525
+ index_alignLen.sort(function(a,b){
40526
+ return b.alignLen - a.alignLen;
40527
+ });
40528
+
40529
+ // start and end of MSA
40530
+ let start_t = 9999, end_t = -1;
40531
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40532
+ if(!ic.qt_start_end[index]) continue;
40533
+
40534
+ for(let i = 0, il = ic.qt_start_end[index].length; i < il; ++i) {
40535
+ let start1, end1;
40536
+
40537
+ start1 = ic.qt_start_end[index][i].t_start;
40538
+ end1 = ic.qt_start_end[index][i].t_end;
40539
+
40540
+ for(let j = start1; j <= end1; ++j) {
40541
+ if(j < start_t) start_t = j;
40542
+ if(j > end_t) end_t = j;
40543
+ }
40544
+ }
40545
+ }
40546
+
40547
+ // N- and C-terminal residues
40548
+ let maxNtermLen = start_t, maxCtermLen = targetSeq.length - (end_t + 1);
40549
+ let startArray = [], endArray = [];
40550
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40551
+ if(!ic.qt_start_end[index]) continue;
40552
+
40553
+ let qPos = ic.qt_start_end[index][0].q_start;
40554
+ startArray.push(qPos);
40555
+ if(maxNtermLen < qPos) maxNtermLen = qPos;
40556
+
40557
+ let lastIndex = ic.qt_start_end[index].length - 1;
40558
+ qPos = ic.qt_start_end[index][lastIndex].q_end;
40559
+ endArray.push(qPos);
40560
+ let dist = querySeqArray[index].length - (qPos + 1);
40561
+ if(maxCtermLen < dist) maxCtermLen = dist;
40562
+ }
40563
+
40564
+ ic.msaSeq = {};
40565
+ // assign the template
40566
+ ic.msaSeq[targetId] = '';
40567
+
40568
+ for(let i = start_t; i <= end_t; ++i) {
40569
+ ic.msaSeq[targetId] += targetSeq[i];
40570
+ }
40571
+
40572
+ // progressively merge sequences, starting from most similar to least similar
40573
+ let alignedChainIndice = [0];
40574
+ for(let arrayIndex = 0, arrayIndexl = index_alignLen.length; arrayIndex < arrayIndexl; ++arrayIndex) {
40575
+ let index = index_alignLen[arrayIndex].index;
40576
+ alignedChainIndice.push(index);
40577
+
40578
+ ic.msaSeq[accArray[index]] = '';
40579
+
40580
+ // some proteins may not be aligned
40581
+ if(!querySeqArray[index]) continue;
40582
+
40583
+ ic.setSeqAlignCls.mergeTwoSeqForAllSimple(targetId, accArray, index, alignedChainIndice, start_t, end_t, querySeqArray);
40584
+ }
40585
+
40586
+ // add N-terminal seq
40587
+ let seqN = '', cnt;
40588
+ for(let i = 0; i < maxNtermLen - start_t; ++i) {
40589
+ seqN += '-';
40590
+ }
40591
+ for(let i = 0; i < start_t; ++i) {
40592
+ seqN += targetSeq[i];
40593
+ }
40594
+ ic.msaSeq[targetId] = seqN + ic.msaSeq[targetId];
40595
+
40596
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40597
+ seqN = '';
40598
+ for(let i = 0; i < maxNtermLen - startArray[index]; ++i) {
40599
+ seqN += '-';
40600
+ }
40601
+ for(let i = 0; i < startArray[index]; ++i) {
40602
+ seqN += querySeqArray[index][i];
40603
+ }
40604
+
40605
+ ic.msaSeq[accArray[index]] = seqN + ic.msaSeq[accArray[index]];
40606
+ }
40607
+
40608
+ // add C-terminal seq
40609
+ for(let i = end_t + 1; i < targetSeq.length; ++i) {
40610
+ ic.msaSeq[targetId] += targetSeq[i];
40611
+ }
40612
+
40613
+ cnt = targetSeq.length - (end_t + 1);
40614
+ for(let i = 0; i < maxCtermLen - cnt; ++i) {
40615
+ ic.msaSeq[targetId] += '-';
40616
+ }
40617
+
40618
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40619
+ for(let i = endArray[index] + 1; i < querySeqArray[index].length; ++i) {
40620
+ ic.msaSeq[accArray[index]] += querySeqArray[index][i];
40621
+ }
40622
+
40623
+ cnt = querySeqArray[index].length - (endArray[index] + 1);
40624
+ for(let i = 0; i < maxCtermLen - cnt; ++i) {
40625
+ ic.msaSeq[accArray[index]] += '-';
40626
+ }
40627
+ }
40628
+
40629
+ for(let acc in ic.msaSeq) {
40630
+ let index = acc2index[acc];
40631
+ trackSeqArray[index] = ic.msaSeq[acc];
40632
+ trackTitleArray[index] = acc;
40633
+ }
40634
+
40635
+ // some of the protein may not be aligned
40636
+ let trackTitleArrayFinal = [], trackSeqArrayFinal = [];
40637
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
40638
+ if(trackSeqArray[i]) {
40639
+ trackSeqArrayFinal.push(trackSeqArray[i]);
40640
+ trackTitleArrayFinal.push(trackTitleArray[i]);
40641
+ }
40642
+ }
40643
+
40644
+ let seqFirst = trackSeqArrayFinal[0];
40645
+
40646
+ trackSeqArrayFinal.splice(0, 1);
40647
+ trackTitleArrayFinal.splice(0, 1);
40648
+
40649
+ return {trackTitleArray: trackTitleArrayFinal, trackSeqArray: trackSeqArrayFinal, seqFirst: seqFirst};
40650
+ }
40651
+
40652
+ async getIsoformMsa(acclist, acc2exons) { let ic = this.icn3d, me = ic.icn3dui;
40653
+ let trackTitleArray = [], trackSeqArray = [];
40654
+ // get all seq
40655
+ let url = me.htmlCls.baseUrl + "/vastdyn/vastdyn.cgi?chainlist=" + acclist;
40656
+ let data = await me.getAjaxPromise(url, 'jsonp');
40657
+ let maxLen = 0, maxIndex = 0, index = 0;
40658
+ let accArray = [], querySeqArray = [];
40659
+ for(let acc in data) {
40660
+ let seq = data[acc];
40661
+ querySeqArray.push(seq);
40662
+
40663
+ let pos = acc.indexOf('.');
40664
+ if(pos != -1) {
40665
+ acc = acc.substr(0, pos);
40666
+ }
40667
+ accArray.push(acc);
40668
+
40669
+ if(seq.length > maxLen) {
40670
+ maxLen = seq.length;
40671
+ maxIndex = index;
40672
+ }
40673
+ ++index;
40674
+ }
40675
+
40676
+ // get aligned length for each pair
40677
+ ic.qt_start_end = {};
40678
+
40679
+ // use the genomic interval as the alignment template
40680
+ let targetId = 'genomeRes';
40681
+
40682
+ let acc2index = {};
40683
+
40684
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40685
+ let acc = accArray[index];
40686
+
40687
+ acc2index[acc] = index;
40688
+
40689
+ ic.qt_start_end[index] = [];
40690
+
40691
+ let segArray = acc2exons[acc];
40692
+
40693
+ for(let i = 0, il = segArray.length; i < il; ++i) {
40694
+ let seg = segArray[i];
40695
+
40696
+ // mRNA has the reverse order, use negative to make the order right, then minus the offset
40697
+ let qt_start_end = {t_start: ic.exonOrder * seg.genResStart, t_end: ic.exonOrder * seg.genResEnd, q_start: seg.resStart, q_end: seg.resEnd};
40698
+ ic.qt_start_end[index].push(qt_start_end);
40699
+ }
40700
+ }
40701
+
40702
+ // start and end of MSA
40703
+ let start_t = 999999999, end_t = -999999999;
40704
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40705
+ if(!ic.qt_start_end[index]) continue;
40706
+
40707
+ for(let i = 0, il = ic.qt_start_end[index].length; i < il; ++i) {
40708
+ let start1, end1;
40709
+
40710
+ start1 = ic.qt_start_end[index][i].t_start;
40711
+ end1 = ic.qt_start_end[index][i].t_end;
40712
+
40713
+ for(let j = start1; j <= end1; ++j) {
40714
+ if(j < start_t) start_t = j;
40715
+ if(j > end_t) end_t = j;
40716
+ }
40717
+ }
40718
+ }
40719
+
40720
+ // minus the offset start_t
40721
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40722
+ let segArray = ic.qt_start_end[index];
40723
+ for(let i = 0, il = segArray.length; i < il; ++i) {
40724
+ let seg = segArray[i];
40725
+ seg.t_start -= start_t;
40726
+ seg.t_end -= start_t;
40727
+ }
40728
+ }
40729
+
40730
+ ic.msaSeq = {};
40731
+ // assign the template
40732
+ ic.msaSeq[targetId] = '';
40733
+
40734
+ let start_tFinal = 0;
40735
+ let end_tFinal = end_t - start_t;
40736
+
40737
+ for(let i = start_tFinal; i <= end_tFinal; ++i) {
40738
+ ic.msaSeq[targetId] += 'X'; // fake seq
40739
+ }
40740
+
40741
+ // progressively merge sequences, starting from most similar to least similar
40742
+ let alignedChainIndice = [0];
40743
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
40744
+ alignedChainIndice.push(index);
40745
+
40746
+ ic.msaSeq[accArray[index]] = '';
40747
+
40748
+ // some proteins may not be aligned
40749
+ if(!querySeqArray[index]) continue;
40750
+ ic.setSeqAlignCls.mergeTwoSeqForAllSimple(targetId, accArray, index, alignedChainIndice, start_tFinal, end_tFinal, querySeqArray);
40751
+ }
40752
+
40753
+ for(let acc in ic.msaSeq) {
40754
+ let index = acc2index[acc];
40755
+
40756
+ if(index !== undefined) {
40757
+ trackSeqArray[index] = ic.msaSeq[acc];
40758
+ trackTitleArray[index] = acc;
40759
+ }
40760
+ }
40761
+
40762
+ // remove introns in trackSeqArray
40763
+ let trackSeqArrayFinal = [];
40764
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
40765
+ trackSeqArrayFinal[i] = '';
40766
+ }
40767
+
40768
+ for(let j = 0, jl = trackSeqArray[maxIndex].length; j < jl; ++j) {
40769
+ let seq = trackSeqArray[maxIndex][j];
40770
+
40771
+ let bExon = (seq != '-') ? true : false;
40772
+ if(!bExon) {
40773
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
40774
+ if(trackSeqArray[i][j] != '-') {
40775
+ bExon = true;
40776
+ break;
40777
+ }
40778
+ }
40779
+ }
40780
+
40781
+ if(bExon) {
40782
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
40783
+ trackSeqArrayFinal[i] += trackSeqArray[i][j];
40784
+ }
40785
+ }
40786
+ }
40787
+
40788
+ return {trackTitleArray: trackTitleArray, trackSeqArray: trackSeqArrayFinal, maxIndex: maxIndex};
40789
+ }
40790
+
40791
+ async showMsaTracks(chainid, seqFirst, trackTitleArray, trackSeqArray, startpos, type, acc2exons) { let ic = this.icn3d; ic.icn3dui;
40792
+ //ic.startposGiSeq = undefined;
40793
+ for(let i = 0, il = ic.giSeq[chainid].length; i < il; ++i) {
40794
+ //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;
40795
+ let pos = ic.ParserUtilsCls.getResi(chainid, i);
40796
+
40797
+ if(pos != startpos) {
40798
+ continue;
40799
+ }
40800
+ else {
40801
+ ic.startposGiSeq = i;
40802
+ }
40803
+ }
40804
+
40805
+ if(ic.startposGiSeq === undefined) {
40806
+ var aaa = 1; //alert("Please double check the start position before clicking \"Add Track\"");
40807
+ return;
40808
+ }
40809
+
40810
+ // set up gap for the master seq
40811
+ // don't count gaps in both ends
40812
+ ic.targetGapHash = {};
40813
+ let prevSeq = '-', prevPos = 0, from, to, cnt = 0, dashCnt = 0;
40814
+ let bFound = false, seqStart = 0, seqEnd = 0, seqLength = seqFirst.length;
40815
+ // add gaps to the N- and C-terminal
40816
+ if(!ic.seqStartLen) ic.seqStartLen = {};
40817
+ if(!ic.seqEndLen) ic.seqEndLen = {};
40818
+ for(let i = 0, il = seqFirst.length; i < il; ++i) {
40819
+ if(seqFirst[i] == '-' && seqFirst[i] != prevSeq) { // start of gap
40820
+ from = cnt;
40821
+ dashCnt = 0;
40822
+ }
40823
+
40824
+ if(prevSeq == '-' && seqFirst[i] != prevSeq && cnt > 0) { // end of gap
40825
+ to = prevPos;
40826
+ ic.targetGapHash[from + ic.startposGiSeq] = {'from': from + ic.startposGiSeq, 'to': to + dashCnt - 1 + ic.startposGiSeq};
40827
+ }
40828
+
40829
+ prevSeq = seqFirst[i];
40830
+ prevPos = cnt;
40831
+
40832
+ if(seqFirst[i] != '-') {
40833
+ ++cnt;
40834
+ seqEnd = i;
40835
+ ic.seqEndLen[chainid] = seqLength - 1 - seqEnd;
40836
+
40837
+ if(!bFound) {
40838
+ seqStart = i;
40839
+ ic.seqStartLen[chainid] = seqStart;
40840
+
40841
+ bFound = true;
40842
+ }
40843
+ }
40844
+ else {
40845
+ ++dashCnt;
40846
+ }
40847
+ }
40848
+
40849
+ // adjust the total length
40850
+ if(ic.maxAnnoLength < ic.maxAnnoLengthOri + ic.seqStartLen[chainid] + ic.seqEndLen[chainid]) {
40851
+ ic.maxAnnoLength = ic.maxAnnoLengthOri + ic.seqStartLen[chainid] + ic.seqEndLen[chainid];
40852
+ }
40853
+
40854
+ await ic.annotationCls.resetAnnoAll();
40855
+
40856
+ let targetGapHashStr = '';
40857
+ let cntTmp = 0;
40858
+ for(let i in ic.targetGapHash) {
40859
+ if(cntTmp > 0) targetGapHashStr += ' ';
40860
+ targetGapHashStr += i + '_' + ic.targetGapHash[i].from + '_' + ic.targetGapHash[i].to;
40861
+ ++cntTmp;
40862
+ }
40863
+
40864
+ //me.htmlCls.clickMenuCls.setLogCmd("msa | " + targetGapHashStr, true);
40865
+
40866
+ // add tracks
40867
+ let resi2cntSameRes = {}; // count of same residue at each position
40868
+ for(let j = 0, jl = trackSeqArray.length; j < jl; ++j) {
40869
+ let resi = startpos;
40870
+ let text = '';
40871
+ for(let k = 0; k < ic.startposGiSeq; ++k) {
40872
+ if(ic.targetGapHash.hasOwnProperty(k)) {
40873
+ for(let m = 0; m < ic.targetGapHash[k].to - ic.targetGapHash[k].from + 1; ++m) {
40874
+ text += '-';
40875
+ }
40876
+ }
40877
+
40878
+ text += '-';
40879
+ }
40880
+
40881
+ let resn, prevResn = '-';
40882
+ let fromArray = [], toArray = [];
40883
+ let bFound = false;
40884
+ let seqStartLen = 0;
40885
+ // for(let k = seqStart; k <= seqEnd; ++k) {
40886
+ for(let k = 0; k < seqLength; ++k) {
40887
+ //if(seqFirst[k] == '-') continue;
40888
+
40889
+ if(j == 0) resi2cntSameRes[resi] = 0;
40890
+
40891
+ resn = trackSeqArray[j][k];
40892
+
40893
+ if(prevResn == '-' && resn != '-') {
40894
+ fromArray.push(k);
40895
+ }
40896
+
40897
+ if(prevResn != '-' && resn == '-') {
40898
+ toArray.push(k - 1);
40899
+ }
40900
+
40901
+ if(resn != '-') {
40902
+ if(!bFound) {
40903
+ seqStartLen = k;
40904
+ bFound = true;
40905
+ }
40906
+ }
40907
+
40908
+ text += resn; //ic.giSeq[chainid][i];
40909
+
40910
+ if(seqFirst[k] != '-') {
40911
+ if(seqFirst[k] == trackSeqArray[j][k]) ++resi2cntSameRes[resi];
40912
+ ++resi;
40913
+ }
40914
+
40915
+ prevResn = resn;
40916
+ }
40917
+
40918
+ // last one
40919
+ if(prevResn != '-') {
40920
+ toArray.push(seqLength - 1);
40921
+ }
40922
+
40923
+ let title =(trackTitleArray[j].length < 20) ? trackTitleArray[j] : trackTitleArray[j].substr(0, 20) + '...';
40924
+ let bMsa = true;
40925
+ let exonArray = (acc2exons) ? acc2exons[trackTitleArray[j]] : undefined;
40926
+ this.showNewTrack(chainid, title, text, undefined, undefined, type, undefined, bMsa, fromArray, toArray, seqStartLen, exonArray);
40927
+ }
40928
+
40929
+ // set color for the master seq
40930
+ if(trackSeqArray.length > 0) {
40931
+ if(ic.queryresi2score === undefined) ic.queryresi2score = {};
40932
+ if(ic.queryresi2score[chainid] === undefined) ic.queryresi2score[chainid] = {};
40933
+
40934
+ let nSeq = trackSeqArray.length;
40935
+ for(let resi in resi2cntSameRes) {
40936
+ let score = parseInt(resi2cntSameRes[resi] / nSeq * 100);
40937
+ ic.queryresi2score[chainid][resi] = score;
40938
+ }
40939
+
40940
+ let resiArray = Object.keys(resi2cntSameRes);
40941
+ let start = Math.min.apply(null, resiArray);
40942
+ let end = Math.max.apply(null, resiArray);
40943
+
40944
+ let resiScoreStr = '';
40945
+ for(let resi = start; resi <= end; ++resi) {
40946
+ if(resi2cntSameRes.hasOwnProperty(resi)) {
40947
+ resiScoreStr += Math.round(resi2cntSameRes[resi] / nSeq * 9); // max 9
40948
+ }
40949
+ else {
40950
+ resiScoreStr += '_';
40951
+ }
40952
+ }
40953
+
40954
+ ic.opts['color'] = 'align custom';
40955
+ ic.setColorCls.setColorByOptions(ic.opts, ic.hAtoms);
40956
+
40957
+ ic.hlUpdateCls.updateHlAll();
40958
+
40959
+ ic.drawCls.draw();
40960
+
40961
+ //me.htmlCls.clickMenuCls.setLogCmd('color align custom | ' + chainid + ' | range ' + start + '_' + end + ' | ' + resiScoreStr, true);
40962
+ }
40963
+ }
40964
+
40965
+ processAccList(acclist) { let ic = this.icn3d; ic.icn3dui;
40966
+ // remove version from acc
40967
+ let accArray = acclist.split(',');
40968
+ let accHash = {};
40969
+ let acclistTmp = '';
40970
+ for(let i = 0, il = accArray.length; i < il; ++i) {
40971
+ let acc = accArray[i];
40972
+
40973
+ if(accHash.hasOwnProperty(acc)) {
40974
+ continue;
40975
+ }
40976
+ else {
40977
+ accHash[acc] = 1;
40978
+ }
40979
+
40980
+ let pos = acc.indexOf('.');
40981
+ if(pos != -1) {
40982
+ acclistTmp += acc.substr(0, pos);
40983
+ }
40984
+ else {
40985
+ acclistTmp += acc;
40986
+ }
40987
+
40988
+ if(i < accArray.length - 1) {
40989
+ acclistTmp += ',';
40990
+ }
40991
+ }
40992
+
40993
+ return acclistTmp;
40994
+ }
40995
+
40996
+ async addExonTracks(chainid, geneid, startpos, type) { let ic = this.icn3d, me = ic.icn3dui;
40997
+ let seqFirst, trackTitleArray = [], trackSeqArray = [];
40998
+
40999
+ // get acclist from geneid
41000
+ let url = me.htmlCls.baseUrl + "/vastdyn/vastdyn.cgi?geneid2isoforms=" + geneid;
41001
+ let data = await me.getAjaxPromise(url, 'jsonp');
41002
+ let accArray = data.acclist;
41003
+ let exons = data.exons;
41004
+ let acc2exons = {};
41005
+
41006
+ let acclist = '';
41007
+ ic.exonOrder = 1; // 1: increasing bp order; -1 decreasing bp order
41008
+ for(let i = 0, il = accArray.length; i < il; ++i) {
41009
+ let accOri = accArray[i];
41010
+ let pos = accOri.indexOf('.');
41011
+ let acc = (pos != -1) ? accOri.substr(0, pos) : accOri;
41012
+
41013
+ let cntTotal = 0, prevCntTotal = 0, rangeArray = [];
41014
+ for(let j = 0, jl = exons[accOri].length; j < jl; ++j) {
41015
+ let itemArray = exons[accOri][j].split('-');
41016
+ itemArray[0] = parseInt(itemArray[0]);
41017
+ itemArray[1] = parseInt(itemArray[1]);
41018
+ itemArray[2] = parseInt(itemArray[2]);
41019
+
41020
+ ic.exonOrder = (itemArray[0] < itemArray[1]) ? 1 : -1;
41021
+
41022
+ let genomeRange = itemArray[0] + '-' + itemArray[1];
41023
+ let cnt = (j == jl - 1) ? itemArray[2] - 3 : itemArray[2]; // The last one is stop codeon
41024
+ cntTotal += cnt;
41025
+
41026
+ let resStart = parseInt(prevCntTotal/3.0 + 0.5); // 0-based
41027
+ let resEnd = parseInt(cntTotal/3.0 + 0.5) - 1; // 0-based
41028
+
41029
+ let genResStart = parseInt(itemArray[0] / 3.0 + 0.5);
41030
+
41031
+ //let genResEnd = parseInt(itemArray[1] / 3.0 + 0.5); // some difference due to round
41032
+ let genResEnd = genResStart + ic.exonOrder * (resEnd - resStart);
41033
+
41034
+ rangeArray.push({genomeRange: genomeRange, genResStart: genResStart, genResEnd: genResEnd, resStart: resStart, resEnd: resEnd});
41035
+
41036
+ prevCntTotal = cntTotal;
41037
+ }
41038
+ acc2exons[acc] = rangeArray;
41039
+
41040
+ acclist += acc;
41041
+ if(i < il - 1) {
41042
+ acclist += ',';
41043
+ }
41044
+ }
41045
+
41046
+ let result = await this.getIsoformMsa(acclist, acc2exons);
41047
+ trackTitleArray = result.trackTitleArray;
41048
+ trackSeqArray = result.trackSeqArray;
41049
+ //seqFirst = result.seqFirst;
41050
+ let maxIndex = result.maxIndex;
41051
+
41052
+ let acclist2 = trackTitleArray[maxIndex];
41053
+ let structure = chainid.substr(0, chainid.indexOf('_'));
41054
+ let firstAcc;
41055
+ if(structure.length > 5) {
41056
+ if(ic.uniprot2acc && ic.uniprot2acc[structure]) structure = ic.uniprot2acc[structure];
41057
+ firstAcc = structure;
41058
+ }
41059
+ else {
41060
+ firstAcc = chainid;
41061
+ }
41062
+
41063
+ // get the sequence from iCn3D because a uniProt ID can not be retrieved in pwaln.fcgi
41064
+ if(structure.length > 5) {
41065
+ let chainSeq = '';
41066
+ for(let i = 0, il = ic.chainsSeq.length; i < il; ++i) {
41067
+ chainSeq += ic.chainsSeq[i].resn;
41068
+ }
41069
+
41070
+ result = await this.getMsa(acclist2, firstAcc, chainSeq);
41071
+ }
41072
+ else {
41073
+ result = await this.getMsa(acclist2, firstAcc);
41074
+ }
41075
+
41076
+ result.trackTitleArray;
41077
+ let trackSeqArray2 = result.trackSeqArray;
41078
+ seqFirst = result.seqFirst;
41079
+
41080
+ // merge trackTitleArray2[0] with trackSeqArray[maxIndex]
41081
+ let A = trackSeqArray[maxIndex], B = trackSeqArray2[0];
41082
+ let i = 0, j = 0;
41083
+
41084
+ let ALen = trackSeqArray.length;
41085
+
41086
+ while (i < A.length && j < B.length) {
41087
+ if(A[i] != B[j]) {
41088
+ if(A[i] == '-') {
41089
+ // inser "-" in B
41090
+ B = B.substr(0, j) + '-' + B.substr(j);
41091
+ seqFirst = seqFirst.substr(0, j) + '-' + seqFirst.substr(j);
41092
+ }
41093
+ else { //if(B[j] == '-') {
41094
+ // inser "-" in A
41095
+ for(let k = 0; k < ALen; ++k) {
41096
+ trackSeqArray[k] = trackSeqArray[k].substr(0, i) + '-' + trackSeqArray[k].substr(i);
41097
+ }
41098
+ }
41099
+ }
41100
+
41101
+ ++i;
41102
+ ++j;
41103
+ }
41104
+
41105
+ await this.showMsaTracks(chainid, seqFirst, trackTitleArray, trackSeqArray, startpos, type, acc2exons);
41106
+
41107
+ me.htmlCls.clickMenuCls.setLogCmd("add exon track | chainid " + chainid + " | geneid " + geneid + " | startpos " + startpos + " | type " + type, true);
41108
+ }
41109
+
41110
+ async addMsaTracks(chainid, startpos, type, fastaList) { let ic = this.icn3d, me = ic.icn3dui;
41111
+ let seqFirst, trackTitleArray = [], trackSeqArray = [];
41112
+
41113
+ let fastaArray = fastaList.split('>');
41114
+
41115
+ // the first array item is empty
41116
+ // the second array item is the sequence of the structure, start with i = 2
41117
+ let posFirst = fastaArray[1].indexOf('\n');
41118
+ //let titleFirst = fastaArray[1].substr(0, posFirst);
41119
+ seqFirst = fastaArray[1].substr(posFirst + 1).replace(/\n/g, '');
41120
+
41121
+ for(let i = 2, il = fastaArray.length; i < il; ++i) {
41122
+ let pos = fastaArray[i].indexOf('\n');
41123
+ let title = fastaArray[i].substr(0, pos);
41124
+ if(title.indexOf('|') != -1) {
41125
+ title = title.split('|')[1];
41126
+ // if(title.indexOf('.') != -1) {
41127
+ // title = title.split('.')[0];
41128
+ // }
41129
+ }
41130
+ trackTitleArray.push(title);
41131
+ let seq = fastaArray[i].substr(pos + 1).replace(/\n/g, '');
41132
+ trackSeqArray.push(seq);
41133
+ }
41134
+
41135
+ await this.showMsaTracks(chainid, seqFirst, trackTitleArray, trackSeqArray, startpos, type);
41136
+
41137
+ me.htmlCls.clickMenuCls.setLogCmd("add msa track | chainid " + chainid + " | startpos " + startpos + " | type " + type + " | fastaList " + fastaList , true);
41138
+ }
40289
41139
  }
40290
41140
 
40291
41141
  /**
@@ -40936,13 +41786,14 @@ class ShowAnno {
40936
41786
  } // if(me.cfg.mmdbid
40937
41787
  } // for(let i = 0
40938
41788
 
40939
- ic.maxAnnoLength = 1;
41789
+ ic.maxAnnoLengthOri = 1;
40940
41790
  for(let chainid in ic.chainsSeq) {
40941
41791
  // use protein or nucleotide as the max length
40942
- if(ic.chainsSeq[chainid].length > ic.maxAnnoLength && (ic.protein_chainid.hasOwnProperty(chainid) || nucleotide_chainid.hasOwnProperty(chainid)) ) {
40943
- ic.maxAnnoLength = ic.chainsSeq[chainid].length;
41792
+ if(ic.chainsSeq[chainid].length > ic.maxAnnoLengthOri && (ic.protein_chainid.hasOwnProperty(chainid) || nucleotide_chainid.hasOwnProperty(chainid)) ) {
41793
+ ic.maxAnnoLengthOri = ic.chainsSeq[chainid].length;
40944
41794
  }
40945
41795
  }
41796
+ ic.maxAnnoLength = ic.maxAnnoLengthOri;
40946
41797
  }
40947
41798
 
40948
41799
  return {'nucleotide_chainid': nucleotide_chainid, 'chemical_chainid': chemical_chainid, 'chemical_set': chemical_set};
@@ -40957,7 +41808,7 @@ class ShowAnno {
40957
41808
  let chemical_chainid = result.chemical_chainid;
40958
41809
  let chemical_set = result.chemical_set;
40959
41810
 
40960
- if(ic.bAnnoShown === undefined || !ic.bAnnoShown || ic.bResetAnno) { // ic.bResetAnno when loading another structure
41811
+ if(!ic.bAnnoShown || ic.bResetAnno) { // ic.bResetAnno when loading another structure
40961
41812
  // assign early to avoid load annotations twice
40962
41813
  ic.bAnnoShown = true;
40963
41814
 
@@ -40993,7 +41844,7 @@ class ShowAnno {
40993
41844
  dataObj['targets'] = me.cfg.blast_rep_id + ':' + target_from_to_array.join(':');
40994
41845
  }
40995
41846
 
40996
- // get seqeunce
41847
+ // get sequence
40997
41848
  if(ic.blastAcxn) {
40998
41849
  let chainid = me.cfg.afid + '_A';
40999
41850
  let seq = '';
@@ -41024,7 +41875,7 @@ class ShowAnno {
41024
41875
  idArray.push(me.cfg.query_id);
41025
41876
  }
41026
41877
 
41027
- // get seqeunce
41878
+ // get sequence
41028
41879
  if(ic.blastAcxn) {
41029
41880
  let chainid = me.cfg.afid + '_A';
41030
41881
  let seq = '';
@@ -41098,13 +41949,52 @@ class ShowAnno {
41098
41949
  let thisClass = this;
41099
41950
  let chnidBaseArray = $.map(ic.protein_chainid, function(v) { return v; });
41100
41951
  let index = 0;
41952
+
41953
+ // get geneid
41954
+ if(!ic.chainsGene) ic.chainsGene = {};
41955
+ for(let chnid in ic.protein_chainid) {
41956
+ let structure = chnid.substr(0, chnid.indexOf('_'));
41957
+ // UniProt or NCBI protein accession
41958
+ if(structure.length > 5) {
41959
+ let refseqid, url;
41960
+ if(ic.uniprot2acc && ic.uniprot2acc[structure]) {
41961
+ refseqid = ic.uniprot2acc[structure];
41962
+ }
41963
+ else {
41964
+ try {
41965
+ if(!ic.uniprot2acc) ic.uniprot2acc = {};
41966
+ url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?uniprot2refseq=" + structure;
41967
+ let result = await me.getAjaxPromise(url, 'jsonp');
41968
+ refseqid = (result && result.refseq) ? result.refseq : structure;
41969
+
41970
+ ic.uniprot2acc[structure] = refseqid;
41971
+ }
41972
+ catch {
41973
+ console.log("Problem in getting protein accession from UniProt ID...");
41974
+ refseqid = structure;
41975
+ }
41976
+ }
41977
+
41978
+ // get Gene info from protein name
41979
+ // url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?protein2gene=" + refseqid;
41980
+ // ic.chainsGene[chnid] = await me.getAjaxPromise(url, 'jsonp');
41981
+
41982
+ // get Gene info from uniprot
41983
+ url = "https://rest.uniprot.org/uniprotkb/search?format=json&fields=xref_geneid,gene_names&query=" + structure;
41984
+ let geneData = await me.getAjaxPromise(url, 'json');
41985
+ let geneId = (geneData.results[0] && geneData.results[0].uniProtKBCrossReferences[0]) ? geneData.results[0].uniProtKBCrossReferences[0].id : undefined;
41986
+ let geneSymbol = (geneData.results[0] && geneData.results[0].genes[0] && geneData.results[0].genes[0].geneName) ? geneData.results[0].genes[0].geneName.value : undefined;
41987
+ ic.chainsGene[chnid] = {geneId: geneId, geneSymbol: geneSymbol};
41988
+ }
41989
+ }
41990
+
41101
41991
  for(let chnid in ic.protein_chainid) {
41102
41992
  let buttonStyle = me.utilsCls.isMobile() ? 'none' : 'button';
41103
41993
  let fullProteinName = ic.showSeqCls.getProteinName(chnid);
41104
41994
  let proteinName = fullProteinName;
41105
41995
  //if(proteinName.length > 40) proteinName = proteinName.substr(0, 40) + "...";
41106
41996
  let categoryStr =(index == 0) ? "<span class='icn3d-annoLargeTitle'><b>Proteins</b>: </span><br><br>" : "";
41107
- 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>)" : '';
41997
+ 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>)" : '';
41108
41998
  let structure = chnid.substr(0, chnid.indexOf('_'));
41109
41999
  let chainLink = (structure.length > 5) ? '<a href="https://alphafold.ebi.ac.uk/entry/' + structure + '" target="_blank">' + chnid + '</a>' : chnid;
41110
42000
  let chainHtml = "<div id='" + ic.pre + "anno_" + chnid + "' class='icn3d-annotation'>" + categoryStr
@@ -41351,7 +42241,7 @@ class ShowAnno {
41351
42241
  let data = ic.seqStructAlignData;
41352
42242
  if(data.data !== undefined) {
41353
42243
  query = data.data[0].query;
41354
- // if target is seqeunce, the key is not chnid
42244
+ // if target is sequence, the key is not chnid
41355
42245
  //target = data.data[0].targets[chnid];
41356
42246
  let keys = Object.keys(data.data[0].targets);
41357
42247
  target = data.data[0].targets[keys[0]];
@@ -41363,7 +42253,7 @@ class ShowAnno {
41363
42253
  evalue = target.scores.e_value.toPrecision(2);
41364
42254
  if(evalue > 1e-200) evalue = parseFloat(evalue).toExponential();
41365
42255
  target.scores.bit_score;
41366
- // if target is seqeunce, the key is not chnid
42256
+ // if target is sequence, the key is not chnid
41367
42257
  // targetSeq = data.targets[chnid].seqdata;
41368
42258
  let keys = Object.keys(data.targets);
41369
42259
  targetSeq = data.targets[keys[0]].seqdata;
@@ -41655,6 +42545,9 @@ class ShowSeq {
41655
42545
  html += htmlTmp + '<span class="icn3d-seqLine">';
41656
42546
  let helixCnt = 0, sheetCnt = 0;
41657
42547
  let savedSsName = '';
42548
+
42549
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqStartLen[chnid], ' ');
42550
+
41658
42551
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41659
42552
  html += this.insertGap(chnid, i, '-');
41660
42553
  let currResi;
@@ -41712,18 +42605,25 @@ class ShowSeq {
41712
42605
  }
41713
42606
  html += '</span>';
41714
42607
  }
42608
+
42609
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqEndLen[chnid], ' ');
42610
+
41715
42611
  html += '<span class="icn3d-residueNum"></span>';
41716
42612
  html += '</span>';
41717
42613
  html += '<br>';
41718
42614
  html += '</div>';
41719
42615
  html3 += '</div>';
41720
42616
  }
42617
+
41721
42618
  // html to display secondary structures
41722
42619
  htmlTmp = '<div class="icn3d-residueLine" style="white-space:nowrap;">';
41723
42620
  htmlTmp += '<div class="icn3d-annoTitle" anno="0"></div>';
41724
42621
  htmlTmp += '<span class="icn3d-residueNum"></span>';
41725
42622
  html3 += htmlTmp + '<br>';
41726
42623
  html += htmlTmp + '<span class="icn3d-seqLine">';
42624
+
42625
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqStartLen[chnid], '-');
42626
+
41727
42627
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41728
42628
  html += this.insertGap(chnid, i, '-');
41729
42629
  // 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;
@@ -41771,6 +42671,9 @@ class ShowSeq {
41771
42671
  html += '<span>-</span>'; //'<span>-</span>';
41772
42672
  }
41773
42673
  }
42674
+
42675
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqEndLen[chnid], '-');
42676
+
41774
42677
  html += '<span class="icn3d-residueNum"></span>';
41775
42678
  html += '</span>';
41776
42679
  html += '<br>';
@@ -41802,6 +42705,9 @@ class ShowSeq {
41802
42705
  html += htmlTmp + htmlTmp2;
41803
42706
  html2 += htmlTmp + htmlTmp2;
41804
42707
  let pos, nGap = 0;
42708
+
42709
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqStartLen[chnid], '-');
42710
+
41805
42711
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41806
42712
  html += this.insertGap(chnid, i, '-');
41807
42713
  if(ic.targetGapHash !== undefined && ic.targetGapHash.hasOwnProperty(i)) nGap += ic.targetGapHash[i].to - ic.targetGapHash[i].from + 1;
@@ -41831,6 +42737,9 @@ class ShowSeq {
41831
42737
  html += '<span id="giseq_' + ic.pre + chnid + '_' + pos + '" title="' + cFull + pos + '" class="icn3d-residue" style="color:#' + color + '">' + c + '</span>';
41832
42738
  }
41833
42739
  }
42740
+
42741
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqEndLen[chnid], '-');
42742
+
41834
42743
  if(me.cfg.blast_rep_id == chnid) {
41835
42744
  // change color in 3D
41836
42745
  ic.opts['color'] = (ic.blastAcxn) ? 'confidence' : 'conservation';
@@ -41841,8 +42750,11 @@ class ShowSeq {
41841
42750
  // sequence, overview
41842
42751
  let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chnid]);
41843
42752
  let color =(atom.color) ? atom.color.getHexString() : "CCCCCC";
41844
- let width = Math.round(ic.seqAnnWidth * giSeq.length / ic.maxAnnoLength);
42753
+ let width = Math.round(ic.seqAnnWidth * giSeq.length / (ic.maxAnnoLength + ic.nTotalGap));
41845
42754
  if(width < 1) width = 1;
42755
+
42756
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html2 += this.insertMulGapOverview(chnid, ic.seqStartLen[chnid]);
42757
+
41846
42758
  if(me.cfg.blast_rep_id != chnid) { // regular
41847
42759
  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>';
41848
42760
  }
@@ -41856,7 +42768,9 @@ class ShowSeq {
41856
42768
  }
41857
42769
  }
41858
42770
  toArray2.push(giSeq.length - 1);
42771
+
41859
42772
  html2 += '<div id="giseq_summary_' + ic.pre + chnid + '" class="icn3d-seqTitle icn3d-link" gi chain="' + chnid + '" style="width:' + width + 'px;">';
42773
+
41860
42774
  for(let i = 0, il = fromArray2.length; i < il; ++i) {
41861
42775
  html2 += this.insertGapOverview(chnid, fromArray2[i]);
41862
42776
  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>';
@@ -41988,6 +42902,9 @@ class ShowSeq {
41988
42902
  htmlTmp += '<span class="icn3d-residueNum"></span>';
41989
42903
  html3 += htmlTmp + '<br>';
41990
42904
  html += htmlTmp + '<span class="icn3d-seqLine">';
42905
+
42906
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqStartLen[chnid], '-');
42907
+
41991
42908
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41992
42909
  html += this.insertGap(chnid, i, '-');
41993
42910
  //if(i >= ic.matchedPos[chnid] && i - ic.matchedPos[chnid] < ic.chainsSeq[chnid].length) {
@@ -42011,6 +42928,9 @@ class ShowSeq {
42011
42928
  // html += '<span></span>';
42012
42929
  // }
42013
42930
  }
42931
+
42932
+ if(ic.seqStartLen && ic.seqStartLen[chnid]) html += this.insertMulGap(ic.seqEndLen[chnid], '-');
42933
+
42014
42934
  html += '<span class="icn3d-residueNum"></span>';
42015
42935
  html += '</span>';
42016
42936
  html += '<br>';
@@ -42658,26 +43578,43 @@ class ShowSeq {
42658
43578
  let html = '';
42659
43579
  //if(me.cfg.blast_rep_id == chnid && ic.targetGapHash!== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
42660
43580
  if(ic.targetGapHash!== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
42661
- for(let j = 0; j <(ic.targetGapHash[seqIndex].to - ic.targetGapHash[seqIndex].from + 1); ++j) {
42662
- if(bNohtml) {
42663
- html += text;
42664
- }
42665
- else {
42666
- html += '<span>' + text + '</span>';
42667
- }
42668
- }
43581
+ html += this.insertMulGap(ic.targetGapHash[seqIndex].to - ic.targetGapHash[seqIndex].from + 1, text, bNohtml);
42669
43582
  }
42670
43583
  return html;
42671
43584
  }
42672
- insertGapOverview(chnid, seqIndex) { let ic = this.icn3d, me = ic.icn3dui;
43585
+
43586
+ insertMulGap(n, text, bNohtml) { let ic = this.icn3d; ic.icn3dui;
43587
+ let html = '';
43588
+ for(let j = 0; j < n; ++j) {
43589
+ if(bNohtml) {
43590
+ html += text;
43591
+ }
43592
+ else {
43593
+ html += '<span>' + text + '</span>';
43594
+ }
43595
+ }
43596
+ return html;
43597
+ }
43598
+
43599
+ insertGapOverview(chnid, seqIndex) { let ic = this.icn3d; ic.icn3dui;
42673
43600
  let html2 = '';
42674
- if(me.cfg.blast_rep_id == chnid && ic.targetGapHash!== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
42675
- let width = ic.seqAnnWidth *(ic.targetGapHash[seqIndex].to - ic.targetGapHash[seqIndex].from + 1) /(ic.maxAnnoLength + ic.nTotalGap);
42676
- html2 += '<div style="display:inline-block; background-color:#333; width:' + width + 'px; height:3px;">&nbsp;</div>';
43601
+ // if(me.cfg.blast_rep_id == chnid && ic.targetGapHash !== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
43602
+ if(ic.targetGapHash !== undefined && ic.targetGapHash.hasOwnProperty(seqIndex)) {
43603
+ html2 += this.insertMulGapOverview(chnid, ic.targetGapHash[seqIndex].to - ic.targetGapHash[seqIndex].from + 1);
42677
43604
  }
42678
43605
  return html2;
42679
43606
  }
42680
43607
 
43608
+ insertMulGapOverview(chnid, n) { let ic = this.icn3d; ic.icn3dui;
43609
+ let html2 = '';
43610
+ let width = ic.seqAnnWidth * n /(ic.maxAnnoLength + ic.nTotalGap);
43611
+ width = parseInt(width);
43612
+
43613
+ // html2 += '<div style="display:inline-block; background-color:#333; width:' + width + 'px; height:3px;">&nbsp;</div>';
43614
+ html2 += '<div style="display:inline-block; width:' + width + 'px;">&nbsp;</div>';
43615
+ return html2;
43616
+ }
43617
+
42681
43618
  setAlternativeSeq(chnid, chnidBase) { let ic = this.icn3d; ic.icn3dui;
42682
43619
  //if(ic.chainsSeq[chnid] !== undefined) {
42683
43620
  let resArray = ic.chainsSeq[chnid];
@@ -42807,7 +43744,7 @@ class HlSeq {
42807
43744
  //});
42808
43745
 
42809
43746
  // remove possible text selection
42810
- // the following code caused the scroll of seqeunce window to the top, remove it for now
43747
+ // the following code caused the scroll of sequence window to the top, remove it for now
42811
43748
  /*
42812
43749
  if(window.getSelection) {
42813
43750
  if(window.getSelection().empty) { // Chrome
@@ -44395,26 +45332,22 @@ class LineGraph {
44395
45332
 
44396
45333
  let pdbAjaxArray = [];
44397
45334
  for(let k = 0, kl = ic.refpdbArray.length; k < kl; ++k) {
44398
- //let urlpdb = me.htmlCls.baseUrl + "icn3d/refpdb/" + ic.refpdbArray[k] + ".pdb";
44399
- let urlpdb = me.htmlCls.baseUrl + "mmcifparser/mmcifparser.cgi?refpdbid=" + ic.refpdbArray[k];
45335
+ //let urlpdb = me.htmlCls.baseUrl + "mmcifparser/mmcifparser.cgi?refpdbid=" + ic.refpdbArray[k];
45336
+ let urlpdb = me.htmlCls.baseUrl + "mmcifparser/mmcifparser.cgi?refjsonid=" + ic.refpdbArray[k];
44400
45337
 
44401
45338
  let pdbAjax = me.getAjaxPromise(urlpdb, 'text');
44402
45339
 
44403
45340
  pdbAjaxArray.push(pdbAjax);
44404
45341
  }
44405
45342
 
44406
- try {
45343
+ // try {
44407
45344
  let allPromise = Promise.allSettled(pdbAjaxArray);
44408
45345
  ic.pdbDataArray = await allPromise;
44409
45346
  await thisClass.parseRefPdbData(ic.pdbDataArray);
44410
- }
44411
- catch(err) {
44412
- if(!me.bNode) var aaa = 1; //alert("Error in retrieveing reference PDB data...");
44413
- //var aaa = 1; //alert("Error in retrieveing reference PDB data...");
44414
- return;
44415
- }
44416
-
44417
45347
  // }
45348
+ // catch(err) {
45349
+ // if(!me.bNode) var aaa = 1; //alert("Error in retrieveing reference PDB data...");
45350
+ // return;
44418
45351
  // }
44419
45352
  }
44420
45353
 
@@ -44426,7 +45359,8 @@ class LineGraph {
44426
45359
  let ajaxArray = [];
44427
45360
  let domainidpairArray = [];
44428
45361
 
44429
- let urltmalign = me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
45362
+ me.htmlCls.baseUrl + "tmalign/tmalign.cgi";
45363
+ let urlalign = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi";
44430
45364
 
44431
45365
  if(!ic.resid2domainid) ic.resid2domainid = {};
44432
45366
  //ic.resid2domainid = {};
@@ -44506,6 +45440,9 @@ class LineGraph {
44506
45440
 
44507
45441
  for(let k = 0, kl = domainAtomsArray.length; k < kl; ++k) {
44508
45442
  let pdb_target = ic.saveFileCls.getAtomPDB(domainAtomsArray[k], undefined, undefined, undefined, undefined, struct);
45443
+ let bForceOneDomain = true;
45444
+ let jsonStr_t = ic.domain3dCls.getDomainJsonForAlign(domainAtomsArray[k], bForceOneDomain);
45445
+
44509
45446
  // ig strand for any subset will have the same k, use the number of residue to separate them
44510
45447
  let atomFirst = ic.firstAtomObjCls.getFirstAtomObj(domainAtomsArray[k]);
44511
45448
  let atomLast = ic.firstAtomObjCls.getLastAtomObj(domainAtomsArray[k]);
@@ -44515,14 +45452,19 @@ class LineGraph {
44515
45452
  ic.domainid2pdb[domainid] = pdb_target;
44516
45453
 
44517
45454
  for(let index = 0, indexl = dataArray.length; index < indexl; ++index) {
44518
- let struct2 = ic.defaultPdbId + index;
44519
- //let pdb_query = (me.bNode) ? dataArray[index] : dataArray[index].value; //[0];
44520
- let pdb_query = dataArray[index].value; //[0];
44521
- let header = 'HEADER ' + struct2 + '\n';
44522
- pdb_query = header + pdb_query;
44523
-
44524
- let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target, "queryid": ic.refpdbArray[index]};
44525
- let alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
45455
+ // let struct2 = ic.defaultPdbId + index;
45456
+ // let pdb_query = dataArray[index].value; //[0];
45457
+ // let header = 'HEADER ' + struct2 + '\n';
45458
+ // pdb_query = header + pdb_query;
45459
+ let jsonStr_q = dataArray[index].value; //[0];
45460
+
45461
+ // TM-align is not good when you align a full structure with the strand-only structure. VAST is better in this case.
45462
+ // let dataObj = {'pdb_query': pdb_query, 'pdb_target': pdb_target, "queryid": ic.refpdbArray[index]};
45463
+ // let alignAjax = me.getAjaxPostPromise(urltmalign, dataObj);
45464
+
45465
+ let dataObj = {'domains1': jsonStr_q, 'domains2': jsonStr_t};
45466
+ let alignAjax = me.getAjaxPostPromise(urlalign, dataObj);
45467
+
44526
45468
  ajaxArray.push(alignAjax);
44527
45469
 
44528
45470
  domainidpairArray.push(domainid + "|" + ic.refpdbArray[index]);
@@ -44601,6 +45543,7 @@ class LineGraph {
44601
45543
  let thisClass = this;
44602
45544
 
44603
45545
  let tmscoreThreshold = 0.4; // 0.4; //0.5;
45546
+ let rmsdThreshold = 10;
44604
45547
 
44605
45548
  // find the best alignment for each chain
44606
45549
  let domainid2score = {}, domainid2segs = {}, chainid2segs = {};
@@ -44628,8 +45571,15 @@ class LineGraph {
44628
45571
 
44629
45572
  if(queryData.length == 0) continue;
44630
45573
 
44631
- if(queryData[0].score < tmscoreThreshold || queryData[0].num_res < minResidues) {
44632
- continue;
45574
+ if(!bRound1) {
45575
+ if(queryData[0].score < tmscoreThreshold || queryData[0].num_res < minResidues) {
45576
+ continue;
45577
+ }
45578
+ }
45579
+ else {
45580
+ if(queryData[0].super_rmsd > rmsdThreshold || queryData[0].num_res < minResidues) {
45581
+ continue;
45582
+ }
44633
45583
  }
44634
45584
 
44635
45585
  //let domainid_index = domainidpairArray[i].split(',');
@@ -44638,44 +45588,63 @@ class LineGraph {
44638
45588
  let refpdbname = domainidpairArray[i].substr(domainidpairArray[i].indexOf('|') + 1);
44639
45589
  //let chainid = domainid.split('-')[0];
44640
45590
 
44641
- if(!me.bNode) console.log("refpdbname " + refpdbname + " TM-score: " + queryData[0].score);
45591
+ if(!bRound1) {
45592
+ if(!me.bNode) console.log("refpdbname " + refpdbname + " TM-score: " + queryData[0].score);
45593
+ }
45594
+ else {
45595
+ if(!me.bNode) console.log("refpdbname " + refpdbname + " RMSD: " + queryData[0].super_rmsd);
45596
+ }
44642
45597
 
44643
45598
  // Ig-like domains: B (2150, 2150a, 2150b), C (3150, 3250), E (7150, 7250), F (8150, 8250) strands
44644
45599
  // Ig domain may require G (7050). But we'll leave that out for now.
44645
- let bBstrand = false, bCstrand = false, bEstrand = false, bFstrand = false;
44646
- for(let i = 0, il = queryData[0].segs.length; i < il; ++i) {
44647
- let seg = queryData[0].segs[i];
45600
+ if(!bRound1) {
45601
+ let bBstrand = false, bCstrand = false, bEstrand = false, bFstrand = false;
45602
+ for(let i = 0, il = queryData[0].segs.length; i < il; ++i) {
45603
+ let seg = queryData[0].segs[i];
44648
45604
 
44649
- if(seg.q_start.indexOf('2150') != -1 || seg.q_start.indexOf('2250') != -1) {
44650
- bBstrand = true;
44651
- }
44652
- else if(seg.q_start.indexOf('3150') != -1 || seg.q_start.indexOf('3250') != -1) {
44653
- bCstrand = true;
44654
- }
44655
- else if(seg.q_start.indexOf('7150') != -1 || seg.q_start.indexOf('7250') != -1) {
44656
- bEstrand = true;
44657
- }
44658
- else if(seg.q_start.indexOf('8150') != -1 || seg.q_start.indexOf('8250') != -1) {
44659
- bFstrand = true;
45605
+ if(seg.q_start.indexOf('2150') != -1 || seg.q_start.indexOf('2250') != -1) {
45606
+ bBstrand = true;
45607
+ }
45608
+ else if(seg.q_start.indexOf('3150') != -1 || seg.q_start.indexOf('3250') != -1) {
45609
+ bCstrand = true;
45610
+ }
45611
+ else if(seg.q_start.indexOf('7150') != -1 || seg.q_start.indexOf('7250') != -1) {
45612
+ bEstrand = true;
45613
+ }
45614
+ else if(seg.q_start.indexOf('8150') != -1 || seg.q_start.indexOf('8250') != -1) {
45615
+ bFstrand = true;
45616
+ }
45617
+
45618
+ //if(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand) break;
45619
+ if(bBstrand && bCstrand && bEstrand && bFstrand) break;
44660
45620
  }
44661
45621
 
44662
- //if(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand) break;
44663
- if(bBstrand && bCstrand && bEstrand && bFstrand) break;
45622
+ //if(!(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand)) continue;
45623
+ if(!(bBstrand && bCstrand && bEstrand && bFstrand)) {
45624
+ if(!me.bNode) console.log("Some of the Ig strands B, C, E, F are missing in the domain " + domainid + "...");
45625
+ continue;
45626
+ }
44664
45627
  }
44665
45628
 
44666
- //if(!(bBstrand && bCstrand && bEstrand && bFstrand && bGstrand)) continue;
44667
- if(!(bBstrand && bCstrand && bEstrand && bFstrand)) {
44668
- if(!me.bNode) console.log("Some of the Ig strands B, C, E, F are missing in the domain " + domainid + "...");
44669
- continue;
45629
+ if(!bRound1) {
45630
+ if(!domainid2score.hasOwnProperty(domainid) || queryData[0].score > domainid2score[domainid]) {
45631
+ domainid2score[domainid] = queryData[0].score;
45632
+
45633
+ ic.domainid2refpdbname[domainid] = refpdbname;
45634
+ domainid2segs[domainid] = queryData[0].segs;
45635
+ ic.domainid2ig2kabat[domainid] = queryData[0].ig2kabat;
45636
+ ic.domainid2ig2imgt[domainid] = queryData[0].ig2imgt;
45637
+ }
44670
45638
  }
44671
-
44672
- if(!domainid2score.hasOwnProperty(domainid) || queryData[0].score > domainid2score[domainid]) {
44673
- domainid2score[domainid] = queryData[0].score;
44674
-
44675
- ic.domainid2refpdbname[domainid] = refpdbname;
44676
- domainid2segs[domainid] = queryData[0].segs;
44677
- ic.domainid2ig2kabat[domainid] = queryData[0].ig2kabat;
44678
- ic.domainid2ig2imgt[domainid] = queryData[0].ig2imgt;
45639
+ else {
45640
+ if(!domainid2score.hasOwnProperty(domainid) || queryData[0].super_rmsd < domainid2score[domainid]) {
45641
+ domainid2score[domainid] = queryData[0].super_rmsd;
45642
+
45643
+ ic.domainid2refpdbname[domainid] = refpdbname;
45644
+ domainid2segs[domainid] = queryData[0].segs;
45645
+ ic.domainid2ig2kabat[domainid] = queryData[0].ig2kabat;
45646
+ ic.domainid2ig2imgt[domainid] = queryData[0].ig2imgt;
45647
+ }
44679
45648
  }
44680
45649
  }
44681
45650
 
@@ -48092,7 +49061,7 @@ class ChainalignParser {
48092
49061
  let hAtomsAll = {};
48093
49062
 
48094
49063
  if(ic.bFullUi && ic.q_rotation !== undefined && !me.cfg.resnum && !me.cfg.resdef) {
48095
- // set multiple seqeunce alignment from ic.qt_start_end
49064
+ // set multiple sequence alignment from ic.qt_start_end
48096
49065
  hAtomsAll = this.setMsa(chainidArray);
48097
49066
  }
48098
49067
 
@@ -48152,7 +49121,7 @@ class ChainalignParser {
48152
49121
  ic.qt_start_end = [];
48153
49122
 
48154
49123
  let mmdbid2cnt = {}, mmdbidpairHash = {};
48155
-
49124
+
48156
49125
  let bFoundAlignment = false;
48157
49126
  for(let i = 0, il = dataArray.length; i < il; ++i) {
48158
49127
  // let align = (me.bNode) ? dataArray[i] : dataArray[i].value;//[0];
@@ -48632,6 +49601,7 @@ class ChainalignParser {
48632
49601
 
48633
49602
  processAlign(align, index, queryData, bEqualMmdbid, bEqualChain, bNoAlert) { let ic = this.icn3d, me = ic.icn3dui;
48634
49603
  let bAligned = false;
49604
+
48635
49605
  if((!align || align.length == 0) && !bNoAlert) {
48636
49606
  let serverName = (me.cfg.aligntool == 'tmalign') ? 'TM-align' : 'VAST';
48637
49607
 
@@ -48816,14 +49786,14 @@ class ChainalignParser {
48816
49786
  ic.ParserUtilsCls.showLoading();
48817
49787
 
48818
49788
  let allPromise = Promise.allSettled(ajaxArray);
48819
- try {
49789
+ // try {
48820
49790
  let dataArray = await allPromise;
48821
49791
  await thisClass.parseMMdbAfData(dataArray, structArray, bQuery, vastplusAtype);
48822
49792
  if(vastplusAtype === undefined) ic.ParserUtilsCls.hideLoading();
48823
- }
48824
- catch(err) {
48825
- var aaa = 1; //alert("There are some problems in retrieving the coordinates...");
48826
- }
49793
+ // }
49794
+ // catch(err) {
49795
+ // var aaa = 1; //alert("There are some problems in retrieving the coordinates...");
49796
+ // }
48827
49797
  // });
48828
49798
 
48829
49799
  // return ic.deferredMmdbaf.promise();
@@ -49445,6 +50415,8 @@ class MmdbParser {
49445
50415
 
49446
50416
  if(data && data.uniprot) {
49447
50417
  me.cfg.afid = data.uniprot;
50418
+ if(!ic.uniprot2acc) ic.uniprot2acc = {};
50419
+ ic.uniprot2acc[data.uniprot] = refseqid;
49448
50420
  }
49449
50421
  else {
49450
50422
  var aaa = 1; //alert('The accession ' + refseqid + ' can not be mapped to AlphaFold UniProt ID. It will be treated as a UniProt ID instead.');
@@ -49462,6 +50434,73 @@ class MmdbParser {
49462
50434
  //await ic.loadScriptCls.loadScript(me.cfg.command, undefined, true);
49463
50435
  }
49464
50436
 
50437
+ async downloadProteinname(protein) { let ic = this.icn3d, me = ic.icn3dui;
50438
+ me.icn3d.bCid = undefined;
50439
+
50440
+ // get RefSeq ID from protein name
50441
+ let url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?protein2acc=" + protein;
50442
+
50443
+ let accJson = await me.getAjaxPromise(url, 'jsonp');
50444
+
50445
+ let accArray = accJson.acc;
50446
+
50447
+ if(accArray.length == 0) {
50448
+ if(!me.bNode) var aaa = 1; //alert('The protein/gene name ' + protein + ' can not be mapped to RefSeq proteins...');
50449
+ return;
50450
+ }
50451
+
50452
+ let ajaxArray = [];
50453
+ for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
50454
+ let refseqid = accArray[index];
50455
+ url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?refseq2uniprot=" + refseqid;
50456
+
50457
+ let ajax = me.getAjaxPromise(url, 'jsonp');
50458
+
50459
+ ajaxArray.push(ajax);
50460
+ }
50461
+
50462
+ let allPromise = Promise.allSettled(ajaxArray);
50463
+ let dataArray = await allPromise;
50464
+
50465
+ ajaxArray = [];
50466
+ let afidArray = [];
50467
+ for(let i = 0, il = dataArray.length; i < il; ++i) {
50468
+ let data = dataArray[i].value;
50469
+
50470
+ if(data && data.uniprot) {
50471
+ let afid = data.uniprot;
50472
+ url = "https://alphafold.ebi.ac.uk/files/AF-" + afid + "-F1-model_" + ic.AFUniprotVersion + ".pdb";
50473
+ ic.ParserUtilsCls.setYourNote(me.cfg.protein + '(NCBI Protein/Gene) in iCn3D');
50474
+
50475
+ let ajax = me.getAjaxPromise(url, 'text', true);
50476
+ ajaxArray.push(ajax);
50477
+ afidArray.push(afid);
50478
+ }
50479
+ }
50480
+
50481
+ allPromise = Promise.allSettled(ajaxArray);
50482
+ dataArray = await allPromise;
50483
+
50484
+ for(let i = 0, il = dataArray.length; i < il; ++i) {
50485
+ let data = dataArray[i].value;
50486
+ me.cfg.afid = afidArray[i];
50487
+
50488
+ if(data) {
50489
+ // add UniProt ID into the header
50490
+ let header = 'HEADER ' + me.cfg.afid + '\n';
50491
+ data = header + data;
50492
+ await ic.opmParserCls.parseAtomData(data, me.cfg.afid, undefined, 'pdb', undefined);
50493
+
50494
+ break;
50495
+ }
50496
+ }
50497
+
50498
+ if(!me.cfg.afid) {
50499
+ if(!me.bNode) var aaa = 1; //alert('The protein/gene name ' + protein + ' can not be mapped to AlphaFold structures...');
50500
+ return;
50501
+ }
50502
+ }
50503
+
49465
50504
  getNoData(mmdbid, bGi) { let ic = this.icn3d, me = ic.icn3dui;
49466
50505
  if(bGi) {
49467
50506
  var aaa = 1; //alert("This gi " + mmdbid + " has no corresponding 3D structure...");
@@ -50538,6 +51577,9 @@ class PdbParser {
50538
51577
  if(me.cfg.refseqid) {
50539
51578
  ic.ParserUtilsCls.setYourNote(me.cfg.refseqid.toUpperCase() + '(NCBI Protein Acc.) in iCn3D');
50540
51579
  }
51580
+ else if(me.cfg.protein) {
51581
+ ic.ParserUtilsCls.setYourNote(me.cfg.protein + '(NCBI Protein/Gene) in iCn3D');
51582
+ }
50541
51583
  else {
50542
51584
  ic.ParserUtilsCls.setYourNote(pdbid.toUpperCase() + '(AlphaFold) in iCn3D');
50543
51585
  }
@@ -51473,6 +52515,7 @@ class RealignParser {
51473
52515
  async realignOnStructAlign(bReverse) { let ic = this.icn3d, me = ic.icn3dui;
51474
52516
  // each 3D domain should have at least 3 secondary structures
51475
52517
  let minSseCnt = (me.cfg.aligntool != 'tmalign') ? 3 : 0;
52518
+
51476
52519
  let struct2domain = {};
51477
52520
  for(let struct in ic.structures) {
51478
52521
  struct2domain[struct] = {};
@@ -51483,7 +52526,7 @@ class RealignParser {
51483
52526
  let sseCnt = 0;
51484
52527
  for(let serial in atoms) {
51485
52528
  if(ic.atoms[serial].ssbegin) ++sseCnt;
51486
- if(sseCnt == minSseCnt) {
52529
+ if(sseCnt > minSseCnt) {
51487
52530
  struct2domain[struct][chainid] = atoms;
51488
52531
  break;
51489
52532
  }
@@ -51515,7 +52558,6 @@ class RealignParser {
51515
52558
  let chainid2 = chainidArray2[j];
51516
52559
 
51517
52560
  let alignAjax;
51518
-
51519
52561
  if(me.cfg.aligntool != 'tmalign') {
51520
52562
  let jsonStr_q = ic.domain3dCls.getDomainJsonForAlign(struct2domain[struct2][chainid2]);
51521
52563
 
@@ -51554,7 +52596,7 @@ class RealignParser {
51554
52596
 
51555
52597
  async realignOnStructAlignMsa(nameArray) { let ic = this.icn3d, me = ic.icn3dui;
51556
52598
  // each 3D domain should have at least 3 secondary structures
51557
- let minSseCnt = 3;
52599
+ let minSseCnt = (me.cfg.aligntool != 'tmalign') ? 3 : 0;
51558
52600
  let chainid2domain = {};
51559
52601
 
51560
52602
  for(let i = 0, il = nameArray.length; i < il; ++i) {
@@ -51563,7 +52605,7 @@ class RealignParser {
51563
52605
  let sseCnt = 0;
51564
52606
  for(let serial in atoms) {
51565
52607
  if(ic.atoms[serial].ssbegin) ++sseCnt;
51566
- if(sseCnt == minSseCnt) {
52608
+ if(sseCnt > minSseCnt) {
51567
52609
  chainid2domain[chainid] = atoms;
51568
52610
  break;
51569
52611
  }
@@ -53684,7 +54726,7 @@ class ParserUtils {
53684
54726
  if(ic.bAnnoShown) await ic.showAnnoCls.showAnnotations();
53685
54727
  }
53686
54728
 
53687
- // Realign by seqeunce alignment with the residues in "segment", i.e., transmembrane helix
54729
+ // Realign by sequence alignment with the residues in "segment", i.e., transmembrane helix
53688
54730
  let segment = data.segment; // e.g., " 361- 379 ( 359- 384)", the first range is trnasmembrane range,
53689
54731
  //the second range is the range of the helix
53690
54732
  let range = segment.replace(/ /gi, '').split('(')[0]; //361-379
@@ -55498,7 +56540,7 @@ class SetSeqAlign {
55498
56540
 
55499
56541
  //mmdbid1 = ic.mmdbid_t;
55500
56542
  mmdbid1 = chainidArray[0].substr(0, pos1); //.toUpperCase();
55501
- mmdbid2 = chainid.substr(0, pos2); //.toUpperCase();
56543
+ mmdbid2 = chainid.substr(0, pos2); //.toUpperCase()mergeTwoSeqForAll;
55502
56544
 
55503
56545
  chain1 = chainidArray[0].substr(pos1 + 1);
55504
56546
  chain2 = chainid.substr(pos2 + 1);
@@ -55657,14 +56699,121 @@ class SetSeqAlign {
55657
56699
  result = this.getTemplatePosFromOriPos(chainid1, prevIndex1, end_t, bRealign);
55658
56700
  pos1 = result.pos1;
55659
56701
  pos2 = result.pos2;
55660
- //for(let i = pos1; i < pos2; ++i) {
55661
- for(let i = pos1; i <= pos2; ++i) {
56702
+ for(let i = pos1; i < pos2; ++i) {
56703
+ //for(let i = pos1; i <= pos2; ++i) {
55662
56704
  ic.alnChainsSeq[chainid2].push(gapResObject2);
55663
56705
  }
55664
56706
 
55665
56707
  return hAtoms;
55666
56708
  }
55667
56709
 
56710
+ // used for seq MSA
56711
+ mergeTwoSeqForAllSimple(targetId, chainidArray, index, alignedChainIndice, start_t, end_t, querySeqArray) { let ic = this.icn3d; ic.icn3dui;
56712
+ let chainid1 = targetId;
56713
+ let chainid2 = chainidArray[index];
56714
+
56715
+ let pos1, pos2, prevIndex1, prevIndex2;
56716
+
56717
+ for(let i = 0, il = ic.qt_start_end[index].length; i < il; ++i) {
56718
+ let start1, start2, end1, end2, resiStart1, start1Pos, end1Pos;
56719
+
56720
+ start1 = ic.qt_start_end[index][i].t_start;
56721
+ start2 = ic.qt_start_end[index][i].q_start;
56722
+ end1 = ic.qt_start_end[index][i].t_end;
56723
+ end2 = ic.qt_start_end[index][i].q_end;
56724
+
56725
+ // 1. before the mapped residues
56726
+ //resiStart1 = ic.ParserUtilsCls.getResi(chainid1, start1);
56727
+ resiStart1 = start1;
56728
+ start1Pos = start1;
56729
+ end1Pos = end1;
56730
+
56731
+ // if the mapping does not start from start_t, add gaps to the query seq
56732
+ if(i == 0) {
56733
+ pos1 = start_t;
56734
+ pos2 = start1Pos;
56735
+
56736
+ if(start1Pos > start_t) {
56737
+ for(let j = 0, jl = pos2 - pos1; j < jl; ++j) {
56738
+ ic.msaSeq[chainid2] += '-';
56739
+ }
56740
+ }
56741
+ }
56742
+ else {
56743
+ pos1 = prevIndex1;
56744
+ pos2 = start1;
56745
+ let notAlnLen1 = pos2 - (pos1 + 1);
56746
+ let notAlnLen2 = start2 - (prevIndex2 + 1);
56747
+
56748
+ // insert non-aligned residues in query seq
56749
+ // this.insertNotAlignRes(chainid2, prevIndex2+1, notAlnLen2, bRealign);
56750
+
56751
+ for(let j = 0, jl = notAlnLen2; j < jl; ++j) {
56752
+ let resn = querySeqArray[index][prevIndex2+1 + j];
56753
+ ic.msaSeq[chainid2] += resn;
56754
+ }
56755
+
56756
+ if(notAlnLen1 >= notAlnLen2) {
56757
+ // add gaps before the query sequence
56758
+ for(let j = 0, jl = notAlnLen1 - notAlnLen2; j < jl; ++j) {
56759
+ ic.msaSeq[chainid2] += '-';
56760
+ }
56761
+ }
56762
+ else {
56763
+ // check the number of gaps before resiStart1 (n), and insert 'notAlnLen2 - notAlnLen1 - n' gaps
56764
+ // this.addGapAllAlnChains(chainidArray, alignedChainIndice, chainid1, resiStart1, notAlnLen2 - notAlnLen1);
56765
+
56766
+ // let result = this.getResiPosInTemplate(chainid1, resi_t);
56767
+ // let nGap = result.ngap, pos_t = result.pos;
56768
+
56769
+ let pos_t = resiStart1; // position to add gap
56770
+
56771
+ // add gaps for all previously aligned sequences, not the current sequence, which is the last one
56772
+ for(let j = 0, jl = alignedChainIndice.length - 1; j < jl; ++j) {
56773
+ let chainidTmp = (j == 0) ? chainid1 : chainidArray[alignedChainIndice[j]];
56774
+
56775
+ for(let k = 0, kl = notAlnLen2 - notAlnLen1; k < kl; ++k) {
56776
+ //ic.msaSeq[chainidTmp].splice(pos_t, 0, '-');
56777
+ ic.msaSeq[chainidTmp] = ic.msaSeq[chainidTmp].substr(0, pos_t) + '-' + ic.msaSeq[chainidTmp].substr(pos_t);
56778
+ }
56779
+ }
56780
+ }
56781
+ }
56782
+
56783
+ // 2. In the mapped residues
56784
+ pos1 = start1Pos;
56785
+ pos2 = end1Pos;
56786
+
56787
+ let k = 0;
56788
+ for(let j = pos1; j <= pos2; ++j) {
56789
+ // inherit the gaps from the template
56790
+ if(ic.msaSeq[chainid1][j] == '-') {
56791
+ ic.msaSeq[chainid2] += '-';
56792
+ }
56793
+ else {
56794
+ //let resn1 = targetSeq[start1 + k];
56795
+ let resn2 = querySeqArray[index][start2 + k];
56796
+ //let resn2 = (querySeqArray[index]) ? querySeqArray[index][start2 + k] : '?';
56797
+
56798
+ ic.msaSeq[chainid2] += resn2;
56799
+
56800
+ ++k;
56801
+ }
56802
+ }
56803
+
56804
+ prevIndex1 = end1;
56805
+ prevIndex2 = end2;
56806
+ }
56807
+
56808
+ // add gaps at the end
56809
+ pos1 = prevIndex1;
56810
+ pos2 = end_t;
56811
+ for(let i = pos1; i < pos2; ++i) {
56812
+ //for(let i = pos1; i <= pos2; ++i) {
56813
+ ic.msaSeq[chainid2] += '-';
56814
+ }
56815
+ }
56816
+
55668
56817
  setSeqAlignForRealign(chainid_t, chainid, chainIndex) { let ic = this.icn3d, me = ic.icn3dui;
55669
56818
  //var chainid_t = ic.chainidArray[0];
55670
56819
 
@@ -55893,7 +57042,7 @@ class LoadPDB {
55893
57042
  getStructureId(id, moleculeNum, bMutation) { let ic = this.icn3d; ic.icn3dui;
55894
57043
  let structure = id;
55895
57044
 
55896
- if(id == ic.defaultPdbId || bMutation) { // bMutation: side chain prediction
57045
+ if(id == ic.defaultPdbId || bMutation || ic.structures.hasOwnProperty(id)) { // bMutation: side chain prediction
55897
57046
  structure = (moleculeNum === 1) ? id : id + moleculeNum.toString();
55898
57047
  }
55899
57048
 
@@ -55961,7 +57110,7 @@ class LoadPDB {
55961
57110
  let prevMissingChain = '';
55962
57111
  let CSerial, prevCSerial, OSerial, prevOSerial;
55963
57112
 
55964
- let bHeader = false;
57113
+ let bHeader = false, bFirstAtom = true;
55965
57114
 
55966
57115
  for (let i in lines) {
55967
57116
  let line = lines[i];
@@ -56122,7 +57271,11 @@ class LoadPDB {
56122
57271
  ic.pmid = line.substr(19).trim();
56123
57272
  }
56124
57273
  } else if (record === 'ATOM ' || record === 'HETATM') {
56125
- structure = this.getStructureId(id, moleculeNum, bMutation);
57274
+ if(bFirstAtom) {
57275
+ structure = this.getStructureId(id, moleculeNum, bMutation);
57276
+
57277
+ bFirstAtom = false;
57278
+ }
56126
57279
 
56127
57280
  let alt = line.substr(16, 1);
56128
57281
  //if (alt !== " " && alt !== "A") continue;
@@ -57013,7 +58166,7 @@ class Vastplus {
57013
58166
 
57014
58167
  // reinitialize the alignment
57015
58168
  $("#" + ic.pre + "dl_sequence2").html('');
57016
-
58169
+
57017
58170
  for(let j = 0, jl = nodeArray.length; j < jl; ++j) {
57018
58171
  let node = parseInt(nodeArray[j]);
57019
58172
  let segs = queryDataArray[node][0].segs;
@@ -57090,7 +58243,7 @@ class Vastplus {
57090
58243
  for(let j = 0, jl = nodeArray.length; j < jl; ++j) {
57091
58244
  chainpairStr += chainidpairArray[parseInt(nodeArray[j])] + '; ';
57092
58245
  }
57093
- console.log("Selected the alignment: " + chainpairStr);
58246
+ if(!me.bNode) console.log("Selected the alignment: " + chainpairStr);
57094
58247
 
57095
58248
  break;
57096
58249
  }
@@ -57099,7 +58252,7 @@ class Vastplus {
57099
58252
  for(let j = 0, jl = nodeArray.length; j < jl; ++j) {
57100
58253
  chainpairStr += chainidpairArray[parseInt(nodeArray[j])] + '; ';
57101
58254
  }
57102
- console.log("skipped the alignment: " + chainpairStr);
58255
+ if(!me.bNode) console.log("skipped the alignment: " + chainpairStr);
57103
58256
  }
57104
58257
  }
57105
58258
  }
@@ -60238,6 +61391,38 @@ class LoadScript {
60238
61391
 
60239
61392
  await ic.cartoon2dCls.draw2Dcartoon(type);
60240
61393
  }
61394
+ else if(command.indexOf('add msa track') == 0) {
61395
+ //add msa track | chainid " + chainid + " | startpos " + startpos + " | type " + type + " | fastaList " + fastaList
61396
+ let paraArray = command.split(' | ');
61397
+
61398
+ let chainid = paraArray[1].substr(8);
61399
+ let startpos = paraArray[2].substr(9);
61400
+ let type = paraArray[3].substr(5);
61401
+ let fastaList = paraArray[4].substr(10);
61402
+
61403
+ if($("#" + ic.pre + "anno_custom")[0]) {
61404
+ $("#" + ic.pre + "anno_custom")[0].checked = true;
61405
+ }
61406
+ $("[id^=" + ic.pre + "custom]").show();
61407
+
61408
+ await ic.addTrackCls.addMsaTracks(chainid, startpos, type, fastaList);
61409
+ }
61410
+ else if(command.indexOf('add exon track') == 0) {
61411
+ //add exon track | chainid " + chainid + " | geneid " + geneid + " | startpos " + startpos + " | type " + type
61412
+ let paraArray = command.split(' | ');
61413
+
61414
+ let chainid = paraArray[1].substr(8);
61415
+ let geneid = paraArray[2].substr(7);
61416
+ let startpos = paraArray[3].substr(9);
61417
+ let type = paraArray[4].substr(5);
61418
+
61419
+ if($("#" + ic.pre + "anno_custom")[0]) {
61420
+ $("#" + ic.pre + "anno_custom")[0].checked = true;
61421
+ }
61422
+ $("[id^=" + ic.pre + "custom]").show();
61423
+
61424
+ await ic.addTrackCls.addExonTracks(chainid, geneid, startpos, type);
61425
+ }
60241
61426
  else {
60242
61427
  await ic.applyCommandCls.applyCommand(ic.commands[i]);
60243
61428
  }
@@ -60484,6 +61669,10 @@ class LoadScript {
60484
61669
  me.cfg.refseqid = id;
60485
61670
  await ic.mmdbParserCls.downloadRefseq(id);
60486
61671
  }
61672
+ else if(command.indexOf('load protein') !== -1) {
61673
+ me.cfg.protein = id;
61674
+ await ic.mmdbParserCls.downloadProteinname(id);
61675
+ }
60487
61676
  else if(command.indexOf('load seq_struct_ids ') !== -1) {
60488
61677
  ic.bSmithwm = false;
60489
61678
  ic.bLocalSmithwm = false;
@@ -60946,12 +62135,18 @@ class SelectByCommand {
60946
62135
  residueStr = "*";
60947
62136
  }
60948
62137
  else if(colonPos2 != -1) {
60949
- refResStr = testStr.substr(colonPos2 + 5);
60950
- testStr = testStr.substr(0, colonPos2);
62138
+ refResStr = testStr.substr(colonPos2 + 5);
62139
+ testStr = testStr.substr(0, colonPos2);
62140
+
62141
+ // somehow sometimes refResStr or residueStr is rmpty
62142
+ if(!refResStr) continue;
60951
62143
  }
60952
62144
  else if(colonPos != -1) {
60953
- residueStr = testStr.substr(colonPos + 1);
60954
- testStr = testStr.substr(0, colonPos);
62145
+ residueStr = testStr.substr(colonPos + 1);
62146
+ testStr = testStr.substr(0, colonPos);
62147
+
62148
+ // somehow sometimes refResStr or residueStr is rmpty
62149
+ if(!residueStr) continue;
60955
62150
  }
60956
62151
 
60957
62152
  if(periodPos === -1) {
@@ -61579,6 +62774,8 @@ class Selection {
61579
62774
  ic.graphStr = this.getGraphDataForDisplayed();
61580
62775
  }
61581
62776
 
62777
+ ic.saveFileCls.showTitle();
62778
+
61582
62779
  // don not redraw graphs after the selection changes
61583
62780
  /*
61584
62781
  if(ic.bGraph) ic.drawGraphCls.drawGraph(ic.graphStr, ic.pre + 'dl_graph');
@@ -66818,7 +68015,7 @@ class ResizeCanvas {
66818
68015
  //let itemArray = ['dl_selectannotations', 'dl_alignment', 'dl_2ddgm', 'dl_definedsets', 'dl_graph',
66819
68016
  // 'dl_linegraph', 'dl_scatterplot', 'dl_contactmap', 'dl_allinteraction', 'dl_copyurl',
66820
68017
  // 'dl_symmetry', 'dl_symd', 'dl_rmsd', 'dl_legend', 'dl_disttable'];
66821
- 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'];
68018
+ 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'];
66822
68019
 
66823
68020
  for(let i in itemArray) {
66824
68021
  let item = itemArray[i];
@@ -67952,13 +69149,13 @@ class SaveFile {
67952
69149
 
67953
69150
  //Show the title and PDB ID of the PDB structure at the beginning of the viewer.
67954
69151
  showTitle() {var ic = this.icn3d, me = ic.icn3dui;
67955
- if(ic.molTitle !== undefined && ic.molTitle !== '') {
67956
- let title = ic.molTitle;
69152
+ // if(ic.molTitle !== undefined && ic.molTitle !== '') {
69153
+ let title = (ic.molTitle) ? ic.molTitle : '';
67957
69154
 
67958
69155
  let titlelinkColor =(ic.opts['background'] == 'black') ? me.htmlCls.GREYD : 'black';
67959
69156
 
67960
69157
  if(ic.inputid === undefined) {
67961
- if(ic.molTitle.length > 40) title = ic.molTitle.substr(0, 40) + "...";
69158
+ if(title.length > 40) title = title.substr(0, 40) + "...";
67962
69159
 
67963
69160
  $("#" + ic.pre + "title").html(title);
67964
69161
  }
@@ -67978,31 +69175,38 @@ class SaveFile {
67978
69175
 
67979
69176
  $("#" + ic.pre + "title").html(title);
67980
69177
  }
67981
- else if(me.cfg.mmdbafid !== undefined) {
67982
- let structureArray = Object.keys(ic.structures); //me.cfg.mmdbafid.split(',');
69178
+ else { //if(me.cfg.mmdbafid !== undefined) {
69179
+ //let structureArray = Object.keys(ic.structures); //me.cfg.mmdbafid.split(',');
69180
+ let structureArray = Object.keys(me.utilsCls.getStructures(ic.dAtoms));
69181
+
67983
69182
  if(structureArray.length > 1) {
67984
- title = 'Multiple structures: ' + structureArray;
69183
+ title = 'Multiple structures: ';
69184
+ for(let i = 0, il = structureArray.length; i < il; ++i) {
69185
+ 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];
69186
+ title += '<a href="' + url + '" style="color:' + titlelinkColor + '" target="_blank">' + structureArray[i] + '</a>';
69187
+ if(i < il - 1) title += ', ';
69188
+ }
67985
69189
  $("#" + ic.pre + "title").html(title);
67986
69190
  }
67987
69191
  else if(structureArray.length == 1) {
67988
69192
  //let url = this.getLinkToStructureSummary();
67989
- 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;
69193
+ 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];
67990
69194
 
67991
69195
  this.setStructureTitle(url, title, titlelinkColor);
67992
69196
  }
67993
69197
  }
67994
- else {
67995
- let url = this.getLinkToStructureSummary();
67996
- this.setStructureTitle(url, title, titlelinkColor);
67997
- }
67998
- }
67999
- else {
68000
- $("#" + ic.pre + "title").html("");
68001
- }
69198
+ // else {
69199
+ // let url = this.getLinkToStructureSummary();
69200
+ // this.setStructureTitle(url, title, titlelinkColor);
69201
+ // }
69202
+ // }
69203
+ // else {
69204
+ // $("#" + ic.pre + "title").html("");
69205
+ // }
68002
69206
  }
68003
69207
 
68004
69208
  setStructureTitle(url, title, titlelinkColor) {var ic = this.icn3d, me = ic.icn3dui;
68005
- if(ic.molTitle.length > 40) title = ic.molTitle.substr(0, 40) + "...";
69209
+ if(title.length > 40) title = title.substr(0, 40) + "...";
68006
69210
 
68007
69211
  let inputid = ic.inputid;
68008
69212
 
@@ -68028,7 +69232,7 @@ class SaveFile {
68028
69232
  let structureidArray = Object.keys(idHash);
68029
69233
  inputid = structureidArray.join(',');
68030
69234
 
68031
- text = (me.cfg.refseqid) ? ic.inputid : inputid.toUpperCase();
69235
+ text = (me.cfg.refseqid || me.cfg.protein) ? ic.inputid : inputid.toUpperCase();
68032
69236
 
68033
69237
  //idName = (isNaN(inputid) && inputid.length > 5) ? "AlphaFold ID" : "PDB ID";
68034
69238
  if(bPdb && bAlphaFold) {
@@ -68054,7 +69258,12 @@ class SaveFile {
68054
69258
  }
68055
69259
  }
68056
69260
 
68057
- if(me.cfg.refseqid) idName = 'NCBI Protein Acc.';
69261
+ if(me.cfg.refseqid) {
69262
+ idName = 'NCBI Protein Acc.';
69263
+ }
69264
+ else if(me.cfg.protein) {
69265
+ idName = 'Protein/Gene Name';
69266
+ }
68058
69267
 
68059
69268
  if(!inputid || inputid.substr(0, 4) == ic.defaultPdbId) {
68060
69269
  $("#" + ic.pre + "title").html(title);
@@ -71326,7 +72535,7 @@ class iCn3DUI {
71326
72535
  //even when multiple iCn3D viewers are shown together.
71327
72536
  this.pre = this.cfg.divid + "_";
71328
72537
 
71329
- this.REVISION = '3.26.0';
72538
+ this.REVISION = '3.28.0';
71330
72539
 
71331
72540
  // In nodejs, iCn3D defines "window = {navigator: {}}"
71332
72541
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -71619,6 +72828,14 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
71619
72828
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
71620
72829
  await ic.mmdbParserCls.downloadRefseq(me.cfg.refseqid);
71621
72830
  }
72831
+ else if(me.cfg.protein !== undefined) {
72832
+ ic.inputid = me.cfg.protein;
72833
+
72834
+ // ic.bNCBI = true;
72835
+ ic.loadCmd = 'load protein ' + me.cfg.protein;
72836
+ me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
72837
+ await ic.mmdbParserCls.downloadProteinname(me.cfg.protein);
72838
+ }
71622
72839
  else if(me.cfg.blast_rep_id !== undefined) {
71623
72840
  // ic.bNCBI = true;
71624
72841
  ic.inputid = me.cfg.query_id + ',' + me.cfg.blast_rep_id;
@@ -71626,7 +72843,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
71626
72843
  me.cfg.oriQuery_id = me.cfg.query_id;
71627
72844
  me.cfg.oriBlast_rep_id = me.cfg.blast_rep_id;
71628
72845
 
71629
- // custom seqeunce has query_id such as "Query_78989" in BLAST
72846
+ // custom sequence has query_id such as "Query_78989" in BLAST
71630
72847
  if(me.cfg.query_id.substr(0,5) !== 'Query' && me.cfg.rid === undefined) {
71631
72848
  // make it backward compatible for figure 2 in iCn3D paper: https://academic.oup.com/bioinformatics/article/36/1/131/5520951
71632
72849
  if(me.cfg.from == 'icn3d' && me.cfg.blast_rep_id == '1TSR_A' && me.cfg.query_id == 'NP_001108451.1') {