icn3d 3.32.0 → 3.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/icn3d.js +694 -334
  2. package/icn3d.min.js +3 -11
  3. package/icn3d.module.js +694 -334
  4. package/package.json +1 -1
package/icn3d.module.js CHANGED
@@ -7794,7 +7794,10 @@ class UtilsCls {
7794
7794
  let nOtherAtoms = 0;
7795
7795
  for(let i in atomlist) {
7796
7796
  if(index < testLength) {
7797
- let atomName = atomlist[i].name.trim();
7797
+ let atomName = atomlist[i].name;
7798
+ if(!atomName) continue;
7799
+ atomName = atomName.trim();
7800
+
7798
7801
  if(atomName !== "CA" && atomName !== "P" && atomName !== "O3'" && atomName !== "O3*") {
7799
7802
  //bOtherAtoms = true;
7800
7803
  //break;
@@ -9947,7 +9950,7 @@ class ClickMenu {
9947
9950
  });
9948
9951
 
9949
9952
  me.myEventCls.onIds("#" + me.pre + "mn1_cid", "click", function(e) { me.icn3d; //e.preventDefault();
9950
- me.htmlCls.dialogCls.openDlg('dl_cid', 'Please input PubChem CID');
9953
+ me.htmlCls.dialogCls.openDlg('dl_cid', 'Please input PubChem Compound');
9951
9954
  });
9952
9955
 
9953
9956
  me.myEventCls.onIds("#" + me.pre + "mn1_pngimage", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -11489,6 +11492,13 @@ class ClickMenu {
11489
11492
  ic.drawCls.draw();
11490
11493
  });
11491
11494
 
11495
+ me.myEventCls.onIds("#" + me.pre + "mn6_addlabelIg", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11496
+ ic.residueLabelsCls.addIgLabels(ic.hAtoms);
11497
+ ic.selectionCls.saveSelectionIfSelected();
11498
+ thisClass.setLogCmd('add ig labels', true);
11499
+ ic.drawCls.draw();
11500
+ });
11501
+
11492
11502
  me.myEventCls.onIds("#" + me.pre + "mn6_addlabelChains", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11493
11503
  ic.analysisCls.addChainLabels(ic.hAtoms);
11494
11504
  ic.selectionCls.saveSelectionIfSelected();
@@ -11564,13 +11574,21 @@ class ClickMenu {
11564
11574
  });
11565
11575
 
11566
11576
  me.myEventCls.onIds("#" + me.pre + "mn6_distManySets", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11567
- me.htmlCls.dialogCls.openDlg('dl_distmanysets', 'Measure the pairwise distance among many sets');
11577
+ me.htmlCls.dialogCls.openDlg('dl_distmanysets', 'Measure the pairwise distances among many sets');
11568
11578
 
11569
11579
  thisClass.setSetsMenus('atomsCustomDistTable');
11570
11580
 
11571
11581
  ic.bMeasureDistance = true;
11572
11582
  });
11573
11583
 
11584
+ me.myEventCls.onIds("#" + me.pre + "mn6_angleManySets", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11585
+ me.htmlCls.dialogCls.openDlg('dl_anglemanysets', 'Measure the pairwise angles among many sets');
11586
+
11587
+ thisClass.setSetsMenus('atomsCustomAngleTable');
11588
+
11589
+ ic.bMeasureAngle = true;
11590
+ });
11591
+
11574
11592
  me.myEventCls.onIds("#" + me.pre + "mn6_distanceNo", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11575
11593
  ic.pickpair = false;
11576
11594
  let select = "set lines off";
@@ -11655,6 +11673,10 @@ class ClickMenu {
11655
11673
  me.htmlCls.dialogCls.openDlg('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
11656
11674
  });
11657
11675
 
11676
+ $(document).on("click", "#" + me.pre + "mn6_angleTwoSets", function(e) { me.icn3d; //e.preventDefault();
11677
+ me.htmlCls.dialogCls.openDlg('dl_angle', 'Measure the angle between two vectors');
11678
+ });
11679
+
11658
11680
  $(document).on("click", "#" + me.pre + "mn2_matrix", function(e) { me.icn3d; //e.preventDefault();
11659
11681
  me.htmlCls.dialogCls.openDlg('dl_matrix', 'Apply matrix to the X,Y,Z coordinates of the structure');
11660
11682
  });
@@ -12575,7 +12597,7 @@ class SetMenu {
12575
12597
  html += this.getLink('mn1_mmcifid', 'RCSB mmCIF ID ' + me.htmlCls.wifiStr, undefined, 2);
12576
12598
  //html += this.getLink('mn1_gi', 'NCBI gi ' + me.htmlCls.wifiStr, undefined, 2);
12577
12599
 
12578
- html += this.getLink('mn1_cid', 'PubChem CID ' + me.htmlCls.wifiStr, 1, 2);
12600
+ html += this.getLink('mn1_cid', 'PubChem CID/Name/InchI ' + me.htmlCls.wifiStr, 1, 2);
12579
12601
 
12580
12602
  html += "</ul>";
12581
12603
  html += "</li>";
@@ -12585,7 +12607,7 @@ class SetMenu {
12585
12607
  // html += this.getLink('mn1_pdbfile', 'PDB File');
12586
12608
  // html += this.getLink('mn1_pdbfile_app', 'PDB File (append)');
12587
12609
  html += this.getLink('mn1_pdbfile_app', 'PDB Files (appendable)', 1, 2);
12588
- html += this.getLink('mn1_mmciffile', 'mmCIF File (appendable)', undefined, 2);
12610
+ html += this.getLink('mn1_mmciffile', 'mmCIF Files (appendable)', undefined, 2);
12589
12611
  html += this.getLink('mn1_mol2file', 'Mol2 File', undefined, 2);
12590
12612
  html += this.getLink('mn1_sdffile', 'SDF File', undefined, 2);
12591
12613
  html += this.getLink('mn1_xyzfile', 'XYZ File', undefined, 2);
@@ -12713,15 +12735,12 @@ class SetMenu {
12713
12735
  html += this.getLink('mn1_exportSecondary', 'Secondary Structure', undefined, 2);
12714
12736
  }
12715
12737
 
12716
- //!!!
12717
- /*
12718
12738
  html += this.getMenuText('m1_exportrefnum', 'Reference Numbers', undefined, undefined, 2);
12719
12739
  html += "<ul>";
12720
12740
  html += this.getLink('mn1_exportIgstrand', 'Ig Strand', undefined, 3);
12721
12741
  html += this.getLink('mn1_exportKabat', 'Kabat', undefined, 3);
12722
12742
  html += this.getLink('mn1_exportImgt', 'IMGT', undefined, 3);
12723
12743
  html += "</ul>";
12724
- */
12725
12744
 
12726
12745
  html += "<li><br/></li>";
12727
12746
 
@@ -13564,9 +13583,8 @@ class SetMenu {
13564
13583
  html += this.getRadio('mn4_clr', 'mn4_clrConfidence', 'pLDDT', undefined, 1, 1);
13565
13584
  //}
13566
13585
 
13567
- //!!!
13568
- // html += this.getRadio('mn4_clr', 'mn4_clrIgstrand', 'Ig Strand', undefined, undefined, 2);
13569
- // html += this.getRadio('mn4_clr', 'mn4_clrIgproto', 'Ig Protodomain', undefined, undefined, 2);
13586
+ html += this.getRadio('mn4_clr', 'mn4_clrIgstrand', 'Ig Strand', undefined, undefined, 2);
13587
+ html += this.getRadio('mn4_clr', 'mn4_clrIgproto', 'Ig Protodomain', undefined, undefined, 2);
13570
13588
  }
13571
13589
  else {
13572
13590
  //if(!me.cfg.hidelicense) html += this.getRadio('mn4_clr', 'mn1_delphi2', 'DelPhi<br><span style="padding-left:1.5em;">Potential ' + me.htmlCls.licenseStr + '</span>');
@@ -13680,11 +13698,18 @@ class SetMenu {
13680
13698
  html += "<ul>";
13681
13699
  html += this.getRadio('mn6_distance', 'mn6_distanceYes', 'between Two Atoms', undefined, 1, 2);
13682
13700
  html += this.getRadio('mn6_distance', 'mn6_distTwoSets', 'between Two Sets', undefined, undefined, 2);
13683
- html += this.getRadio('mn6_distance', 'mn6_distManySets', 'Among Many Sets', undefined, undefined, 2);
13701
+ html += this.getRadio('mn6_distance', 'mn6_distManySets', 'among Many Sets', undefined, undefined, 2);
13684
13702
  html += this.getRadio('mn6_distance', 'mn6_distanceNo', 'Hide', true, 1, 2);
13685
13703
  html += "</ul>";
13686
13704
  html += "</li>";
13687
13705
 
13706
+ html += this.getMenuText('mn6_anglewrap', 'Angle', undefined, 1, 1);
13707
+ html += "<ul>";
13708
+ html += this.getRadio('mn6_angle', 'mn6_angleManySets', 'among Many Sets', undefined, 1, 2);
13709
+ html += this.getRadio('mn6_angle', 'mn6_angleTwoSets', 'b/w Two Vectors', undefined, undefined, 2);
13710
+ html += "</ul>";
13711
+ html += "</li>";
13712
+
13688
13713
  html += this.getLink('mn6_area', 'Surface Area', 1, 1);
13689
13714
 
13690
13715
  html += this.getMenuText('mn6_addlabelwrap', 'Label', undefined, 1, 1);
@@ -13696,8 +13721,10 @@ class SetMenu {
13696
13721
  if(me.cfg.cid === undefined) {
13697
13722
  html += this.getRadio('mn6_addlabel', 'mn6_addlabelResidues', 'per Residue', undefined, 1, 2);
13698
13723
  html += this.getRadio('mn6_addlabel', 'mn6_addlabelResnum', 'per Residue & Number', undefined, 1, 2);
13699
- //!!!
13700
- // html += this.getRadio('mn6_addlabel', 'mn6_addlabelRefnum', 'per Reference Number', undefined, 1, 2);
13724
+
13725
+ html += this.getRadio('mn6_addlabel', 'mn6_addlabelRefnum', 'per Reference Number', undefined, 1, 2);
13726
+ html += this.getRadio('mn6_addlabel', 'mn6_addlabelIg', 'per Ig Domain', undefined, 1, 2);
13727
+
13701
13728
  html += this.getRadio('mn6_addlabel', 'mn6_addlabelChains', 'per Chain', undefined, undefined, 2);
13702
13729
  html += this.getRadio('mn6_addlabel', 'mn6_addlabelTermini', 'N- & C-Termini', undefined, 1, 2);
13703
13730
  }
@@ -13790,17 +13817,13 @@ class SetMenu {
13790
13817
  html += this.getMenuText('mn6_igrefwrap', 'Ref. Number', undefined, undefined, 1);
13791
13818
 
13792
13819
  html += "<ul>";
13793
- //!!!
13794
- /*
13820
+
13795
13821
  html += this.getLink('mn6_igrefYes', 'Show Ig for Selection', undefined, 2);
13796
13822
  html += this.getLink('mn6_igrefTpl', 'Ig w/ Specified Template', undefined, 2);
13797
13823
  html += this.getLink('mn6_alignrefTpl', 'Align w/ Specified Template', undefined, 2);
13798
13824
  html += this.getLink('mn6_igrefNo', 'Reset Ig Ref. Number', undefined, 2);
13799
13825
 
13800
13826
  html += this.getMenuSep();
13801
- */
13802
-
13803
-
13804
13827
 
13805
13828
  html += this.getLink('mn6_customref', 'Custom Ref. Number', undefined, 2);
13806
13829
  html += "</ul>";
@@ -13890,6 +13913,7 @@ class SetMenu {
13890
13913
  html += this.getMenuUrl('faq_simialphapdb', me.htmlCls.baseUrl + "icn3d/icn3d.html#simifoldseek", "Similar AlphaFold/PDB", 1, 2);
13891
13914
  html += this.getMenuUrl('faq_alnstru', me.htmlCls.baseUrl + "icn3d/icn3d.html#alignmul", "Align Multiple Structures", 1, 2);
13892
13915
  html += this.getMenuUrl('faq_batchanal', me.htmlCls.baseUrl + "icn3d/icn3d.html#batchanalysis", "Batch Analysis", 1, 2);
13916
+ html += this.getMenuUrl('faq_batchanal', me.htmlCls.baseUrl + "icn3d/icn3d.html#igrefnum", "Assign Ig Ref. Numbers", 1, 2);
13893
13917
  html += this.getMenuUrl('faq_embedicn3d', me.htmlCls.baseUrl + "icn3d/icn3d.html#embedicn3d", "Embed iCn3D", 1, 2);
13894
13918
  html += "</ul>";
13895
13919
  html += "</li>";
@@ -15001,8 +15025,8 @@ class SetDialog {
15001
15025
  html += "</div>";
15002
15026
 
15003
15027
  html += me.htmlCls.divStr + "dl_cid' class='" + dialogClass + "'>";
15004
- html += this.addNotebookTitle('dl_cid', 'Please input a PubChem CID');
15005
- html += "PubChem CID: " + me.htmlCls.inputTextStr + "id='" + me.pre + "cid' value='2244' size=8> ";
15028
+ html += this.addNotebookTitle('dl_cid', 'Please input a PubChem Compound');
15029
+ html += "PubChem CID/Name/InchI: " + me.htmlCls.inputTextStr + "id='" + me.pre + "cid' value='2244' size=8> ";
15006
15030
  html += me.htmlCls.buttonStr + "reload_cid'>Load</button>";
15007
15031
  html += "</div>";
15008
15032
 
@@ -15633,6 +15657,28 @@ class SetDialog {
15633
15657
  html += me.htmlCls.spanNowrapStr + "2. " + me.htmlCls.buttonStr + "applydisttable'>Distances in Table</button></span>";
15634
15658
  html += "</div>";
15635
15659
 
15660
+
15661
+ html += me.htmlCls.divStr + "dl_anglemanysets' class='" + dialogClass + "'>";
15662
+ html += this.addNotebookTitle('dl_anglemanysets', 'Measure angles among many sets');
15663
+ html += me.htmlCls.spanNowrapStr + "1. Select sets for pairwise angles</span><br/>";
15664
+ html += "<table border=0 width=400 cellspacing=10><tr><td>";
15665
+
15666
+ html += me.htmlCls.divNowrapStr + "First sets:</div>";
15667
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "atomsCustomAngleTable2' multiple size='5' style='min-width:130px;'>";
15668
+ html += "</select></div>";
15669
+
15670
+ html += "</td><td>";
15671
+
15672
+ html += me.htmlCls.divNowrapStr + "Second sets:</div>";
15673
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "atomsCustomAngleTable' multiple size='5' style='min-width:130px;'>";
15674
+ html += "</select></div>";
15675
+
15676
+ html += "</td></tr></table>";
15677
+
15678
+ html += me.htmlCls.spanNowrapStr + "2. " + me.htmlCls.buttonStr + "applyangletable'>Angles in Table</button></span>";
15679
+ html += "</div>";
15680
+
15681
+
15636
15682
  html += me.htmlCls.divStr + "dl_stabilizer_rm' class='" + dialogClass + "'>";
15637
15683
  html += this.addNotebookTitle('dl_stabilizer_rm', 'Remove a stabilizer');
15638
15684
  if(me.utilsCls.isMobile()) {
@@ -15912,6 +15958,11 @@ class SetDialog {
15912
15958
  html += this.addNotebookTitle('dl_disttable', 'Distance Table', true);
15913
15959
  html += "</div>";
15914
15960
 
15961
+
15962
+ html += me.htmlCls.divStr + "dl_angletable' class='" + dialogClass + "'>";
15963
+ html += this.addNotebookTitle('dl_angletable', 'Angle Table', true);
15964
+ html += "</div>";
15965
+
15915
15966
  html += me.htmlCls.divStr + "dl_translate' class='" + dialogClass + "'>";
15916
15967
  html += this.addNotebookTitle('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
15917
15968
  html += "X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "translateX' value='' size=4> ";
@@ -15920,6 +15971,20 @@ class SetDialog {
15920
15971
  html += me.htmlCls.buttonStr + "translate_pdb'>Translate</button>";
15921
15972
  html += "</div>";
15922
15973
 
15974
+ html += me.htmlCls.divStr + "dl_angle' class='" + dialogClass + "'>";
15975
+ html += this.addNotebookTitle('dl_angle', 'Measure the angle between two vectors');
15976
+ html += "<b>Vector 1</b>, X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1X' value='' size=6> ";
15977
+ html += "Y: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1Y' value='' size=6> ";
15978
+ html += "Z: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v1Z' value='' size=6><br>";
15979
+ html += "<b>Vector 2</b>, X: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2X' value='' size=6> ";
15980
+ html += "Y: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2Y' value='' size=6> ";
15981
+ html += "Z: " + me.htmlCls.inputTextStr + "id='" + me.pre + "v2Z' value='' size=6><br>";
15982
+ html += "<br>";
15983
+
15984
+ html += me.htmlCls.buttonStr + "measure_angle'>Measure Angle</button>";
15985
+ html += "The angle is: " + me.htmlCls.inputTextStr + "id='" + me.pre + "angle_value' value='' size=6> degree.";
15986
+ html += "</div>";
15987
+
15923
15988
  html += me.htmlCls.divStr + "dl_matrix' class='" + dialogClass + "'>";
15924
15989
  html += this.addNotebookTitle('dl_matrix', 'Apply matrix to the X,Y,Z coordinates of the structure');
15925
15990
  html += "0: " + me.htmlCls.inputTextStr + "id='" + me.pre + "matrix0' value='1' size=2> ";
@@ -16078,13 +16143,10 @@ class SetDialog {
16078
16143
  html += tmpStr1 + me.htmlCls.inputCheckStr + "id='" + me.pre + "anno_interact'>Interactions" + me.htmlCls.space2 + "</span></td>";
16079
16144
  html += tmpStr1 + me.htmlCls.inputCheckStr + "id='" + me.pre + "anno_crosslink'>Cross-Linkages" + me.htmlCls.space2 + "</span></td>";
16080
16145
  html += tmpStr1 + me.htmlCls.inputCheckStr + "id='" + me.pre + "anno_transmem'>Transmembrane" + me.htmlCls.space2 + "</span></td>";
16081
- //!!!
16082
- /*
16146
+
16083
16147
  html += "<td></td>";
16084
16148
  html += "</tr><tr>";
16085
16149
  html += tmpStr1 + me.htmlCls.inputCheckStr + "id='" + me.pre + "anno_ig'>Ig Domains" + me.htmlCls.space2 + "</span></td>";
16086
- */
16087
-
16088
16150
 
16089
16151
  html += "<td></td>";
16090
16152
  html += "</tr></table></div></div>";
@@ -16766,6 +16828,27 @@ class Events {
16766
16828
  thisClass.setLogCmd("translate pdb " + dx + " " + dy + " " + dz, true);
16767
16829
  });
16768
16830
 
16831
+ me.myEventCls.onIds("#" + me.pre + "measure_angle", "click", function(e) { me.icn3d;
16832
+ e.preventDefault();
16833
+ if(!me.cfg.notebook) dialog.dialog( "close" );
16834
+ let v1X = $("#" + me.pre + "v1X").val();
16835
+ let v1Y = $("#" + me.pre + "v1Y").val();
16836
+ let v1Z= $("#" + me.pre + "v1Z").val();
16837
+
16838
+ let v2X = $("#" + me.pre + "v2X").val();
16839
+ let v2Y = $("#" + me.pre + "v2Y").val();
16840
+ let v2Z = $("#" + me.pre + "v2Z").val();
16841
+
16842
+ let angleRad = new THREE.Vector3(parseFloat(v1X), parseFloat(v1Y), parseFloat(v1Z)).angleTo(new THREE.Vector3(parseFloat(v2X), parseFloat(v2Y), parseFloat(v2Z)));
16843
+ let angle = angleRad / 3.1416 * 180;
16844
+ angle = Math.abs(angle).toFixed(0);
16845
+ if(angle > 180) angle -= 180;
16846
+ if(angle > 90) angle = 180 - angle;
16847
+
16848
+ thisClass.setLogCmd("The angle is " + angle + " degree", false);
16849
+ $("#" + me.pre + "angle_value").val(angle);
16850
+ });
16851
+
16769
16852
  me.myEventCls.onIds("#" + me.pre + "matrix_pdb", "click", function(e) { let ic = me.icn3d;
16770
16853
  e.preventDefault();
16771
16854
  if(!me.cfg.notebook) dialog.dialog( "close" );
@@ -18422,6 +18505,20 @@ class Events {
18422
18505
  thisClass.setLogCmd("disttable | " + nameArray2 + " " + nameArray, true);
18423
18506
  });
18424
18507
 
18508
+ me.myEventCls.onIds("#" + me.pre + "applyangletable", "click", function(e) { let ic = me.icn3d;
18509
+ e.preventDefault();
18510
+ if(!me.cfg.notebook) dialog.dialog( "close" );
18511
+ ic.bMeasureAngle = false;
18512
+
18513
+ let nameArray = $("#" + me.pre + "atomsCustomAngleTable").val();
18514
+ let nameArray2 = $("#" + me.pre + "atomsCustomAngleTable2").val();
18515
+
18516
+ ic.analysisCls.measureAngleManySets(nameArray, nameArray2);
18517
+ me.htmlCls.dialogCls.openDlg('dl_angletable', 'Angles among the sets');
18518
+
18519
+ thisClass.setLogCmd("angletable | " + nameArray2 + " " + nameArray, true);
18520
+ });
18521
+
18425
18522
  me.myEventCls.onIds("#" + me.pre + "applylinebtwsets", "click", function(e) { let ic = me.icn3d;
18426
18523
  e.preventDefault();
18427
18524
 
@@ -29011,18 +29108,17 @@ class Strand {
29011
29108
 
29012
29109
  let bRibbon = fill ? true: false;
29013
29110
 
29014
- // when highlight, the input atoms may only include part of sheet or helix
29015
- // include the whole sheet or helix when highlighting
29111
+ // when highlight, the input atoms may only include one rediue.
29112
+ // add one extra residue to show the strand
29016
29113
  let atomsAdjust = {};
29017
29114
 
29018
- // if( Object.keys(atoms).length < Object.keys(ic.atoms).length) {
29019
- // atomsAdjust = this.getSSExpandedAtoms(atoms);
29020
- // }
29021
- // else {
29022
- // atomsAdjust = atoms;
29023
- // }
29024
-
29025
- atomsAdjust = atoms;
29115
+ let residueHashTmp = ic.firstAtomObjCls.getResiduesFromAtoms(atoms);
29116
+ if( Object.keys(residueHashTmp).length == 1) {
29117
+ atomsAdjust = this.getOneExtraResidue(residueHashTmp);
29118
+ }
29119
+ else {
29120
+ atomsAdjust = atoms;
29121
+ }
29026
29122
 
29027
29123
  if(bHighlight === 2) {
29028
29124
  if(fill) {
@@ -29057,22 +29153,24 @@ class Strand {
29057
29153
  let currentChain, currentResi, currentCA = null, currentO = null, currentColor = null, prevCoorCA = null, prevCoorO = null, prevColor = null;
29058
29154
  let prevCO = null, ss = null, ssend = false, atomid = null, prevAtomid = null, prevAtomSelected = null, prevResi = null, calphaid = null, prevCalphaid = null;
29059
29155
  let strandWidth, bSheetSegment = false, bHelixSegment = false;
29060
- let atom, tubeAtoms = {};
29061
29156
 
29062
- // test the first 30 atoms to see whether only C-alpha is available
29063
- ic.bCalphaOnly = me.utilsCls.isCalphaPhosOnly(atomsAdjust); //, 'CA');
29157
+ // For each chain, test the first 30 atoms to see whether only C-alpha is available
29158
+ let bCalphaOnlyHash = {};
29159
+ for(let chainid in ic.chains) {
29160
+ let atoms = me.hashUtilsCls.hash2Atoms(ic.chains[chainid], ic.atoms);
29161
+ let bCalphaOnly = me.utilsCls.isCalphaPhosOnly(atoms); //, 'CA');
29162
+ bCalphaOnlyHash[chainid] = bCalphaOnly;
29163
+ }
29064
29164
 
29065
29165
  // when highlight, draw whole beta sheet and use bShowArray to show the highlight part
29066
29166
  let residueHash = {};
29067
29167
  for(let i in atomsAdjust) {
29068
- let atom = atomsAdjust[i];
29168
+ let atom = ic.atoms[i];
29069
29169
 
29070
29170
  let residueid = atom.structure + '_' + atom.chain + '_' + atom.resi;
29071
29171
  residueHash[residueid] = 1;
29072
29172
  }
29073
- let totalResidueCount = Object.keys(residueHash).length;
29074
-
29075
- let drawnResidueCount = 0;
29173
+ Object.keys(residueHash).length;
29076
29174
 
29077
29175
  let bFullAtom = (Object.keys(ic.hAtoms).length == Object.keys(ic.atoms).length) ? true : false;
29078
29176
 
@@ -29081,22 +29179,20 @@ class Strand {
29081
29179
  let maxDist = 6.0;
29082
29180
 
29083
29181
  //get the last residue
29084
- let atomArray = Object.keys(atoms);
29182
+ let atomArray = Object.keys(atomsAdjust);
29085
29183
  let lastAtomSerial = atomArray[atomArray.length - 1];
29086
- let lastAtom = atoms[lastAtomSerial];
29184
+ let lastAtom = ic.atoms[lastAtomSerial];
29087
29185
  let lastResid = lastAtom.structure + '_' + lastAtom.chain + '_' + lastAtom.resi;
29088
29186
 
29089
29187
  for (let i in atomsAdjust) {
29090
- atom = atomsAdjust[i];
29188
+ let atom = ic.atoms[i];
29091
29189
  let chainid = atom.structure + '_' + atom.chain;
29092
29190
  let resid = atom.structure + '_' + atom.chain + '_' + atom.resi;
29093
29191
  if ((atom.name === 'O' || atom.name === 'CA') && !atom.het) {
29094
29192
  // "CA" has to appear before "O"
29095
29193
 
29096
29194
  if (atom.name === 'CA') {
29097
- if ( atoms.hasOwnProperty(i) && ((atom.ss !== 'helix' && atom.ss !== 'sheet') || atom.ssend || atom.ssbegin) ) {
29098
- tubeAtoms[i] = atom;
29099
- }
29195
+ if ( atoms.hasOwnProperty(i) && ((atom.ss !== 'helix' && atom.ss !== 'sheet') || atom.ssend || atom.ssbegin) ) ;
29100
29196
 
29101
29197
  currentCA = atom.coord;
29102
29198
  currentColor = atom.color;
@@ -29105,7 +29201,7 @@ class Strand {
29105
29201
  caArray.push(atom.serial);
29106
29202
  }
29107
29203
 
29108
- if (atom.name === 'O' || (ic.bCalphaOnly && atom.name === 'CA')) {
29204
+ if (atom.name === 'O' || (bCalphaOnlyHash[chainid] && atom.name === 'CA')) {
29109
29205
  if(currentCA === null || currentCA === undefined) {
29110
29206
  currentCA = atom.coord;
29111
29207
  currentColor = atom.color;
@@ -29168,7 +29264,7 @@ class Strand {
29168
29264
  }
29169
29265
  }
29170
29266
  }
29171
- else if(ic.bCalphaOnly && atom.name === 'CA') {
29267
+ else if(bCalphaOnlyHash[chainid] && atom.name === 'CA') {
29172
29268
  if(caArray.length > resSpan + 1) { // use the calpha and the previous 4th c-alpha to calculate the helix direction
29173
29269
  O = prevCoorCA.clone();
29174
29270
  oldCA = ic.atoms[caArray[caArray.length - 1 - resSpan - 1]].coord.clone();
@@ -29203,8 +29299,6 @@ class Strand {
29203
29299
  bShowArray.push(0);
29204
29300
  calphaIdArray.push(0);
29205
29301
  }
29206
-
29207
- ++drawnResidueCount;
29208
29302
  }
29209
29303
 
29210
29304
  //let bBrokenSs = ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + currentChain, currentResi) + 1 !== ic.ParserUtilsCls.getResiNCBI(chainid, atom.resi) || (prevCoorCA && Math.abs(currentCA.x - prevCoorCA.x) > maxDist) || (prevCoorCA && Math.abs(currentCA.y - prevCoorCA.y) > maxDist) || (prevCoorCA && Math.abs(currentCA.z - prevCoorCA.z) > maxDist);
@@ -29233,7 +29327,9 @@ class Strand {
29233
29327
  // }
29234
29328
 
29235
29329
  //if ((atom.ssbegin || atom.ssend || (drawnResidueCount === totalResidueCount - 1) || bBrokenSs) && pnts[0].length > 0 && bSameChain) {
29236
- if ((currentChain !== atom.chain || atom.ssbegin || atom.ssend || (drawnResidueCount === totalResidueCount - 1) || bBrokenSs || resid == lastResid) && pnts[0].length > 0) {
29330
+ // if ((currentChain !== atom.chain || atom.ssbegin || atom.ssend || (drawnResidueCount === totalResidueCount - 1) || bBrokenSs || resid == lastResid) && pnts[0].length > 0) { // last coil was not drawn correctly, e.g., in 1TOP
29331
+
29332
+ if ((currentChain !== atom.chain || atom.ssbegin || atom.ssend || bBrokenSs || (resid == lastResid && atom.ss != 'coil')) && pnts[0].length > 0) {
29237
29333
  let atomName = 'CA';
29238
29334
 
29239
29335
  let prevone = [], nexttwo = [];
@@ -29290,7 +29386,7 @@ class Strand {
29290
29386
  O = currentO.clone();
29291
29387
  O.sub(currentCA);
29292
29388
  }
29293
- else if(ic.bCalphaOnly && atom.name === 'CA') {
29389
+ else if(bCalphaOnlyHash[chainid] && atom.name === 'CA') {
29294
29390
  if(caArray.length > resSpan) { // use the calpha and the previous 4th c-alpha to calculate the helix direction
29295
29391
  O = currentCA.clone();
29296
29392
  oldCA = ic.atoms[caArray[caArray.length - 1 - resSpan]].coord.clone();
@@ -29379,7 +29475,9 @@ class Strand {
29379
29475
  // end of a chain, or end of selection
29380
29476
  if ((currentChain !== atom.chain
29381
29477
  || ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + currentChain, currentResi) + 1 !== ic.ParserUtilsCls.getResiNCBI(chainid, atom.resi)
29382
- || resid == lastResid
29478
+ // || (drawnResidueCount === totalResidueCount - 1)
29479
+ // || bBrokenSs
29480
+ || (resid == lastResid && atom.ss != 'coil')
29383
29481
  ) && pnts[0].length > 0) {
29384
29482
  //if ((currentChain !== atom.chain) && pnts[0].length > 0) {
29385
29483
 
@@ -29447,18 +29545,42 @@ class Strand {
29447
29545
  prevCoorCA = currentCA;
29448
29546
  prevCoorO = atom.coord;
29449
29547
  prevColor = currentColor;
29450
- } // end if (atom.name === 'O' || (ic.bCalphaOnly && atom.name === 'CA') ) {
29548
+ } // end if (atom.name === 'O' || (bCalphaOnlyHash[chainid] && atom.name === 'CA') ) {
29451
29549
  } // end if ((atom.name === 'O' || atom.name === 'CA') && !atom.het) {
29452
29550
  } // end for
29453
29551
 
29454
29552
  caArray = [];
29455
29553
 
29456
- ic.tubeCls.createTube(tubeAtoms, 'CA', coilWidth, bHighlight);
29457
-
29458
- tubeAtoms = {};
29554
+ // ic.tubeCls.createTube(tubeAtoms, 'CA', coilWidth, bHighlight);
29555
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
29556
+ ic.tubeCls.createTube(atomsAdjust, 'CA', coilWidth, bHighlight);
29459
29557
  pnts = {};
29460
29558
  }
29461
29559
 
29560
+ getOneExtraResidue(residueHash) { let ic = this.icn3d, me = ic.icn3dui;
29561
+ let atomsAdjust = {};
29562
+
29563
+ for(let resid in residueHash) {
29564
+ atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, ic.residues[resid]);
29565
+
29566
+ let residNcbi = ic.resid2ncbi[resid];
29567
+ let resiNcbi = residNcbi.substr(residNcbi.lastIndexOf('_') + 1);
29568
+
29569
+ let nextResidNcbi = residNcbi.substr(0, residNcbi.lastIndexOf('_')) + '_' + (parseInt(resiNcbi) + 1);
29570
+ let nextResid = ic.ncbi2resid[nextResidNcbi];
29571
+
29572
+ if(!nextResid) {
29573
+ nextResidNcbi = residNcbi.substr(0, residNcbi.lastIndexOf('_')) + '_' + (parseInt(resiNcbi) - 1);
29574
+ nextResid = ic.ncbi2resid[nextResidNcbi];
29575
+ }
29576
+
29577
+ if(nextResid) atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, ic.residues[nextResid]);
29578
+ }
29579
+
29580
+ return atomsAdjust;
29581
+ }
29582
+
29583
+ /*
29462
29584
  getSSExpandedAtoms(atoms, bHighlight) { let ic = this.icn3d, me = ic.icn3dui;
29463
29585
  let currChain, currResi, currAtom, prevChain, prevResi, prevAtom;
29464
29586
  let firstAtom, lastAtom;
@@ -29565,6 +29687,7 @@ class Strand {
29565
29687
 
29566
29688
  return atomsAdjust;
29567
29689
  }
29690
+ */
29568
29691
  }
29569
29692
 
29570
29693
  /**
@@ -29584,7 +29707,8 @@ class Strip {
29584
29707
  if (p0.length < 2) return;
29585
29708
  div = div || ic.axisDIV;
29586
29709
 
29587
- if(pntsCA && ic.bDoublecolor && !ic.bCalphaOnly) {
29710
+ // if(pntsCA && ic.bDoublecolor && !ic.bCalphaOnly) {
29711
+ if(pntsCA && ic.bDoublecolor) {
29588
29712
  let bExtendLastRes = false; //true;
29589
29713
 
29590
29714
  let pnts_clrs = me.subdivideCls.subdivide(pntsCA, colors, div, bShowArray, bHighlight, prevone, nexttwo, bExtendLastRes);
@@ -29912,7 +30036,7 @@ class Tube {
29912
30036
  //Create tubes for "atoms" with certain "atomName". "radius" is the radius of the tubes.
29913
30037
  //"bHighlight" is an option to draw the highlight for these atoms. The highlight could be
29914
30038
  //outlines with bHighlight=1 and 3D objects with bHighlight=2.
29915
- createTube(atoms, atomName, radius, bHighlight, bCustom, bRadiusArray) { let ic = this.icn3d, me = ic.icn3dui;
30039
+ createTube(atoms, atomName, radius, bHighlight, bCustom, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
29916
30040
  if(me.bNode) return;
29917
30041
 
29918
30042
  let pnts = [], colors = [], radii = [], prevone = [], nexttwo = [];
@@ -30024,6 +30148,9 @@ class Tube {
30024
30148
  else {
30025
30149
  radiusFinal = this.getRadius(radius, atom);
30026
30150
  }
30151
+
30152
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
30153
+ if(!bNonCoil && atom.ss != 'coil' && !atom.ssbegin && !atom.ssend ) radiusFinal = 0;
30027
30154
 
30028
30155
  //radii.push(radius || (atom.b > 0 ? atom.b * 0.01 : ic.coilWidth));
30029
30156
  radii.push(radiusFinal);
@@ -30097,183 +30224,247 @@ class Tube {
30097
30224
  let prevone = pnts_colors_radii_prevone_nexttwo[i].prevone;
30098
30225
  let nexttwo = pnts_colors_radii_prevone_nexttwo[i].nexttwo;
30099
30226
 
30100
- this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bRadiusArray);
30227
+ this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil);
30101
30228
  }
30102
30229
 
30103
- pnts_colors_radii_prevone_nexttwo = [];
30230
+ pnts_colors_radii_prevone_nexttwo = [];
30104
30231
  }
30105
30232
 
30106
- getCustomtubesize(resid) { let ic = this.icn3d; ic.icn3dui;
30107
- let pos = resid.lastIndexOf('_');
30108
- let resi = resid.substr(pos + 1);
30109
- let chainid = resid.substr(0, pos);
30233
+ /*
30234
+ createTube(atoms, atomName, radius, bHighlight, bCustom, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
30235
+ if(me.bNode) return;
30110
30236
 
30111
- let radiusFinal = (ic.queryresi2score[chainid] && ic.queryresi2score[chainid].hasOwnProperty(resi)) ? ic.queryresi2score[chainid][resi] * 0.01 : ic.coilWidth;
30237
+ let pnts = [], colors = [], radii = [], prevone = [], nexttwo = [];
30238
+ let currentChain, currentResi;
30239
+ let index = 0;
30240
+ let maxDist = 6.0;
30241
+ let maxDist2 = 3.0; // avoid tube between the residues in 3 residue helix
30112
30242
 
30113
- return radiusFinal;
30114
- };
30243
+ let pnts_colors_radii_prevone_nexttwo = [];
30244
+ let firstAtom, atom, prevAtom;
30115
30245
 
30116
- // modified from iview (http://istar.cse.cuhk.edu.hk/iview/)
30117
- createTubeSub(_pnts, colors, radii, bHighlight, prevone, nexttwo, bRadiusArray) { let ic = this.icn3d, me = ic.icn3dui;
30118
- if(me.bNode) return;
30246
+ for (let i in atoms) {
30247
+ atom = atoms[i];
30248
+ if ((atom.name === atomName) && !atom.het) {
30249
+ if(index == 0) {
30250
+ firstAtom = atom;
30251
+ }
30119
30252
 
30120
- if (_pnts.length < 2) return;
30253
+ if (index > 0 && (currentChain !== atom.chain || Math.abs(atom.coord.x - prevAtom.coord.x) > maxDist || Math.abs(atom.coord.y - prevAtom.coord.y) > maxDist || Math.abs(atom.coord.z - prevAtom.coord.z) > maxDist
30254
+ || (ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + currentChain, currentResi) + 1 < ic.ParserUtilsCls.getResiNCBI(atom.structure + '_' + atom.chain, atom.resi) && (Math.abs(atom.coord.x - prevAtom.coord.x) > maxDist2 || Math.abs(atom.coord.y - prevAtom.coord.y) > maxDist2 || Math.abs(atom.coord.z - prevAtom.coord.z) > maxDist2))
30255
+ ) ) {
30256
+ if(bHighlight !== 2) {
30257
+ if(!isNaN(firstAtom.resi) && !isNaN(prevAtom.resi)) {
30258
+ let prevoneResid = firstAtom.structure + '_' + firstAtom.chain + '_' + (parseInt(firstAtom.resi) - 1).toString();
30259
+ let prevoneCoord = ic.firstAtomObjCls.getAtomCoordFromResi(prevoneResid, atomName);
30260
+ prevone = (prevoneCoord !== undefined) ? [prevoneCoord] : [];
30121
30261
 
30122
- // if(bRadiusArray) {
30123
- let circleDiv = ic.tubeDIV, axisDiv = ic.axisDIV;
30124
- let circleDivInv = 1 / circleDiv, axisDivInv = 1 / axisDiv;
30125
- //var geo = new THREE.Geometry();
30126
- let geo = new THREE.BufferGeometry();
30127
- let verticeArray = [], colorArray = [],indexArray = [], color;
30128
- let offset = 0, offset2 = 0, offset3 = 0;
30262
+ let nextoneResid = prevAtom.structure + '_' + prevAtom.chain + '_' + (parseInt(prevAtom.resi) + 1).toString();
30129
30263
 
30130
- let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
30264
+ // add one more residue if only one residue is available
30265
+ if(pnts.length == 1 && ic.residues.hasOwnProperty(nextoneResid)) {
30266
+ let nextAtom = ic.firstAtomObjCls.getAtomFromResi(nextoneResid, atomName);
30131
30267
 
30132
- let pnts = pnts_clrs[0];
30133
- colors = pnts_clrs[2];
30268
+ if(nextAtom) {
30269
+ pnts.push(nextAtom.coord);
30270
+ colors.push(nextAtom.color);
30134
30271
 
30135
- let prevAxis1 = new THREE.Vector3(), prevAxis2;
30136
- for (let i = 0, lim = pnts.length; i < lim; ++i) {
30137
- let r, idx = (i - 1) * axisDivInv;
30138
- if (i === 0) r = radii[0];
30139
- else {
30140
- if (idx % 1 === 0) r = radii[idx];
30141
- else {
30142
- let floored = Math.floor(idx);
30143
- let tmp = idx - floored;
30144
- r = radii[floored] * tmp + radii[floored + 1] * (1 - tmp);
30272
+ let radiusFinal = this.getRadius(radius, atom);
30273
+ radii.push(radiusFinal);
30274
+ }
30275
+ }
30276
+
30277
+ }
30278
+
30279
+ pnts_colors_radii_prevone_nexttwo.push({'pnts':pnts, 'colors':colors, 'radii':radii, 'prevone':prevone, 'nexttwo':nexttwo});
30145
30280
  }
30281
+ pnts = []; colors = []; radii = []; prevone = []; nexttwo = [];
30282
+ firstAtom = atom;
30283
+ index = 0;
30146
30284
  }
30147
- let delta, axis1, axis2;
30148
- if (i < lim - 1) {
30149
- delta = pnts[i].clone().sub(pnts[i + 1]);
30150
- axis1 = new THREE.Vector3(0, -delta.z, delta.y).normalize().multiplyScalar(r);
30151
- axis2 = delta.clone().cross(axis1).normalize().multiplyScalar(r);
30152
- // let dir = 1, offset = 0;
30153
- if (prevAxis1.dot(axis1) < 0) {
30154
- axis1.negate(); axis2.negate(); //dir = -1;//offset = 2 * Math.PI / axisDiv;
30155
- }
30156
- prevAxis1 = axis1; prevAxis2 = axis2;
30157
- } else {
30158
- axis1 = prevAxis1; axis2 = prevAxis2;
30285
+
30286
+ pnts.push(atom.coord);
30287
+
30288
+ let radiusFinal;
30289
+ if(bCustom) {
30290
+ radiusFinal = this.getCustomtubesize(atom.structure + '_' + atom.chain + '_' + atom.resi);
30291
+ }
30292
+ else {
30293
+ radiusFinal = this.getRadius(radius, atom);
30159
30294
  }
30160
- for (let j = 0; j < circleDiv; ++j) {
30161
- let angle = 2 * Math.PI * circleDivInv * j; //* dir + offset;
30162
- let point = pnts[i].clone().add(axis1.clone().multiplyScalar(Math.cos(angle))).add(axis2.clone().multiplyScalar(Math.sin(angle)));
30163
- verticeArray[offset++] = point.x;
30164
- verticeArray[offset++] = point.y;
30165
- verticeArray[offset++] = point.z;
30166
30295
 
30167
- color = (i == colors.length - 1 && colors.length > 1) ? me.parasCls.thr(colors[colors.length - 2]) : me.parasCls.thr(colors[i]);
30168
- colorArray[offset2++] = color.r;
30169
- colorArray[offset2++] = color.g;
30170
- colorArray[offset2++] = color.b;
30296
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
30297
+ if(!bNonCoil && atom.ss != 'coil' && !atom.ssbegin && !atom.ssend ) radiusFinal = 0;
30298
+
30299
+ //radii.push(radius || (atom.b > 0 ? atom.b * 0.01 : ic.coilWidth));
30300
+ radii.push(radiusFinal);
30301
+
30302
+ colors.push(atom.color);
30303
+ // the starting residue of a coil uses the color from the next residue to avoid using the color of the last helix/sheet residue
30304
+ if(index === 1) colors[colors.length - 2] = atom.color;
30305
+
30306
+ currentChain = atom.chain;
30307
+ currentResi = atom.resi;
30308
+
30309
+ let scale = 1.2;
30310
+ if(bHighlight === 2 && !atom.ssbegin) {
30311
+ ic.boxCls.createBox(atom, undefined, undefined, scale, undefined, bHighlight);
30171
30312
  }
30313
+
30314
+ ++index;
30315
+
30316
+ prevAtom = atom;
30172
30317
  }
30173
- let offsetTmp = 0, nComp = 3;
30174
- for (let i = 0, lim = pnts.length - 1; i < lim; ++i) {
30175
- let reg = 0;
30176
- //var r1 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv]).lengthSq();
30177
- //var r2 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv + 1]).lengthSq();
30178
- let pos = offsetTmp * nComp;
30179
- let point1 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30180
- pos = (offsetTmp + circleDiv) * nComp;
30181
- let point2 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30182
- pos = (offsetTmp + circleDiv + 1) * nComp;
30183
- let point3 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30184
-
30185
- let r1 = point1.clone().sub(point2).lengthSq();
30186
- let r2 = point1.clone().sub(point3).lengthSq();
30187
- if (r1 > r2) { r1 = r2; reg = 1; } for (let j = 0; j < circleDiv; ++j) {
30188
- //geo.faces.push(new THREE.Face3(offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv, undefined, c));
30189
- //geo.faces.push(new THREE.Face3(offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv, undefined, c));
30190
- //indexArray = indexArray.concat([offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv]);
30191
- indexArray[offset3++] = offsetTmp + j;
30192
- indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
30193
- indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
30194
-
30195
- //indexArray = indexArray.concat([offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv]);
30196
- indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
30197
- indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
30198
- indexArray[offset3++] = offsetTmp + (j + reg + 1) % circleDiv + circleDiv;
30199
- }
30200
- offsetTmp += circleDiv;
30201
- }
30318
+ }
30202
30319
 
30203
- geo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(verticeArray), nComp));
30204
- geo.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colorArray), nComp));
30320
+ if(bHighlight !== 2) {
30321
+ pnts_colors_radii_prevone_nexttwo.push({'pnts':pnts, 'colors':colors, 'radii':radii, 'prevone':prevone, 'nexttwo':nexttwo});
30322
+ }
30205
30323
 
30206
- geo.setIndex(new THREE.BufferAttribute(new Uint32Array(indexArray), 1));
30207
- //geo.setIndex(indexArray);
30324
+ for(let i = 0, il = pnts_colors_radii_prevone_nexttwo.length; i < il; ++i) {
30325
+ let pnts = pnts_colors_radii_prevone_nexttwo[i].pnts;
30326
+ let colors = pnts_colors_radii_prevone_nexttwo[i].colors;
30327
+ let radii = pnts_colors_radii_prevone_nexttwo[i].radii;
30328
+ let prevone = []; // = pnts_colors_radii_prevone_nexttwo[i].prevone;
30329
+ let nexttwo = []; // = pnts_colors_radii_prevone_nexttwo[i].nexttwo;
30208
30330
 
30209
- //geo.computeFaceNormals();
30210
- //geo.computeVertexNormals(false);
30211
- geo.computeVertexNormals();
30212
- /*
30331
+ this.createTubeSub(pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil);
30213
30332
  }
30214
- else {
30215
- let axisDiv = ic.axisDIV;
30216
30333
 
30217
- let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
30218
- // extend one residue
30219
- //var pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo, true);
30334
+ pnts_colors_radii_prevone_nexttwo = [];
30335
+ }
30336
+ */
30220
30337
 
30221
- _pnts = pnts_clrs[0];
30222
- colors = pnts_clrs[2];
30338
+ getCustomtubesize(resid) { let ic = this.icn3d; ic.icn3dui;
30339
+ let pos = resid.lastIndexOf('_');
30340
+ let resi = resid.substr(pos + 1);
30341
+ let chainid = resid.substr(0, pos);
30223
30342
 
30224
- let radius = ic.coilWidth;
30225
- segments = _pnts.length;
30226
- //radiusSegments = 8;
30227
- radiusSegments = 4; // save memory
30228
- let closed = false;
30343
+ let radiusFinal = (ic.queryresi2score[chainid] && ic.queryresi2score[chainid].hasOwnProperty(resi)) ? ic.queryresi2score[chainid][resi] * 0.01 : ic.coilWidth;
30229
30344
 
30230
- // when using radiusArray with modified three.js, the tube didn't work in picking
30231
- let geo = new THREE.TubeGeometry(
30232
- new THREE.CatmullRomCurve3(_pnts), // path
30233
- segments,
30234
- radius, //radiusArray, //radius,
30235
- radiusSegments,
30236
- closed
30237
- );
30345
+ return radiusFinal;
30346
+ };
30347
+
30348
+ // modified from iview (http://istar.cse.cuhk.edu.hk/iview/)
30349
+ createTubeSub(_pnts, colors, radii, bHighlight, prevone, nexttwo, bNonCoil) { let ic = this.icn3d, me = ic.icn3dui;
30350
+ if(me.bNode) return;
30351
+
30352
+ if (_pnts.length < 2) return;
30238
30353
 
30239
- //https://stemkoski.github.io/Three.js/Graphulus-Curve.html
30240
- let color, face, numberOfSides, vertexIndex;
30241
- // faces are indexed using characters
30242
- let faceIndices = [ 'a', 'b', 'c', 'd' ];
30354
+ let circleDiv = ic.tubeDIV, axisDiv = ic.axisDIV;
30355
+ let circleDivInv = 1 / circleDiv, axisDivInv = 1 / axisDiv;
30356
+ //var geo = new THREE.Geometry();
30357
+ let geo = new THREE.BufferGeometry();
30358
+ let verticeArray = [], colorArray = [],indexArray = [], color;
30359
+ let offset = 0, offset2 = 0, offset3 = 0;
30243
30360
 
30244
- // first, assign colors to vertices as desired
30245
- let prevColor, geoColors = {};
30246
- for ( let s = 0; s <= segments; s++ ) {
30247
- for ( let r = 0; r < radiusSegments; r++ )
30248
- {
30249
- vertexIndex = r + s * radiusSegments;
30250
- color = colors[s];
30251
- if(!color) color = prevColor;
30361
+ let pnts_clrs = me.subdivideCls.subdivide(_pnts, colors, axisDiv, undefined, undefined, prevone, nexttwo);
30252
30362
 
30253
- geoColors[vertexIndex] = color; // use this array for convenience
30363
+ let pnts = pnts_clrs[0];
30364
+ colors = pnts_clrs[2];
30254
30365
 
30255
- prevColor = color;
30256
- }
30257
- }
30366
+ let constRadiius;
30367
+ // a threshold to stop drawing the tube if it's less than this ratio of radius
30368
+ let thresholdRatio = 1; //0.9;
30258
30369
 
30259
- // copy the colors as necessary to the face's vertexColors array.
30260
- // after version r125, geo.faces is undefined for TubeGeometry
30261
- for ( let i = 0; geo.faces && i < geo.faces.length; i++ )
30262
- {
30263
- face = geo.faces[ i ];
30370
+ let prevAxis1 = new THREE.Vector3(), prevAxis2;
30371
+ for (let i = 0, lim = pnts.length; i < lim; ++i) {
30372
+ let r, idx = (i - 1) * axisDivInv;
30264
30373
 
30265
- numberOfSides = ( face instanceof THREE.Face3 ) ? 3 : 4;
30266
- for( let j = 0; j < numberOfSides; j++ )
30267
- {
30268
- vertexIndex = face[ faceIndices[ j ] ];
30269
- face.vertexColors[ j ] = geoColors[ vertexIndex ];
30374
+ if (i === 0) {
30375
+ r = radii[0];
30376
+ if(r > 0) constRadiius = r;
30377
+ }
30378
+ else {
30379
+ if (idx % 1 === 0) {
30380
+ r = radii[idx];
30381
+ if(r > 0) constRadiius = r;
30382
+ }
30383
+ else {
30384
+ let floored = Math.floor(idx);
30385
+ let tmp = idx - floored;
30386
+ // draw all atoms in tubes and assign zero radius when the residue is not coil
30387
+ // r = radii[floored] * tmp + radii[floored + 1] * (1 - tmp);
30388
+ r = radii[floored] * (1 - tmp) + radii[floored + 1] * tmp;
30389
+
30390
+ // a threshold to stop drawing the tube if it's less than this ratio of radius.
30391
+ // The extra bit of tube connects coil with strands or helices
30392
+ if(!bNonCoil) {
30393
+ if(r < thresholdRatio * constRadiius) {
30394
+ r = 0;
30395
+ }
30396
+ // else if(r < constRadiius) {
30397
+ // r *= 0.5; // use small radius for the connection between coild and sheets/helices
30398
+ // }
30399
+ }
30270
30400
  }
30271
30401
  }
30272
-
30273
- geo.computeFaceNormals();
30274
- geo.computeVertexNormals(false);
30402
+ let delta, axis1, axis2;
30403
+ if (i < lim - 1) {
30404
+ delta = pnts[i].clone().sub(pnts[i + 1]);
30405
+ axis1 = new THREE.Vector3(0, -delta.z, delta.y).normalize().multiplyScalar(r);
30406
+ axis2 = delta.clone().cross(axis1).normalize().multiplyScalar(r);
30407
+ // let dir = 1, offset = 0;
30408
+ if (prevAxis1.dot(axis1) < 0) {
30409
+ axis1.negate(); axis2.negate(); //dir = -1;//offset = 2 * Math.PI / axisDiv;
30410
+ }
30411
+ prevAxis1 = axis1; prevAxis2 = axis2;
30412
+ } else {
30413
+ axis1 = prevAxis1; axis2 = prevAxis2;
30414
+ }
30415
+ for (let j = 0; j < circleDiv; ++j) {
30416
+ let angle = 2 * Math.PI * circleDivInv * j; //* dir + offset;
30417
+ let point = pnts[i].clone().add(axis1.clone().multiplyScalar(Math.cos(angle))).add(axis2.clone().multiplyScalar(Math.sin(angle)));
30418
+ verticeArray[offset++] = point.x;
30419
+ verticeArray[offset++] = point.y;
30420
+ verticeArray[offset++] = point.z;
30421
+
30422
+ color = (i == colors.length - 1 && colors.length > 1) ? me.parasCls.thr(colors[colors.length - 2]) : me.parasCls.thr(colors[i]);
30423
+ colorArray[offset2++] = color.r;
30424
+ colorArray[offset2++] = color.g;
30425
+ colorArray[offset2++] = color.b;
30426
+ }
30427
+ }
30428
+ let offsetTmp = 0, nComp = 3;
30429
+ for (let i = 0, lim = pnts.length - 1; i < lim; ++i) {
30430
+ let reg = 0;
30431
+ //var r1 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv]).lengthSq();
30432
+ //var r2 = geo.vertices[offset].clone().sub(geo.vertices[offset + circleDiv + 1]).lengthSq();
30433
+ let pos = offsetTmp * nComp;
30434
+ let point1 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30435
+ pos = (offsetTmp + circleDiv) * nComp;
30436
+ let point2 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30437
+ pos = (offsetTmp + circleDiv + 1) * nComp;
30438
+ let point3 = new THREE.Vector3(verticeArray[pos], verticeArray[pos + 1], verticeArray[pos + 2]);
30439
+
30440
+ let r1 = point1.clone().sub(point2).lengthSq();
30441
+ let r2 = point1.clone().sub(point3).lengthSq();
30442
+ if (r1 > r2) { r1 = r2; reg = 1; } for (let j = 0; j < circleDiv; ++j) {
30443
+ //geo.faces.push(new THREE.Face3(offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv, undefined, c));
30444
+ //geo.faces.push(new THREE.Face3(offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv, undefined, c));
30445
+ //indexArray = indexArray.concat([offset + j, offset + (j + reg) % circleDiv + circleDiv, offset + (j + 1) % circleDiv]);
30446
+ indexArray[offset3++] = offsetTmp + j;
30447
+ indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
30448
+ indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
30449
+
30450
+ //indexArray = indexArray.concat([offset + (j + 1) % circleDiv, offset + (j + reg) % circleDiv + circleDiv, offset + (j + reg + 1) % circleDiv + circleDiv]);
30451
+ indexArray[offset3++] = offsetTmp + (j + 1) % circleDiv;
30452
+ indexArray[offset3++] = offsetTmp + (j + reg) % circleDiv + circleDiv;
30453
+ indexArray[offset3++] = offsetTmp + (j + reg + 1) % circleDiv + circleDiv;
30454
+ }
30455
+ offsetTmp += circleDiv;
30275
30456
  }
30276
- */
30457
+
30458
+ geo.setAttribute('position', new THREE.BufferAttribute(new Float32Array(verticeArray), nComp));
30459
+ geo.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colorArray), nComp));
30460
+
30461
+ geo.setIndex(new THREE.BufferAttribute(new Uint32Array(indexArray), 1));
30462
+ //geo.setIndex(indexArray);
30463
+
30464
+ //geo.computeFaceNormals();
30465
+ //geo.computeVertexNormals(false);
30466
+ geo.computeVertexNormals();
30467
+
30277
30468
  let mesh;
30278
30469
  if(bHighlight === 2) {
30279
30470
  //mesh = new THREE.Mesh(geo, new THREE.MeshPhongMaterial({ transparent: true, opacity: 0.5, specular: ic.frac, shininess: ic.shininess, emissive: ic.emissive, vertexColors: THREE.FaceColors, side: THREE.DoubleSide }));
@@ -30856,7 +31047,7 @@ class Axes {
30856
31047
  return cone;
30857
31048
  }
30858
31049
 
30859
- setPc1Axes() { let ic = this.icn3d, me = ic.icn3dui;
31050
+ setPc1Axes(bXAxis) { let ic = this.icn3d, me = ic.icn3dui;
30860
31051
  if(me.bNode) return;
30861
31052
 
30862
31053
  let atomHash = me.hashUtilsCls.intHash(ic.hAtoms, ic.dAtoms);
@@ -30937,6 +31128,11 @@ class Axes {
30937
31128
 
30938
31129
  let positionX = center.clone().add(vecX.normalize().multiplyScalar(maxD * 0.4));
30939
31130
 
31131
+ let prinXaxis = vecX.normalize();
31132
+ me.htmlCls.clickMenuCls.setLogCmd('Principle X-Axis: ' + prinXaxis.x.toFixed(3) + " " + prinXaxis.y.toFixed(3) + " " + prinXaxis.z.toFixed(3), false);
31133
+
31134
+ if(bXAxis) return prinXaxis;
31135
+
30940
31136
  let vecY = new THREE.Vector3(eigenRet.h2[0], eigenRet.h2[1], eigenRet.h2[2]);
30941
31137
  let positionY = center.clone().add(vecY.normalize().multiplyScalar(maxD * 0.3));
30942
31138
 
@@ -35155,6 +35351,9 @@ class ApplySymd {
35155
35351
 
35156
35352
  ic.cylinderCls.createCylinder(start, end, axisRadius, colorAxis, 0);
35157
35353
 
35354
+ let SymAxis = end.clone().sub(start).normalize();
35355
+ me.htmlCls.clickMenuCls.setLogCmd('Symmetry Axis: ' + SymAxis.x.toFixed(3) + " " + SymAxis.y.toFixed(3) + " " + SymAxis.z.toFixed(3), false);
35356
+
35158
35357
  if(ic.bAxisOnly) continue;
35159
35358
 
35160
35359
  if(symmetryType == 'C' || (symmetryType == 'D' && order == nSide) ) {
@@ -35311,87 +35510,87 @@ class ApplySymd {
35311
35510
  pointArray.push(end);
35312
35511
  }
35313
35512
  else ;
35314
- }
35315
35513
 
35316
- if(symmetryType == 'T') {
35317
- let pos1 = pointArray[0]; // pointArray: start, end, start, end, ...
35318
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35514
+ if(symmetryType == 'T') {
35515
+ let pos1 = pointArray[0]; // pointArray: start, end, start, end, ...
35516
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35319
35517
 
35320
- let dist2 = pos1.distanceTo(pointArray[2]);
35321
- let dist3 = pos1.distanceTo(pointArray[3]);
35518
+ let dist2 = pos1.distanceTo(pointArray[2]);
35519
+ let dist3 = pos1.distanceTo(pointArray[3]);
35322
35520
 
35323
- let distSmall, posSel;
35324
- if(dist2 < dist3) {
35325
- distSmall = dist2;
35326
- posSel = pointArray[3];
35327
- }
35328
- else {
35329
- distSmall = dist3;
35330
- posSel = pointArray[2];
35331
- }
35521
+ let distSmall, posSel;
35522
+ if(dist2 < dist3) {
35523
+ distSmall = dist2;
35524
+ posSel = pointArray[3];
35525
+ }
35526
+ else {
35527
+ distSmall = dist3;
35528
+ posSel = pointArray[2];
35529
+ }
35332
35530
 
35333
- ic.sphereCls.createSphereBase(posSel, colorPolygon, polygonRadius, 1.0, 0);
35334
- ic.cylinderCls.createCylinder(pos1, posSel, polygonRadius, colorPolygon, 0);
35531
+ ic.sphereCls.createSphereBase(posSel, colorPolygon, polygonRadius, 1.0, 0);
35532
+ ic.cylinderCls.createCylinder(pos1, posSel, polygonRadius, colorPolygon, 0);
35335
35533
 
35336
- let iPrev;
35337
- for(let i = 4, il = pointArray.length; i < il; ++i) {
35338
- let pos2 = pointArray[i];
35534
+ let iPrev;
35535
+ for(let i = 4, il = pointArray.length; i < il; ++i) {
35536
+ let pos2 = pointArray[i];
35339
35537
 
35340
- let dist = pos1.distanceTo(pos2);
35341
- if(dist > distSmall) {
35342
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35343
- ic.cylinderCls.createCylinder(pos1, pos2, polygonRadius, colorPolygon, 0);
35538
+ let dist = pos1.distanceTo(pos2);
35539
+ if(dist > distSmall) {
35540
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35541
+ ic.cylinderCls.createCylinder(pos1, pos2, polygonRadius, colorPolygon, 0);
35344
35542
 
35345
- ic.cylinderCls.createCylinder(posSel, pos2, polygonRadius, colorPolygon, 0);
35346
- if(iPrev !== undefined) {
35347
- ic.cylinderCls.createCylinder(pointArray[iPrev], pos2, polygonRadius, colorPolygon, 0);
35348
- }
35543
+ ic.cylinderCls.createCylinder(posSel, pos2, polygonRadius, colorPolygon, 0);
35544
+ if(iPrev !== undefined) {
35545
+ ic.cylinderCls.createCylinder(pointArray[iPrev], pos2, polygonRadius, colorPolygon, 0);
35546
+ }
35349
35547
 
35350
- iPrev = i;
35548
+ iPrev = i;
35549
+ }
35351
35550
  }
35352
35551
  }
35353
- }
35354
- else if(symmetryType == 'O') {
35355
- for(let i = 0, il = pointArray.length; i < il; i += 2) {
35356
- let pos1 = pointArray[i];
35357
- let pos2 = pointArray[i+1];
35358
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35359
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35360
- for(let j = i + 2, jl = pointArray.length; j < jl; ++j) {
35361
- let pos3 = pointArray[j];
35362
- ic.sphereCls.createSphereBase(pos3, colorPolygon, polygonRadius, 1.0, 0);
35363
- ic.cylinderCls.createCylinder(pos1, pos3, polygonRadius, colorPolygon, 0);
35364
- ic.cylinderCls.createCylinder(pos2, pos3, polygonRadius, colorPolygon, 0);
35552
+ else if(symmetryType == 'O') {
35553
+ for(let i = 0, il = pointArray.length; i < il; i += 2) {
35554
+ let pos1 = pointArray[i];
35555
+ let pos2 = pointArray[i+1];
35556
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35557
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35558
+ for(let j = i + 2, jl = pointArray.length; j < jl; ++j) {
35559
+ let pos3 = pointArray[j];
35560
+ ic.sphereCls.createSphereBase(pos3, colorPolygon, polygonRadius, 1.0, 0);
35561
+ ic.cylinderCls.createCylinder(pos1, pos3, polygonRadius, colorPolygon, 0);
35562
+ ic.cylinderCls.createCylinder(pos2, pos3, polygonRadius, colorPolygon, 0);
35563
+ }
35365
35564
  }
35366
35565
  }
35367
- }
35368
- else if(symmetryType == 'I') {
35369
- for(let i = 0, il = pointArray.length; i < il; i += 2) {
35370
- let pos1 = pointArray[i];
35371
- let pos2 = pointArray[i+1];
35372
- ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35373
- ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35374
- for(let j = i + 2, jl = pointArray.length; j < jl; j += 2) {
35375
- let pos3 = pointArray[j];
35376
- let pos4 = pointArray[j+1];
35566
+ else if(symmetryType == 'I') {
35567
+ for(let i = 0, il = pointArray.length; i < il; i += 2) {
35568
+ let pos1 = pointArray[i];
35569
+ let pos2 = pointArray[i+1];
35570
+ ic.sphereCls.createSphereBase(pos1, colorPolygon, polygonRadius, 1.0, 0);
35571
+ ic.sphereCls.createSphereBase(pos2, colorPolygon, polygonRadius, 1.0, 0);
35572
+ for(let j = i + 2, jl = pointArray.length; j < jl; j += 2) {
35573
+ let pos3 = pointArray[j];
35574
+ let pos4 = pointArray[j+1];
35377
35575
 
35378
- let dist3 = pos1.distanceTo(pos3);
35379
- let dist4 = pos1.distanceTo(pos4);
35576
+ let dist3 = pos1.distanceTo(pos3);
35577
+ let dist4 = pos1.distanceTo(pos4);
35380
35578
 
35381
- let pos1Sel, pos2Sel;
35382
- if(dist3 < dist4) {
35383
- pos1Sel = pos3;
35384
- pos2Sel = pos4;
35385
- }
35386
- else {
35387
- pos1Sel = pos4;
35388
- pos2Sel = pos3;
35389
- }
35579
+ let pos1Sel, pos2Sel;
35580
+ if(dist3 < dist4) {
35581
+ pos1Sel = pos3;
35582
+ pos2Sel = pos4;
35583
+ }
35584
+ else {
35585
+ pos1Sel = pos4;
35586
+ pos2Sel = pos3;
35587
+ }
35390
35588
 
35391
- ic.sphereCls.createSphereBase(pos1Sel, colorPolygon, polygonRadius, 1.0, 0);
35392
- ic.sphereCls.createSphereBase(pos2Sel, colorPolygon, polygonRadius, 1.0, 0);
35393
- ic.cylinderCls.createCylinder(pos1, pos1Sel, polygonRadius, colorPolygon, 0);
35394
- ic.cylinderCls.createCylinder(pos2, pos2Sel, polygonRadius, colorPolygon, 0);
35589
+ ic.sphereCls.createSphereBase(pos1Sel, colorPolygon, polygonRadius, 1.0, 0);
35590
+ ic.sphereCls.createSphereBase(pos2Sel, colorPolygon, polygonRadius, 1.0, 0);
35591
+ ic.cylinderCls.createCylinder(pos1, pos1Sel, polygonRadius, colorPolygon, 0);
35592
+ ic.cylinderCls.createCylinder(pos2, pos2Sel, polygonRadius, colorPolygon, 0);
35593
+ }
35395
35594
  }
35396
35595
  }
35397
35596
  }
@@ -35755,6 +35954,33 @@ class ResidueLabels {
35755
35954
  ic.hlObjectsCls.removeHlObjects();
35756
35955
  }
35757
35956
 
35957
+ //Add labels for each Ig domain
35958
+ addIgLabels(atoms) { let ic = this.icn3d, me = ic.icn3dui;
35959
+ if(me.bNode) return;
35960
+
35961
+ let size = 60; //18;
35962
+
35963
+ ic.labels['ig'] = [];
35964
+ let chainidHash = ic.firstAtomObjCls.getChainsFromAtoms(atoms);
35965
+
35966
+ for(let chainid in ic.igLabel2Pos) {
35967
+ if(!chainidHash.hasOwnProperty(chainid)) continue;
35968
+
35969
+ for(let text in ic.igLabel2Pos[chainid]) {
35970
+ let label = {}; // Each label contains 'position', 'text', 'color', 'background'
35971
+ label.position = ic.igLabel2Pos[chainid][text];
35972
+ label.text = text;
35973
+
35974
+ label.size = size;
35975
+ label.color = '#00FFFF';
35976
+
35977
+ ic.labels['ig'].push(label);
35978
+ }
35979
+ }
35980
+
35981
+ ic.hlObjectsCls.removeHlObjects();
35982
+ }
35983
+
35758
35984
  addNonCarbonAtomLabels(atoms) { let ic = this.icn3d, me = ic.icn3dui;
35759
35985
  if(me.bNode) return;
35760
35986
 
@@ -42025,6 +42251,8 @@ class AnnoIg {
42025
42251
  let igCnt = ic.chain2igArray[chnid].length;
42026
42252
  let fromArray = [], toArray = [];
42027
42253
  let posindex2domainindex = {};
42254
+ if(!ic.igLabel2Pos) ic.igLabel2Pos = {};
42255
+ ic.igLabel2Pos[chnid] = {};
42028
42256
  for(let i = 0; i < igCnt; ++i) {
42029
42257
  let igElem = ic.chain2igArray[chnid][i];
42030
42258
  fromArray = fromArray.concat(igElem.startPosArray);
@@ -42034,6 +42262,18 @@ class AnnoIg {
42034
42262
  let pos = igElem.startPosArray[j];
42035
42263
  posindex2domainindex[pos] = i;
42036
42264
  }
42265
+
42266
+ let resi1 = ic.ParserUtilsCls.getResi(chnid, igElem.startPosArray[0]);
42267
+ let resid1 = chnid + "_" + resi1;
42268
+ let calpha1 = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.residues[resid1]);
42269
+
42270
+ let resi2 = ic.ParserUtilsCls.getResi(chnid, igElem.endPosArray[igElem.endPosArray.length - 1]);
42271
+ let resid2 = chnid + "_" + resi2;
42272
+ let calpha2 = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.residues[resid2]);
42273
+
42274
+ let label = chnid.substr(chnid.lastIndexOf('_') + 1) + '-Ig' + (i+1).toString();
42275
+
42276
+ ic.igLabel2Pos[chnid][label] = calpha1.coord.clone().add(calpha2.coord).multiplyScalar(0.5);
42037
42277
  }
42038
42278
 
42039
42279
  // let htmlCnt = '<span class="icn3d-residueNum" title="Ig domain count">' + igCnt.toString() + ' Igs</span>';
@@ -42084,6 +42324,7 @@ class AnnoIg {
42084
42324
  if(igArray.length == 0) return {html: html, html2: html2, html3: html3}
42085
42325
  let rangeArray = [], titleArray = [], fullTitleArray = [], domainArray = [];
42086
42326
 
42327
+ let chain = chnid.substr(chnid.lastIndexOf('_') + 1);
42087
42328
  for(let i = 0, il = igArray.length; i < il; ++i) {
42088
42329
  let domainid = igArray[i].domainid;
42089
42330
  if(!ic.domainid2info) continue;
@@ -42095,7 +42336,7 @@ class AnnoIg {
42095
42336
 
42096
42337
  let igType = (parseFloat(tmscore) < ic.refnumCls.TMThresholdIgType ) ? 'Ig' : ic.ref2igtype[info.refpdbname];
42097
42338
  titleArray.push(igType + ' (TM:' + parseFloat(tmscore).toFixed(2) + ')');
42098
- fullTitleArray.push(igType + ' (TM:' + parseFloat(tmscore).toFixed(2) + '), template: ' + info.refpdbname + ', type: ' + ic.ref2igtype[info.refpdbname] + ', Seq. identity: ' + parseFloat(info.seqid).toFixed(2) + ', aligned residues: ' + info.nresAlign);
42339
+ fullTitleArray.push(igType + ' (TM:' + parseFloat(tmscore).toFixed(2) + '), template: ' + info.refpdbname + ', type: ' + ic.ref2igtype[info.refpdbname] + ', Seq. identity: ' + parseFloat(info.seqid).toFixed(2) + ', aligned residues: ' + info.nresAlign + ', label in 3D: ' + chain + '-Ig' + (i+1).toString());
42099
42340
 
42100
42341
  domainArray.push(igType);
42101
42342
 
@@ -45527,7 +45768,6 @@ class AddTrack {
45527
45768
  }
45528
45769
 
45529
45770
  getExonHtml(exonIndex, colorGradient, from, to, genomeRange, chainid, simpTitle) { let ic = this.icn3d; ic.icn3dui;
45530
- // 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" domain="' + (exonIndex + 1) + '" from="' + from + '" to="' + to + '" setname="' + simpTitle + ', Exon ' + (exonIndex + 1) + '" title="Exon ' + (exonIndex + 1) + ': ' + genomeRange + ' genomic interval" anno="sequence" chain="' + chainid + '"><div style="height: 12px; border: 1px solid #000; background: linear-gradient(to right, ' + colorGradient + ');"></div></div>';
45531
45771
  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" domain="' + (exonIndex + 1) + '" from="' + from + '" to="' + to + '" setname="' + simpTitle + ', ' + (exonIndex + 1) + '" title="Exon: ' + genomeRange + ' genomic interval" anno="sequence" chain="' + chainid + '"><div style="height: 12px; border: 1px solid #000; background: linear-gradient(to right, ' + colorGradient + ');"></div></div>';
45532
45772
  }
45533
45773
 
@@ -46269,7 +46509,7 @@ class AddTrack {
46269
46509
  let targetId = 'genomeRes';
46270
46510
 
46271
46511
  let acc2index = {};
46272
-
46512
+
46273
46513
  for(let index = 0, indexl = accArray.length; index < indexl; ++index) {
46274
46514
  let acc = accArray[index];
46275
46515
 
@@ -46354,22 +46594,24 @@ class AddTrack {
46354
46594
  trackSeqArrayFinal[i] = '';
46355
46595
  }
46356
46596
 
46357
- for(let j = 0, jl = trackSeqArray[maxIndex].length; j < jl; ++j) {
46358
- let seq = trackSeqArray[maxIndex][j];
46597
+ if(trackSeqArray[maxIndex]) {
46598
+ for(let j = 0, jl = trackSeqArray[maxIndex].length; j < jl; ++j) {
46599
+ let seq = trackSeqArray[maxIndex][j];
46359
46600
 
46360
- let bExon = (seq != '-') ? true : false;
46361
- if(!bExon) {
46362
- for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
46363
- if(trackSeqArray[i][j] != '-') {
46364
- bExon = true;
46365
- break;
46601
+ let bExon = (seq != '-') ? true : false;
46602
+ if(!bExon) {
46603
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
46604
+ if(trackSeqArray[i][j] != '-') {
46605
+ bExon = true;
46606
+ break;
46607
+ }
46366
46608
  }
46367
46609
  }
46368
- }
46369
-
46370
- if(bExon) {
46371
- for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
46372
- trackSeqArrayFinal[i] += trackSeqArray[i][j];
46610
+
46611
+ if(bExon) {
46612
+ for(let i = 0, il = trackSeqArray.length; i < il; ++i) {
46613
+ trackSeqArrayFinal[i] += trackSeqArray[i][j];
46614
+ }
46373
46615
  }
46374
46616
  }
46375
46617
  }
@@ -46440,7 +46682,9 @@ class AddTrack {
46440
46682
  ic.maxAnnoLength = ic.maxAnnoLengthOri + ic.seqStartLen[chainid] + ic.seqEndLen[chainid];
46441
46683
  }
46442
46684
 
46443
- await ic.annotationCls.resetAnnoAll();
46685
+ // do not remove other tracks
46686
+ // await ic.annotationCls.resetAnnoAll();
46687
+ await ic.showAnnoCls.processSeqData(ic.chainid_seq);
46444
46688
 
46445
46689
  let targetGapHashStr = '';
46446
46690
  let cntTmp = 0;
@@ -46607,7 +46851,7 @@ class AddTrack {
46607
46851
 
46608
46852
  let type = 'identity';
46609
46853
 
46610
- await thisClass.addExonTracks(chainid, geneid, startpos, type);
46854
+ await this.addExonTracks(chainid, geneid, startpos, type);
46611
46855
  }
46612
46856
 
46613
46857
  async addExonTracks(chainid, geneid, startpos, type) { let ic = this.icn3d, me = ic.icn3dui;
@@ -46642,13 +46886,12 @@ class AddTrack {
46642
46886
  let cnt = (j == jl - 1) ? itemArray[2] - 3 : itemArray[2]; // The last one is stop codeon
46643
46887
  cntTotal += cnt;
46644
46888
 
46645
- let resStart = parseInt(prevCntTotal/3.0 + 0.5); // 0-based
46646
- let resEnd = parseInt(cntTotal/3.0 + 0.5) - 1; // 0-based
46889
+ let resStart = parseInt((prevCntTotal+2)/3.0); // 0-based
46890
+ let resEnd = parseInt((cntTotal+2)/3.0) - 1; // 0-based
46647
46891
 
46648
- let genResStart = parseInt(itemArray[0] / 3.0 + 0.5);
46649
-
46650
- //let genResEnd = parseInt(itemArray[1] / 3.0 + 0.5); // some difference due to round
46651
- let genResEnd = genResStart + ic.exonOrder * (resEnd - resStart);
46892
+ let genResEnd = parseInt((itemArray[1]+2) / 3.0);
46893
+ // let genResStart = parseInt((itemArray[0]+2) / 3.0); // some difference due to round
46894
+ let genResStart = genResEnd - ic.exonOrder * (resEnd - resStart);
46652
46895
 
46653
46896
  rangeArray.push({genomeRange: genomeRange, genResStart: genResStart, genResEnd: genResEnd, resStart: resStart, resEnd: resEnd});
46654
46897
 
@@ -46702,7 +46945,7 @@ class AddTrack {
46702
46945
 
46703
46946
  let ALen = trackSeqArray.length;
46704
46947
 
46705
- while (i < A.length && j < B.length) {
46948
+ while (A && B && i < A.length && j < B.length) {
46706
46949
  if(A[i] != B[j]) {
46707
46950
  if(A[i] == '-') {
46708
46951
  // insert "-" in B
@@ -49365,7 +49608,7 @@ class HlUpdate {
49365
49608
  }
49366
49609
 
49367
49610
  //Remove the highlight in the 2D interaction diagram.
49368
- removeHl2D() { let ic = this.icn3d; ic.icn3dui;
49611
+ removeHl2D(bRemoveChainOnly) { let ic = this.icn3d; ic.icn3dui;
49369
49612
  // clear nodes in 2d dgm
49370
49613
  $("#" + ic.pre + "dl_2ddgm rect").attr('stroke', '#000000');
49371
49614
  $("#" + ic.pre + "dl_2ddgm circle").attr('stroke', '#000000');
@@ -49379,6 +49622,22 @@ class HlUpdate {
49379
49622
  $("#" + ic.pre + "dl_2ddgm svg line").attr('stroke', '#000000');
49380
49623
  $("#" + ic.pre + "dl_2ddgm line").attr('stroke-width', 1);
49381
49624
  }
49625
+
49626
+ if(!bRemoveChainOnly) {
49627
+ // clear nodes in 2d interaction network
49628
+ // $("#" + ic.pre + "dl_linegraph rect").attr('stroke', '#000000');
49629
+ $("#" + ic.pre + "dl_linegraph circle").attr('stroke', '#000000');
49630
+
49631
+ // $("#" + ic.pre + "dl_linegraph rect").attr('stroke-width', 1);
49632
+ $("#" + ic.pre + "dl_linegraph circle").attr('stroke-width', 1);
49633
+
49634
+ // clear nodes in 2d interaction graph
49635
+ $("#" + ic.pre + "dl_scatterplot rect").attr('stroke', '#000000');
49636
+ $("#" + ic.pre + "dl_scatterplot circle").attr('stroke', '#000000');
49637
+
49638
+ $("#" + ic.pre + "dl_scatterplot rect").attr('stroke-width', 1);
49639
+ $("#" + ic.pre + "dl_scatterplot circle").attr('stroke-width', 1);
49640
+ }
49382
49641
  }
49383
49642
 
49384
49643
  //Remove the selection in the menu of defined sets.
@@ -49476,7 +49735,7 @@ class HlUpdate {
49476
49735
  // update highlight in 2D window
49477
49736
  //Update the highlight of 2D interaction diagram according to the current highlighted atoms.
49478
49737
  updateHl2D(chainArray2d) { let ic = this.icn3d, me = ic.icn3dui;
49479
- this.removeHl2D();
49738
+ this.removeHl2D(true);
49480
49739
 
49481
49740
  if(ic.hAtoms && ic.atoms && Object.keys(ic.hAtoms).length == Object.keys(ic.atoms).length) return;
49482
49741
 
@@ -49903,6 +50162,8 @@ class LineGraph {
49903
50162
  && ic.chainsMapping[chainid2] && ic.chainsMapping[chainid2][resid2]) {
49904
50163
  mapping1 = (nodeA.s == "a") ? ic.chainsMapping[chainid1][resid1] : ic.chainsMapping[chainid2][resid2];
49905
50164
  mapping2 = (nodeA.s == "a") ? ic.chainsMapping[chainid2][resid2] : ic.chainsMapping[chainid1][resid1];
50165
+
50166
+ let bIgRef = (mapping1.length > 4 && !isNaN(parseInt(mapping1.substr(-4, 4)))) || (mapping2.length > 4 && !isNaN(parseInt(mapping2.substr(-4, 4))));
49906
50167
 
49907
50168
  let mappingid = mapping1 + '_' + mapping2 + '_' + link.c; // link.c determines the interaction type
49908
50169
 
@@ -49914,7 +50175,7 @@ class LineGraph {
49914
50175
  linkDiff.source += separatorDiff + ic.chainsMapping[chainid1][resid1];
49915
50176
  linkDiff.target += separatorDiff + ic.chainsMapping[chainid2][resid2];
49916
50177
 
49917
- if(linkedNodeCnt[mappingid] == structureArray.length && linkedNodeInterDiffBool[mappingid] == 0) {
50178
+ if(linkedNodeCnt[mappingid] == structureArray.length && (bIgRef || linkedNodeInterDiffBool[mappingid] == 0)) {
49918
50179
  linkArraySplitCommon[index].push(linkCommon);
49919
50180
  }
49920
50181
  else {
@@ -58493,13 +58754,7 @@ class RealignParser {
58493
58754
 
58494
58755
  let allPromise = Promise.allSettled(ajaxArray);
58495
58756
  // try {
58496
- // let dataArray = await allPromise;
58497
-
58498
- let startDate = new Date();
58499
58757
  let dataArray = await allPromise;
58500
- let endDate = new Date();
58501
- let miliseconds = (endDate.getTime() - startDate.getTime());
58502
- console.log("vastdyn time: " + miliseconds + " miliseconds");
58503
58758
 
58504
58759
  ic.qt_start_end = []; // reset the alignment
58505
58760
  await ic.chainalignParserCls.downloadChainalignmentPart2bRealign(dataArray, chainidPairArray, bReverse);
@@ -58591,6 +58846,8 @@ class RealignParser {
58591
58846
  async realignChainOnSeqAlign(chainresiCalphaHash2, chainidArray, bRealign, bPredefined) { let ic = this.icn3d, me = ic.icn3dui;
58592
58847
  let thisClass = this;
58593
58848
 
58849
+ me.cfg.aligntool = 'seqalign';
58850
+
58594
58851
  //bRealign: realign based on seq alignment
58595
58852
  //bPredefined: chain alignment with predefined matching residues
58596
58853
 
@@ -60788,9 +61045,11 @@ class LoadAtomData {
60788
61045
  serial2structure[j] = pdbidTmp.toString();
60789
61046
  mmdbid2pdbid[mmdbidTmp] = pdbidTmp;
60790
61047
  }
60791
-
61048
+
60792
61049
  for(let j = 0, jl = structure.molecules.length; j < jl; ++j) {
60793
61050
  let chain = structure.molecules[j].chain;
61051
+ chain = chain.replace(/_/g, ''); // change "A_1" to "A1"
61052
+
60794
61053
  let kind = structure.molecules[j].kind;
60795
61054
  let title = structure.molecules[j].name;
60796
61055
  //var seq = structure.molecules[j].sequence;
@@ -61783,7 +62042,9 @@ class SetSeqAlign {
61783
62042
 
61784
62043
  let resid = chainid + '_' + resi;
61785
62044
  let resn = ic.residueId2Name[resid];
61786
- if(!resn) resn = '?';
62045
+ if(!resn) {
62046
+ resn = '?';
62047
+ }
61787
62048
 
61788
62049
  return resn;
61789
62050
  }
@@ -64837,7 +65098,7 @@ class Vastplus {
64837
65098
  let chainid = chainidArray[i];
64838
65099
  let atoms = me.hashUtilsCls.intHash(ic.hAtoms, ic.chains[chainid]);
64839
65100
  let firstAtom = ic.firstAtomObjCls.getFirstAtomObj(atoms);
64840
- structHash[firstAtom.structure] = 1;
65101
+ if(firstAtom) structHash[firstAtom.structure] = 1;
64841
65102
  }
64842
65103
  }
64843
65104
 
@@ -65859,6 +66120,11 @@ class ApplyCommand {
65859
66120
 
65860
66121
  ic.drawCls.draw();
65861
66122
  }
66123
+ else if(command == 'add ig labels') {
66124
+ ic.residueLabelsCls.addIgLabels(ic.hAtoms);
66125
+
66126
+ ic.drawCls.draw();
66127
+ }
65862
66128
  else if(command == 'add atom labels') {
65863
66129
  ic.residueLabelsCls.addAtomLabels(ic.hAtoms);
65864
66130
 
@@ -66490,7 +66756,21 @@ class ApplyCommand {
66490
66756
  let nameArray2 = setNameArray[1].split(',');
66491
66757
 
66492
66758
  ic.analysisCls.measureDistManySets(nameArray, nameArray2);
66493
- me.htmlCls.dialogCls.openDlg('dl_disttable', 'Distance among the sets');
66759
+ me.htmlCls.dialogCls.openDlg('dl_disttable', 'Distances among the sets');
66760
+ }
66761
+ }
66762
+ }
66763
+ else if(commandOri.indexOf('angletable') == 0) {
66764
+ let paraArray = commandOri.split(' | ');
66765
+ if(paraArray.length == 2) {
66766
+ let setNameArray = paraArray[1].split(' ');
66767
+
66768
+ if(setNameArray.length == 2) {
66769
+ let nameArray = setNameArray[0].split(',');
66770
+ let nameArray2 = setNameArray[1].split(',');
66771
+
66772
+ ic.analysisCls.measureAngleManySets(nameArray, nameArray2);
66773
+ me.htmlCls.dialogCls.openDlg('dl_angletable', 'Angles among the sets');
66494
66774
  }
66495
66775
  }
66496
66776
  }
@@ -67185,6 +67465,7 @@ class ApplyCommand {
67185
67465
  else if(cmd.indexOf('hide annotation') == 0) return seqAnnoStr + ': checkboxes off';
67186
67466
  else if(cmd == 'add residue labels') return labelStr + 'per Residue';
67187
67467
  else if(cmd == 'add residue number labels') return labelStr + 'per Residue & Number';
67468
+ else if(cmd == 'add Ig domain labels') return labelStr + 'per Ig Domain';
67188
67469
  else if(cmd == 'add atom labels') return labelStr + 'per Atom';
67189
67470
  else if(cmd == 'add chain labels') return labelStr + 'per Chain';
67190
67471
  else if(cmd == 'add terminal labels') return labelStr + 'N- & C- Termini';
@@ -68097,9 +68378,9 @@ class SelectCollections {
68097
68378
  'chemicals': {},
68098
68379
  'ions': {},
68099
68380
  'water': {},
68100
- 'structures': {}, // getSSExpandedAtoms
68381
+ 'structures': {},
68101
68382
  'ssbondpnts': {},
68102
- 'residues': {}, // getSSExpandedAtoms
68383
+ 'residues': {},
68103
68384
  'chains': {},
68104
68385
  'chainsSeq': {}, //Sequences and Annotation
68105
68386
  'defNames2Atoms': {},
@@ -68148,9 +68429,9 @@ class SelectCollections {
68148
68429
  'chemicals': ic.chemicals,
68149
68430
  'ions': ic.ions,
68150
68431
  'water': ic.water,
68151
- 'structures': ic.structures, // getSSExpandedAtoms
68432
+ 'structures': ic.structures,
68152
68433
  'ssbondpnts': ic.ssbondpnts,
68153
- 'residues': ic.residues, // getSSExpandedAtoms
68434
+ 'residues': ic.residues,
68154
68435
  'chains': ic.chains,
68155
68436
  'chainsSeq': ic.chainsSeq, //Sequences and Annotation
68156
68437
  'defNames2Atoms': ic.defNames2Atoms,
@@ -68164,9 +68445,9 @@ class SelectCollections {
68164
68445
  'chemicals': thisClass.dictionaryDifference(ic.allData['prev']['chemicals'], ic.chemicals),
68165
68446
  'ions': thisClass.dictionaryDifference(ic.allData['prev']['ions'], ic.ions),
68166
68447
  'water': thisClass.dictionaryDifference(ic.allData['prev']['water'], ic.water),
68167
- 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures), // getSSExpandedAtoms
68448
+ 'structures': thisClass.dictionaryDifference(ic.allData['prev']['structures'], ic.structures),
68168
68449
  'ssbondpnts': thisClass.dictionaryDifference(ic.allData['prev']['ssbondpnts'], ic.ssbondpnts),
68169
- 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues), // getSSExpandedAtoms
68450
+ 'residues': thisClass.dictionaryDifference(ic.allData['prev']['residues'], ic.residues),
68170
68451
  'chains': thisClass.dictionaryDifference(ic.allData['prev']['chains'], ic.chains),
68171
68452
  'chainsSeq': thisClass.dictionaryDifference(ic.allData['prev']['chainsSeq'], ic.chainsSeq), //Sequences and Annotation
68172
68453
  'defNames2Atoms': thisClass.dictionaryDifference(ic.allData['prev']['defNames2Atoms'], ic.defNames2Atoms),
@@ -74981,7 +75262,73 @@ class Analysis {
74981
75262
 
74982
75263
  $("#" + me.pre + "dl_disttable_html").html(tableHtml);
74983
75264
  }
74984
- }
75265
+ }
75266
+
75267
+ measureAngleManySets(nameArray, nameArray2) {var ic = this.icn3d, me = ic.icn3dui;
75268
+ if(nameArray.length == 0 || nameArray2.length == 0) {
75269
+ alert("Please select sets for angleance calculation...");
75270
+ }
75271
+ else {
75272
+ let angleHash = {};
75273
+
75274
+ for(let i = 0, il = nameArray.length; i < il; ++i) {
75275
+ let set1 = nameArray[i];
75276
+ let array1 = [set1];
75277
+ angleHash[set1] = {};
75278
+
75279
+ ic.hAtoms = ic.definedSetsCls.getAtomsFromNameArray(array1);
75280
+ let axis1 = ic.axesCls.setPc1Axes(true);
75281
+
75282
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
75283
+ let set2 = nameArray2[j];
75284
+ let array2 = [set2];
75285
+
75286
+ if(set1 == set2) continue;
75287
+
75288
+ ic.hAtoms = ic.definedSetsCls.getAtomsFromNameArray(array2);
75289
+ let axis2 = ic.axesCls.setPc1Axes(true);
75290
+
75291
+ let angleRad = new THREE.Vector3(parseFloat(axis1.x), parseFloat(axis1.y), parseFloat(axis1.z)).angleTo(new THREE.Vector3(parseFloat(axis2.x), parseFloat(axis2.y), parseFloat(axis2.z)));
75292
+
75293
+ let angle = angleRad / 3.1416 * 180;
75294
+ angle = Math.abs(angle).toFixed(0);
75295
+ if(angle > 180) angle -= 180;
75296
+ if(angle > 90) angle = 180 - angle;
75297
+
75298
+ angleHash[set1][set2] = angle;
75299
+ }
75300
+ }
75301
+
75302
+ let tableHtml = '<table align=center border=1 cellpadding=10 cellspacing=0><tr><th></th>';
75303
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
75304
+ let set2 = nameArray2[j];
75305
+ tableHtml += '<th><b>' + set2 + '</b> (&deg;)</th>';
75306
+ }
75307
+ tableHtml += '</tr>';
75308
+
75309
+ for(let i = 0, il = nameArray.length; i < il; ++i) {
75310
+ let set1 = nameArray[i];
75311
+ tableHtml += '<tr><th><b>' + set1 + '</b> (&deg;)</th>';
75312
+
75313
+ for(let j = 0, jl = nameArray2.length; j < jl; ++j) {
75314
+ let set2 = nameArray2[j];
75315
+
75316
+ if(angleHash[set1] && angleHash[set1][set2]) {
75317
+ tableHtml += '<td><span>' + angleHash[set1][set2] + '</span></td>';
75318
+ }
75319
+ else {
75320
+ tableHtml += '<td>0</td>';
75321
+ }
75322
+ }
75323
+
75324
+ tableHtml += '</tr>';
75325
+ }
75326
+
75327
+ tableHtml += '</table><br><br>';
75328
+
75329
+ $("#" + me.pre + "dl_angletable_html").html(tableHtml);
75330
+ }
75331
+ }
74985
75332
 
74986
75333
  //Add a line between the position (x1, y1, z1) and the position (x2, y2, z2) with the input "color".
74987
75334
  //The line can be dashed if "dashed" is set true.
@@ -78824,7 +79171,8 @@ class ShareLink {
78824
79171
  }
78825
79172
  else {
78826
79173
  text += "\nStart of type file======\n";
78827
- text += ic.InputfileType + "\n";
79174
+ // text += ic.InputfileType + "\n";
79175
+ text += "pdb\n";
78828
79176
  text += "End of type file======\n";
78829
79177
 
78830
79178
  text += "Start of data file======\n";
@@ -81689,7 +82037,7 @@ class iCn3DUI {
81689
82037
  //even when multiple iCn3D viewers are shown together.
81690
82038
  this.pre = this.cfg.divid + "_";
81691
82039
 
81692
- this.REVISION = '3.32.0';
82040
+ this.REVISION = '3.33.2';
81693
82041
 
81694
82042
  // In nodejs, iCn3D defines "window = {navigator: {}}"
81695
82043
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -81833,7 +82181,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81833
82181
  ic.setStyleCls.handleContextLost();
81834
82182
  ic.applyCenterCls.setWidthHeight(width, height);
81835
82183
  ic.ori_chemicalbinding = ic.opts['chemicalbinding'];
81836
- if(me.cfg.bCalphaOnly !== undefined) ic.bCalphaOnly = me.cfg.bCalphaOnly;
82184
+ // if(me.cfg.bCalphaOnly !== undefined) ic.bCalphaOnly = me.cfg.bCalphaOnly;
81837
82185
  ic.opts = me.hashUtilsCls.cloneHash(ic.opts);
81838
82186
  ic.STATENUMBER = ic.commands.length;
81839
82187
  // If previously crashed, recover it
@@ -81861,7 +82209,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81861
82209
  ic.bInputfile = true;
81862
82210
  ic.InputfileType = 'pdb';
81863
82211
  ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + pdbStr : pdbStr;
81864
-
82212
+
81865
82213
  await ic.pdbParserCls.loadPdbData(pdbStr);
81866
82214
 
81867
82215
  if(me.cfg.resdef !== undefined && me.cfg.chains !== undefined) {
@@ -81872,9 +82220,9 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81872
82220
  for(let i = 0, il = structureArray.length; i < il; ++i) {
81873
82221
  chainidArray.push(structureArray[i] + '_' + chainArray[i]);
81874
82222
  }
81875
-
82223
+
81876
82224
  chainidArray = ic.chainalignParserCls.addPostfixForChainids(chainidArray);
81877
-
82225
+
81878
82226
  let bRealign = true, bPredefined = true;
81879
82227
  await ic.realignParserCls.realignChainOnSeqAlign(undefined, chainidArray, bRealign, bPredefined);
81880
82228
  }
@@ -81895,7 +82243,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81895
82243
  chainidArray.push(domainidArray[i]);
81896
82244
  }
81897
82245
  }
81898
-
82246
+
81899
82247
  // get the matched structures, do not include the template
81900
82248
  let mmdbafid = '';
81901
82249
  for(let i = 0, il = chainidArray.length; i < il; ++i) {
@@ -81906,7 +82254,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81906
82254
  // realign, include the template
81907
82255
  ic.chainidArray = [chain_t].concat(chainidArray);
81908
82256
  ic.chainidArray = ic.chainalignParserCls.addPostfixForChainids(ic.chainidArray);
81909
-
82257
+
81910
82258
  me.htmlCls.clickMenuCls.setLogCmd('resdef ' + me.cfg.resdef, true);
81911
82259
 
81912
82260
  ic.loadCmd = 'vast_search_chainid ' + ic.chainidArray;
@@ -81983,7 +82331,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81983
82331
  }
81984
82332
  else if(me.cfg.refseqid !== undefined) {
81985
82333
  ic.inputid = me.cfg.refseqid;
81986
-
82334
+
81987
82335
  // ic.bNCBI = true;
81988
82336
  ic.loadCmd = 'load refseq ' + me.cfg.refseqid;
81989
82337
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
@@ -81991,7 +82339,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
81991
82339
  }
81992
82340
  else if(me.cfg.protein !== undefined) {
81993
82341
  ic.inputid = me.cfg.protein;
81994
-
82342
+
81995
82343
  // ic.bNCBI = true;
81996
82344
  ic.loadCmd = 'load protein ' + me.cfg.protein;
81997
82345
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
@@ -82000,7 +82348,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82000
82348
  else if(me.cfg.blast_rep_id !== undefined) {
82001
82349
  // ic.bNCBI = true;
82002
82350
  ic.inputid = me.cfg.query_id + ',' + me.cfg.blast_rep_id;
82003
-
82351
+
82004
82352
  me.cfg.oriQuery_id = me.cfg.query_id;
82005
82353
  me.cfg.oriBlast_rep_id = me.cfg.blast_rep_id;
82006
82354
 
@@ -82024,7 +82372,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82024
82372
  ic.bSmithwm = false;
82025
82373
  ic.bLocalSmithwm = false;
82026
82374
  }
82027
-
82375
+
82028
82376
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
82029
82377
  await ic.mmdbParserCls.downloadBlast_rep_id(me.cfg.query_id + ',' + me.cfg.blast_rep_id);
82030
82378
  }
@@ -82033,7 +82381,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82033
82381
  let data = await me.getAjaxPromise(url, 'json', false, 'The RID ' + me.cfg.rid + ' may have expired...');
82034
82382
 
82035
82383
  for(let q = 0, ql = data.BlastOutput2.length; q < ql; ++q) {
82036
-
82384
+
82037
82385
  let hitArray;
82038
82386
  if(data.BlastOutput2[q].report.results.iterations) { // psi-blast may have "iterations". Use the last iteration.
82039
82387
  let nIterations = data.BlastOutput2[q].report.results.iterations.length;
@@ -82044,7 +82392,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82044
82392
  if(data.BlastOutput2[q].report.results.search.query_id != me.cfg.query_id) continue;
82045
82393
  hitArray = data.BlastOutput2[q].report.results.search.hits;
82046
82394
  }
82047
-
82395
+
82048
82396
  let qseq = undefined;
82049
82397
  for(let i = 0, il = hitArray.length; i < il; ++i) {
82050
82398
  let hit = hitArray[i];
@@ -82076,6 +82424,18 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82076
82424
  }
82077
82425
  }
82078
82426
  else if(me.cfg.cid !== undefined) {
82427
+ if(isNaN(me.cfg.cid)) {
82428
+ let urlCid = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?compound2cid=" + me.cfg.cid;
82429
+ let cidJson = await me.getAjaxPromise(urlCid, 'jsonp');
82430
+ if(cidJson.cid && cidJson.cid[0]) {
82431
+ me.cfg.cid = cidJson.cid[0];
82432
+ }
82433
+ else {
82434
+ alert("Please input an valid PubChem CID...");
82435
+ return;
82436
+ }
82437
+ }
82438
+
82079
82439
  ic.inputid = me.cfg.cid;
82080
82440
 
82081
82441
  let url = "https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/" + ic.inputid + "/description/jsonp";
@@ -82140,7 +82500,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82140
82500
  }
82141
82501
  me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
82142
82502
 
82143
- await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
82503
+ await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
82144
82504
  //await ic.loadScriptCls.loadScript(me.cfg.command, undefined, true);
82145
82505
  }
82146
82506
  else if(me.cfg.command !== undefined && me.cfg.command !== '') {
@@ -82154,7 +82514,7 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
82154
82514
 
82155
82515
  return;
82156
82516
  }
82157
-
82517
+
82158
82518
  await ic.loadScriptCls.loadScript(me.cfg.command, undefined, true);
82159
82519
  // });
82160
82520
  // return me.deferred.promise();
@@ -82222,7 +82582,7 @@ iCn3DUI.prototype.getXMLHttpRqstPromise = function(url, dataType, responseType,
82222
82582
  let oReq = new XMLHttpRequest();
82223
82583
  oReq.open(dataType, url, true);
82224
82584
  oReq.responseType = responseType;
82225
-
82585
+
82226
82586
  oReq.onreadystatechange = function() {
82227
82587
  if (this.readyState == 4) {
82228
82588
  if(this.status == 200) {
@@ -82274,7 +82634,7 @@ iCn3DUI.prototype.getAjaxPromise = function(url, dataType, beforeSend, alertMess
82274
82634
  error : function() {
82275
82635
  if(alertMess) alert(alertMess);
82276
82636
  if(logMess) console.log(logMess);
82277
-
82637
+
82278
82638
  reject('error');
82279
82639
  }
82280
82640
  });
@@ -82317,7 +82677,7 @@ iCn3DUI.prototype.getAjaxPostPromise = async function(url, data, beforeSend, ale
82317
82677
  //if(alertMess) alert(alertMess);
82318
82678
  if(!me.bNode && alertMess) console.log(alertMess);
82319
82679
  if(!me.bNode && logMess) console.log(logMess);
82320
-
82680
+
82321
82681
  // reject('error');
82322
82682
  // keep running the program
82323
82683
  resolve('error');