icn3d 3.49.6 → 3.50.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.
package/icn3d.js CHANGED
@@ -54657,6 +54657,19 @@ class UtilsCls {
54657
54657
 
54658
54658
  return date.getFullYear().toString() + monthStr + dateStr;
54659
54659
  }
54660
+
54661
+ compMatrix(mat1, mat2, len) { this.icn3dui;
54662
+ let eps = 1e-6;
54663
+ let bEqual = true;
54664
+ for (let i = 0; i < len; i++) {
54665
+ if (Math.abs(mat1.elements[i] - mat2.elements[i]) > eps) {
54666
+ bEqual = false;
54667
+ break;
54668
+ }
54669
+ }
54670
+
54671
+ return bEqual;
54672
+ }
54660
54673
  }
54661
54674
 
54662
54675
  /**
@@ -58574,7 +58587,8 @@ class ClickMenu {
58574
58587
  me.myEventCls.onIds("#" + me.pre + "2ddgm_r2dt", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
58575
58588
  thisClass.SetChainsAdvancedMenu();
58576
58589
 
58577
- let definedAtomsHtml = ic.definedSetsCls.setAtomMenu(['protein'], true);
58590
+ let bNucleotides = true;
58591
+ let definedAtomsHtml = ic.definedSetsCls.setAtomMenu(['protein'], bNucleotides);
58578
58592
  if($("#" + me.pre + "atomsCustomNucleotide").length && definedAtomsHtml) {
58579
58593
  $("#" + me.pre + "atomsCustomNucleotide").html(definedAtomsHtml);
58580
58594
  me.htmlCls.dialogCls.openDlg('dl_2ddgm_r2dt', 'Show R2DT Diagram for Nucleotides');
@@ -60506,7 +60520,7 @@ class SetMenu {
60506
60520
 
60507
60521
  html += this.getMenuText('2ddgmwrap', '2D Diagram', undefined, 1, 1);
60508
60522
  html += "<ul>";
60509
- html += this.getLink('2ddgm_r2dt', 'for Nucleotides (R2DT)' + me.htmlCls.wifiStr, 1, 2);
60523
+ html += this.getLink('2ddgm_r2dt', 'for Nucleotides' + me.htmlCls.wifiStr, 1, 2);
60510
60524
  html += this.getLink('2ddgm_igdgm', 'for Ig Domains' + me.htmlCls.wifiStr, 1, 2);
60511
60525
  if(me.cfg.mmdbid !== undefined || me.cfg.gi !== undefined || me.cfg.blast_rep_id !== undefined || me.cfg.align !== undefined || me.cfg.chainalign !== undefined) {
60512
60526
  html += this.getLink('mn2_2ddgm', 'for Chains ' + me.htmlCls.wifiStr, 1, 2);
@@ -60959,6 +60973,7 @@ class Dialog {
60959
60973
  let bLigplot = $('#' + me.pre + 'dl_ligplot').hasClass('ui-dialog-content'); // initialized
60960
60974
  let bContactmap = $('#' + me.pre + 'dl_contactmap').hasClass('ui-dialog-content'); // initialized
60961
60975
  let b2ddiagram = $('#' + me.pre + 'dl_2ddiagram').hasClass('ui-dialog-content'); // initialized
60976
+ let brnacanvas = $('#' + me.pre + 'dl_rnacanvas').hasClass('ui-dialog-content'); // initialized
60962
60977
  let bAlignerrormap = $('#' + me.pre + 'dl_alignerrormap').hasClass('ui-dialog-content'); // initialized
60963
60978
  let bTable = $('#' + me.pre + 'dl_interactionsorted').hasClass('ui-dialog-content'); // initialized
60964
60979
  let bAlignmentInit = $('#' + me.pre + 'dl_alignment').hasClass('ui-dialog-content'); // initialized
@@ -60979,6 +60994,7 @@ class Dialog {
60979
60994
  id2flag.dl_ligplot = 'bLigplot2';
60980
60995
  id2flag.dl_contactmap = 'bContactmap2';
60981
60996
  id2flag.dl_2ddiagram = 'b2ddiagram2';
60997
+ id2flag.dl_rnacanvas = 'brnacanvas2';
60982
60998
  id2flag.dl_alignerrormap = 'bAlignerrormap2';
60983
60999
  id2flag.dl_interactionsorted = 'bTable2';
60984
61000
  id2flag.dl_alignment = 'bAlignmentInit2';
@@ -60995,6 +61011,7 @@ class Dialog {
60995
61011
  if(bLigplot) status.bLigplot2 = $('#' + me.pre + 'dl_ligplot').dialog( 'isOpen' );
60996
61012
  if(bContactmap) status.bContactmap2 = $('#' + me.pre + 'dl_contactmap').dialog( 'isOpen' );
60997
61013
  if(b2ddiagram) status.b2ddiagram2 = $('#' + me.pre + 'dl_2ddiagram').dialog( 'isOpen' );
61014
+ if(brnacanvas) status.brnacanvas2 = $('#' + me.pre + 'dl_rnacanvas').dialog( 'isOpen' );
60998
61015
  if(bAlignerrormap) status.bAlignerror2 = $('#' + me.pre + 'dl_alignerrormap').dialog( 'isOpen' );
60999
61016
  if(bTable) status.bTable2 = $('#' + me.pre + 'dl_interactionsorted').dialog( 'isOpen' );
61000
61017
  if(bAlignmentInit) status.bAlignmentInit2 = $('#' + me.pre + 'dl_alignment').dialog( 'isOpen' );
@@ -61080,7 +61097,7 @@ class Dialog {
61080
61097
 
61081
61098
  d3.select("#" + me.svgid).attr("width", width).attr("height", height);
61082
61099
  }
61083
- else if(id == me.pre + 'dl_linegraph' || id == me.pre + 'dl_scatterplot' || id == me.pre + 'dl_ligplot' || id == me.pre + 'dl_contactmap' || id == me.pre + 'dl_2ddiagram' || id == me.pre + 'dl_alignerrormap') {
61100
+ else if(id == me.pre + 'dl_linegraph' || id == me.pre + 'dl_scatterplot' || id == me.pre + 'dl_ligplot' || id == me.pre + 'dl_contactmap' || id == me.pre + 'dl_alignerrormap') {
61084
61101
  let oriWidth =(status.bTwoddgmInit2 || status.bSetsInit2) ?(me.htmlCls.WIDTH - twoddgmWidth)/2 : me.htmlCls.WIDTH / 2;
61085
61102
  let ratio = $("#" + id).width() / oriWidth;
61086
61103
 
@@ -61104,10 +61121,6 @@ class Dialog {
61104
61121
  let width = ic.contactmapWidth * ratio;
61105
61122
  $("#" + me.contactmapid).attr("width", width);
61106
61123
  }
61107
- // else if(id == me.pre + 'dl_2ddiagram') {
61108
- // let width = ic.twoddiagramWidth * ratio;
61109
- // $("#" + me.twoddiagramid).attr("width", width);
61110
- // }
61111
61124
  else if(id == me.pre + 'dl_alignerrormap') {
61112
61125
  let width = ic.alignerrormapWidth * ratio;
61113
61126
  $("#" + me.alignerrormapid).attr("width", width);
@@ -61186,7 +61199,7 @@ class Dialog {
61186
61199
 
61187
61200
  let status = this.getDialogStatus().status;
61188
61201
 
61189
- 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_alignerrormap' || id === me.pre + 'dl_interactionsorted' || id === me.pre + 'dl_alignment') {
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') {
61190
61203
  //var dialogWidth = 0.5 *(me.htmlCls.WIDTH - me.htmlCls.LESSWIDTH) - twoddgmWidth * 0.5;
61191
61204
  let dialogWidth = 0.5 *(me.htmlCls.WIDTH) - twoddgmWidth * 0.5;
61192
61205
 
@@ -61222,17 +61235,18 @@ class Dialog {
61222
61235
  modal: false,
61223
61236
  position: position,
61224
61237
  close: function(e) {
61225
- if((id === me.pre + 'dl_selectannotations' &&(!status.bAlignmentInit2) &&(!status.bGraph2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61226
- ||(id === me.pre + 'dl_graph' &&(!status.bSelectannotationsInit2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61227
- ||(id === me.pre + 'dl_alignment' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61228
- ||(id === me.pre + 'dl_interactionsorted' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61229
- ||(id === me.pre + 'dl_linegraph' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61230
- ||(id === me.pre + 'dl_scatterplot' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61231
- ||(id === me.pre + 'dl_ligplot' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61232
- ||(id === me.pre + 'dl_contactmap' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61233
- ||(id === me.pre + 'dl_alignerrormap' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61234
- ||(id === me.pre + 'dl_hbondplot' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.b2ddiagram2))
61235
- ||(id === me.pre + 'dl_2ddiagram' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2))
61238
+ if((id === me.pre + 'dl_selectannotations' &&(!status.bAlignmentInit2) &&(!status.bGraph2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61239
+ ||(id === me.pre + 'dl_graph' &&(!status.bSelectannotationsInit2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61240
+ ||(id === me.pre + 'dl_alignment' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61241
+ ||(id === me.pre + 'dl_interactionsorted' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61242
+ ||(id === me.pre + 'dl_linegraph' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61243
+ ||(id === me.pre + 'dl_scatterplot' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61244
+ ||(id === me.pre + 'dl_ligplot' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61245
+ ||(id === me.pre + 'dl_contactmap' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61246
+ ||(id === me.pre + 'dl_alignerrormap' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61247
+ ||(id === me.pre + 'dl_hbondplot' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.b2ddiagram2) &&(!status.brnacanvas2))
61248
+ ||(id === me.pre + 'dl_2ddiagram' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.brnacanvas2))
61249
+ ||(id === me.pre + 'dl_rnacanvas' &&(!status.bSelectannotationsInit2) &&(!status.bGraph2) &&(!status.bAlignmentInit2) &&(!status.bTable2) &&(!status.bLineGraph2) &&(!status.bScatterplot2) &&(!status.bLigplot2) &&(!status.bContactmap2) &&(!status.bAlignerrormap2) &&(!status.bHbondplot2) &&(!status.b2ddiagram2))
61236
61250
  ) {
61237
61251
  if(status.bTwoddgmInit2 || status.bTwodctnInit2 || status.bSetsInit2) {
61238
61252
  let canvasWidth = me.utilsCls.isMobile() ? me.htmlCls.WIDTH : me.htmlCls.WIDTH - twoddgmWidth;
@@ -61258,7 +61272,7 @@ class Dialog {
61258
61272
 
61259
61273
  d3.select("#" + me.svgid).attr("width", width).attr("height", height);
61260
61274
  }
61261
- else if(id == me.pre + 'dl_linegraph' || id == me.pre + 'dl_scatterplot' || id == me.pre + 'dl_ligplot' || id == me.pre + 'dl_contactmap' || id == me.pre + 'dl_2ddiagram' || id == me.pre + 'dl_alignerrormap') {
61275
+ else if(id == me.pre + 'dl_linegraph' || id == me.pre + 'dl_scatterplot' || id == me.pre + 'dl_ligplot' || id == me.pre + 'dl_contactmap' || id == me.pre + 'dl_alignerrormap') {
61262
61276
  let oriWidth =(status.bTwoddgmInit2 || status.bSetsInit2) ?(me.htmlCls.WIDTH - twoddgmWidth)/2 : me.htmlCls.WIDTH / 2;
61263
61277
  let ratio = $("#" + id).width() / oriWidth;
61264
61278
 
@@ -61278,10 +61292,6 @@ class Dialog {
61278
61292
  let width = ic.contactmapWidth * ratio;
61279
61293
  $("#" + me.contactmapid).attr("width", width);
61280
61294
  }
61281
- // else if(id == me.pre + 'dl_2ddiagram') {
61282
- // let width = ic.twoddiagramWidth * ratio;
61283
- // $("#" + me.twoddiagramid).attr("width", width);
61284
- // }
61285
61295
  else if(id == me.pre + 'dl_alignerrormap') {
61286
61296
  let width = ic.alignerrormapWidth * ratio;
61287
61297
  $("#" + me.alignerrormapid).attr("width", width);
@@ -61418,7 +61428,7 @@ class Dialog {
61418
61428
  let width = 400, height = 150;
61419
61429
  let twoddgmWidth = me.htmlCls.width2d + 20;
61420
61430
 
61421
- 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_alignerrormap' || id === me.pre + 'dl_interactionsorted' || id === me.pre + 'dl_alignment') {
61431
+ 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') {
61422
61432
  $( "#" + id ).show();
61423
61433
  $( "#" + id + "_nb").show();
61424
61434
  $( "#" + id + "_title").html(title);
@@ -61463,11 +61473,6 @@ class Dialog {
61463
61473
 
61464
61474
  $("#" + me.contactmapid).attr("width", width);
61465
61475
  }
61466
- // else if(id == me.pre + 'dl_2ddiagram') {
61467
- // let width = ic.twoddiagramWidth * ratio;
61468
-
61469
- // $("#" + me.twoddiagramid).attr("width", width);
61470
- // }
61471
61476
  else if(id == me.pre + 'dl_alignerrormap') {
61472
61477
  let width = ic.alignerrormapWidth * ratio;
61473
61478
 
@@ -61568,7 +61573,7 @@ class SetDialog {
61568
61573
 
61569
61574
  me.svgid_ct = me.pre + "icn3d_cartoon";
61570
61575
 
61571
- let buttonStrTmp = '<button class="icn3d-commandTitle" style="-webkit-appearance:button; height:24px;background-color:#DDD;" id="';
61576
+ let buttonStrTmp = '<button class="icn3d-commandTitle" style="-webkit-appearance:button; height:24px;background-color:#DDD; margin:1px;" id="';
61572
61577
  let tmpStr = 'icn3d-node-text';
61573
61578
  html += me.htmlCls.divNowrapStr + "Dynamically generated for selected residues. <br>Nodes can be dragged or clicked.</div>";
61574
61579
  html += me.htmlCls.divNowrapStr + buttonStrTmp + me.svgid_ct + '_svg">SVG</button>' + me.htmlCls.space2;
@@ -62161,10 +62166,10 @@ class SetDialog {
62161
62166
 
62162
62167
  html += me.htmlCls.divStr + "dl_2ddgm_r2dt' class='" + dialogClass + "'>";
62163
62168
  html += this.addNotebookTitle('dl_2ddgm_r2dt', '2D Diagram for Nucleotides (R2DT)');
62164
- html += "1. Select a nucleotide chain to show R2DT diagram:<br>";
62169
+ html += "1. Select a nucleotide chain to show 2D diagram:<br>";
62165
62170
  html += "<select style='max-width:200px' id='" + me.pre + "atomsCustomNucleotide' size='5' style='min-width:130px;'>";
62166
62171
  html += "</select><br>";
62167
- html += me.htmlCls.buttonStr + "applyr2dt'>Show R2DT Diagram</button> <br><br>(Hints: Click on Residues in 2D to highlight in 3D. <br>Ctrl + click to select multiple residues.)<br>";
62172
+ 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>";
62168
62173
  html += "</div>";
62169
62174
 
62170
62175
  html += me.htmlCls.divStr + "dl_2ddgm_igdgm' class='" + dialogClass + "'>";
@@ -62503,8 +62508,31 @@ class SetDialog {
62503
62508
  html += "</div>";
62504
62509
 
62505
62510
  html += me.htmlCls.divStr + "dl_2ddiagram' style='background-color:white' class='" + dialogClass + "'>";
62506
- html += this.addNotebookTitle('dl_2ddiagram', '2D Diagram');
62507
- html += '<div id="' + me.pre + '2ddiagramDiv"></div>';
62511
+ html += this.addNotebookTitle('dl_2ddiagram', 'R2DT Diagram');
62512
+ html += '<div id="' + me.pre + '2ddiagramDiv"></div><br>';
62513
+ html += "<b>Download</b>: " + me.htmlCls.buttonStr + "r2dt_svg'>SVG</button>" + me.htmlCls.buttonStr + "r2dt_dotb' style='margin-left:12px'>Dot-Bracket</button>" + me.htmlCls.buttonStr + "r2dt_seq' style='margin-left:12px'>Sequence</button><br>";
62514
+ html += "</div>";
62515
+
62516
+ me.rnacanvasid = me.pre + 'rancanvas';
62517
+ html += me.htmlCls.divStr + "dl_rnacanvas' style='background-color:white' class='" + dialogClass + "'>";
62518
+ html += this.addNotebookTitle('dl_rnacanvas', '2D Diagram with RNAcanvas');
62519
+
62520
+ me.lwTypes = ['cWW', 'tWW', 'cWH', 'tWH', 'cWS', 'tWS', 'cHH', 'tHH', 'cHS', 'tHS', 'cSS', 'tSS']; // exclude 'cWW'
62521
+ html += "<table><tr><td>Show non-nested BPs:<br>";
62522
+ html += me.htmlCls.divNowrapStr + "<select id='" + me.pre + "basepairType' multiple size='2' style='min-width:130px;'>";
62523
+ html += "<option value='' selected>None</option>";
62524
+ html += "<option value='" + me.lwTypes.join(',') + "'>All</option>";
62525
+ for(let i = 0, il = me.lwTypes.length; i < il; i++) {
62526
+ let name = me.lwTypes[i];
62527
+ html += "<option value='" + name + "'>" + name + "</option>";
62528
+ }
62529
+ html += "</select></td><td valign='top'>";
62530
+
62531
+ html += me.htmlCls.space2 + buttonStrTmp + me.rnacanvasid + '_wconly">Show Only Nested BPs</button><br>';
62532
+ html += me.htmlCls.space2 + buttonStrTmp + me.rnacanvasid + '_dotb">Download Dot-Bracket</button><br>';
62533
+ html += me.htmlCls.space2 + buttonStrTmp + me.rnacanvasid + '_fr3d">FR3D Basepairs</button></td></tr></table><br>';
62534
+
62535
+ html += '<div id="' + me.pre + 'rnacanvasDiv"></div>';
62508
62536
  html += "</div>";
62509
62537
 
62510
62538
  html += me.htmlCls.divStr + "dl_alignerrormap' style='background-color:white' class='" + dialogClass + "'>";
@@ -65763,10 +65791,22 @@ class Events {
65763
65791
  //if(!me.cfg.notebook) dialog.dialog( "close" );
65764
65792
 
65765
65793
  let chainid = $("#" + ic.pre + "atomsCustomNucleotide").val();
65794
+ ic.r2dt_chainid = chainid;
65766
65795
 
65767
65796
  await ic.diagram2dCls.drawR2dt(chainid);
65768
65797
  thisClass.setLogCmd('diagram 2d nucleotide | ' + chainid, true);
65769
65798
  });
65799
+
65800
+ me.myEventCls.onIds("#" + me.pre + "applyfr3d", "click", async function(e) { let ic = me.icn3d;
65801
+ e.preventDefault();
65802
+ //if(!me.cfg.notebook) dialog.dialog( "close" );
65803
+
65804
+ let chainid = $("#" + ic.pre + "atomsCustomNucleotide").val();
65805
+
65806
+ await ic.diagram2dCls.drawRnacanvas(chainid);
65807
+ thisClass.setLogCmd('diagram 2d fr3d | ' + chainid, true);
65808
+ });
65809
+
65770
65810
  me.myEventCls.onIds("#" + me.pre + "applyigdgm", "click", async function(e) { let ic = me.icn3d;
65771
65811
  e.preventDefault();
65772
65812
  //if(!me.cfg.notebook) dialog.dialog( "close" );
@@ -65917,6 +65957,57 @@ class Events {
65917
65957
  thisClass.setLogCmd("cartoon label " + className, true);
65918
65958
  });
65919
65959
 
65960
+ me.myEventCls.onIds("#" + me.rnacanvasid + "_wconly", "click", function(e) { me.icn3d;
65961
+ e.preventDefault();
65962
+
65963
+ $('#' + me.pre + 'basepairType').val($('#' + me.pre + 'basepairType option:first').val()).trigger('change');
65964
+ });
65965
+ me.myEventCls.onIds("#" + me.rnacanvasid + "_svg", "click", function(e) { let ic = me.icn3d;
65966
+ e.preventDefault();
65967
+
65968
+ ic.saveFileCls.saveSvg("rnacanvasSvg", ic.inputid + "_rnacanvas.svg");
65969
+ });
65970
+ me.myEventCls.onIds("#" + me.rnacanvasid + "_dotb", "click", function(e) { let ic = me.icn3d;
65971
+ e.preventDefault();
65972
+
65973
+ ic.saveFileCls.saveFile(ic.inputid + "_dot_bracket.txt", "text", [ic.dot_bracket]);
65974
+ });
65975
+
65976
+ me.myEventCls.onIds("#" + me.rnacanvasid + "_fr3d", "click", function(e) { let ic = me.icn3d;
65977
+ e.preventDefault();
65978
+
65979
+ let url = 'https://rna.bgsu.edu/rna3dhub/pdb/' + Object.keys(ic.structures)[0] + '/interactions/fr3d/basepairs/';
65980
+
65981
+ window.open(url, '_blank');
65982
+ });
65983
+
65984
+ me.myEventCls.onIds("#" + me.pre + "r2dt_svg", "click", function(e) { let ic = me.icn3d;
65985
+ e.preventDefault();
65986
+
65987
+ let bClassName = true;
65988
+ ic.saveFileCls.saveSvg("rnaTopoSvg", ic.r2dt_chainid + "_r2dt.svg", undefined, undefined, bClassName);
65989
+ });
65990
+ me.myEventCls.onIds("#" + me.pre + "r2dt_dotb", "click", async function(e) { let ic = me.icn3d;
65991
+ e.preventDefault();
65992
+
65993
+ let chainid = $("#" + ic.pre + "atomsCustomNucleotide").val();
65994
+ let result = await ic.diagram2dCls.getDotbracket(chainid);
65995
+ ic.saveFileCls.saveFile(chainid + "_dot_bracket.txt", "text", [result.dotb]);
65996
+ });
65997
+
65998
+ me.myEventCls.onIds("#" + me.pre + "r2dt_seq", "click", function(e) { let ic = me.icn3d;
65999
+ e.preventDefault();
66000
+
66001
+ let chainid = $("#" + ic.pre + "atomsCustomNucleotide").val();
66002
+ let seq = '';
66003
+ for(let i = 0; i < ic.chainsSeq[chainid].length; ++i) {
66004
+ seq += ic.chainsSeq[chainid][i].name;
66005
+ }
66006
+
66007
+ ic.saveFileCls.saveFile(chainid + "_seq.txt", "text", [seq]);
66008
+ });
66009
+
66010
+
65920
66011
  me.myEventCls.onIds("#" + me.linegraphid + "_svg", "click", function(e) { let ic = me.icn3d;
65921
66012
  e.preventDefault();
65922
66013
 
@@ -78084,7 +78175,7 @@ class Line$1 {
78084
78175
  let radius = (line.radius) ? line.radius : ic.lineRadius;
78085
78176
  let opacity = (line.opacity) ? line.opacity : 1.0;
78086
78177
 
78087
- let colorStr = '#' + line.color.replace(/\#/g, '');
78178
+ let colorStr = (line.color) ? '#' + line.color.replace(/\#/g, '') : '#000';
78088
78179
 
78089
78180
  let color = me.parasCls.thr(colorStr);
78090
78181
 
@@ -80120,6 +80211,24 @@ class CartoonNucl {
80120
80211
  let currentChain, currentResi, currentO3;
80121
80212
  let prevOO = null;
80122
80213
 
80214
+ // add one extra residue for highlighting one residue
80215
+ if(bHighlight === 1) {
80216
+ let residueArray= ic.resid2specCls.atoms2residues(Object.keys(atomlist));
80217
+
80218
+ if(residueArray.length == 1) {
80219
+ let ncbiresid = ic.resid2ncbi[residueArray[0]];
80220
+ ic.firstAtomObjCls.getFirstAtomObj(atomlist);
80221
+ let ncbiresi = ncbiresid.substr(ncbiresid.lastIndexOf('_') + 1);
80222
+ let ncbiresid2 = ncbiresid.substr(0, ncbiresid.lastIndexOf('_')) + '_' + (parseInt(ncbiresi) + 1).toString();
80223
+ let residueid2 = ic.ncbi2resid[ncbiresid2];
80224
+
80225
+ if(ic.residues.hasOwnProperty(residueid2)) {
80226
+ let atomsAdjust = me.hashUtilsCls.hash2Atoms(ic.residues[residueid2], ic.atoms);
80227
+ atomlist = me.hashUtilsCls.unionHash(atomlist, atomsAdjust);
80228
+ }
80229
+ }
80230
+ }
80231
+
80123
80232
  for (i in atomlist) {
80124
80233
  let atom = atomlist[i];
80125
80234
  if (atom === undefined) continue;
@@ -84064,7 +84173,7 @@ class ApplyMissingRes {
84064
84173
  line.serial1 = ic.missingResResid2serial[resid0 + ',' + resid1];
84065
84174
  line.serial2 = ic.missingResResid2serial[resid1 + ',' + resid0];
84066
84175
 
84067
- line.color = (ic.atoms[line.serial1]) ? "#" + ic.atoms[line.serial1].color.getHexString() : undefined;
84176
+ line.color = (ic.atoms[line.serial1] && ic.atoms[line.serial1].color) ? "#" + ic.atoms[line.serial1].color.getHexString() : undefined;
84068
84177
 
84069
84178
  line.radius = ic.coilWidth;
84070
84179
 
@@ -86391,7 +86500,7 @@ class Instancing {
86391
86500
  }
86392
86501
  }
86393
86502
 
86394
- drawSymmetryMatesNoInstancing() { let ic = this.icn3d; ic.icn3dui;
86503
+ drawSymmetryMatesNoInstancing() { let ic = this.icn3d, me = ic.icn3dui;
86395
86504
  if (ic.biomtMatrices === undefined || ic.biomtMatrices.length == 0) return;
86396
86505
  let cnt = 1; // itself
86397
86506
  let centerSum = ic.center.clone();
@@ -86409,7 +86518,7 @@ class Instancing {
86409
86518
  if (mat === undefined) continue;
86410
86519
 
86411
86520
  // skip itself
86412
- if(mat.equals(identity)) continue;
86521
+ if(me.utilsCls.compMatrix(mat, identity, 16)) continue;
86413
86522
 
86414
86523
  let symmetryMate;
86415
86524
 
@@ -86685,7 +86794,7 @@ class Instancing {
86685
86794
  }
86686
86795
  }
86687
86796
 
86688
- drawSymmetryMatesInstancing() { let ic = this.icn3d; ic.icn3dui;
86797
+ drawSymmetryMatesInstancing() { let ic = this.icn3d, me = ic.icn3dui;
86689
86798
  if (ic.biomtMatrices === undefined || ic.biomtMatrices.length == 0) return;
86690
86799
  let cnt = 1; // itself
86691
86800
  let centerSum = ic.center.clone();
@@ -86707,10 +86816,13 @@ class Instancing {
86707
86816
  let mat = ic.biomtMatrices[i];
86708
86817
  if (mat === undefined) continue;
86709
86818
 
86710
- let matArray = mat.toArray();
86819
+ let matArray = mat.toArray().map(x => parseFloat(x)); // some values are string and others are number
86820
+ mat.fromArray(matArray);
86711
86821
 
86712
86822
  // skip itself
86713
- if(mat.equals(identity)) continue;
86823
+ //if(mat.equals(identity)) continue; // equals seemed to have some problem in comparing two matrices
86824
+ let bEqual = me.utilsCls.compMatrix(mat, identity, 16);
86825
+ if(bEqual) continue;
86714
86826
 
86715
86827
  ic.matricesElements1.push(matArray[0], matArray[1], matArray[2], matArray[3]);
86716
86828
  ic.matricesElements2.push(matArray[4], matArray[5], matArray[6], matArray[7]);
@@ -86718,7 +86830,7 @@ class Instancing {
86718
86830
  ic.matricesElements4.push(matArray[12], matArray[13], matArray[14], matArray[15]);
86719
86831
 
86720
86832
  let center = ic.center.clone();
86721
- center.applyMatrix4(mat);
86833
+ center.applyMatrix4(mat);
86722
86834
  centerSum.add(center);
86723
86835
 
86724
86836
  ++cnt;
@@ -86944,7 +87056,7 @@ class Alternate {
86944
87056
  }
86945
87057
 
86946
87058
  ic.setColorCls.applyPrevColor();
86947
-
87059
+
86948
87060
  if(ic.biomtMatrices !== undefined && ic.biomtMatrices.length > 1) {
86949
87061
  if(ic.bAssembly && Object.keys(ic.structures).length == 1 && ((me.cfg.mmdbid === undefined && me.cfg.bu == 1)
86950
87062
  || (me.cfg.mmdbid !== undefined && me.cfg.bu == 1 && Object.keys(ic.atoms).length * ic.biomtMatrices.length > ic.maxatomcnt)) ) {
@@ -86972,6 +87084,7 @@ class Alternate {
86972
87084
  }
86973
87085
 
86974
87086
  this.applyTransformation(ic._zoomFactor, ic.mouseChange, ic.quaternion);
87087
+
86975
87088
  this.render(bVrAr);
86976
87089
  }
86977
87090
  //ic.impostorCls.clearImpostors();
@@ -97706,6 +97819,8 @@ class ShowAnno {
97706
97819
  ic.maxAnnoLength = ic.maxAnnoLengthOri;
97707
97820
  }
97708
97821
 
97822
+ ic.nucleotide_chainid = nucleotide_chainid;
97823
+
97709
97824
  return {'nucleotide_chainid': nucleotide_chainid, 'chemical_chainid': chemical_chainid, 'chemical_set': chemical_set};
97710
97825
  }
97711
97826
 
@@ -102915,14 +103030,23 @@ class DrawGraph {
102915
103030
  }).strength(function(d) { return 0.4; }))
102916
103031
  .force("x", d3v4.forceX(parentWidth / 2).strength(function(d) { return 0.02; }));
102917
103032
  } else if (me.htmlCls.force == 3) { // circle
103033
+ // me.htmlCls.simulation.force("r", d3v4.forceRadial(function(d) {
103034
+ // if (d.s == 'a') {
103035
+ // return 200;
103036
+ // } else {
103037
+ // return 100;
103038
+ // }
103039
+
103040
+ // }, parentWidth / 2, parentHeight / 2).strength(function(d) { return 0.8; }));
103041
+
102918
103042
  me.htmlCls.simulation.force("r", d3v4.forceRadial(function(d) {
102919
103043
  if (d.s == 'a') {
102920
- return 200;
103044
+ return 60; //200;
102921
103045
  } else {
102922
- return 100;
103046
+ return 30; //100;
102923
103047
  }
102924
103048
 
102925
- }, parentWidth / 2, parentHeight / 2).strength(function(d) { return 0.8; }));
103049
+ }, parentWidth / 2, parentHeight / 2).strength(function(d) { return 0.1; }));
102926
103050
  } else if (me.htmlCls.force == 4) ;
102927
103051
 
102928
103052
  me.htmlCls.simulation
@@ -106208,7 +106332,8 @@ class MmcifParser {
106208
106332
  if(ic.bAssemblyUseAsu) {
106209
106333
  for(let i = 0, il = data.assembly.length; i < il; ++i) {
106210
106334
  let mat4 = new Matrix4$1();
106211
- mat4.fromArray(data.assembly[i]);
106335
+ let tmpArray = data.assembly[i].map(x => parseFloat(x)); // some values are string and others are number
106336
+ mat4.fromArray(tmpArray);
106212
106337
 
106213
106338
  // sometimes an extra matrix as included, e.g., PDb ID 2GTL
106214
106339
  if(i == 0 && data.assembly[i][0] != 1) continue;
@@ -106288,14 +106413,14 @@ class MmcifParser {
106288
106413
  async loadMultipleMmcifData(data, mmcifid, bAppend) { let ic = this.icn3d; ic.icn3dui;
106289
106414
  let bText = true;
106290
106415
  ic.loadCIFCls.loadCIF(data, mmcifid, bText, bAppend);
106291
-
106416
+
106292
106417
  if(Object.keys(ic.structures).length > 1) {
106293
106418
  ic.opts['color'] = 'structure';
106294
106419
  }
106295
106420
 
106296
106421
  ic.opmParserCls.modifyUIMapAssembly();
106297
106422
 
106298
- ic.pdbParserCls.addSecondary(bAppend);
106423
+ await ic.pdbParserCls.addSecondary(bAppend);
106299
106424
 
106300
106425
  // ic.setStyleCls.setAtomStyleByOptions(ic.opts);
106301
106426
  // ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
@@ -106738,6 +106863,7 @@ class MmdbParser {
106738
106863
  //ic.molid2color = molid2color;
106739
106864
  //ic.chain2molid = chain2molid;
106740
106865
  ic.molid2chain = molid2chain;
106866
+
106741
106867
  // small structure with all atoms
106742
106868
  // show surface options
106743
106869
  $("#" + ic.pre + "accordion5").show();
@@ -108177,7 +108303,8 @@ class PdbParser {
108177
108303
  // DSSP only works for structures with all atoms. The Calpha only structures didn't work
108178
108304
  //if(!ic.bSecondaryStructure && !bCalphaOnly) {
108179
108305
  let bCalcSecondary = false;
108180
- if(ic.bSecondaryStructure && Object.keys(ic.structures).length == 1) {
108306
+ // if(ic.bSecondaryStructure && Object.keys(ic.structures).length == 1) {
108307
+ if(ic.bSecondaryStructure) {
108181
108308
  bCalcSecondary = false;
108182
108309
  }
108183
108310
  else if(!me.cfg.mmtfid && !me.cfg.pdbid && !me.cfg.opmid && !me.cfg.mmdbid && !me.cfg.gi && !me.cfg.uniprotid && !me.cfg.blast_rep_id && !me.cfg.cid && !me.cfg.mmcifid && !me.cfg.align && !me.cfg.chainalign) {
@@ -108185,7 +108312,7 @@ class PdbParser {
108185
108312
  }
108186
108313
 
108187
108314
  // if(!ic.bSecondaryStructure && Object.keys(ic.proteins).length > 0) {
108188
- if((!ic.bSecondaryStructure || bCalcSecondary) && Object.keys(ic.proteins).length > 0 && !bNoDssp) {
108315
+ if((!ic.bSecondaryStructure || bCalcSecondary) && Object.keys(ic.proteins).length > 0 && !bNoDssp) {
108189
108316
  await this.applyCommandDssp(bAppend);
108190
108317
  }
108191
108318
  else {
@@ -108230,7 +108357,7 @@ class PdbParser {
108230
108357
 
108231
108358
  if(me.cfg.rotate !== undefined) ic.resizeCanvasCls.rotStruc(me.cfg.rotate, true);
108232
108359
 
108233
- if(bAppend && !me.bNode) {
108360
+ if(bAppend && Object.keys(ic.structures).length == 1 && !me.bNode) {
108234
108361
  // show all
108235
108362
  ic.definedSetsCls.setModeAndDisplay('all');
108236
108363
  }
@@ -115173,7 +115300,9 @@ class LoadPDB {
115173
115300
 
115174
115301
  let bHeader = false, bFirstAtom = true;
115175
115302
 
115176
- let segId, prevSegId;
115303
+ let segId, prevSegId, entityid;
115304
+
115305
+ if(!ic.molid2chain) ic.molid2chain = {};
115177
115306
 
115178
115307
  for (let i in lines) {
115179
115308
  let line = lines[i];
@@ -115318,6 +115447,17 @@ class LoadPDB {
115318
115447
  ic.organism = line.substr(28).toLowerCase().trim();
115319
115448
 
115320
115449
  ic.organism = ic.organism.substr(0, ic.organism.length - 1);
115450
+ } else if (record === 'COMPND') {
115451
+ if(line.indexOf('MOL_ID: ') != -1) { // COMPND MOL_ID: 1;
115452
+ let itemArray = line.trim().split(' ');
115453
+ let lastItem = itemArray[itemArray.length - 1];
115454
+ entityid = lastItem.substr(0, lastItem.length - 1);
115455
+ }
115456
+ else if(line.indexOf('CHAIN: ') != -1) { // COMPND 3 CHAIN: H;
115457
+ let itemArray = line.trim().split(' ');
115458
+ let lastItem = itemArray[itemArray.length - 1];
115459
+ ic.molid2chain[parseInt(entityid)] = structure + '_' + lastItem.substr(0, lastItem.length - 1);
115460
+ }
115321
115461
  } else if (record === 'ENDMDL') {
115322
115462
  if(ic.statefileArray) {
115323
115463
  ic.struct_statefile.push({'structure': structure, 'statefile': ic.statefileArray[moleculeNum - 1]});
@@ -116307,9 +116447,9 @@ class LoadCIF {
116307
116447
  if(struct_oper_id == "X0") continue;
116308
116448
 
116309
116449
  if (ic.biomtMatrices[i] == undefined) ic.biomtMatrices[i] = new Matrix4$1().identity();
116310
- ic.biomtMatrices[i].set(m11Array.getString(i), m12Array.getString(i), m13Array.getString(i), m14Array.getString(i),
116311
- m21Array.getString(i), m22Array.getString(i), m23Array.getString(i), m24Array.getString(i),
116312
- m31Array.getString(i), m32Array.getString(i), m33Array.getString(i), m34Array.getString(i),
116450
+ ic.biomtMatrices[i].set(parseFloat(m11Array.getString(i)), parseFloat(m12Array.getString(i)), parseFloat(m13Array.getString(i)), parseFloat(m14Array.getString(i)),
116451
+ parseFloat(m21Array.getString(i)), parseFloat(m22Array.getString(i)), parseFloat(m23Array.getString(i)), parseFloat(m24Array.getString(i)),
116452
+ parseFloat(m31Array.getString(i)), parseFloat(m32Array.getString(i)), parseFloat(m33Array.getString(i)), parseFloat(m34Array.getString(i)),
116313
116453
  0, 0, 0, 1);
116314
116454
  }
116315
116455
 
@@ -116341,6 +116481,44 @@ class LoadCIF {
116341
116481
  ic.pmid = block.getCategory("_citation").getColumn("pdbx_database_id_PubMed").getString(0);
116342
116482
  }
116343
116483
 
116484
+ // retrieve RNA pair info
116485
+ let pairInfo = block.getCategory("_ndb_base_pair_list");
116486
+
116487
+ if(pairInfo) {
116488
+ let chainArray2, pairidArray, pos1Array, pos2Array, resn1Array, resn2Array;
116489
+ chainArray2 = pairInfo.getColumn("asym_id_1");
116490
+ pairidArray = pairInfo.getColumn("base_pair_id");
116491
+ pos1Array = pairInfo.getColumn("seq_id_1");
116492
+ pos2Array = pairInfo.getColumn("seq_id_2");
116493
+ resn1Array = pairInfo.getColumn("comp_id_1");
116494
+ resn2Array = pairInfo.getColumn("comp_id_2");
116495
+ let pairSize = pairInfo.rowCount;
116496
+
116497
+ let annoInfo = block.getCategory("_ndb_base_pair_annotation");
116498
+
116499
+ let pairidArray2, typeArray;
116500
+ pairidArray2 = annoInfo.getColumn("base_pair_id");
116501
+ typeArray = annoInfo.getColumn("l-w_family");
116502
+
116503
+ ic.chain2pairs_resns_lw = {};
116504
+ for(let i = 0; i < pairSize; ++i) {
116505
+ if(pairidArray.getString(i) == pairidArray2.getString(i)) {
116506
+ let chain = chainArray2.getString(i);
116507
+ let pos1 = pos1Array.getString(i);
116508
+ let pos2 = pos2Array.getString(i);
116509
+ let resn1 = resn1Array.getString(i);
116510
+ let resn2 = resn2Array.getString(i);
116511
+ let lwtype = typeArray.getString(i);
116512
+ if(!ic.chain2pairs_resns_lw[chain]) ic.chain2pairs_resns_lw[chain] = [];
116513
+ ic.chain2pairs_resns_lw[chain].push(pos1);
116514
+ ic.chain2pairs_resns_lw[chain].push(pos2);
116515
+ ic.chain2pairs_resns_lw[chain].push(resn1);
116516
+ ic.chain2pairs_resns_lw[chain].push(resn2);
116517
+ ic.chain2pairs_resns_lw[chain].push(lwtype);
116518
+ }
116519
+ }
116520
+ }
116521
+
116344
116522
  // Retrieve the table corresponding to the atom_site category, which delineates atomic constituents
116345
116523
  let atom_site = block.getCategory("_atom_site");
116346
116524
  let atomSize = atom_site.rowCount;
@@ -116356,6 +116534,7 @@ class LoadCIF {
116356
116534
  let resnArray = atom_site.getColumn("label_comp_id");
116357
116535
  let elemArray = atom_site.getColumn("type_symbol");
116358
116536
  let nameArray = atom_site.getColumn("label_atom_id");
116537
+ let entiyidArray = atom_site.getColumn("label_entity_id");
116359
116538
 
116360
116539
  let chainArray = atom_site.getColumn("auth_asym_id");
116361
116540
 
@@ -116377,6 +116556,8 @@ class LoadCIF {
116377
116556
  let prevResn;
116378
116557
  let sChain = {};
116379
116558
  let prevModelNum = '';
116559
+ if(!ic.molid2chain) ic.molid2chain = {};
116560
+
116380
116561
  for (let i = 0; i < atomSize; ++i) {
116381
116562
  let modelNum = modelNumArray.getString(i);
116382
116563
  if(i > 0 && modelNum != prevModelNum) {
@@ -116395,6 +116576,7 @@ class LoadCIF {
116395
116576
  let resn = resnArray.getString(i);
116396
116577
  let elem = elemArray.getString(i);
116397
116578
  let atom = nameArray.getString(i);
116579
+ let entityid = entiyidArray.getString(i);
116398
116580
  let chain = chainArray.getString(i);
116399
116581
  let resi = resiArray.getString(i);
116400
116582
  let oriResi = resiOriArray.getString(i);
@@ -116501,6 +116683,8 @@ class LoadCIF {
116501
116683
  chainNum = structure + "_" + chain;
116502
116684
  oriResidueNum = chainNum + "_" + oriResi;
116503
116685
 
116686
+ ic.molid2chain[parseInt(entityid)] = chainNum;
116687
+
116504
116688
  residueNum = chainNum + "_" + resi;
116505
116689
 
116506
116690
  //let chain_resi = chain + "_" + resi;
@@ -119663,6 +119847,7 @@ class DefinedSets {
119663
119847
  });
119664
119848
 
119665
119849
  let bFoundNucleotide = false, bFoundProtein = false;
119850
+ let cnt = 0;
119666
119851
  for(let i = 0, il = nameArray.length; i < il; ++i) {
119667
119852
  let name = nameArray[i];
119668
119853
 
@@ -119687,16 +119872,22 @@ class DefinedSets {
119687
119872
 
119688
119873
  if(bNucleotide && atom) {
119689
119874
  // Handle nucleotide-specific logic
119690
- if(ic.nucleotides.hasOwnProperty(atom.serial) && name != 'nucleotides' && !ic.structures.hasOwnProperty(name)) {
119691
- html += "<option value='" + name + "' style='color:#" + color + "'>" + name + "</option>";
119875
+ if(ic.nucleotides.hasOwnProperty(atom.serial) && name.split('_').length == 2 && !ic.structures.hasOwnProperty(name)) {
119876
+ let selectStr = (cnt == 0) ? "selected" : "";
119877
+
119878
+ html += "<option value='" + name + "' style='color:#" + color + "' " + selectStr + ">" + name + "</option>";
119692
119879
  bFoundNucleotide = true;
119880
+ ++cnt;
119693
119881
  }
119694
119882
  }
119695
119883
  else if(bProtein && atom) {
119696
119884
  // Handle protein-specific logic
119697
- if(ic.proteins.hasOwnProperty(atom.serial) && name != 'proteins' && !ic.structures.hasOwnProperty(name)) {
119698
- html += "<option value='" + name + "' style='color:#" + color + "'>" + name + "</option>";
119885
+ if(ic.proteins.hasOwnProperty(atom.serial) && name.split('_').length == 2 && !ic.structures.hasOwnProperty(name)) {
119886
+ let selectStr = (cnt == 0) ? "selected" : "";
119887
+
119888
+ html += "<option value='" + name + "' style='color:#" + color + "' " + selectStr + ">" + name + "</option>";
119699
119889
  bFoundProtein = true;
119890
+ ++cnt;
119700
119891
  }
119701
119892
  }
119702
119893
  else {
@@ -119706,6 +119897,7 @@ class DefinedSets {
119706
119897
  else {
119707
119898
  html += "<option value='" + name + "' style='color:#" + color + "'>" + name + "</option>";
119708
119899
  }
119900
+ ++cnt;
119709
119901
  }
119710
119902
  }
119711
119903
 
@@ -120858,6 +121050,20 @@ class LoadScript {
120858
121050
  await ic.diagram2dCls.drawR2dt(chainid);
120859
121051
  ic.bRender = false;
120860
121052
  }
121053
+ else if(command.indexOf('diagram 2d fr3d') == 0) {
121054
+ let paraArray = command.split(' | ');
121055
+ let pos = command.lastIndexOf(' ');
121056
+ let chainid = (paraArray.length == 2) ? paraArray[1] : command.substr(pos + 1);
121057
+
121058
+ ic.bRender = true;
121059
+ await ic.diagram2dCls.drawRnacanvas(chainid);
121060
+ ic.bRender = false;
121061
+ }
121062
+ else if(command.indexOf('update rnacanvas') == 0) {
121063
+ let paraArray = command.split(' ');
121064
+ let nonWC = (paraArray.length == 3) ? paraArray[2] : '';
121065
+ ic.diagram2dCls.updateRnacanvas(nonWC);
121066
+ }
120861
121067
  else if(command.indexOf('diagram 2d ig') == 0) {
120862
121068
  let paraArray = command.split(' | ');
120863
121069
  let pos = command.lastIndexOf(' ');
@@ -121981,7 +122187,7 @@ class SelectByCommand {
121981
122187
  residueAtomArray = Object.keys(atomHash);
121982
122188
  }
121983
122189
 
121984
- if(commandname != "") {
122190
+ if(!commandname) {
121985
122191
  ic.selectionCls.addCustomSelection(residueAtomArray, commandname, commanddesc, select, bSelectResidues);
121986
122192
 
121987
122193
  let nameArray = [commandname];
@@ -128177,60 +128383,42 @@ class Diagram2d {
128177
128383
  thisClass.clickNode(this);
128178
128384
  });
128179
128385
 
128180
- // event for R2DT
128181
- //document.addEventListener('click', (event) => {
128182
- $(document).on("click", "r2dt-web", function(e) { let ic = thisClass.icn3d;
128183
- // The 2nd element in the path is the actual clicked g element
128184
- const path = e.originalEvent.composedPath();
128185
- const clickedElement = path[1];
128186
- let titleElem = clickedElement.querySelector('title');
128386
+ $(document).on("change", "#" + me.pre + "basepairType", function(e) { thisClass.icn3d;
128387
+ let nonWC = $("#" + me.pre + "basepairType").val().join(',');
128187
128388
 
128188
- if(titleElem) {
128189
- let title = titleElem.textContent; // e.g., 14 (position.label in template: 14.A)
128190
- let textArray = title.split(' ');
128191
- let position_resn = textArray[textArray.length - 1].split('.');
128192
- let pos = position_resn[0];
128193
- let resn = position_resn[1].substr(0, position_resn[1].length - 1);
128389
+ thisClass.updateRnacanvas(nonWC);
128390
+ me.htmlCls.clickMenuCls.setLogCmd('update rnacanvas ' + nonWC, true);
128391
+ });
128194
128392
 
128195
- let resid = ic.ncbi2resid[ic.r2dt_chainid + '_' + pos];
128196
- let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
128393
+ $(document).on("from_rnacanvas", function(event, data) {
128394
+ let pos_resn = data.split('_');
128395
+ let resn = pos_resn[1];
128197
128396
 
128198
- if(!atom) {
128199
- var aaa = 1; //alert("This residue has no 3D coordinates...");
128200
- }
128201
- else {
128202
- let oneLetterRes = me.utilsCls.residueName2Abbr(atom.resn);
128397
+ let resid = ic.ncbi2resid[ic.rnacanvas_chainid + '_' + pos_resn[0]];
128398
+ let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
128203
128399
 
128204
- let realResn = (resn == 'T') ? 'U' : resn;
128400
+ if(!atom) {
128401
+ var aaa = 1; //alert('This residue has no 3D coordinates...');
128402
+ }
128403
+ else {
128404
+ let oneLetterRes = me.utilsCls.residueName2Abbr(atom.resn);
128205
128405
 
128206
- if(resn != oneLetterRes && realResn != oneLetterRes) {
128207
- var aaa = 1; //alert("The residue number in R2DT didn't match that in 3D view...");
128406
+ if(resn != oneLetterRes) {
128407
+ console.log('The residue name in 2D ' + resn + ' did not match that in 3D view ' + oneLetterRes + '...');
128408
+ }
128409
+ //else {
128410
+ // highlight the selected residue
128411
+ if(ic.bCtrl || ic.bShift) {
128412
+ ic.hAtoms = me.hashUtilsCls.unionHash(ic.hAtoms, ic.residues[resid]);
128208
128413
  }
128209
128414
  else {
128210
- // highlight the selected residue
128211
- if(ic.bCtrl || ic.bShift) {
128212
- ic.hAtoms = me.hashUtilsCls.unionHash(ic.hAtoms, ic.residues[resid]);
128213
- }
128214
- else {
128215
- ic.hAtoms = ic.residues[resid];
128216
- }
128217
-
128218
- ic.hlUpdateCls.showHighlight();
128415
+ ic.hAtoms = ic.residues[resid];
128219
128416
  }
128220
- }
128221
-
128222
- // highlight the selected residue in 2D
128223
- let textElem = clickedElement.querySelector('text');
128224
- textElem.setAttribute("stroke", "#f8b84e");
128225
- textElem.setAttribute("stroke-width", "0.5px");
128226
128417
 
128227
- // add cursor
128228
- if(!ic.bAddedCursors) {
128229
- ic.bAddedCursors = true;
128230
- ic.diagram2dCls.makeResiduesClickable();
128231
- }
128418
+ ic.hlUpdateCls.showHighlight();
128419
+ //}
128232
128420
  }
128233
- });
128421
+ });
128234
128422
  }
128235
128423
 
128236
128424
  clickNode(node) { let ic = this.icn3d, me = ic.icn3dui;
@@ -128456,42 +128644,467 @@ class Diagram2d {
128456
128644
  return html;
128457
128645
  }
128458
128646
 
128459
- makeResiduesClickable() { let ic = this.icn3d; ic.icn3dui;
128460
- let r2dt = document.querySelector('r2dt-web').shadowRoot;
128461
- let elemArray = r2dt.querySelectorAll('g:has(title)');
128462
- for(let i = 0, il = elemArray.length; i < il; ++i) {
128463
- if(!elemArray[i].hasAttribute('id')) { // skip the main g element
128464
- elemArray[i].style.cursor = "pointer";
128647
+ async drawR2dt(chainid) { let ic = this.icn3d, me = ic.icn3dui;
128648
+ ic.bAddedCursors = false;
128649
+
128650
+ let pos = chainid.lastIndexOf('_');
128651
+ let pdbid = chainid.substr(0, pos);
128652
+ let chain = chainid.substr(pos + 1);
128653
+
128654
+ //https://9c5d031c.na-hackathon-2026.pages.dev/api.json
128655
+ //https://www.ebi.ac.uk/pdbe/static/entry/1ffk_2_9.json, or 1ffk_1_0.json [pdbid_molid_chain]
128656
+ let molid = 1;
128657
+ for(let i in ic.molid2chain) {
128658
+ if(ic.molid2chain[i] == chainid) {
128659
+ molid = i;
128660
+ break;
128465
128661
  }
128466
128662
  }
128663
+
128664
+ let url = "https://www.ebi.ac.uk/pdbe/static/entry/" + pdbid.toLowerCase() + "_" + molid + "_" + chain + ".json";
128665
+ let apiData = await me.getAjaxPromise(url, 'json', undefined, 'The chain ' + chainid + ' with molid ' + molid + ' has no R2DT information in PDBe...');
128666
+
128667
+ //https://9c5d031c.na-hackathon-2026.pages.dev/fr3d.json
128668
+ //https://www.ebi.ac.uk/pdbe/static/entry/1ffk_9_basepair.json
128669
+ let url2 = "https://www.ebi.ac.uk/pdbe/static/entry/" + pdbid.toLowerCase() + "_" + chain + "_basepair.json";
128670
+ let fr3dData = await me.getAjaxPromise(url2, 'json', undefined, 'The chain ' + chainid + ' with molid ' + molid + ' has no FR3D information in PDBe...');
128671
+
128672
+ let html = '';
128673
+
128674
+ html += "<link rel='stylesheet' type='text/css' href='./script/pdb-rna-viewer-0.3.0.css'>\n";
128675
+ html += "<div id='pdb-rna-viewer' style='width: " + ($(window).width() / 2 - 150) + "px; height: " + ($(window).height() - 240) + "px'></div>\n";
128676
+ html += "<script type='text/javascript' src='./script/pdb-rna-viewer-plugin-0.3.0.js'></script>\n";
128677
+ html += "<script type='text/javascript'>\n";
128678
+ html += " var rnaPlugin = new PdbRnaViewerPlugin();\n";
128679
+ html += " rnaPlugin.render(\n";
128680
+ html += " document.getElementById('pdb-rna-viewer'),\n";
128681
+ html += " {\n";
128682
+ html += " pdbId: '" + pdbid.toLowerCase() + "',\n";
128683
+ html += " entityId: '1',\n";
128684
+ html += " chainId: '" + chain + "',\n";
128685
+ html += " subscribeEvents: true,\n";
128686
+ html += " apiData: " + JSON.stringify(apiData) + ",\n";
128687
+ html += " FR3DData: " + JSON.stringify(fr3dData) + ",\n";
128688
+ html += " theme: { unobservedColor: '#bbbbbb' },\n";
128689
+ html += " }\n";
128690
+ html += " );\n";
128691
+ html += "</script>\n";
128692
+
128693
+ $("#" + me.pre + "2ddiagramDiv").html(html);
128694
+
128695
+ setTimeout(function(){
128696
+ // grey out residues without 3D coordinates
128697
+ const unobserved = apiData.unobserved_label_seq_ids || [];
128698
+ const PDB_LOWER = pdbid.toLowerCase();
128699
+ unobserved.forEach((seqId) => {
128700
+ document
128701
+ .querySelectorAll(`text.rnaview_${PDB_LOWER}_${seqId}`)
128702
+ .forEach((el) => { el.setAttribute('fill', '#bbbbbb');});
128703
+ });
128704
+
128705
+ // click 2D to show in 3D
128706
+ document.addEventListener('PDB.RNA.viewer.click', (ev) => {
128707
+ // $(document).on("PDB.RNA.viewer.click", function(ev, data) {
128708
+ let posArray = [];
128709
+ const d = ev.eventData || ev.detail || {};
128710
+ if (Array.isArray(d.label_seq_ids)) posArray = d.label_seq_ids;
128711
+ if (d.label_seq_id !== undefined && d.label_seq_id !== null) posArray = [d.label_seq_id];
128712
+
128713
+ let hAtoms = {};
128714
+ for(let i = 0, il = posArray.length; i < il; ++i) {
128715
+ let resid = ic.ncbi2resid[chainid + '_' + posArray[i]];
128716
+ // highlight the selected residue
128717
+ hAtoms = me.hashUtilsCls.unionHash(hAtoms, ic.residues[resid]);
128718
+ }
128719
+
128720
+ if(ic.bCtrl || ic.bShift) {
128721
+ ic.hAtoms = me.hashUtilsCls.unionHash(ic.hAtoms, hAtoms);
128722
+ }
128723
+ else {
128724
+ ic.hAtoms = hAtoms;
128725
+ }
128726
+
128727
+ ic.hlUpdateCls.showHighlight();
128728
+ });
128729
+
128730
+ // click 3D to highlight in 2D
128731
+ $(document).on("icn3d.pick.click", function(ev, data) {
128732
+ // get the residue position in the selection
128733
+ let ncbiresid = data;
128734
+ let pos = ncbiresid.substr(ncbiresid.lastIndexOf('_') + 1);
128735
+
128736
+ document.dispatchEvent(new CustomEvent('protvista-click', {
128737
+ detail: { start: pos, end: pos }
128738
+ }));
128739
+ });
128740
+
128741
+ $(document).on("icn3d.pick.mouseover", function(ev, data) {
128742
+ // get the residue position in the selection
128743
+ let ncbiresid = data;
128744
+ let pos = ncbiresid.substr(ncbiresid.lastIndexOf('_') + 1);
128745
+
128746
+ document.dispatchEvent(new CustomEvent('protvista-mouseover', {
128747
+ detail: { start: pos, end: pos }
128748
+ }));
128749
+ });
128750
+
128751
+ }, 1000);
128752
+
128753
+ me.htmlCls.dialogCls.openDlg('dl_2ddiagram', 'Show R2DT Diagram for chain ' + chainid);
128467
128754
  }
128468
128755
 
128469
- async drawR2dt(chainid) { let ic = this.icn3d, me = ic.icn3dui;
128470
- let thisClass = this;
128471
- ic.bAddedCursors = false;
128756
+ async getDotbracket(chainid) { let ic = this.icn3d, me = ic.icn3dui;
128757
+ let pos = chainid.lastIndexOf('_');
128758
+ let pdbid = chainid.substr(0, pos);
128759
+ let chain = chainid.substr(pos + 1);
128472
128760
 
128473
- ic.r2dt_chainid = chainid;
128761
+ let result;
128762
+ if(ic.chain2pairs_resns_lw) {
128763
+ let pairs_resns_lw = ic.chain2pairs_resns_lw[chain];
128764
+ let pairs = [], lw2pairs = {};
128765
+
128766
+ for(let i = 0, il = pairs_resns_lw.length; i < il; i += 5) {
128767
+ let pos1 = pairs_resns_lw[i];
128768
+ let pos2 = pairs_resns_lw[i + 1];
128769
+ pairs_resns_lw[i + 2];
128770
+ pairs_resns_lw[i + 3];
128771
+ let lw = pairs_resns_lw[i + 4];
128772
+
128773
+ if(lw == 'cWW') {
128774
+ pairs.push([parseInt(pos1), parseInt(pos2)]);
128775
+ }
128776
+ else {
128777
+ if(!lw2pairs[lw]) lw2pairs[lw] = [];
128778
+ lw2pairs[lw].push(parseInt(pos1));
128779
+ lw2pairs[lw].push(parseInt(pos2));
128780
+ }
128781
+ }
128474
128782
 
128475
- let url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?chainid2rnaid=" + chainid;
128783
+ result = this.pairs2dotbracket(pairs, lw2pairs, chainid);
128784
+ }
128785
+ else {
128786
+ let url = "https://rna.bgsu.edu/rna3dhub/pdb/" + pdbid + "/interactions/fr3d/basepairs/tsv";
128476
128787
 
128477
- let data = await me.getAjaxPromise(url, 'jsonp');
128788
+ let data = await me.getAjaxPromise(url, 'text');
128789
+ if(!data || data == 'Not a valid PDB id.') {
128790
+ var aaa = 1; //alert('The chain ' + chainid + ' has no basepair information in FR3D...');
128791
+ return;
128792
+ }
128478
128793
 
128479
- let html = '';
128480
- if(data && data.rnaid) {
128481
- html += '<r2dt-web search=\'{"urs": "' + data.rnaid + '"}\' />';
128482
- html += '<script type="text/javascript" src="https://rnacentral.github.io/r2dt-web/dist/r2dt-web.js"></script>';
128483
- $("#" + me.pre + "2ddiagramDiv").html(html);
128484
- me.htmlCls.dialogCls.openDlg('dl_2ddiagram', 'Show R2DT Diagram for chain ' + chainid);
128794
+ let ret2 = this.fr3d2pairs(data, chainid); //pairs_lw2pairs_annotations
128795
+ // annotations = ret2.anno;
128796
+ result = this.pairs2dotbracket(ret2.pairs, ret2.lw2pairs, chainid);
128797
+ }
128798
+
128799
+
128800
+ return result;
128801
+ }
128802
+
128803
+ fr3d2pairs(data, chainid) { let ic = this.icn3d; ic.icn3dui;
128804
+ let pos = chainid.lastIndexOf('_');
128805
+ let chain = chainid.substr(pos + 1);
128806
+
128807
+ let lines = data.split('\n');
128808
+
128809
+ let pairs = []; // 0-based, only for canonical base pairs
128810
+ let lw2pairs = {}; // 1-based, for non-canonical base pairs and base stacking interactions
128811
+ for (let i in lines) {
128812
+ let line = lines[i]; // e.g., 9CFN|1|A|A|2 cWW 9CFN|1|A|U|38
128813
+ let from_type_to = line.trim().split('\t');
128814
+ if(from_type_to.length != 3) continue;
128815
+
128816
+ let fromArray = from_type_to[0].split('|'), toArray = from_type_to[2].split('|');
128817
+ if(fromArray.length < 5 || toArray.length < 5) continue;
128818
+ if(fromArray[2] != chain || toArray[2] != chain) continue;
128819
+ let resi1 = fromArray[4], resi2 = toArray[4];
128820
+ let ncbiResid1 = ic.resid2ncbi[chainid + '_' + resi1], ncbiResid2 = ic.resid2ncbi[chainid + '_' + resi2];
128821
+ let pos1 = parseInt(ncbiResid1.substr(ncbiResid1.lastIndexOf('_') + 1)) - 1, pos2 = parseInt(ncbiResid2.substr(ncbiResid2.lastIndexOf('_') + 1)) - 1;
128485
128822
 
128486
- // set cursor for all nodes
128487
- setTimeout(function(){
128488
- //ic.bAddedCursors = true;
128489
- thisClass.makeResiduesClickable();
128490
- }, 3000);
128823
+ if(pos1 > pos2) continue; // each pair is listed twice in FR3D data, with the from and to residues swapped. Only process the one with pos1 < pos2 to avoid duplication.
128824
+
128825
+ if(from_type_to[1] == 'cWW') {
128826
+ if(fromArray[2] == chain && toArray[2] == chain) {
128827
+ pairs.push([Math.min(pos1, pos2), Math.max(pos1, pos2)]);
128828
+ }
128829
+ }
128830
+ else {
128831
+ let type = from_type_to[1];
128832
+ if(!lw2pairs[type]) lw2pairs[type] = [];
128833
+
128834
+ lw2pairs[type].push(pos1);
128835
+ lw2pairs[type].push(pos2);
128836
+ }
128837
+
128491
128838
  }
128492
- else {
128493
- var aaa = 1; //alert("No R2DT diagram can be found for chain " + chainid);
128839
+
128840
+ return {'pairs': pairs, 'lw2pairs': lw2pairs};
128841
+ }
128842
+
128843
+ isCrossed(pair1, pair2) {
128844
+ let i = pair1[0], j = pair1[1];
128845
+ let k = pair2[0], l = pair2[1];
128846
+ return (i < k && k < j && j < l) || (k < i && i < l && l < j);
128847
+ }
128848
+
128849
+ // modified from a python script by Eugene Baulin (https://imol.institute/leaders/baulin-group/)
128850
+ // pairs: list of (i, j) with 0 <= i < j < length
128851
+ pairs2dotbracket(pairs, lw2pairs, chainid) { let ic = this.icn3d; ic.icn3dui;
128852
+ //Dot-bracket notation for RNA secondary structures with pseudoknots.
128853
+
128854
+ //Positions are 0-indexed. Crossing pairs require different bracket types.
128855
+ //Levels are minimized by greedy coloring of the crossing graph, with pairs
128856
+ //sorted by ascending conflict count so that pairs involved in fewer crossings
128857
+ //(which form larger conflict-free groups) occupy the lower bracket levels.
128858
+
128859
+ //Bracket levels: () [] {} <> Aa Bb Cc ... Zz (30 levels total).
128860
+
128861
+ let BRACKETS = ['()', '[]', '{}', '<>'];
128862
+ for(let ch of 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') {
128863
+ BRACKETS.push(ch + ch.toLowerCase());
128864
+ }
128865
+
128866
+ pairs.sort((a, b) => parseInt(a[0]) - parseInt(b[0]));
128867
+
128868
+ // Pairs with fewer crossings tend to belong to larger conflict-free groups
128869
+ // and should occupy lower levels. Sort ascending by crossing count so they
128870
+ // are placed at level 0 first; break ties by left endpoint for determinism.
128871
+ let pairstr2crosscnt = {};
128872
+ for(let i = 0, il = pairs.length; i < il; ++i) {
128873
+ let pairstr1 = pairs[i][0] + '_' + pairs[i][1];
128874
+ for(let j = i + 1; j < il; ++j) {
128875
+ let pairstr2 = pairs[j][0] + '_' + pairs[j][1];
128876
+ if(this.isCrossed(pairs[i], pairs[j])) {
128877
+ pairstr2crosscnt[pairstr1] = (pairstr2crosscnt[pairstr1] || 0) + 1;
128878
+ pairstr2crosscnt[pairstr2] = (pairstr2crosscnt[pairstr2] || 0) + 1;
128879
+ }
128880
+ }
128494
128881
  }
128882
+
128883
+ let pairsSortbyCross = pairs.sort((a, b) => {
128884
+ let pairstr1 = a[0] + '_' + a[1], pairstr2 = b[0] + '_' + b[1];
128885
+ let crosscnt1 = pairstr2crosscnt[pairstr1] || 0, crosscnt2 = pairstr2crosscnt[pairstr2] || 0;
128886
+ if(crosscnt1 != crosscnt2) {
128887
+ return crosscnt1 - crosscnt2;
128888
+ } else {
128889
+ return a[0] - b[0];
128890
+ }
128891
+ });
128892
+
128893
+ // Greedy level assignment: for each pair (in conflict-count order),
128894
+ // use the lowest level whose existing pairs do not cross it.
128895
+ let levels = []; // each level is an array of pairs
128896
+ for(let index = 0, indexl = pairsSortbyCross.length; index < indexl; ++index) {
128897
+ let pair = pairsSortbyCross[index];
128898
+
128899
+ if(levels.length == 0) {
128900
+ levels.push([pair]);
128901
+ continue;
128902
+ }
128903
+
128904
+ let bCrossed = false;
128905
+ for(let i = 0, il = levels.length; i < il; ++i) {
128906
+ bCrossed = false;
128907
+
128908
+ let level_pairs = levels[i];
128909
+
128910
+ for(let j = 0, jl = level_pairs.length; j < jl; ++j) {
128911
+ if(this.isCrossed(pair, level_pairs[j])) {
128912
+ bCrossed = true;
128913
+ break;
128914
+ }
128915
+ }
128916
+
128917
+ if(!bCrossed) {
128918
+ levels[i].push(pair);
128919
+ break;
128920
+ }
128921
+ }
128922
+
128923
+ if(bCrossed) {
128924
+ levels.push([pair]);
128925
+ }
128926
+ }
128927
+
128928
+ // Relabel so larger groups use lower-level brackets, minimising the total
128929
+ // number of characters at higher levels. Bracket types are just labels —
128930
+ // any permutation of levels is valid as long as pairs on the same level
128931
+ // do not cross.
128932
+ levels.sort((a, b) => b.length - a.length); // sort descending by group size
128933
+
128934
+ let dotb = [], seq = '';
128935
+ for(let i = 0; i < ic.chainsSeq[chainid].length; ++i) {
128936
+ dotb.push('.');
128937
+ seq += ic.chainsSeq[chainid][i].name;
128938
+ }
128939
+
128940
+ let type = 'cWW';
128941
+ if(!lw2pairs[type]) lw2pairs[type] = [];
128942
+
128943
+ for(let i = 0, il = levels.length; i < il; ++i) {
128944
+ let pairs = levels[i];
128945
+ for(let j = 0, jl = pairs.length; j < jl; ++j) {
128946
+ dotb[pairs[j][0]] = BRACKETS[i][0];
128947
+ dotb[pairs[j][1]] = BRACKETS[i][1];
128948
+
128949
+ if(i > 0) { // level 0 is for nested base pairs
128950
+ lw2pairs[type].push(pairs[j][0] + 1); // 1-based
128951
+ lw2pairs[type].push(pairs[j][1] + 1);
128952
+ }
128953
+ }
128954
+ }
128955
+
128956
+ return {'dotb': dotb.join(''), 'seq': seq, 'lw2pairs': lw2pairs};
128957
+ }
128958
+
128959
+ async drawRnacanvas(chainid) { let ic = this.icn3d, me = ic.icn3dui;
128960
+ ic.bAddedCursors = false;
128961
+
128962
+ ic.rnacanvas_chainid = chainid;
128963
+
128964
+ let pos = chainid.lastIndexOf('_');
128965
+ chainid.substr(0, pos);
128966
+
128967
+ let result = await this.getDotbracket(chainid);
128968
+
128969
+ ic.dot_bracket = result.dotb;
128970
+ ic.rnaseq = result.seq;
128971
+ ic.lw2pairs = result.lw2pairs;
128972
+
128973
+ let nonWC = '';
128974
+ this.updateRnacanvas(nonWC);
128975
+ //me.htmlCls.clickMenuCls.setLogCmd('update forna ' + nonWC, true);
128976
+
128977
+ me.htmlCls.dialogCls.openDlg('dl_rnacanvas', 'Show 2D Diagram for chain ' + chainid + ' with RNAcanvas');
128978
+ $("#" + me.pre + "basepairType").resizable();
128979
+ }
128980
+
128981
+ updateRnacanvas(nonWC) { let ic = this.icn3d, me = ic.icn3dui;
128982
+ let html = '';
128983
+
128984
+ html += "<div id='rnacanvasSvg'></div>\n";
128985
+
128986
+ html += "<script type='module'>\n";
128987
+ //html += " import 'https://cdn.jsdelivr.net/npm/@rnacanvas/embedded@3.1.0';\n";
128988
+ html += " import './script/rnacanvas-4.0.0.js';\n";
128989
+ html += "</script>\n";
128990
+
128991
+ html += "<script type='text/javascript'>\n";
128992
+ html += "var attempts = 0;\n";
128993
+ html += "var tick = () => {\n";
128994
+ html += " if (typeof RNAcanvas !== 'undefined') {\n";
128995
+
128996
+ // html += "<script type='text/javascript'>\n";
128997
+ // html += "setTimeout(function(){\n";
128998
+ html += " // create a new RNAcanvas app instance\n";
128999
+ html += " var rnaCanvas = new RNAcanvas();\n";
129000
+ html += " // Target your container and append the canvas element\n";
129001
+ html += " var container = document.getElementById('rnacanvasSvg');\n";
129002
+ html += " rnaCanvas.appendTo(container);\n";
129003
+ html += " // control the size of the component\n";
129004
+ html += " rnaCanvas.domNode.style.width = '" + ($(window).width() / 2 - 150) + "px';\n";
129005
+ html += " rnaCanvas.domNode.style.height = '" + ($(window).height() - 200) + "px';\n";
129006
+ //html += " rnaCanvas.domNode.style.width = '600px';\n";
129007
+ //html += " rnaCanvas.domNode.style.height = '600px';\n";
129008
+ html += " // Render the structure\n";
129009
+ html += " rnaCanvas.drawDotBracket('" + ic.rnaseq + "', '" + ic.dot_bracket + "');\n";
129010
+ html += " // add padding around the drawn structure\n";
129011
+ html += " rnaCanvas.drawing.setPadding(20);\n";
129012
+ //html += " rnaCanvas.drawing.setPadding(1000);\n";
129013
+ html += " // bring the drawn structure into view\n";
129014
+ html += " rnaCanvas.drawingView.fitToContent();\n";
129015
+ html += " $('.UDedZ1UaiPZJsRmm1yxA').hide();\n"; // hide the "Powered by RNAcanvas" label
129016
+
129017
+ html += "var pos2node = {};\n";
129018
+ html += "var nodes = rnaCanvas.drawing.bases;\n";
129019
+
129020
+ html += "for (var i = 0, il = nodes.length; i < il; i++) {\n";
129021
+ html += " pos2node[i + 1] = nodes[i];\n";
129022
+ html += " nodes[i].setAttribute('resi', i + 1);\n";
129023
+ html += "}\n";
129024
+
129025
+ html += "$(document).on('click', '#rnacanvasSvg svg text', function(e) {\n";
129026
+ html += " var id = $(this).attr('id');\n";
129027
+ html += " // clear all node color\n";
129028
+ html += " for (var i = 0, il = nodes.length; i < il; i++) {\n";
129029
+ html += " nodes[i].setAttribute('fill', '#000');\n";
129030
+ html += " }\n";
129031
+ html += " $(this)[0].setAttribute('fill', '#f8b84e');\n";
129032
+
129033
+ html += " var resn = $(this).text().split(' ')[0];\n"; //C Position 8
129034
+ html += " $(document).trigger('from_rnacanvas', $(this).attr('resi') + '_' + resn);\n";
129035
+ html += " document.dispatchEvent(event);\n";
129036
+ html += "});\n";
129037
+
129038
+ html += "$(document).on('mouseover', '#rnacanvasSvg svg text', function(e) {\n";
129039
+ html += " var id = $(this).attr('id');\n";
129040
+ html += " $(this)[0].setAttribute('fill', '#f8b84e');\n";
129041
+ html += " if(!$(this)[0].querySelector('title')) {\n";
129042
+ html += " var title = document.createElementNS('http://www.w3.org/2000/svg', 'title');\n";
129043
+ html += " title.textContent = ' Position ' + $(this).attr('resi');\n";
129044
+ html += " $(this)[0].appendChild(title);\n";
129045
+ html += " }\n";
129046
+ html += "});\n";
129047
+
129048
+ html += "$(document).on('mouseout', '#rnacanvasSvg svg text', function(e) {\n";
129049
+ html += " var id = $(this).attr('id');\n";
129050
+ html += " $(this)[0].setAttribute('fill', '#000');\n";
129051
+ html += "});\n";
129052
+
129053
+ // click 3D to highlight in 2D
129054
+ html += "$(document).on('icn3d.pick.click icn3d.pick.mouseover', function(ev, data) {\n";
129055
+ html += " // get the residues in the selection\n";
129056
+ html += " var ncbiresid = data;\n";
129057
+ html += " var pos = ncbiresid.substr(ncbiresid.lastIndexOf('_') + 1);\n";
129058
+
129059
+ html += " // clear all node color\n";
129060
+ html += " for (var i = 0, il = nodes.length; i < il; i++) {\n";
129061
+ html += " nodes[i].setAttribute('fill', '#000');\n";
129062
+ html += " }\n";
129063
+
129064
+ html += " var node = pos2node[parseInt(pos)];\n";
129065
+ html += " node.setAttribute('fill', '#f8b84e');\n";
129066
+ html += "});\n";
129067
+
129068
+ if(nonWC) {
129069
+ let lwTypesTmp = nonWC.split(',');
129070
+ let lwTypes = [...new Set(lwTypesTmp)]; // unique
129071
+
129072
+ for(let i = 0, il = lwTypes.length; i < il; ++i) {
129073
+ let type = lwTypes[i];
129074
+ let pairs = ic.lw2pairs[type];
129075
+ if(!pairs) continue;
129076
+
129077
+ for(let j = 0, jl = pairs.length; j < jl; j += 2) {
129078
+ let pos1 = pairs[j], pos2 = pairs[j + 1];
129079
+ html += "if(pos2node[" + pos1 + "] && pos2node[" + pos2 + "]) {\n";
129080
+ html += " var node1 = pos2node[" + pos1 + "].centerPoint;\n";
129081
+ html += " var node2 = pos2node[" + pos2 + "].centerPoint;\n";
129082
+ html += " const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n";
129083
+ html += " line.setAttribute('x1', node1.x);\n";
129084
+ html += " line.setAttribute('y1', node1.y);\n";
129085
+ html += " line.setAttribute('x2', node2.x);\n";
129086
+ html += " line.setAttribute('y2', node2.y);\n";
129087
+ html += " line.setAttribute('stroke', 'black');\n";
129088
+ html += " line.setAttribute('stroke-width', '1');\n";
129089
+ html += " line.setAttribute('title', '" + type + "');\n";
129090
+ html += " rnaCanvas.drawing.domNode.appendChild(line);";
129091
+ html += "}\n";
129092
+ }
129093
+ }
129094
+ }
129095
+
129096
+ // html += "}, 10000);\n";
129097
+
129098
+ html += " return;\n";
129099
+ html += " }\n";
129100
+ html += " if (attempts++ > 200) return;\n";
129101
+ html += " setTimeout(tick, 100);\n";
129102
+ html += "};\n";
129103
+ html += "tick();\n";
129104
+
129105
+ html += "</script>\n";
129106
+
129107
+ $("#" + me.pre + "rnacanvasDiv").html(html);
128495
129108
  }
128496
129109
 
128497
129110
  async drawIgdgm(chainid) { let ic = this.icn3d, me = ic.icn3dui;
@@ -130666,7 +131279,7 @@ class SaveFile {
130666
131279
  }
130667
131280
  }
130668
131281
 
130669
- saveSvg(id, filename, bContactmap, bLigplot) { let ic = this.icn3d, me = ic.icn3dui;
131282
+ saveSvg(id, filename, bContactmap, bLigplot, bClassName) { let ic = this.icn3d, me = ic.icn3dui;
130670
131283
  if(me.bNode) return '';
130671
131284
 
130672
131285
  let width = $("#" + id).width();
@@ -130679,17 +131292,24 @@ class SaveFile {
130679
131292
  height += ic.len4ang;
130680
131293
  }
130681
131294
 
130682
- let svgXml = this.getSvgXml(id, width, height, bContactmap, bLigplot);
131295
+ let svgXml = this.getSvgXml(id, width, height, bContactmap, bLigplot, bClassName);
131296
+
131297
+ if(id == me.rnacanvasid) { // replace the font to 8
131298
+ svgXml = svgXml.replace('font-size: 18px', 'font-size: 8px');
131299
+ }
130683
131300
 
130684
131301
  let blob = new Blob([svgXml], {type: "image/svg+xml"});
130685
131302
  saveAs(blob, filename);
130686
131303
  }
130687
131304
 
130688
- getSvgXml(id, width, height, bContactmap, bLigplot) { let ic = this.icn3d, me = ic.icn3dui;
131305
+ getSvgXml(id, width, height, bContactmap, bLigplot, bClassName) { let ic = this.icn3d, me = ic.icn3dui;
130689
131306
  if(me.bNode) return '';
130690
131307
 
130691
131308
  // font is not good
130692
- let svg_data = document.getElementById(id).innerHTML; //put id of your svg element here
131309
+ let svg_data = (!bClassName) ? document.getElementById(id).innerHTML : document.querySelector('.' + id).innerHTML; //put id of your svg element here
131310
+ svg_data = svg_data.replace(/ fill=" #ccc"=""/g, '" fill="#ccc"'); // fix some data
131311
+ svg_data = svg_data.replace(/style="cursor: pointer;"/g, '');
131312
+ svg_data = svg_data.replace(/ font-size="/g, ' style="font-size: ');
130693
131313
 
130694
131314
  let startX = (bLigplot) ? -30 : 0;
130695
131315
  let startY = (bLigplot) ? -30 : 0;
@@ -130979,10 +131599,10 @@ class SaveFile {
130979
131599
  for(let n = 0; n < 3; ++n) {
130980
131600
  let nNum = n + 1;
130981
131601
  stru2header[stru] += "REMARK 350 BIOMT" + nNum.toString() + " " + mNum.toString().padStart(2, ' ')
130982
- + " " + ic.biomtMatrices[m].elements[n + 0].toFixed(6).toString().padStart(9, ' ')
130983
- + " " + ic.biomtMatrices[m].elements[n + 4].toFixed(6).toString().padStart(9, ' ')
130984
- + " " + ic.biomtMatrices[m].elements[n + 8].toFixed(6).toString().padStart(9, ' ')
130985
- + " " + ic.biomtMatrices[m].elements[n + 12].toFixed(6).toString().padStart(14, ' ') + "\n";
131602
+ + " " + parseFloat(ic.biomtMatrices[m].elements[n + 0]).toFixed(6).toString().padStart(9, ' ')
131603
+ + " " + parseFloat(ic.biomtMatrices[m].elements[n + 4]).toFixed(6).toString().padStart(9, ' ')
131604
+ + " " + parseFloat(ic.biomtMatrices[m].elements[n + 8]).toFixed(6).toString().padStart(9, ' ')
131605
+ + " " + parseFloat(ic.biomtMatrices[m].elements[n + 12]).toFixed(6).toString().padStart(14, ' ') + "\n";
130986
131606
  }
130987
131607
  }
130988
131608
  }
@@ -132423,7 +133043,7 @@ class Export3D {
132423
133043
  let mat = ic.biomtMatrices[i];
132424
133044
  if(mat === undefined) continue;
132425
133045
  // skip itself
132426
- if(mat.equals(identity)) continue;
133046
+ if(me.utilsCls.compMatrix(mat, identity, 16)) continue;
132427
133047
  let time =(i + 1) * 100;
132428
133048
  //https://stackoverflow.com/questions/1190642/how-can-i-pass-a-parameter-to-a-settimeout-callback
132429
133049
  setTimeout(function(mat, index){
@@ -132465,7 +133085,7 @@ class Export3D {
132465
133085
  let mat = ic.biomtMatrices[i];
132466
133086
  if(mat === undefined) continue;
132467
133087
  // skip itself
132468
- if(mat.equals(identity)) continue;
133088
+ if(me.utilsCls.compMatrix(mat, identity, 16)) continue;
132469
133089
  let time =(i + 1) * 100;
132470
133090
  //https://stackoverflow.com/questions/1190642/how-can-i-pass-a-parameter-to-a-settimeout-callback
132471
133091
  setTimeout(function(mat, index){
@@ -132582,7 +133202,7 @@ class Export3D {
132582
133202
  if(mat1 === undefined) continue;
132583
133203
 
132584
133204
  // skip itself
132585
- if(mat1.equals(identity)) continue;
133205
+ if(me.utilsCls.compMatrix(mat1, identity, 16)) continue;
132586
133206
 
132587
133207
  blobArray = this.processStlMeshGroup( ic.mdl, blobArray, mat1 );
132588
133208
 
@@ -132681,7 +133301,7 @@ class Export3D {
132681
133301
 
132682
133302
  //http://gun.teipir.gr/VRML-amgem/spec/part1/examples.html
132683
133303
  //Save the VRML file for 3D color printing.
132684
- saveVrmlFile( mat ){ let ic = this.icn3d; ic.icn3dui;
133304
+ saveVrmlFile( mat ){ let ic = this.icn3d, me = ic.icn3dui;
132685
133305
  if(Object.keys(ic.dAtoms).length > 50000) {
132686
133306
  var aaa = 1; //alert('Please display a subset of the structure to export 3D files. Then merge the files for 3D printing...');
132687
133307
  return [''];
@@ -132712,7 +133332,7 @@ class Export3D {
132712
133332
  if(mat1 === undefined) continue;
132713
133333
 
132714
133334
  // skip itself
132715
- if(mat1.equals(identity)) continue;
133335
+ if(me.utilsCls.compMatrix(mat1, identity, 16)) continue;
132716
133336
 
132717
133337
  result = this.processVrmlMeshGroup( ic.mdl, vrmlStrArray, vertexCnt, mat1 );
132718
133338
  vrmlStrArray = result.vrmlStrArray;
@@ -133362,6 +133982,9 @@ class Picking {
133362
133982
  this.showPickingBase(atom, x, y);
133363
133983
 
133364
133984
  if(ic.pk != 0) {
133985
+ let resid = atom.structure + '_' + atom.chain + '_' + atom.resi;
133986
+ let ncbiresid = (ic.resid2ncbi[resid]) ? ic.resid2ncbi[resid] : resid;
133987
+
133365
133988
  if(x !== undefined && y !== undefined) { // mouse over
133366
133989
  if(me.cfg.showmenu != undefined && me.cfg.showmenu == true) {
133367
133990
  y += me.htmlCls.MENU_HEIGHT;
@@ -133388,6 +134011,8 @@ class Picking {
133388
134011
 
133389
134012
  $("#" + ic.pre + "popup").html(text);
133390
134013
  $("#" + ic.pre + "popup").css("top", y).css("left", x+20).show();
134014
+
134015
+ $(document).trigger('icn3d.pick.mouseover', ncbiresid);
133391
134016
  }
133392
134017
  else {
133393
134018
  // highlight the sequence background
@@ -133400,6 +134025,8 @@ class Picking {
133400
134025
  // update the interaction flag
133401
134026
  ic.bSphereCalc = false;
133402
134027
  ic.bHbondCalc = false;
134028
+
134029
+ $(document).trigger('icn3d.pick.click', ncbiresid);
133403
134030
  }
133404
134031
  }
133405
134032
  }
@@ -134896,7 +135523,7 @@ class iCn3DUI {
134896
135523
  //even when multiple iCn3D viewers are shown together.
134897
135524
  this.pre = this.cfg.divid + "_";
134898
135525
 
134899
- this.REVISION = '3.49.2';
135526
+ this.REVISION = '3.50.0';
134900
135527
 
134901
135528
  // In nodejs, iCn3D defines "window = {navigator: {}}", and added window = {navigator: {}, "__THREE__":"177"}
134902
135529
  this.bNode = (Object.keys(window).length < 3) ? true : false;