icn3d 3.50.0 → 3.51.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
@@ -58591,7 +58591,7 @@ class ClickMenu {
58591
58591
  let definedAtomsHtml = ic.definedSetsCls.setAtomMenu(['protein'], bNucleotides);
58592
58592
  if($("#" + me.pre + "atomsCustomNucleotide").length && definedAtomsHtml) {
58593
58593
  $("#" + me.pre + "atomsCustomNucleotide").html(definedAtomsHtml);
58594
- me.htmlCls.dialogCls.openDlg('dl_2ddgm_r2dt', 'Show R2DT Diagram for Nucleotides');
58594
+ me.htmlCls.dialogCls.openDlg('dl_2ddgm_r2dt', 'Show R2DT Diagram for RNAs');
58595
58595
  $("#" + me.pre + "atomsCustomNucleotide").resizable();
58596
58596
  }
58597
58597
  else {
@@ -60520,7 +60520,7 @@ class SetMenu {
60520
60520
 
60521
60521
  html += this.getMenuText('2ddgmwrap', '2D Diagram', undefined, 1, 1);
60522
60522
  html += "<ul>";
60523
- html += this.getLink('2ddgm_r2dt', 'for Nucleotides' + me.htmlCls.wifiStr, 1, 2);
60523
+ html += this.getLink('2ddgm_r2dt', 'for RNAs' + me.htmlCls.wifiStr, 1, 2);
60524
60524
  html += this.getLink('2ddgm_igdgm', 'for Ig Domains' + me.htmlCls.wifiStr, 1, 2);
60525
60525
  if(me.cfg.mmdbid !== undefined || me.cfg.gi !== undefined || me.cfg.blast_rep_id !== undefined || me.cfg.align !== undefined || me.cfg.chainalign !== undefined) {
60526
60526
  html += this.getLink('mn2_2ddgm', 'for Chains ' + me.htmlCls.wifiStr, 1, 2);
@@ -60973,6 +60973,7 @@ class Dialog {
60973
60973
  let bLigplot = $('#' + me.pre + 'dl_ligplot').hasClass('ui-dialog-content'); // initialized
60974
60974
  let bContactmap = $('#' + me.pre + 'dl_contactmap').hasClass('ui-dialog-content'); // initialized
60975
60975
  let b2ddiagram = $('#' + me.pre + 'dl_2ddiagram').hasClass('ui-dialog-content'); // initialized
60976
+ let big2ddgm = $('#' + me.pre + 'dl_ig2ddgm').hasClass('ui-dialog-content'); // initialized
60976
60977
  let brnacanvas = $('#' + me.pre + 'dl_rnacanvas').hasClass('ui-dialog-content'); // initialized
60977
60978
  let bAlignerrormap = $('#' + me.pre + 'dl_alignerrormap').hasClass('ui-dialog-content'); // initialized
60978
60979
  let bTable = $('#' + me.pre + 'dl_interactionsorted').hasClass('ui-dialog-content'); // initialized
@@ -60995,6 +60996,7 @@ class Dialog {
60995
60996
  id2flag.dl_contactmap = 'bContactmap2';
60996
60997
  id2flag.dl_2ddiagram = 'b2ddiagram2';
60997
60998
  id2flag.dl_rnacanvas = 'brnacanvas2';
60999
+ id2flag.dl_ig2ddgm = 'big2ddgm2';
60998
61000
  id2flag.dl_alignerrormap = 'bAlignerrormap2';
60999
61001
  id2flag.dl_interactionsorted = 'bTable2';
61000
61002
  id2flag.dl_alignment = 'bAlignmentInit2';
@@ -61012,6 +61014,7 @@ class Dialog {
61012
61014
  if(bContactmap) status.bContactmap2 = $('#' + me.pre + 'dl_contactmap').dialog( 'isOpen' );
61013
61015
  if(b2ddiagram) status.b2ddiagram2 = $('#' + me.pre + 'dl_2ddiagram').dialog( 'isOpen' );
61014
61016
  if(brnacanvas) status.brnacanvas2 = $('#' + me.pre + 'dl_rnacanvas').dialog( 'isOpen' );
61017
+ if(big2ddgm) status.big2ddgm2 = $('#' + me.pre + 'dl_ig2ddgm').dialog( 'isOpen' );
61015
61018
  if(bAlignerrormap) status.bAlignerror2 = $('#' + me.pre + 'dl_alignerrormap').dialog( 'isOpen' );
61016
61019
  if(bTable) status.bTable2 = $('#' + me.pre + 'dl_interactionsorted').dialog( 'isOpen' );
61017
61020
  if(bAlignmentInit) status.bAlignmentInit2 = $('#' + me.pre + 'dl_alignment').dialog( 'isOpen' );
@@ -61199,7 +61202,7 @@ class Dialog {
61199
61202
 
61200
61203
  let status = this.getDialogStatus().status;
61201
61204
 
61202
- if(id === me.pre + 'dl_selectannotations' || id === me.pre + 'dl_graph' || id === me.pre + 'dl_linegraph' || id === me.pre + 'dl_scatterplot' || id === me.pre + 'dl_rmsdplot' || id === me.pre + 'dl_hbondplot' || id === me.pre + 'dl_ligplot' || id === me.pre + 'dl_contactmap' || id === me.pre + 'dl_2ddiagram' || id === me.pre + 'dl_rnacanvas' || id === me.pre + 'dl_alignerrormap' || id === me.pre + 'dl_interactionsorted' || id === me.pre + 'dl_alignment') {
61205
+ if(id === me.pre + 'dl_selectannotations' || id === me.pre + 'dl_graph' || id === me.pre + 'dl_linegraph' || id === me.pre + 'dl_scatterplot' || id === me.pre + 'dl_rmsdplot' || id === me.pre + 'dl_hbondplot' || id === me.pre + 'dl_ligplot' || id === me.pre + 'dl_contactmap' || id === me.pre + 'dl_2ddiagram' || id === me.pre + 'dl_rnacanvas' || id === me.pre + 'dl_ig2ddgm' || id === me.pre + 'dl_alignerrormap' || id === me.pre + 'dl_interactionsorted' || id === me.pre + 'dl_alignment') {
61203
61206
  //var dialogWidth = 0.5 *(me.htmlCls.WIDTH - me.htmlCls.LESSWIDTH) - twoddgmWidth * 0.5;
61204
61207
  let dialogWidth = 0.5 *(me.htmlCls.WIDTH) - twoddgmWidth * 0.5;
61205
61208
 
@@ -62165,19 +62168,19 @@ class SetDialog {
62165
62168
  html += "</div>";
62166
62169
 
62167
62170
  html += me.htmlCls.divStr + "dl_2ddgm_r2dt' class='" + dialogClass + "'>";
62168
- html += this.addNotebookTitle('dl_2ddgm_r2dt', '2D Diagram for Nucleotides (R2DT)');
62169
- html += "1. Select a nucleotide chain to show 2D diagram:<br>";
62171
+ html += this.addNotebookTitle('dl_2ddgm_r2dt', '2D Diagram for RNAs (R2DT)');
62172
+ html += "1. Select a RNA chain to show 2D diagram:<br>";
62170
62173
  html += "<select style='max-width:200px' id='" + me.pre + "atomsCustomNucleotide' size='5' style='min-width:130px;'>";
62171
62174
  html += "</select><br>";
62172
62175
  html += "2. " + me.htmlCls.buttonStr + "applyr2dt'>R2DT Diagram</button>" + me.htmlCls.buttonStr + "applyfr3d' style='margin-left:12px'>2D Diagram with RNAcanvas</button><br><br>(Hints: Click on Residues in 2D to highlight in 3D. <br>Ctrl + click to select multiple residues.)<br>";
62173
62176
  html += "</div>";
62174
62177
 
62175
62178
  html += me.htmlCls.divStr + "dl_2ddgm_igdgm' class='" + dialogClass + "'>";
62176
- html += this.addNotebookTitle('dl_2ddgm_igdgm', '2D Diagram for Ig Domains (R2DT)');
62179
+ html += this.addNotebookTitle('dl_2ddgm_igdgm', '2D Diagram for Ig Domains');
62177
62180
  html += "1. Select a protein chain to show Ig diagram. An Excel file containing <br>the Ig diagram will be saved to your computer.<br>";
62178
62181
  html += "<select style='max-width:200px' id='" + me.pre + "atomsCustomProtein' size='5' style='min-width:130px;'>";
62179
62182
  html += "</select><br>";
62180
- html += me.htmlCls.buttonStr + "applyigdgm'>Show Ig Diagram</button><br>";
62183
+ html += "2. " + me.htmlCls.buttonStr + "applyigdgm' style='margin-right:12px;'>Show Ig Diagram</button>" + me.htmlCls.buttonStr + "saveigdgm'>Download Ig Diagrams in Excel</button><br>";
62181
62184
  html += "</div>";
62182
62185
 
62183
62186
  html += me.htmlCls.divStr + "dl_hbonds' class='" + dialogClass + "'>";
@@ -62535,6 +62538,20 @@ class SetDialog {
62535
62538
  html += '<div id="' + me.pre + 'rnacanvasDiv"></div>';
62536
62539
  html += "</div>";
62537
62540
 
62541
+
62542
+ me.ig2ddgmid = me.pre + 'ig2ddgm';
62543
+ html += me.htmlCls.divStr + "dl_ig2ddgm' style='background-color:white' class='" + dialogClass + "'>";
62544
+ html += this.addNotebookTitle('dl_ig2ddgm', '2D Diagram for Ig domains');
62545
+
62546
+ html += "<table><tr><td>Select an Ig domain:<br>";
62547
+ html += me.htmlCls.divNowrapStr + "<select id='" + me.pre + "iglist' size='2' style='min-width:130px;'>";
62548
+ html += "</select></td><td valign='top'>";
62549
+ html += me.htmlCls.space2 + buttonStrTmp + me.ig2ddgmid + '_svg">Download SVG</button></td></tr></table><br>';
62550
+
62551
+ html += '<div id="' + me.pre + 'ig2ddgmDiv"></div>';
62552
+ html += "</div>";
62553
+
62554
+
62538
62555
  html += me.htmlCls.divStr + "dl_alignerrormap' style='background-color:white' class='" + dialogClass + "'>";
62539
62556
  html += this.addNotebookTitle('dl_alignerrormap', 'PAE Map');
62540
62557
 
@@ -65807,7 +65824,17 @@ class Events {
65807
65824
  thisClass.setLogCmd('diagram 2d fr3d | ' + chainid, true);
65808
65825
  });
65809
65826
 
65810
- me.myEventCls.onIds("#" + me.pre + "applyigdgm", "click", async function(e) { let ic = me.icn3d;
65827
+ me.myEventCls.onIds("#" + me.pre + "saveigdgm", "click", async function(e) { let ic = me.icn3d;
65828
+ e.preventDefault();
65829
+ //if(!me.cfg.notebook) dialog.dialog( "close" );
65830
+
65831
+ let chainid = $("#" + ic.pre + "atomsCustomProtein").val();
65832
+
65833
+ let bSave = true;
65834
+ await ic.diagram2dCls.drawIgdgm(chainid, bSave);
65835
+ thisClass.setLogCmd('download 2d ig | ' + chainid, true);
65836
+ });
65837
+ me.myEventCls.onIds("#" + me.pre + "applyigdgm", "click", async function(e) { let ic = me.icn3d;
65811
65838
  e.preventDefault();
65812
65839
  //if(!me.cfg.notebook) dialog.dialog( "close" );
65813
65840
 
@@ -66007,6 +66034,11 @@ class Events {
66007
66034
  ic.saveFileCls.saveFile(chainid + "_seq.txt", "text", [seq]);
66008
66035
  });
66009
66036
 
66037
+ me.myEventCls.onIds("#" + me.ig2ddgmid + "_svg", "click", function(e) { let ic = me.icn3d;
66038
+ e.preventDefault();
66039
+
66040
+ ic.saveFileCls.saveSvg("ig2ddgmSvg", ic.ig2ddgm_chainid + "_ig_2d.svg");
66041
+ });
66010
66042
 
66011
66043
  me.myEventCls.onIds("#" + me.linegraphid + "_svg", "click", function(e) { let ic = me.icn3d;
66012
66044
  e.preventDefault();
@@ -84089,6 +84121,28 @@ class ApplyClbonds {
84089
84121
  } // if
84090
84122
  } // if
84091
84123
 
84124
+ // add crosslink chemicals to the linked protein/nucleotide residues
84125
+ for(let structure in ic.structures) {
84126
+ let clbondArray = ic.clbondpnts[structure];
84127
+ if(clbondArray === undefined) {
84128
+ break;
84129
+ }
84130
+ for(let i = 0, il = clbondArray.length; i < il; i = i + 2) {
84131
+ let resid1 = clbondArray[i];
84132
+ let resid2 = clbondArray[i+1];
84133
+
84134
+ let atom1 = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid1]);
84135
+ let atom2 = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid2]);
84136
+
84137
+ if((ic.proteins.hasOwnProperty(atom1.serial) || ic.nucleotides.hasOwnProperty(atom1.serial)) && ic.chemicals.hasOwnProperty(atom2.serial)) {
84138
+ ic.residues[resid1] = me.hashUtilsCls.unionHash(ic.residues[resid1], ic.residues[resid2]);
84139
+ }
84140
+ else if((ic.proteins.hasOwnProperty(atom2.serial) || ic.nucleotides.hasOwnProperty(atom2.serial)) && ic.chemicals.hasOwnProperty(atom1.serial)) {
84141
+ ic.residues[resid2] = me.hashUtilsCls.unionHash(ic.residues[resid2], ic.residues[resid1]);
84142
+ }
84143
+ }
84144
+ }
84145
+
84092
84146
  return ic.residuesHashClbonds;
84093
84147
  }
84094
84148
 
@@ -84435,7 +84489,7 @@ class ApplyDisplay {
84435
84489
 
84436
84490
  // remove schematic labels
84437
84491
  //if(ic.labels !== undefined) ic.labels['schematic'] = undefined;
84438
- if(ic.labels !== undefined) delete ic.labels['schematic'];
84492
+ if(!bHighlight && ic.labels !== undefined) delete ic.labels['schematic'];
84439
84493
  /*
84440
84494
  if(bHighlight) {
84441
84495
  //let residueHashCalpha = ic.firstAtomObjCls.getResiduesFromCalphaAtoms(ic.hAtoms);
@@ -84456,6 +84510,7 @@ class ApplyDisplay {
84456
84510
  //var bPhosphorusOnly = me.utilsCls.isCalphaPhosOnly(me.hashUtilsCls.hash2Atoms(atomHash), "O3'", "O3*") || me.utilsCls.isCalphaPhosOnly(me.hashUtilsCls.hash2Atoms(atomHash), "P");
84457
84511
  //let bPhosphorusOnly = me.utilsCls.isCalphaPhosOnly(me.hashUtilsCls.hash2Atoms(atomHash, ic.atoms));
84458
84512
  let nucleotidesAtoms = me.hashUtilsCls.intHash(atomHash, ic.nucleotides);
84513
+
84459
84514
  let bPhosphorusOnly = me.utilsCls.isCalphaPhosOnly(me.hashUtilsCls.hash2Atoms(nucleotidesAtoms, ic.atoms));
84460
84515
 
84461
84516
  if(style === 'ribbon') {
@@ -84494,13 +84549,13 @@ class ApplyDisplay {
84494
84549
 
84495
84550
  //if(firstAtom.het) { // chemicals
84496
84551
  if(ic.chemicals.hasOwnProperty(firstAtom.serial)) { // chemicals
84497
- ic.residueLabelsCls.addNonCarbonAtomLabels(me.hashUtilsCls.hash2Atoms(atomHash, ic.atoms));
84552
+ if(!bHighlight) ic.residueLabelsCls.addNonCarbonAtomLabels(me.hashUtilsCls.hash2Atoms(atomHash, ic.atoms));
84498
84553
 
84499
84554
  let bSchematic = true;
84500
84555
  ic.stickCls.createStickRepresentation(me.hashUtilsCls.hash2Atoms(atomHash, ic.atoms), chemicalSchematicRadius, chemicalSchematicRadius, undefined, bHighlight, bSchematic);
84501
84556
  }
84502
84557
  else { // nucleotides or proteins
84503
- ic.residueLabelsCls.addResidueLabels(me.hashUtilsCls.hash2Atoms(atomHash, ic.atoms), true);
84558
+ if(!bHighlight) ic.residueLabelsCls.addResidueLabels(me.hashUtilsCls.hash2Atoms(atomHash, ic.atoms), true);
84504
84559
 
84505
84560
  if(bPhosphorusOnly) {
84506
84561
  ic.cylinderCls.createCylinderCurve(me.hashUtilsCls.hash2Atoms(atomHash, ic.atoms), ["P"], ic.traceRadius, false, bHighlight);
@@ -90116,7 +90171,7 @@ class SetOption {
90116
90171
  ic.atoms[i].style2 = style;
90117
90172
  }
90118
90173
  }
90119
- else {
90174
+ else {
90120
90175
  for(let i in atoms) {
90121
90176
  ic.atoms[i].style = style;
90122
90177
  }
@@ -106863,6 +106918,7 @@ class MmdbParser {
106863
106918
  //ic.molid2color = molid2color;
106864
106919
  //ic.chain2molid = chain2molid;
106865
106920
  ic.molid2chain = molid2chain;
106921
+
106866
106922
  // small structure with all atoms
106867
106923
  // show surface options
106868
106924
  $("#" + ic.pre + "accordion5").show();
@@ -115299,7 +115355,9 @@ class LoadPDB {
115299
115355
 
115300
115356
  let bHeader = false, bFirstAtom = true;
115301
115357
 
115302
- let segId, prevSegId;
115358
+ let segId, prevSegId, entityid;
115359
+
115360
+ if(!ic.molid2chain) ic.molid2chain = {};
115303
115361
 
115304
115362
  for (let i in lines) {
115305
115363
  let line = lines[i];
@@ -115444,6 +115502,17 @@ class LoadPDB {
115444
115502
  ic.organism = line.substr(28).toLowerCase().trim();
115445
115503
 
115446
115504
  ic.organism = ic.organism.substr(0, ic.organism.length - 1);
115505
+ } else if (record === 'COMPND') {
115506
+ if(line.indexOf('MOL_ID: ') != -1) { // COMPND MOL_ID: 1;
115507
+ let itemArray = line.trim().split(' ');
115508
+ let lastItem = itemArray[itemArray.length - 1];
115509
+ entityid = lastItem.substr(0, lastItem.length - 1);
115510
+ }
115511
+ else if(line.indexOf('CHAIN: ') != -1) { // COMPND 3 CHAIN: H;
115512
+ let itemArray = line.trim().split(' ');
115513
+ let lastItem = itemArray[itemArray.length - 1];
115514
+ ic.molid2chain[parseInt(entityid)] = structure + '_' + lastItem.substr(0, lastItem.length - 1);
115515
+ }
115447
115516
  } else if (record === 'ENDMDL') {
115448
115517
  if(ic.statefileArray) {
115449
115518
  ic.struct_statefile.push({'structure': structure, 'statefile': ic.statefileArray[moleculeNum - 1]});
@@ -116520,6 +116589,7 @@ class LoadCIF {
116520
116589
  let resnArray = atom_site.getColumn("label_comp_id");
116521
116590
  let elemArray = atom_site.getColumn("type_symbol");
116522
116591
  let nameArray = atom_site.getColumn("label_atom_id");
116592
+ let entiyidArray = atom_site.getColumn("label_entity_id");
116523
116593
 
116524
116594
  let chainArray = atom_site.getColumn("auth_asym_id");
116525
116595
 
@@ -116541,6 +116611,8 @@ class LoadCIF {
116541
116611
  let prevResn;
116542
116612
  let sChain = {};
116543
116613
  let prevModelNum = '';
116614
+ if(!ic.molid2chain) ic.molid2chain = {};
116615
+
116544
116616
  for (let i = 0; i < atomSize; ++i) {
116545
116617
  let modelNum = modelNumArray.getString(i);
116546
116618
  if(i > 0 && modelNum != prevModelNum) {
@@ -116559,6 +116631,7 @@ class LoadCIF {
116559
116631
  let resn = resnArray.getString(i);
116560
116632
  let elem = elemArray.getString(i);
116561
116633
  let atom = nameArray.getString(i);
116634
+ let entityid = entiyidArray.getString(i);
116562
116635
  let chain = chainArray.getString(i);
116563
116636
  let resi = resiArray.getString(i);
116564
116637
  let oriResi = resiOriArray.getString(i);
@@ -116665,6 +116738,8 @@ class LoadCIF {
116665
116738
  chainNum = structure + "_" + chain;
116666
116739
  oriResidueNum = chainNum + "_" + oriResi;
116667
116740
 
116741
+ ic.molid2chain[parseInt(entityid)] = chainNum;
116742
+
116668
116743
  residueNum = chainNum + "_" + resi;
116669
116744
 
116670
116745
  //let chain_resi = chain + "_" + resi;
@@ -118335,7 +118410,7 @@ class ApplyCommand {
118335
118410
  ic.definedSetsCls.deleteSelectedSets();
118336
118411
  }
118337
118412
  else if(command == 'view interactions' || command == 'view 2d diagram') {
118338
- if(me.cfg.mmdbid !== undefined || me.cfg.gi !== undefined) {
118413
+ if(me.cfg.mmdbid !== undefined || me.cfg.gi !== undefined || me.cfg.mmdbafid !== undefined) {
118339
118414
  ic.ParserUtilsCls.set2DDiagrams(ic.inputid);
118340
118415
  }
118341
118416
  }
@@ -119850,27 +119925,31 @@ class DefinedSets {
119850
119925
  let colorStr =(atom === undefined || atom.color === undefined || atom.color.getHexString().toUpperCase() === 'FFFFFF') ? 'DDDDDD' : atom.color.getHexString();
119851
119926
  let color =(atom !== undefined && atom.color !== undefined) ? colorStr : '000000';
119852
119927
 
119853
- if(bNucleotide && atom) {
119928
+ if(bNucleotide) {
119854
119929
  // Handle nucleotide-specific logic
119855
- if(ic.nucleotides.hasOwnProperty(atom.serial) && name.split('_').length == 2 && !ic.structures.hasOwnProperty(name)) {
119930
+ if(atom && ic.nucleotides.hasOwnProperty(atom.serial) && name.split('_').length == 2 && !ic.structures.hasOwnProperty(name)) {
119856
119931
  let selectStr = (cnt == 0) ? "selected" : "";
119857
119932
 
119933
+ if(cnt == 0) this.selectSets([name]);
119934
+
119858
119935
  html += "<option value='" + name + "' style='color:#" + color + "' " + selectStr + ">" + name + "</option>";
119859
119936
  bFoundNucleotide = true;
119860
119937
  ++cnt;
119861
119938
  }
119862
119939
  }
119863
- else if(bProtein && atom) {
119940
+ else if(bProtein) {
119864
119941
  // Handle protein-specific logic
119865
- if(ic.proteins.hasOwnProperty(atom.serial) && name.split('_').length == 2 && !ic.structures.hasOwnProperty(name)) {
119942
+ if(atom && ic.proteins.hasOwnProperty(atom.serial) && name.split('_').length == 2 && !ic.structures.hasOwnProperty(name)) {
119866
119943
  let selectStr = (cnt == 0) ? "selected" : "";
119867
119944
 
119945
+ if(cnt == 0) this.selectSets([name]);
119946
+
119868
119947
  html += "<option value='" + name + "' style='color:#" + color + "' " + selectStr + ">" + name + "</option>";
119869
119948
  bFoundProtein = true;
119870
119949
  ++cnt;
119871
119950
  }
119872
119951
  }
119873
- else {
119952
+ else {
119874
119953
  if(commandnameArray.indexOf(name) != -1) {
119875
119954
  html += "<option value='" + name + "' style='color:#" + color + "' selected='selected'>" + name + "</option>";
119876
119955
  }
@@ -121053,6 +121132,20 @@ class LoadScript {
121053
121132
  await ic.diagram2dCls.drawIgdgm(chainid);
121054
121133
  ic.bRender = false;
121055
121134
  }
121135
+ else if(command.indexOf('update ig') == 0) {
121136
+ let paraArray = command.split(' ');
121137
+ let igIndex_igType = (paraArray.length == 3) ? paraArray[2] : '';
121138
+ await ic.diagram2dCls.show2DdgmForIg(igIndex_igType[0], igIndex_igType[1]);
121139
+ }
121140
+ else if(command.indexOf('download 2d ig') == 0) {
121141
+ let paraArray = command.split(' | ');
121142
+ let pos = command.lastIndexOf(' ');
121143
+ let chainid = (paraArray.length == 2) ? paraArray[1] : command.substr(pos + 1);
121144
+
121145
+ ic.bRender = true;
121146
+ await ic.diagram2dCls.drawIgdgm(chainid, true);
121147
+ ic.bRender = false;
121148
+ }
121056
121149
  else if(command.indexOf('add msa track') == 0) {
121057
121150
  //add msa track | chainid " + chainid + " | startpos " + startpos + " | type " + type + " | fastaList " + fastaList
121058
121151
  let paraArray = command.split(' | ');
@@ -128399,6 +128492,74 @@ class Diagram2d {
128399
128492
  //}
128400
128493
  }
128401
128494
  });
128495
+
128496
+ //$("#" + me.pre + "ig2ddgmDiv").html(svgHtml);
128497
+ $(document).on("change", "#" + me.pre + "iglist", async function(e) { thisClass.icn3d;
128498
+ let igIndex_igType = $("#" + me.pre + "iglist").val().split('_');
128499
+
128500
+ await thisClass.show2DdgmForIg(igIndex_igType[0], igIndex_igType[1]);
128501
+
128502
+ me.htmlCls.clickMenuCls.setLogCmd('update ig ' + igIndex_igType, true);
128503
+ });
128504
+
128505
+ // ig 2D diagram: 2D -> 3D
128506
+ $(document).on('click', '#ig2ddgmSvg .node', function(e) { let ic = thisClass.icn3d;
128507
+ // clear all node color
128508
+ thisClass.resetAllNodes('ig2ddgmSvg');
128509
+
128510
+ $(this).css({'font-size': '20px', 'font-weight': 'bold'});
128511
+
128512
+ //<text x="502.1" y="301.8" class="s9 c8547"><title>Ref. Num. 8547</title> N99 </text>
128513
+ let text = $(this).html().trim();
128514
+ let resnresi = text.substr(text.lastIndexOf(' ') + 1);
128515
+
128516
+ let resid = ic.ncbi2resid[ic.ig2ddgm_chainid + '_' + resnresi.substr(1)];
128517
+
128518
+ // highlight the selected residue
128519
+ if(ic.bCtrl || ic.bShift) {
128520
+ ic.hAtoms = me.hashUtilsCls.unionHash(ic.hAtoms, ic.residues[resid]);
128521
+ }
128522
+ else {
128523
+ ic.hAtoms = ic.residues[resid];
128524
+ }
128525
+
128526
+ ic.hlUpdateCls.showHighlight();
128527
+ });
128528
+
128529
+ // $(document).on('mouseout', '#ig2ddgmSvg .node', function(e) { let ic = thisClass.icn3d;
128530
+ // thisClass.resetAllNodes('ig2ddgmSvg');
128531
+ // });
128532
+
128533
+ // ig 2D diagram: 3D -> 2D
128534
+ $(document).on('icn3d.pick.click icn3d.pick.mouseover', function(ev, data) { let ic = thisClass.icn3d;
128535
+ // get the residues in the selection
128536
+ let ncbiresid = data;
128537
+ let resid = ic.ncbi2resid[ncbiresid];
128538
+
128539
+ if(ic.ig2ddgm_chainid && ic.resid2refnum && ic.resid2refnum[resid]) {
128540
+ let refnumLabel = ic.resid2refnum[resid];
128541
+ let refnumStr = ic.refnumCls.rmStrandFromRefnumlabel(refnumLabel);
128542
+
128543
+ // clear all node color
128544
+ thisClass.resetAllNodes('ig2ddgmSvg');
128545
+
128546
+ // highlight the residue
128547
+ $("#ig2ddgmSvg .c" + refnumStr).css({'font-size': '20px', 'font-weight': 'bold'});
128548
+ }
128549
+ });
128550
+ }
128551
+
128552
+ // reset all nodes
128553
+ resetAllNodes(id) { let ic = this.icn3d; ic.icn3dui;
128554
+ // Select the SVG container
128555
+ const svg = document.getElementById(id);
128556
+
128557
+ // Select all text-related nodes: <text>
128558
+ const textElements = svg.querySelectorAll('text');
128559
+
128560
+ textElements.forEach((node) => {
128561
+ node.style = {};
128562
+ });
128402
128563
  }
128403
128564
 
128404
128565
  clickNode(node) { let ic = this.icn3d, me = ic.icn3dui;
@@ -128633,19 +128794,14 @@ class Diagram2d {
128633
128794
 
128634
128795
  //https://9c5d031c.na-hackathon-2026.pages.dev/api.json
128635
128796
  //https://www.ebi.ac.uk/pdbe/static/entry/1ffk_2_9.json, or 1ffk_1_0.json [pdbid_molid_chain]
128636
- if(!ic.chainid2molid) {
128637
- ic.chainid2molid = {};
128638
-
128639
- await ic.showAnnoCls.showAnnotations();
128640
- let molidTmp = 1;
128641
- for(let id in ic.nucleotide_chainid) {
128642
- ic.chainid2molid[id] = molidTmp;
128643
- ++molidTmp;
128797
+ let molid = 1;
128798
+ for(let i in ic.molid2chain) {
128799
+ if(ic.molid2chain[i] == chainid) {
128800
+ molid = i;
128801
+ break;
128644
128802
  }
128645
128803
  }
128646
128804
 
128647
- let molid = ic.chainid2molid[chainid] ? ic.chainid2molid[chainid] : 1;
128648
-
128649
128805
  let url = "https://www.ebi.ac.uk/pdbe/static/entry/" + pdbid.toLowerCase() + "_" + molid + "_" + chain + ".json";
128650
128806
  let apiData = await me.getAjaxPromise(url, 'json', undefined, 'The chain ' + chainid + ' with molid ' + molid + ' has no R2DT information in PDBe...');
128651
128807
 
@@ -128799,7 +128955,7 @@ class Diagram2d {
128799
128955
  if(from_type_to.length != 3) continue;
128800
128956
 
128801
128957
  let fromArray = from_type_to[0].split('|'), toArray = from_type_to[2].split('|');
128802
- if(fromArray.length != 5 || toArray.length != 5) continue;
128958
+ if(fromArray.length < 5 || toArray.length < 5) continue;
128803
128959
  if(fromArray[2] != chain || toArray[2] != chain) continue;
128804
128960
  let resi1 = fromArray[4], resi2 = toArray[4];
128805
128961
  let ncbiResid1 = ic.resid2ncbi[chainid + '_' + resi1], ncbiResid2 = ic.resid2ncbi[chainid + '_' + resi2];
@@ -128999,12 +129155,12 @@ class Diagram2d {
128999
129155
  html += " rnaCanvas.drawingView.fitToContent();\n";
129000
129156
  html += " $('.UDedZ1UaiPZJsRmm1yxA').hide();\n"; // hide the "Powered by RNAcanvas" label
129001
129157
 
129002
- html += "var pos2node = {}, id2pos = {};\n";
129158
+ html += "var pos2node = {};\n";
129003
129159
  html += "var nodes = rnaCanvas.drawing.bases;\n";
129004
129160
 
129005
129161
  html += "for (var i = 0, il = nodes.length; i < il; i++) {\n";
129006
129162
  html += " pos2node[i + 1] = nodes[i];\n";
129007
- html += " id2pos[nodes[i].id] = i + 1;\n";
129163
+ html += " nodes[i].setAttribute('resi', i + 1);\n";
129008
129164
  html += "}\n";
129009
129165
 
129010
129166
  html += "$(document).on('click', '#rnacanvasSvg svg text', function(e) {\n";
@@ -129015,19 +129171,17 @@ class Diagram2d {
129015
129171
  html += " }\n";
129016
129172
  html += " $(this)[0].setAttribute('fill', '#f8b84e');\n";
129017
129173
 
129018
- html += " var pos = id2pos[id];\n";
129019
129174
  html += " var resn = $(this).text().split(' ')[0];\n"; //C Position 8
129020
- html += " $(document).trigger('from_rnacanvas', pos + '_' + resn);\n";
129175
+ html += " $(document).trigger('from_rnacanvas', $(this).attr('resi') + '_' + resn);\n";
129021
129176
  html += " document.dispatchEvent(event);\n";
129022
129177
  html += "});\n";
129023
129178
 
129024
129179
  html += "$(document).on('mouseover', '#rnacanvasSvg svg text', function(e) {\n";
129025
129180
  html += " var id = $(this).attr('id');\n";
129026
129181
  html += " $(this)[0].setAttribute('fill', '#f8b84e');\n";
129027
-
129028
129182
  html += " if(!$(this)[0].querySelector('title')) {\n";
129029
129183
  html += " var title = document.createElementNS('http://www.w3.org/2000/svg', 'title');\n";
129030
- html += " title.textContent = ' Position ' + id2pos[id];\n";
129184
+ html += " title.textContent = ' Position ' + $(this).attr('resi');\n";
129031
129185
  html += " $(this)[0].appendChild(title);\n";
129032
129186
  html += " }\n";
129033
129187
  html += "});\n";
@@ -129073,7 +129227,12 @@ class Diagram2d {
129073
129227
  html += " line.setAttribute('y2', node2.y);\n";
129074
129228
  html += " line.setAttribute('stroke', 'black');\n";
129075
129229
  html += " line.setAttribute('stroke-width', '1');\n";
129076
- html += " line.setAttribute('title', '" + type + "');\n";
129230
+ //html += " line.setAttribute('title', '" + type + "');\n";
129231
+
129232
+ html += " var title = document.createElementNS('http://www.w3.org/2000/svg', 'title');\n";
129233
+ html += " title.textContent = '" + pos1 + " - " + pos2 + "; " + type + "';\n";
129234
+ html += " line.appendChild(title);\n";
129235
+
129077
129236
  html += " rnaCanvas.drawing.domNode.appendChild(line);";
129078
129237
  html += "}\n";
129079
129238
  }
@@ -129094,10 +129253,12 @@ class Diagram2d {
129094
129253
  $("#" + me.pre + "rnacanvasDiv").html(html);
129095
129254
  }
129096
129255
 
129097
- async drawIgdgm(chainid) { let ic = this.icn3d, me = ic.icn3dui;
129256
+ async drawIgdgm(chainid, bDownload) { let ic = this.icn3d, me = ic.icn3dui;
129098
129257
  // select the current chain
129099
129258
  //ic.hAtoms = me.hashUtilsCls.cloneHash(ic.chains[chainid]);
129100
129259
 
129260
+ ic.ig2ddgm_chainid = chainid;
129261
+
129101
129262
  // run ig detection
129102
129263
  ic.bRunRefnumAgain = true;
129103
129264
  if(!ic.bAnnoShown) await ic.showAnnoCls.showAnnotations();
@@ -129121,7 +129282,7 @@ class Diagram2d {
129121
129282
 
129122
129283
  let igType = ic.ref2igtype[info.refpdbname];
129123
129284
 
129124
- if(igType == 'IgV' || igType == 'IgC1' || igType == 'IgC2' || igType == 'IgI') {
129285
+ if(igType == 'IgV' || igType == 'IgC1' || igType == 'IgC2' || igType == 'IgI' || igType == 'IgFN3') {
129125
129286
  bFound = true;
129126
129287
  }
129127
129288
 
@@ -129129,12 +129290,12 @@ class Diagram2d {
129129
129290
  }
129130
129291
 
129131
129292
  if(!bFound) {
129132
- var aaa = 1; //alert("The Ig type(s) for chain " + chainid + " is/are " + igTypeArray + ". Currently only IgV, IgC1, IgC2 and IgI types are supported for drawing Ig diagrams.");
129293
+ var aaa = 1; //alert("The Ig type(s) for chain " + chainid + " is/are " + igTypeArray + ". Currently only IgV, IgC1, IgC2, IgI and IgFN3 types are supported for drawing Ig diagrams.");
129133
129294
  return;
129134
129295
  }
129135
129296
 
129136
129297
  // get the hash of refnum to resn
129137
- let refnum2resn = {};
129298
+ ic.refnum2resn = {};
129138
129299
  for(let resid in ic.resid2refnum) {
129139
129300
  let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
129140
129301
  if(!atom) continue;
@@ -129147,88 +129308,154 @@ class Diagram2d {
129147
129308
 
129148
129309
  if(refnumLabel) {
129149
129310
  refnumStr = ic.refnumCls.rmStrandFromRefnumlabel(refnumLabel);
129150
- if(!refnum2resn[domainid]) refnum2resn[domainid] = {};
129151
- refnum2resn[domainid][refnumStr] = resn + resid.split('_')[2];
129311
+ if(!ic.refnum2resn[domainid]) ic.refnum2resn[domainid] = {};
129312
+ ic.refnum2resn[domainid][refnumStr] = resn + resid.split('_')[2];
129152
129313
  }
129153
129314
  }
129154
129315
 
129155
- if(ic.bXlsx === undefined) {
129156
- let urlScript = "/Structure/icn3d/script/exceljs.min.js";
129157
- await me.getAjaxPromise(urlScript, 'script');
129316
+ if(bDownload) {
129317
+ if(ic.bXlsx === undefined) {
129318
+ let urlScript = "/Structure/icn3d/script/exceljs.min.js";
129319
+ await me.getAjaxPromise(urlScript, 'script');
129158
129320
 
129159
- ic.bXlsx = true;
129160
- }
129321
+ ic.bXlsx = true;
129322
+ }
129161
129323
 
129162
- const mainWorkbook = new ExcelJS.Workbook();
129324
+ const mainWorkbook = new ExcelJS.Workbook();
129163
129325
 
129164
- let ig2width = {'IgC1': 17, 'IgC2': 18, 'IgI': 19, 'IgV': 19};
129326
+ let ig2width = {'IgC1': 17, 'IgC2': 18, 'IgI': 19, 'IgV': 19};
129165
129327
 
129166
- for(let i = 0, il = igArray.length; i < il; ++i) {
129167
- let domainid = igArray[i].domainid;
129168
- let igType = igTypeArray[i];
129169
- if(!(igType == 'IgV' || igType == 'IgC1' || igType == 'IgC2' || igType == 'IgI')) {
129170
- mainWorkbook.addWorksheet((i + 1) + ". " + igType);
129171
- }
129172
- else {
129173
- let url = "/Structure/icn3d/template/igstrand_template_" + igType + ".xlsx";
129174
- let arrayBuffer = await me.getXMLHttpRqstPromise(url, 'GET', 'arraybuffer', 'xlsx');
129175
-
129176
- const workbook = new ExcelJS.Workbook();
129177
- // Load the workbook from the buffer
129178
- await workbook.xlsx.load(arrayBuffer);
129179
- const worksheet = workbook.getWorksheet(1);
129180
-
129181
- const newSheet = mainWorkbook.addWorksheet();
129182
- // Clone the model to transfer styles and data
129183
- newSheet.model = worksheet.model;
129184
- newSheet.name = (i + 1) + ". " + igType;
129185
-
129186
- // Iterate over all rows that have values
129187
- newSheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
129188
- // Iterate over all cells in the row
129189
- row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
129190
- //console.log(`Cell [${rowNumber}, ${colNumber}] = ${cell.value}`);
129191
- if (cell.value && !isNaN(cell.value) && cell.value > 1000 && cell.value < 10000) {
129192
- if(refnum2resn[domainid].hasOwnProperty(cell.value)) {
129193
- cell.value = refnum2resn[domainid][cell.value];
129328
+ for(let i = 0, il = igArray.length; i < il; ++i) {
129329
+ let domainid = igArray[i].domainid;
129330
+ let igType = igTypeArray[i];
129331
+ if(!(igType == 'IgV' || igType == 'IgC1' || igType == 'IgC2' || igType == 'IgI' || igType == 'IgFN3')) {
129332
+ mainWorkbook.addWorksheet((i + 1) + ". " + igType);
129333
+ }
129334
+ else {
129335
+ let url = "/Structure/icn3d/template/igstrand_template_" + igType + ".xlsx";
129336
+ let arrayBuffer = await me.getXMLHttpRqstPromise(url, 'GET', 'arraybuffer', 'xlsx');
129337
+
129338
+ const workbook = new ExcelJS.Workbook();
129339
+ // Load the workbook from the buffer
129340
+ await workbook.xlsx.load(arrayBuffer);
129341
+ const worksheet = workbook.getWorksheet(1);
129342
+
129343
+ const newSheet = mainWorkbook.addWorksheet();
129344
+ // Clone the model to transfer styles and data
129345
+ newSheet.model = worksheet.model;
129346
+ newSheet.name = (i + 1) + ". " + igType;
129347
+
129348
+ // Iterate over all rows that have values
129349
+ newSheet.eachRow({ includeEmpty: true }, (row, rowNumber) => {
129350
+ // Iterate over all cells in the row
129351
+ row.eachCell({ includeEmpty: true }, (cell, colNumber) => {
129352
+ //console.log(`Cell [${rowNumber}, ${colNumber}] = ${cell.value}`);
129353
+ if (cell.value && !isNaN(cell.value) && cell.value > 1000 && cell.value < 10000) {
129354
+ if(ic.refnum2resn[domainid].hasOwnProperty(cell.value)) {
129355
+ cell.value = ic.refnum2resn[domainid][cell.value];
129356
+ }
129357
+ else {
129358
+ cell.value = '';
129359
+ }
129194
129360
  }
129195
- else {
129361
+ else if(cell.value == 'NUMBERING') {
129196
129362
  cell.value = '';
129197
129363
  }
129198
- }
129199
- else if(cell.value == 'NUMBERING') {
129200
- cell.value = '';
129201
- }
129364
+ });
129202
129365
  });
129203
- });
129204
129366
 
129205
- // copy the original data
129206
- let colNum = ig2width[igType]; // some extra columns
129207
- for(let i = 1; i <= colNum; ++i) {
129208
- const sourceCol = worksheet.getColumn(i);
129367
+ // copy the original data
129368
+ let colNum = ig2width[igType]; // some extra columns
129369
+ for(let i = 1; i <= colNum; ++i) {
129370
+ const sourceCol = worksheet.getColumn(i);
129209
129371
 
129210
- // Copy values and styles
129211
- sourceCol.eachCell({ includeEmpty: true }, (cell, rowNumber) => {
129212
- const targetCell = newSheet.getRow(rowNumber).getCell(colNum + 2 + i);
129213
-
129214
- targetCell.value = cell.value;
129215
- targetCell.style = cell.style; // Copies font, borders, and fills
129216
- });
129372
+ // Copy values and styles
129373
+ sourceCol.eachCell({ includeEmpty: true }, (cell, rowNumber) => {
129374
+ const targetCell = newSheet.getRow(rowNumber).getCell(colNum + 2 + i);
129375
+
129376
+ targetCell.value = cell.value;
129377
+ targetCell.style = cell.style; // Copies font, borders, and fills
129378
+ });
129217
129379
 
129218
- // reset width for each column
129219
- newSheet.getColumn(colNum + 2 + i).width = worksheet.getColumn(i).width;
129380
+ // reset width for each column
129381
+ newSheet.getColumn(colNum + 2 + i).width = worksheet.getColumn(i).width;
129382
+ }
129220
129383
  }
129221
129384
  }
129222
- }
129223
129385
 
129224
- // Generate the workbook as a Buffer
129225
- const data = await mainWorkbook.xlsx.writeBuffer();
129386
+ // Generate the workbook as a Buffer
129387
+ const data = await mainWorkbook.xlsx.writeBuffer();
129226
129388
 
129227
- // Access the underlying ArrayBuffer
129228
- ic.saveFileCls.saveFile(ic.inputid + '_ig_diagram.xlsx', 'xlsx', data);
129389
+ // Access the underlying ArrayBuffer
129390
+ ic.saveFileCls.saveFile(ic.inputid + '_ig_diagram.xlsx', 'xlsx', data);
129391
+ }
129392
+ else { // show interactive SVG
129393
+ // generate a dropdown menu
129394
+ let menuHtml = '';
129395
+ for(let i = 0, il = igArray.length; i < il; ++i) {
129396
+ igArray[i].domainid;
129397
+ let igType = igTypeArray[i];
129398
+
129399
+ let selStr = (i == 0) ? ' selected' : '';
129400
+ menuHtml += "<option value='" + i + '_' + igType + "' " + selStr + ">" + (i+1) + ". " + igType + "</option>";
129401
+ }
129402
+ $("#" + me.pre + "iglist").html(menuHtml);
129403
+
129404
+ await this.show2DdgmForIg(0, igTypeArray[0]); // default
129405
+
129406
+ $("#" + me.pre + "iglist").resizable();
129407
+ }
129229
129408
 
129230
129409
  ic.drawCls.draw();
129231
129410
  }
129411
+
129412
+ async show2DdgmForIg(igIndex, igType) { let ic = this.icn3d, me = ic.icn3dui;
129413
+ if(!(igType == 'IgV' || igType == 'IgC1' || igType == 'IgC2' || igType == 'IgI' || igType == 'IgFN3')) {
129414
+ var aaa = 1; //alert("This Ig type " + igType + "has no 2D template yet...");
129415
+ return '';
129416
+ }
129417
+ else {
129418
+ let url = "/Structure/icn3d/template/igstrand_template_" + igType + ".svg";
129419
+ let svgHtml = await me.getAjaxPromise(url, 'text');
129420
+
129421
+ let igArray = ic.chain2igArray[ic.ig2ddgm_chainid];
129422
+ let domainid = igArray[igIndex].domainid;
129423
+
129424
+ // loop through all text node
129425
+ let lineArray = svgHtml.split('\n');
129426
+
129427
+ let html = '';
129428
+ for(let i = 0, il = lineArray.length; i < il; ++i) {
129429
+ let line = lineArray[i];
129430
+ if(line.indexOf('<text ') == 0) { // <text x="502.1" y="301.8" class="s9 c8547"><title>Ref. Num. 8547</title> 8547 </text>
129431
+ let pos = line.indexOf('</title> ');
129432
+ let refnumStr = line.substr(pos + 9).split(' ')[0];
129433
+ let refnum = parseInt(refnumStr);
129434
+
129435
+ if(!isNaN(refnumStr) && refnum > 1000 && refnum < 10000) {
129436
+ if(ic.refnum2resn[domainid].hasOwnProperty(refnumStr)) {
129437
+ let resn = ic.refnum2resn[domainid][refnumStr];
129438
+ let pos2 = line.indexOf('class=');
129439
+ html += line.substr(0, pos2) + 'class="node ' + line.substr(pos2 + 7, pos - (pos2 + 7)) + '</title> ' + resn + ' </text>';
129440
+ }
129441
+ else {
129442
+ html += line.substr(0, pos) + '</title> </text>';
129443
+ }
129444
+ }
129445
+ else {
129446
+ html += line + '\n';
129447
+ }
129448
+ }
129449
+ else {
129450
+ html += line + '\n';
129451
+ }
129452
+ }
129453
+
129454
+ $("#" + me.pre + "ig2ddgmDiv").html(html);
129455
+
129456
+ me.htmlCls.dialogCls.openDlg('dl_ig2ddgm', 'Show 2D diagram for Ig ' + (igIndex + 1) + '.' + igType + ' in ' + ic.ig2ddgm_chainid);
129457
+ }
129458
+ }
129232
129459
  }
129233
129460
 
129234
129461
  /**
@@ -135510,7 +135737,7 @@ class iCn3DUI {
135510
135737
  //even when multiple iCn3D viewers are shown together.
135511
135738
  this.pre = this.cfg.divid + "_";
135512
135739
 
135513
- this.REVISION = '3.50.0';
135740
+ this.REVISION = '3.51.0';
135514
135741
 
135515
135742
  // In nodejs, iCn3D defines "window = {navigator: {}}", and added window = {navigator: {}, "__THREE__":"177"}
135516
135743
  this.bNode = (Object.keys(window).length < 3) ? true : false;