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.module.js CHANGED
@@ -55558,6 +55558,19 @@ class UtilsCls {
55558
55558
 
55559
55559
  return date.getFullYear().toString() + monthStr + dateStr;
55560
55560
  }
55561
+
55562
+ compMatrix(mat1, mat2, len) { this.icn3dui;
55563
+ let eps = 1e-6;
55564
+ let bEqual = true;
55565
+ for (let i = 0; i < len; i++) {
55566
+ if (Math.abs(mat1.elements[i] - mat2.elements[i]) > eps) {
55567
+ bEqual = false;
55568
+ break;
55569
+ }
55570
+ }
55571
+
55572
+ return bEqual;
55573
+ }
55561
55574
  }
55562
55575
 
55563
55576
  /**
@@ -59475,7 +59488,8 @@ class ClickMenu {
59475
59488
  me.myEventCls.onIds("#" + me.pre + "2ddgm_r2dt", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
59476
59489
  thisClass.SetChainsAdvancedMenu();
59477
59490
 
59478
- let definedAtomsHtml = ic.definedSetsCls.setAtomMenu(['protein'], true);
59491
+ let bNucleotides = true;
59492
+ let definedAtomsHtml = ic.definedSetsCls.setAtomMenu(['protein'], bNucleotides);
59479
59493
  if($("#" + me.pre + "atomsCustomNucleotide").length && definedAtomsHtml) {
59480
59494
  $("#" + me.pre + "atomsCustomNucleotide").html(definedAtomsHtml);
59481
59495
  me.htmlCls.dialogCls.openDlg('dl_2ddgm_r2dt', 'Show R2DT Diagram for Nucleotides');
@@ -61407,7 +61421,7 @@ class SetMenu {
61407
61421
 
61408
61422
  html += this.getMenuText('2ddgmwrap', '2D Diagram', undefined, 1, 1);
61409
61423
  html += "<ul>";
61410
- html += this.getLink('2ddgm_r2dt', 'for Nucleotides (R2DT)' + me.htmlCls.wifiStr, 1, 2);
61424
+ html += this.getLink('2ddgm_r2dt', 'for Nucleotides' + me.htmlCls.wifiStr, 1, 2);
61411
61425
  html += this.getLink('2ddgm_igdgm', 'for Ig Domains' + me.htmlCls.wifiStr, 1, 2);
61412
61426
  if(me.cfg.mmdbid !== undefined || me.cfg.gi !== undefined || me.cfg.blast_rep_id !== undefined || me.cfg.align !== undefined || me.cfg.chainalign !== undefined) {
61413
61427
  html += this.getLink('mn2_2ddgm', 'for Chains ' + me.htmlCls.wifiStr, 1, 2);
@@ -61860,6 +61874,7 @@ class Dialog {
61860
61874
  let bLigplot = $('#' + me.pre + 'dl_ligplot').hasClass('ui-dialog-content'); // initialized
61861
61875
  let bContactmap = $('#' + me.pre + 'dl_contactmap').hasClass('ui-dialog-content'); // initialized
61862
61876
  let b2ddiagram = $('#' + me.pre + 'dl_2ddiagram').hasClass('ui-dialog-content'); // initialized
61877
+ let brnacanvas = $('#' + me.pre + 'dl_rnacanvas').hasClass('ui-dialog-content'); // initialized
61863
61878
  let bAlignerrormap = $('#' + me.pre + 'dl_alignerrormap').hasClass('ui-dialog-content'); // initialized
61864
61879
  let bTable = $('#' + me.pre + 'dl_interactionsorted').hasClass('ui-dialog-content'); // initialized
61865
61880
  let bAlignmentInit = $('#' + me.pre + 'dl_alignment').hasClass('ui-dialog-content'); // initialized
@@ -61880,6 +61895,7 @@ class Dialog {
61880
61895
  id2flag.dl_ligplot = 'bLigplot2';
61881
61896
  id2flag.dl_contactmap = 'bContactmap2';
61882
61897
  id2flag.dl_2ddiagram = 'b2ddiagram2';
61898
+ id2flag.dl_rnacanvas = 'brnacanvas2';
61883
61899
  id2flag.dl_alignerrormap = 'bAlignerrormap2';
61884
61900
  id2flag.dl_interactionsorted = 'bTable2';
61885
61901
  id2flag.dl_alignment = 'bAlignmentInit2';
@@ -61896,6 +61912,7 @@ class Dialog {
61896
61912
  if(bLigplot) status.bLigplot2 = $('#' + me.pre + 'dl_ligplot').dialog( 'isOpen' );
61897
61913
  if(bContactmap) status.bContactmap2 = $('#' + me.pre + 'dl_contactmap').dialog( 'isOpen' );
61898
61914
  if(b2ddiagram) status.b2ddiagram2 = $('#' + me.pre + 'dl_2ddiagram').dialog( 'isOpen' );
61915
+ if(brnacanvas) status.brnacanvas2 = $('#' + me.pre + 'dl_rnacanvas').dialog( 'isOpen' );
61899
61916
  if(bAlignerrormap) status.bAlignerror2 = $('#' + me.pre + 'dl_alignerrormap').dialog( 'isOpen' );
61900
61917
  if(bTable) status.bTable2 = $('#' + me.pre + 'dl_interactionsorted').dialog( 'isOpen' );
61901
61918
  if(bAlignmentInit) status.bAlignmentInit2 = $('#' + me.pre + 'dl_alignment').dialog( 'isOpen' );
@@ -61981,7 +61998,7 @@ class Dialog {
61981
61998
 
61982
61999
  d3.select("#" + me.svgid).attr("width", width).attr("height", height);
61983
62000
  }
61984
- 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') {
62001
+ 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') {
61985
62002
  let oriWidth =(status.bTwoddgmInit2 || status.bSetsInit2) ?(me.htmlCls.WIDTH - twoddgmWidth)/2 : me.htmlCls.WIDTH / 2;
61986
62003
  let ratio = $("#" + id).width() / oriWidth;
61987
62004
 
@@ -62005,10 +62022,6 @@ class Dialog {
62005
62022
  let width = ic.contactmapWidth * ratio;
62006
62023
  $("#" + me.contactmapid).attr("width", width);
62007
62024
  }
62008
- // else if(id == me.pre + 'dl_2ddiagram') {
62009
- // let width = ic.twoddiagramWidth * ratio;
62010
- // $("#" + me.twoddiagramid).attr("width", width);
62011
- // }
62012
62025
  else if(id == me.pre + 'dl_alignerrormap') {
62013
62026
  let width = ic.alignerrormapWidth * ratio;
62014
62027
  $("#" + me.alignerrormapid).attr("width", width);
@@ -62087,7 +62100,7 @@ class Dialog {
62087
62100
 
62088
62101
  let status = this.getDialogStatus().status;
62089
62102
 
62090
- 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') {
62103
+ 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') {
62091
62104
  //var dialogWidth = 0.5 *(me.htmlCls.WIDTH - me.htmlCls.LESSWIDTH) - twoddgmWidth * 0.5;
62092
62105
  let dialogWidth = 0.5 *(me.htmlCls.WIDTH) - twoddgmWidth * 0.5;
62093
62106
 
@@ -62123,17 +62136,18 @@ class Dialog {
62123
62136
  modal: false,
62124
62137
  position: position,
62125
62138
  close: function(e) {
62126
- 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))
62127
- ||(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))
62128
- ||(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))
62129
- ||(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))
62130
- ||(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))
62131
- ||(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))
62132
- ||(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))
62133
- ||(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))
62134
- ||(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))
62135
- ||(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))
62136
- ||(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))
62139
+ 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))
62140
+ ||(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))
62141
+ ||(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))
62142
+ ||(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))
62143
+ ||(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))
62144
+ ||(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))
62145
+ ||(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))
62146
+ ||(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))
62147
+ ||(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))
62148
+ ||(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))
62149
+ ||(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))
62150
+ ||(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))
62137
62151
  ) {
62138
62152
  if(status.bTwoddgmInit2 || status.bTwodctnInit2 || status.bSetsInit2) {
62139
62153
  let canvasWidth = me.utilsCls.isMobile() ? me.htmlCls.WIDTH : me.htmlCls.WIDTH - twoddgmWidth;
@@ -62159,7 +62173,7 @@ class Dialog {
62159
62173
 
62160
62174
  d3.select("#" + me.svgid).attr("width", width).attr("height", height);
62161
62175
  }
62162
- 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') {
62176
+ 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') {
62163
62177
  let oriWidth =(status.bTwoddgmInit2 || status.bSetsInit2) ?(me.htmlCls.WIDTH - twoddgmWidth)/2 : me.htmlCls.WIDTH / 2;
62164
62178
  let ratio = $("#" + id).width() / oriWidth;
62165
62179
 
@@ -62179,10 +62193,6 @@ class Dialog {
62179
62193
  let width = ic.contactmapWidth * ratio;
62180
62194
  $("#" + me.contactmapid).attr("width", width);
62181
62195
  }
62182
- // else if(id == me.pre + 'dl_2ddiagram') {
62183
- // let width = ic.twoddiagramWidth * ratio;
62184
- // $("#" + me.twoddiagramid).attr("width", width);
62185
- // }
62186
62196
  else if(id == me.pre + 'dl_alignerrormap') {
62187
62197
  let width = ic.alignerrormapWidth * ratio;
62188
62198
  $("#" + me.alignerrormapid).attr("width", width);
@@ -62319,7 +62329,7 @@ class Dialog {
62319
62329
  let width = 400, height = 150;
62320
62330
  let twoddgmWidth = me.htmlCls.width2d + 20;
62321
62331
 
62322
- 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') {
62332
+ 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') {
62323
62333
  $( "#" + id ).show();
62324
62334
  $( "#" + id + "_nb").show();
62325
62335
  $( "#" + id + "_title").html(title);
@@ -62364,11 +62374,6 @@ class Dialog {
62364
62374
 
62365
62375
  $("#" + me.contactmapid).attr("width", width);
62366
62376
  }
62367
- // else if(id == me.pre + 'dl_2ddiagram') {
62368
- // let width = ic.twoddiagramWidth * ratio;
62369
-
62370
- // $("#" + me.twoddiagramid).attr("width", width);
62371
- // }
62372
62377
  else if(id == me.pre + 'dl_alignerrormap') {
62373
62378
  let width = ic.alignerrormapWidth * ratio;
62374
62379
 
@@ -62469,7 +62474,7 @@ class SetDialog {
62469
62474
 
62470
62475
  me.svgid_ct = me.pre + "icn3d_cartoon";
62471
62476
 
62472
- let buttonStrTmp = '<button class="icn3d-commandTitle" style="-webkit-appearance:button; height:24px;background-color:#DDD;" id="';
62477
+ let buttonStrTmp = '<button class="icn3d-commandTitle" style="-webkit-appearance:button; height:24px;background-color:#DDD; margin:1px;" id="';
62473
62478
  let tmpStr = 'icn3d-node-text';
62474
62479
  html += me.htmlCls.divNowrapStr + "Dynamically generated for selected residues. <br>Nodes can be dragged or clicked.</div>";
62475
62480
  html += me.htmlCls.divNowrapStr + buttonStrTmp + me.svgid_ct + '_svg">SVG</button>' + me.htmlCls.space2;
@@ -63062,10 +63067,10 @@ class SetDialog {
63062
63067
 
63063
63068
  html += me.htmlCls.divStr + "dl_2ddgm_r2dt' class='" + dialogClass + "'>";
63064
63069
  html += this.addNotebookTitle('dl_2ddgm_r2dt', '2D Diagram for Nucleotides (R2DT)');
63065
- html += "1. Select a nucleotide chain to show R2DT diagram:<br>";
63070
+ html += "1. Select a nucleotide chain to show 2D diagram:<br>";
63066
63071
  html += "<select style='max-width:200px' id='" + me.pre + "atomsCustomNucleotide' size='5' style='min-width:130px;'>";
63067
63072
  html += "</select><br>";
63068
- 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>";
63073
+ 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>";
63069
63074
  html += "</div>";
63070
63075
 
63071
63076
  html += me.htmlCls.divStr + "dl_2ddgm_igdgm' class='" + dialogClass + "'>";
@@ -63404,8 +63409,31 @@ class SetDialog {
63404
63409
  html += "</div>";
63405
63410
 
63406
63411
  html += me.htmlCls.divStr + "dl_2ddiagram' style='background-color:white' class='" + dialogClass + "'>";
63407
- html += this.addNotebookTitle('dl_2ddiagram', '2D Diagram');
63408
- html += '<div id="' + me.pre + '2ddiagramDiv"></div>';
63412
+ html += this.addNotebookTitle('dl_2ddiagram', 'R2DT Diagram');
63413
+ html += '<div id="' + me.pre + '2ddiagramDiv"></div><br>';
63414
+ 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>";
63415
+ html += "</div>";
63416
+
63417
+ me.rnacanvasid = me.pre + 'rancanvas';
63418
+ html += me.htmlCls.divStr + "dl_rnacanvas' style='background-color:white' class='" + dialogClass + "'>";
63419
+ html += this.addNotebookTitle('dl_rnacanvas', '2D Diagram with RNAcanvas');
63420
+
63421
+ me.lwTypes = ['cWW', 'tWW', 'cWH', 'tWH', 'cWS', 'tWS', 'cHH', 'tHH', 'cHS', 'tHS', 'cSS', 'tSS']; // exclude 'cWW'
63422
+ html += "<table><tr><td>Show non-nested BPs:<br>";
63423
+ html += me.htmlCls.divNowrapStr + "<select id='" + me.pre + "basepairType' multiple size='2' style='min-width:130px;'>";
63424
+ html += "<option value='' selected>None</option>";
63425
+ html += "<option value='" + me.lwTypes.join(',') + "'>All</option>";
63426
+ for(let i = 0, il = me.lwTypes.length; i < il; i++) {
63427
+ let name = me.lwTypes[i];
63428
+ html += "<option value='" + name + "'>" + name + "</option>";
63429
+ }
63430
+ html += "</select></td><td valign='top'>";
63431
+
63432
+ html += me.htmlCls.space2 + buttonStrTmp + me.rnacanvasid + '_wconly">Show Only Nested BPs</button><br>';
63433
+ html += me.htmlCls.space2 + buttonStrTmp + me.rnacanvasid + '_dotb">Download Dot-Bracket</button><br>';
63434
+ html += me.htmlCls.space2 + buttonStrTmp + me.rnacanvasid + '_fr3d">FR3D Basepairs</button></td></tr></table><br>';
63435
+
63436
+ html += '<div id="' + me.pre + 'rnacanvasDiv"></div>';
63409
63437
  html += "</div>";
63410
63438
 
63411
63439
  html += me.htmlCls.divStr + "dl_alignerrormap' style='background-color:white' class='" + dialogClass + "'>";
@@ -66664,10 +66692,22 @@ class Events {
66664
66692
  //if(!me.cfg.notebook) dialog.dialog( "close" );
66665
66693
 
66666
66694
  let chainid = $("#" + ic.pre + "atomsCustomNucleotide").val();
66695
+ ic.r2dt_chainid = chainid;
66667
66696
 
66668
66697
  await ic.diagram2dCls.drawR2dt(chainid);
66669
66698
  thisClass.setLogCmd('diagram 2d nucleotide | ' + chainid, true);
66670
66699
  });
66700
+
66701
+ me.myEventCls.onIds("#" + me.pre + "applyfr3d", "click", async function(e) { let ic = me.icn3d;
66702
+ e.preventDefault();
66703
+ //if(!me.cfg.notebook) dialog.dialog( "close" );
66704
+
66705
+ let chainid = $("#" + ic.pre + "atomsCustomNucleotide").val();
66706
+
66707
+ await ic.diagram2dCls.drawRnacanvas(chainid);
66708
+ thisClass.setLogCmd('diagram 2d fr3d | ' + chainid, true);
66709
+ });
66710
+
66671
66711
  me.myEventCls.onIds("#" + me.pre + "applyigdgm", "click", async function(e) { let ic = me.icn3d;
66672
66712
  e.preventDefault();
66673
66713
  //if(!me.cfg.notebook) dialog.dialog( "close" );
@@ -66818,6 +66858,57 @@ class Events {
66818
66858
  thisClass.setLogCmd("cartoon label " + className, true);
66819
66859
  });
66820
66860
 
66861
+ me.myEventCls.onIds("#" + me.rnacanvasid + "_wconly", "click", function(e) { me.icn3d;
66862
+ e.preventDefault();
66863
+
66864
+ $('#' + me.pre + 'basepairType').val($('#' + me.pre + 'basepairType option:first').val()).trigger('change');
66865
+ });
66866
+ me.myEventCls.onIds("#" + me.rnacanvasid + "_svg", "click", function(e) { let ic = me.icn3d;
66867
+ e.preventDefault();
66868
+
66869
+ ic.saveFileCls.saveSvg("rnacanvasSvg", ic.inputid + "_rnacanvas.svg");
66870
+ });
66871
+ me.myEventCls.onIds("#" + me.rnacanvasid + "_dotb", "click", function(e) { let ic = me.icn3d;
66872
+ e.preventDefault();
66873
+
66874
+ ic.saveFileCls.saveFile(ic.inputid + "_dot_bracket.txt", "text", [ic.dot_bracket]);
66875
+ });
66876
+
66877
+ me.myEventCls.onIds("#" + me.rnacanvasid + "_fr3d", "click", function(e) { let ic = me.icn3d;
66878
+ e.preventDefault();
66879
+
66880
+ let url = 'https://rna.bgsu.edu/rna3dhub/pdb/' + Object.keys(ic.structures)[0] + '/interactions/fr3d/basepairs/';
66881
+
66882
+ window.open(url, '_blank');
66883
+ });
66884
+
66885
+ me.myEventCls.onIds("#" + me.pre + "r2dt_svg", "click", function(e) { let ic = me.icn3d;
66886
+ e.preventDefault();
66887
+
66888
+ let bClassName = true;
66889
+ ic.saveFileCls.saveSvg("rnaTopoSvg", ic.r2dt_chainid + "_r2dt.svg", undefined, undefined, bClassName);
66890
+ });
66891
+ me.myEventCls.onIds("#" + me.pre + "r2dt_dotb", "click", async function(e) { let ic = me.icn3d;
66892
+ e.preventDefault();
66893
+
66894
+ let chainid = $("#" + ic.pre + "atomsCustomNucleotide").val();
66895
+ let result = await ic.diagram2dCls.getDotbracket(chainid);
66896
+ ic.saveFileCls.saveFile(chainid + "_dot_bracket.txt", "text", [result.dotb]);
66897
+ });
66898
+
66899
+ me.myEventCls.onIds("#" + me.pre + "r2dt_seq", "click", function(e) { let ic = me.icn3d;
66900
+ e.preventDefault();
66901
+
66902
+ let chainid = $("#" + ic.pre + "atomsCustomNucleotide").val();
66903
+ let seq = '';
66904
+ for(let i = 0; i < ic.chainsSeq[chainid].length; ++i) {
66905
+ seq += ic.chainsSeq[chainid][i].name;
66906
+ }
66907
+
66908
+ ic.saveFileCls.saveFile(chainid + "_seq.txt", "text", [seq]);
66909
+ });
66910
+
66911
+
66821
66912
  me.myEventCls.onIds("#" + me.linegraphid + "_svg", "click", function(e) { let ic = me.icn3d;
66822
66913
  e.preventDefault();
66823
66914
 
@@ -78985,7 +79076,7 @@ class Line$1 {
78985
79076
  let radius = (line.radius) ? line.radius : ic.lineRadius;
78986
79077
  let opacity = (line.opacity) ? line.opacity : 1.0;
78987
79078
 
78988
- let colorStr = '#' + line.color.replace(/\#/g, '');
79079
+ let colorStr = (line.color) ? '#' + line.color.replace(/\#/g, '') : '#000';
78989
79080
 
78990
79081
  let color = me.parasCls.thr(colorStr);
78991
79082
 
@@ -81021,6 +81112,24 @@ class CartoonNucl {
81021
81112
  let currentChain, currentResi, currentO3;
81022
81113
  let prevOO = null;
81023
81114
 
81115
+ // add one extra residue for highlighting one residue
81116
+ if(bHighlight === 1) {
81117
+ let residueArray= ic.resid2specCls.atoms2residues(Object.keys(atomlist));
81118
+
81119
+ if(residueArray.length == 1) {
81120
+ let ncbiresid = ic.resid2ncbi[residueArray[0]];
81121
+ ic.firstAtomObjCls.getFirstAtomObj(atomlist);
81122
+ let ncbiresi = ncbiresid.substr(ncbiresid.lastIndexOf('_') + 1);
81123
+ let ncbiresid2 = ncbiresid.substr(0, ncbiresid.lastIndexOf('_')) + '_' + (parseInt(ncbiresi) + 1).toString();
81124
+ let residueid2 = ic.ncbi2resid[ncbiresid2];
81125
+
81126
+ if(ic.residues.hasOwnProperty(residueid2)) {
81127
+ let atomsAdjust = me.hashUtilsCls.hash2Atoms(ic.residues[residueid2], ic.atoms);
81128
+ atomlist = me.hashUtilsCls.unionHash(atomlist, atomsAdjust);
81129
+ }
81130
+ }
81131
+ }
81132
+
81024
81133
  for (i in atomlist) {
81025
81134
  let atom = atomlist[i];
81026
81135
  if (atom === undefined) continue;
@@ -84965,7 +85074,7 @@ class ApplyMissingRes {
84965
85074
  line.serial1 = ic.missingResResid2serial[resid0 + ',' + resid1];
84966
85075
  line.serial2 = ic.missingResResid2serial[resid1 + ',' + resid0];
84967
85076
 
84968
- line.color = (ic.atoms[line.serial1]) ? "#" + ic.atoms[line.serial1].color.getHexString() : undefined;
85077
+ line.color = (ic.atoms[line.serial1] && ic.atoms[line.serial1].color) ? "#" + ic.atoms[line.serial1].color.getHexString() : undefined;
84969
85078
 
84970
85079
  line.radius = ic.coilWidth;
84971
85080
 
@@ -87292,7 +87401,7 @@ class Instancing {
87292
87401
  }
87293
87402
  }
87294
87403
 
87295
- drawSymmetryMatesNoInstancing() { let ic = this.icn3d; ic.icn3dui;
87404
+ drawSymmetryMatesNoInstancing() { let ic = this.icn3d, me = ic.icn3dui;
87296
87405
  if (ic.biomtMatrices === undefined || ic.biomtMatrices.length == 0) return;
87297
87406
  let cnt = 1; // itself
87298
87407
  let centerSum = ic.center.clone();
@@ -87310,7 +87419,7 @@ class Instancing {
87310
87419
  if (mat === undefined) continue;
87311
87420
 
87312
87421
  // skip itself
87313
- if(mat.equals(identity)) continue;
87422
+ if(me.utilsCls.compMatrix(mat, identity, 16)) continue;
87314
87423
 
87315
87424
  let symmetryMate;
87316
87425
 
@@ -87586,7 +87695,7 @@ class Instancing {
87586
87695
  }
87587
87696
  }
87588
87697
 
87589
- drawSymmetryMatesInstancing() { let ic = this.icn3d; ic.icn3dui;
87698
+ drawSymmetryMatesInstancing() { let ic = this.icn3d, me = ic.icn3dui;
87590
87699
  if (ic.biomtMatrices === undefined || ic.biomtMatrices.length == 0) return;
87591
87700
  let cnt = 1; // itself
87592
87701
  let centerSum = ic.center.clone();
@@ -87608,10 +87717,13 @@ class Instancing {
87608
87717
  let mat = ic.biomtMatrices[i];
87609
87718
  if (mat === undefined) continue;
87610
87719
 
87611
- let matArray = mat.toArray();
87720
+ let matArray = mat.toArray().map(x => parseFloat(x)); // some values are string and others are number
87721
+ mat.fromArray(matArray);
87612
87722
 
87613
87723
  // skip itself
87614
- if(mat.equals(identity)) continue;
87724
+ //if(mat.equals(identity)) continue; // equals seemed to have some problem in comparing two matrices
87725
+ let bEqual = me.utilsCls.compMatrix(mat, identity, 16);
87726
+ if(bEqual) continue;
87615
87727
 
87616
87728
  ic.matricesElements1.push(matArray[0], matArray[1], matArray[2], matArray[3]);
87617
87729
  ic.matricesElements2.push(matArray[4], matArray[5], matArray[6], matArray[7]);
@@ -87619,7 +87731,7 @@ class Instancing {
87619
87731
  ic.matricesElements4.push(matArray[12], matArray[13], matArray[14], matArray[15]);
87620
87732
 
87621
87733
  let center = ic.center.clone();
87622
- center.applyMatrix4(mat);
87734
+ center.applyMatrix4(mat);
87623
87735
  centerSum.add(center);
87624
87736
 
87625
87737
  ++cnt;
@@ -87845,7 +87957,7 @@ class Alternate {
87845
87957
  }
87846
87958
 
87847
87959
  ic.setColorCls.applyPrevColor();
87848
-
87960
+
87849
87961
  if(ic.biomtMatrices !== undefined && ic.biomtMatrices.length > 1) {
87850
87962
  if(ic.bAssembly && Object.keys(ic.structures).length == 1 && ((me.cfg.mmdbid === undefined && me.cfg.bu == 1)
87851
87963
  || (me.cfg.mmdbid !== undefined && me.cfg.bu == 1 && Object.keys(ic.atoms).length * ic.biomtMatrices.length > ic.maxatomcnt)) ) {
@@ -87873,6 +87985,7 @@ class Alternate {
87873
87985
  }
87874
87986
 
87875
87987
  this.applyTransformation(ic._zoomFactor, ic.mouseChange, ic.quaternion);
87988
+
87876
87989
  this.render(bVrAr);
87877
87990
  }
87878
87991
  //ic.impostorCls.clearImpostors();
@@ -98607,6 +98720,8 @@ class ShowAnno {
98607
98720
  ic.maxAnnoLength = ic.maxAnnoLengthOri;
98608
98721
  }
98609
98722
 
98723
+ ic.nucleotide_chainid = nucleotide_chainid;
98724
+
98610
98725
  return {'nucleotide_chainid': nucleotide_chainid, 'chemical_chainid': chemical_chainid, 'chemical_set': chemical_set};
98611
98726
  }
98612
98727
 
@@ -103816,14 +103931,23 @@ class DrawGraph {
103816
103931
  }).strength(function(d) { return 0.4; }))
103817
103932
  .force("x", d3v4.forceX(parentWidth / 2).strength(function(d) { return 0.02; }));
103818
103933
  } else if (me.htmlCls.force == 3) { // circle
103934
+ // me.htmlCls.simulation.force("r", d3v4.forceRadial(function(d) {
103935
+ // if (d.s == 'a') {
103936
+ // return 200;
103937
+ // } else {
103938
+ // return 100;
103939
+ // }
103940
+
103941
+ // }, parentWidth / 2, parentHeight / 2).strength(function(d) { return 0.8; }));
103942
+
103819
103943
  me.htmlCls.simulation.force("r", d3v4.forceRadial(function(d) {
103820
103944
  if (d.s == 'a') {
103821
- return 200;
103945
+ return 60; //200;
103822
103946
  } else {
103823
- return 100;
103947
+ return 30; //100;
103824
103948
  }
103825
103949
 
103826
- }, parentWidth / 2, parentHeight / 2).strength(function(d) { return 0.8; }));
103950
+ }, parentWidth / 2, parentHeight / 2).strength(function(d) { return 0.1; }));
103827
103951
  } else if (me.htmlCls.force == 4) ;
103828
103952
 
103829
103953
  me.htmlCls.simulation
@@ -107109,7 +107233,8 @@ class MmcifParser {
107109
107233
  if(ic.bAssemblyUseAsu) {
107110
107234
  for(let i = 0, il = data.assembly.length; i < il; ++i) {
107111
107235
  let mat4 = new Matrix4$1();
107112
- mat4.fromArray(data.assembly[i]);
107236
+ let tmpArray = data.assembly[i].map(x => parseFloat(x)); // some values are string and others are number
107237
+ mat4.fromArray(tmpArray);
107113
107238
 
107114
107239
  // sometimes an extra matrix as included, e.g., PDb ID 2GTL
107115
107240
  if(i == 0 && data.assembly[i][0] != 1) continue;
@@ -107189,14 +107314,14 @@ class MmcifParser {
107189
107314
  async loadMultipleMmcifData(data, mmcifid, bAppend) { let ic = this.icn3d; ic.icn3dui;
107190
107315
  let bText = true;
107191
107316
  ic.loadCIFCls.loadCIF(data, mmcifid, bText, bAppend);
107192
-
107317
+
107193
107318
  if(Object.keys(ic.structures).length > 1) {
107194
107319
  ic.opts['color'] = 'structure';
107195
107320
  }
107196
107321
 
107197
107322
  ic.opmParserCls.modifyUIMapAssembly();
107198
107323
 
107199
- ic.pdbParserCls.addSecondary(bAppend);
107324
+ await ic.pdbParserCls.addSecondary(bAppend);
107200
107325
 
107201
107326
  // ic.setStyleCls.setAtomStyleByOptions(ic.opts);
107202
107327
  // ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
@@ -107639,6 +107764,7 @@ class MmdbParser {
107639
107764
  //ic.molid2color = molid2color;
107640
107765
  //ic.chain2molid = chain2molid;
107641
107766
  ic.molid2chain = molid2chain;
107767
+
107642
107768
  // small structure with all atoms
107643
107769
  // show surface options
107644
107770
  $("#" + ic.pre + "accordion5").show();
@@ -109078,7 +109204,8 @@ class PdbParser {
109078
109204
  // DSSP only works for structures with all atoms. The Calpha only structures didn't work
109079
109205
  //if(!ic.bSecondaryStructure && !bCalphaOnly) {
109080
109206
  let bCalcSecondary = false;
109081
- if(ic.bSecondaryStructure && Object.keys(ic.structures).length == 1) {
109207
+ // if(ic.bSecondaryStructure && Object.keys(ic.structures).length == 1) {
109208
+ if(ic.bSecondaryStructure) {
109082
109209
  bCalcSecondary = false;
109083
109210
  }
109084
109211
  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) {
@@ -109086,7 +109213,7 @@ class PdbParser {
109086
109213
  }
109087
109214
 
109088
109215
  // if(!ic.bSecondaryStructure && Object.keys(ic.proteins).length > 0) {
109089
- if((!ic.bSecondaryStructure || bCalcSecondary) && Object.keys(ic.proteins).length > 0 && !bNoDssp) {
109216
+ if((!ic.bSecondaryStructure || bCalcSecondary) && Object.keys(ic.proteins).length > 0 && !bNoDssp) {
109090
109217
  await this.applyCommandDssp(bAppend);
109091
109218
  }
109092
109219
  else {
@@ -109131,7 +109258,7 @@ class PdbParser {
109131
109258
 
109132
109259
  if(me.cfg.rotate !== undefined) ic.resizeCanvasCls.rotStruc(me.cfg.rotate, true);
109133
109260
 
109134
- if(bAppend && !me.bNode) {
109261
+ if(bAppend && Object.keys(ic.structures).length == 1 && !me.bNode) {
109135
109262
  // show all
109136
109263
  ic.definedSetsCls.setModeAndDisplay('all');
109137
109264
  }
@@ -116074,7 +116201,9 @@ class LoadPDB {
116074
116201
 
116075
116202
  let bHeader = false, bFirstAtom = true;
116076
116203
 
116077
- let segId, prevSegId;
116204
+ let segId, prevSegId, entityid;
116205
+
116206
+ if(!ic.molid2chain) ic.molid2chain = {};
116078
116207
 
116079
116208
  for (let i in lines) {
116080
116209
  let line = lines[i];
@@ -116219,6 +116348,17 @@ class LoadPDB {
116219
116348
  ic.organism = line.substr(28).toLowerCase().trim();
116220
116349
 
116221
116350
  ic.organism = ic.organism.substr(0, ic.organism.length - 1);
116351
+ } else if (record === 'COMPND') {
116352
+ if(line.indexOf('MOL_ID: ') != -1) { // COMPND MOL_ID: 1;
116353
+ let itemArray = line.trim().split(' ');
116354
+ let lastItem = itemArray[itemArray.length - 1];
116355
+ entityid = lastItem.substr(0, lastItem.length - 1);
116356
+ }
116357
+ else if(line.indexOf('CHAIN: ') != -1) { // COMPND 3 CHAIN: H;
116358
+ let itemArray = line.trim().split(' ');
116359
+ let lastItem = itemArray[itemArray.length - 1];
116360
+ ic.molid2chain[parseInt(entityid)] = structure + '_' + lastItem.substr(0, lastItem.length - 1);
116361
+ }
116222
116362
  } else if (record === 'ENDMDL') {
116223
116363
  if(ic.statefileArray) {
116224
116364
  ic.struct_statefile.push({'structure': structure, 'statefile': ic.statefileArray[moleculeNum - 1]});
@@ -117208,9 +117348,9 @@ class LoadCIF {
117208
117348
  if(struct_oper_id == "X0") continue;
117209
117349
 
117210
117350
  if (ic.biomtMatrices[i] == undefined) ic.biomtMatrices[i] = new Matrix4$1().identity();
117211
- ic.biomtMatrices[i].set(m11Array.getString(i), m12Array.getString(i), m13Array.getString(i), m14Array.getString(i),
117212
- m21Array.getString(i), m22Array.getString(i), m23Array.getString(i), m24Array.getString(i),
117213
- m31Array.getString(i), m32Array.getString(i), m33Array.getString(i), m34Array.getString(i),
117351
+ ic.biomtMatrices[i].set(parseFloat(m11Array.getString(i)), parseFloat(m12Array.getString(i)), parseFloat(m13Array.getString(i)), parseFloat(m14Array.getString(i)),
117352
+ parseFloat(m21Array.getString(i)), parseFloat(m22Array.getString(i)), parseFloat(m23Array.getString(i)), parseFloat(m24Array.getString(i)),
117353
+ parseFloat(m31Array.getString(i)), parseFloat(m32Array.getString(i)), parseFloat(m33Array.getString(i)), parseFloat(m34Array.getString(i)),
117214
117354
  0, 0, 0, 1);
117215
117355
  }
117216
117356
 
@@ -117242,6 +117382,44 @@ class LoadCIF {
117242
117382
  ic.pmid = block.getCategory("_citation").getColumn("pdbx_database_id_PubMed").getString(0);
117243
117383
  }
117244
117384
 
117385
+ // retrieve RNA pair info
117386
+ let pairInfo = block.getCategory("_ndb_base_pair_list");
117387
+
117388
+ if(pairInfo) {
117389
+ let chainArray2, pairidArray, pos1Array, pos2Array, resn1Array, resn2Array;
117390
+ chainArray2 = pairInfo.getColumn("asym_id_1");
117391
+ pairidArray = pairInfo.getColumn("base_pair_id");
117392
+ pos1Array = pairInfo.getColumn("seq_id_1");
117393
+ pos2Array = pairInfo.getColumn("seq_id_2");
117394
+ resn1Array = pairInfo.getColumn("comp_id_1");
117395
+ resn2Array = pairInfo.getColumn("comp_id_2");
117396
+ let pairSize = pairInfo.rowCount;
117397
+
117398
+ let annoInfo = block.getCategory("_ndb_base_pair_annotation");
117399
+
117400
+ let pairidArray2, typeArray;
117401
+ pairidArray2 = annoInfo.getColumn("base_pair_id");
117402
+ typeArray = annoInfo.getColumn("l-w_family");
117403
+
117404
+ ic.chain2pairs_resns_lw = {};
117405
+ for(let i = 0; i < pairSize; ++i) {
117406
+ if(pairidArray.getString(i) == pairidArray2.getString(i)) {
117407
+ let chain = chainArray2.getString(i);
117408
+ let pos1 = pos1Array.getString(i);
117409
+ let pos2 = pos2Array.getString(i);
117410
+ let resn1 = resn1Array.getString(i);
117411
+ let resn2 = resn2Array.getString(i);
117412
+ let lwtype = typeArray.getString(i);
117413
+ if(!ic.chain2pairs_resns_lw[chain]) ic.chain2pairs_resns_lw[chain] = [];
117414
+ ic.chain2pairs_resns_lw[chain].push(pos1);
117415
+ ic.chain2pairs_resns_lw[chain].push(pos2);
117416
+ ic.chain2pairs_resns_lw[chain].push(resn1);
117417
+ ic.chain2pairs_resns_lw[chain].push(resn2);
117418
+ ic.chain2pairs_resns_lw[chain].push(lwtype);
117419
+ }
117420
+ }
117421
+ }
117422
+
117245
117423
  // Retrieve the table corresponding to the atom_site category, which delineates atomic constituents
117246
117424
  let atom_site = block.getCategory("_atom_site");
117247
117425
  let atomSize = atom_site.rowCount;
@@ -117257,6 +117435,7 @@ class LoadCIF {
117257
117435
  let resnArray = atom_site.getColumn("label_comp_id");
117258
117436
  let elemArray = atom_site.getColumn("type_symbol");
117259
117437
  let nameArray = atom_site.getColumn("label_atom_id");
117438
+ let entiyidArray = atom_site.getColumn("label_entity_id");
117260
117439
 
117261
117440
  let chainArray = atom_site.getColumn("auth_asym_id");
117262
117441
 
@@ -117278,6 +117457,8 @@ class LoadCIF {
117278
117457
  let prevResn;
117279
117458
  let sChain = {};
117280
117459
  let prevModelNum = '';
117460
+ if(!ic.molid2chain) ic.molid2chain = {};
117461
+
117281
117462
  for (let i = 0; i < atomSize; ++i) {
117282
117463
  let modelNum = modelNumArray.getString(i);
117283
117464
  if(i > 0 && modelNum != prevModelNum) {
@@ -117296,6 +117477,7 @@ class LoadCIF {
117296
117477
  let resn = resnArray.getString(i);
117297
117478
  let elem = elemArray.getString(i);
117298
117479
  let atom = nameArray.getString(i);
117480
+ let entityid = entiyidArray.getString(i);
117299
117481
  let chain = chainArray.getString(i);
117300
117482
  let resi = resiArray.getString(i);
117301
117483
  let oriResi = resiOriArray.getString(i);
@@ -117402,6 +117584,8 @@ class LoadCIF {
117402
117584
  chainNum = structure + "_" + chain;
117403
117585
  oriResidueNum = chainNum + "_" + oriResi;
117404
117586
 
117587
+ ic.molid2chain[parseInt(entityid)] = chainNum;
117588
+
117405
117589
  residueNum = chainNum + "_" + resi;
117406
117590
 
117407
117591
  //let chain_resi = chain + "_" + resi;
@@ -120564,6 +120748,7 @@ class DefinedSets {
120564
120748
  });
120565
120749
 
120566
120750
  let bFoundNucleotide = false, bFoundProtein = false;
120751
+ let cnt = 0;
120567
120752
  for(let i = 0, il = nameArray.length; i < il; ++i) {
120568
120753
  let name = nameArray[i];
120569
120754
 
@@ -120588,16 +120773,22 @@ class DefinedSets {
120588
120773
 
120589
120774
  if(bNucleotide && atom) {
120590
120775
  // Handle nucleotide-specific logic
120591
- if(ic.nucleotides.hasOwnProperty(atom.serial) && name != 'nucleotides' && !ic.structures.hasOwnProperty(name)) {
120592
- html += "<option value='" + name + "' style='color:#" + color + "'>" + name + "</option>";
120776
+ if(ic.nucleotides.hasOwnProperty(atom.serial) && name.split('_').length == 2 && !ic.structures.hasOwnProperty(name)) {
120777
+ let selectStr = (cnt == 0) ? "selected" : "";
120778
+
120779
+ html += "<option value='" + name + "' style='color:#" + color + "' " + selectStr + ">" + name + "</option>";
120593
120780
  bFoundNucleotide = true;
120781
+ ++cnt;
120594
120782
  }
120595
120783
  }
120596
120784
  else if(bProtein && atom) {
120597
120785
  // Handle protein-specific logic
120598
- if(ic.proteins.hasOwnProperty(atom.serial) && name != 'proteins' && !ic.structures.hasOwnProperty(name)) {
120599
- html += "<option value='" + name + "' style='color:#" + color + "'>" + name + "</option>";
120786
+ if(ic.proteins.hasOwnProperty(atom.serial) && name.split('_').length == 2 && !ic.structures.hasOwnProperty(name)) {
120787
+ let selectStr = (cnt == 0) ? "selected" : "";
120788
+
120789
+ html += "<option value='" + name + "' style='color:#" + color + "' " + selectStr + ">" + name + "</option>";
120600
120790
  bFoundProtein = true;
120791
+ ++cnt;
120601
120792
  }
120602
120793
  }
120603
120794
  else {
@@ -120607,6 +120798,7 @@ class DefinedSets {
120607
120798
  else {
120608
120799
  html += "<option value='" + name + "' style='color:#" + color + "'>" + name + "</option>";
120609
120800
  }
120801
+ ++cnt;
120610
120802
  }
120611
120803
  }
120612
120804
 
@@ -121759,6 +121951,20 @@ class LoadScript {
121759
121951
  await ic.diagram2dCls.drawR2dt(chainid);
121760
121952
  ic.bRender = false;
121761
121953
  }
121954
+ else if(command.indexOf('diagram 2d fr3d') == 0) {
121955
+ let paraArray = command.split(' | ');
121956
+ let pos = command.lastIndexOf(' ');
121957
+ let chainid = (paraArray.length == 2) ? paraArray[1] : command.substr(pos + 1);
121958
+
121959
+ ic.bRender = true;
121960
+ await ic.diagram2dCls.drawRnacanvas(chainid);
121961
+ ic.bRender = false;
121962
+ }
121963
+ else if(command.indexOf('update rnacanvas') == 0) {
121964
+ let paraArray = command.split(' ');
121965
+ let nonWC = (paraArray.length == 3) ? paraArray[2] : '';
121966
+ ic.diagram2dCls.updateRnacanvas(nonWC);
121967
+ }
121762
121968
  else if(command.indexOf('diagram 2d ig') == 0) {
121763
121969
  let paraArray = command.split(' | ');
121764
121970
  let pos = command.lastIndexOf(' ');
@@ -122882,7 +123088,7 @@ class SelectByCommand {
122882
123088
  residueAtomArray = Object.keys(atomHash);
122883
123089
  }
122884
123090
 
122885
- if(commandname != "") {
123091
+ if(!commandname) {
122886
123092
  ic.selectionCls.addCustomSelection(residueAtomArray, commandname, commanddesc, select, bSelectResidues);
122887
123093
 
122888
123094
  let nameArray = [commandname];
@@ -129078,60 +129284,42 @@ class Diagram2d {
129078
129284
  thisClass.clickNode(this);
129079
129285
  });
129080
129286
 
129081
- // event for R2DT
129082
- //document.addEventListener('click', (event) => {
129083
- $(document).on("click", "r2dt-web", function(e) { let ic = thisClass.icn3d;
129084
- // The 2nd element in the path is the actual clicked g element
129085
- const path = e.originalEvent.composedPath();
129086
- const clickedElement = path[1];
129087
- let titleElem = clickedElement.querySelector('title');
129287
+ $(document).on("change", "#" + me.pre + "basepairType", function(e) { thisClass.icn3d;
129288
+ let nonWC = $("#" + me.pre + "basepairType").val().join(',');
129088
129289
 
129089
- if(titleElem) {
129090
- let title = titleElem.textContent; // e.g., 14 (position.label in template: 14.A)
129091
- let textArray = title.split(' ');
129092
- let position_resn = textArray[textArray.length - 1].split('.');
129093
- let pos = position_resn[0];
129094
- let resn = position_resn[1].substr(0, position_resn[1].length - 1);
129290
+ thisClass.updateRnacanvas(nonWC);
129291
+ me.htmlCls.clickMenuCls.setLogCmd('update rnacanvas ' + nonWC, true);
129292
+ });
129095
129293
 
129096
- let resid = ic.ncbi2resid[ic.r2dt_chainid + '_' + pos];
129097
- let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
129294
+ $(document).on("from_rnacanvas", function(event, data) {
129295
+ let pos_resn = data.split('_');
129296
+ let resn = pos_resn[1];
129098
129297
 
129099
- if(!atom) {
129100
- var aaa = 1; //alert("This residue has no 3D coordinates...");
129101
- }
129102
- else {
129103
- let oneLetterRes = me.utilsCls.residueName2Abbr(atom.resn);
129298
+ let resid = ic.ncbi2resid[ic.rnacanvas_chainid + '_' + pos_resn[0]];
129299
+ let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
129104
129300
 
129105
- let realResn = (resn == 'T') ? 'U' : resn;
129301
+ if(!atom) {
129302
+ var aaa = 1; //alert('This residue has no 3D coordinates...');
129303
+ }
129304
+ else {
129305
+ let oneLetterRes = me.utilsCls.residueName2Abbr(atom.resn);
129106
129306
 
129107
- if(resn != oneLetterRes && realResn != oneLetterRes) {
129108
- var aaa = 1; //alert("The residue number in R2DT didn't match that in 3D view...");
129307
+ if(resn != oneLetterRes) {
129308
+ console.log('The residue name in 2D ' + resn + ' did not match that in 3D view ' + oneLetterRes + '...');
129309
+ }
129310
+ //else {
129311
+ // highlight the selected residue
129312
+ if(ic.bCtrl || ic.bShift) {
129313
+ ic.hAtoms = me.hashUtilsCls.unionHash(ic.hAtoms, ic.residues[resid]);
129109
129314
  }
129110
129315
  else {
129111
- // highlight the selected residue
129112
- if(ic.bCtrl || ic.bShift) {
129113
- ic.hAtoms = me.hashUtilsCls.unionHash(ic.hAtoms, ic.residues[resid]);
129114
- }
129115
- else {
129116
- ic.hAtoms = ic.residues[resid];
129117
- }
129118
-
129119
- ic.hlUpdateCls.showHighlight();
129316
+ ic.hAtoms = ic.residues[resid];
129120
129317
  }
129121
- }
129122
-
129123
- // highlight the selected residue in 2D
129124
- let textElem = clickedElement.querySelector('text');
129125
- textElem.setAttribute("stroke", "#f8b84e");
129126
- textElem.setAttribute("stroke-width", "0.5px");
129127
129318
 
129128
- // add cursor
129129
- if(!ic.bAddedCursors) {
129130
- ic.bAddedCursors = true;
129131
- ic.diagram2dCls.makeResiduesClickable();
129132
- }
129319
+ ic.hlUpdateCls.showHighlight();
129320
+ //}
129133
129321
  }
129134
- });
129322
+ });
129135
129323
  }
129136
129324
 
129137
129325
  clickNode(node) { let ic = this.icn3d, me = ic.icn3dui;
@@ -129357,42 +129545,467 @@ class Diagram2d {
129357
129545
  return html;
129358
129546
  }
129359
129547
 
129360
- makeResiduesClickable() { let ic = this.icn3d; ic.icn3dui;
129361
- let r2dt = document.querySelector('r2dt-web').shadowRoot;
129362
- let elemArray = r2dt.querySelectorAll('g:has(title)');
129363
- for(let i = 0, il = elemArray.length; i < il; ++i) {
129364
- if(!elemArray[i].hasAttribute('id')) { // skip the main g element
129365
- elemArray[i].style.cursor = "pointer";
129548
+ async drawR2dt(chainid) { let ic = this.icn3d, me = ic.icn3dui;
129549
+ ic.bAddedCursors = false;
129550
+
129551
+ let pos = chainid.lastIndexOf('_');
129552
+ let pdbid = chainid.substr(0, pos);
129553
+ let chain = chainid.substr(pos + 1);
129554
+
129555
+ //https://9c5d031c.na-hackathon-2026.pages.dev/api.json
129556
+ //https://www.ebi.ac.uk/pdbe/static/entry/1ffk_2_9.json, or 1ffk_1_0.json [pdbid_molid_chain]
129557
+ let molid = 1;
129558
+ for(let i in ic.molid2chain) {
129559
+ if(ic.molid2chain[i] == chainid) {
129560
+ molid = i;
129561
+ break;
129366
129562
  }
129367
129563
  }
129564
+
129565
+ let url = "https://www.ebi.ac.uk/pdbe/static/entry/" + pdbid.toLowerCase() + "_" + molid + "_" + chain + ".json";
129566
+ let apiData = await me.getAjaxPromise(url, 'json', undefined, 'The chain ' + chainid + ' with molid ' + molid + ' has no R2DT information in PDBe...');
129567
+
129568
+ //https://9c5d031c.na-hackathon-2026.pages.dev/fr3d.json
129569
+ //https://www.ebi.ac.uk/pdbe/static/entry/1ffk_9_basepair.json
129570
+ let url2 = "https://www.ebi.ac.uk/pdbe/static/entry/" + pdbid.toLowerCase() + "_" + chain + "_basepair.json";
129571
+ let fr3dData = await me.getAjaxPromise(url2, 'json', undefined, 'The chain ' + chainid + ' with molid ' + molid + ' has no FR3D information in PDBe...');
129572
+
129573
+ let html = '';
129574
+
129575
+ html += "<link rel='stylesheet' type='text/css' href='./script/pdb-rna-viewer-0.3.0.css'>\n";
129576
+ html += "<div id='pdb-rna-viewer' style='width: " + ($(window).width() / 2 - 150) + "px; height: " + ($(window).height() - 240) + "px'></div>\n";
129577
+ html += "<script type='text/javascript' src='./script/pdb-rna-viewer-plugin-0.3.0.js'></script>\n";
129578
+ html += "<script type='text/javascript'>\n";
129579
+ html += " var rnaPlugin = new PdbRnaViewerPlugin();\n";
129580
+ html += " rnaPlugin.render(\n";
129581
+ html += " document.getElementById('pdb-rna-viewer'),\n";
129582
+ html += " {\n";
129583
+ html += " pdbId: '" + pdbid.toLowerCase() + "',\n";
129584
+ html += " entityId: '1',\n";
129585
+ html += " chainId: '" + chain + "',\n";
129586
+ html += " subscribeEvents: true,\n";
129587
+ html += " apiData: " + JSON.stringify(apiData) + ",\n";
129588
+ html += " FR3DData: " + JSON.stringify(fr3dData) + ",\n";
129589
+ html += " theme: { unobservedColor: '#bbbbbb' },\n";
129590
+ html += " }\n";
129591
+ html += " );\n";
129592
+ html += "</script>\n";
129593
+
129594
+ $("#" + me.pre + "2ddiagramDiv").html(html);
129595
+
129596
+ setTimeout(function(){
129597
+ // grey out residues without 3D coordinates
129598
+ const unobserved = apiData.unobserved_label_seq_ids || [];
129599
+ const PDB_LOWER = pdbid.toLowerCase();
129600
+ unobserved.forEach((seqId) => {
129601
+ document
129602
+ .querySelectorAll(`text.rnaview_${PDB_LOWER}_${seqId}`)
129603
+ .forEach((el) => { el.setAttribute('fill', '#bbbbbb');});
129604
+ });
129605
+
129606
+ // click 2D to show in 3D
129607
+ document.addEventListener('PDB.RNA.viewer.click', (ev) => {
129608
+ // $(document).on("PDB.RNA.viewer.click", function(ev, data) {
129609
+ let posArray = [];
129610
+ const d = ev.eventData || ev.detail || {};
129611
+ if (Array.isArray(d.label_seq_ids)) posArray = d.label_seq_ids;
129612
+ if (d.label_seq_id !== undefined && d.label_seq_id !== null) posArray = [d.label_seq_id];
129613
+
129614
+ let hAtoms = {};
129615
+ for(let i = 0, il = posArray.length; i < il; ++i) {
129616
+ let resid = ic.ncbi2resid[chainid + '_' + posArray[i]];
129617
+ // highlight the selected residue
129618
+ hAtoms = me.hashUtilsCls.unionHash(hAtoms, ic.residues[resid]);
129619
+ }
129620
+
129621
+ if(ic.bCtrl || ic.bShift) {
129622
+ ic.hAtoms = me.hashUtilsCls.unionHash(ic.hAtoms, hAtoms);
129623
+ }
129624
+ else {
129625
+ ic.hAtoms = hAtoms;
129626
+ }
129627
+
129628
+ ic.hlUpdateCls.showHighlight();
129629
+ });
129630
+
129631
+ // click 3D to highlight in 2D
129632
+ $(document).on("icn3d.pick.click", function(ev, data) {
129633
+ // get the residue position in the selection
129634
+ let ncbiresid = data;
129635
+ let pos = ncbiresid.substr(ncbiresid.lastIndexOf('_') + 1);
129636
+
129637
+ document.dispatchEvent(new CustomEvent('protvista-click', {
129638
+ detail: { start: pos, end: pos }
129639
+ }));
129640
+ });
129641
+
129642
+ $(document).on("icn3d.pick.mouseover", function(ev, data) {
129643
+ // get the residue position in the selection
129644
+ let ncbiresid = data;
129645
+ let pos = ncbiresid.substr(ncbiresid.lastIndexOf('_') + 1);
129646
+
129647
+ document.dispatchEvent(new CustomEvent('protvista-mouseover', {
129648
+ detail: { start: pos, end: pos }
129649
+ }));
129650
+ });
129651
+
129652
+ }, 1000);
129653
+
129654
+ me.htmlCls.dialogCls.openDlg('dl_2ddiagram', 'Show R2DT Diagram for chain ' + chainid);
129368
129655
  }
129369
129656
 
129370
- async drawR2dt(chainid) { let ic = this.icn3d, me = ic.icn3dui;
129371
- let thisClass = this;
129372
- ic.bAddedCursors = false;
129657
+ async getDotbracket(chainid) { let ic = this.icn3d, me = ic.icn3dui;
129658
+ let pos = chainid.lastIndexOf('_');
129659
+ let pdbid = chainid.substr(0, pos);
129660
+ let chain = chainid.substr(pos + 1);
129373
129661
 
129374
- ic.r2dt_chainid = chainid;
129662
+ let result;
129663
+ if(ic.chain2pairs_resns_lw) {
129664
+ let pairs_resns_lw = ic.chain2pairs_resns_lw[chain];
129665
+ let pairs = [], lw2pairs = {};
129666
+
129667
+ for(let i = 0, il = pairs_resns_lw.length; i < il; i += 5) {
129668
+ let pos1 = pairs_resns_lw[i];
129669
+ let pos2 = pairs_resns_lw[i + 1];
129670
+ pairs_resns_lw[i + 2];
129671
+ pairs_resns_lw[i + 3];
129672
+ let lw = pairs_resns_lw[i + 4];
129673
+
129674
+ if(lw == 'cWW') {
129675
+ pairs.push([parseInt(pos1), parseInt(pos2)]);
129676
+ }
129677
+ else {
129678
+ if(!lw2pairs[lw]) lw2pairs[lw] = [];
129679
+ lw2pairs[lw].push(parseInt(pos1));
129680
+ lw2pairs[lw].push(parseInt(pos2));
129681
+ }
129682
+ }
129375
129683
 
129376
- let url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?chainid2rnaid=" + chainid;
129684
+ result = this.pairs2dotbracket(pairs, lw2pairs, chainid);
129685
+ }
129686
+ else {
129687
+ let url = "https://rna.bgsu.edu/rna3dhub/pdb/" + pdbid + "/interactions/fr3d/basepairs/tsv";
129377
129688
 
129378
- let data = await me.getAjaxPromise(url, 'jsonp');
129689
+ let data = await me.getAjaxPromise(url, 'text');
129690
+ if(!data || data == 'Not a valid PDB id.') {
129691
+ var aaa = 1; //alert('The chain ' + chainid + ' has no basepair information in FR3D...');
129692
+ return;
129693
+ }
129379
129694
 
129380
- let html = '';
129381
- if(data && data.rnaid) {
129382
- html += '<r2dt-web search=\'{"urs": "' + data.rnaid + '"}\' />';
129383
- html += '<script type="text/javascript" src="https://rnacentral.github.io/r2dt-web/dist/r2dt-web.js"></script>';
129384
- $("#" + me.pre + "2ddiagramDiv").html(html);
129385
- me.htmlCls.dialogCls.openDlg('dl_2ddiagram', 'Show R2DT Diagram for chain ' + chainid);
129695
+ let ret2 = this.fr3d2pairs(data, chainid); //pairs_lw2pairs_annotations
129696
+ // annotations = ret2.anno;
129697
+ result = this.pairs2dotbracket(ret2.pairs, ret2.lw2pairs, chainid);
129698
+ }
129699
+
129700
+
129701
+ return result;
129702
+ }
129703
+
129704
+ fr3d2pairs(data, chainid) { let ic = this.icn3d; ic.icn3dui;
129705
+ let pos = chainid.lastIndexOf('_');
129706
+ let chain = chainid.substr(pos + 1);
129707
+
129708
+ let lines = data.split('\n');
129709
+
129710
+ let pairs = []; // 0-based, only for canonical base pairs
129711
+ let lw2pairs = {}; // 1-based, for non-canonical base pairs and base stacking interactions
129712
+ for (let i in lines) {
129713
+ let line = lines[i]; // e.g., 9CFN|1|A|A|2 cWW 9CFN|1|A|U|38
129714
+ let from_type_to = line.trim().split('\t');
129715
+ if(from_type_to.length != 3) continue;
129716
+
129717
+ let fromArray = from_type_to[0].split('|'), toArray = from_type_to[2].split('|');
129718
+ if(fromArray.length < 5 || toArray.length < 5) continue;
129719
+ if(fromArray[2] != chain || toArray[2] != chain) continue;
129720
+ let resi1 = fromArray[4], resi2 = toArray[4];
129721
+ let ncbiResid1 = ic.resid2ncbi[chainid + '_' + resi1], ncbiResid2 = ic.resid2ncbi[chainid + '_' + resi2];
129722
+ let pos1 = parseInt(ncbiResid1.substr(ncbiResid1.lastIndexOf('_') + 1)) - 1, pos2 = parseInt(ncbiResid2.substr(ncbiResid2.lastIndexOf('_') + 1)) - 1;
129386
129723
 
129387
- // set cursor for all nodes
129388
- setTimeout(function(){
129389
- //ic.bAddedCursors = true;
129390
- thisClass.makeResiduesClickable();
129391
- }, 3000);
129724
+ 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.
129725
+
129726
+ if(from_type_to[1] == 'cWW') {
129727
+ if(fromArray[2] == chain && toArray[2] == chain) {
129728
+ pairs.push([Math.min(pos1, pos2), Math.max(pos1, pos2)]);
129729
+ }
129730
+ }
129731
+ else {
129732
+ let type = from_type_to[1];
129733
+ if(!lw2pairs[type]) lw2pairs[type] = [];
129734
+
129735
+ lw2pairs[type].push(pos1);
129736
+ lw2pairs[type].push(pos2);
129737
+ }
129738
+
129392
129739
  }
129393
- else {
129394
- var aaa = 1; //alert("No R2DT diagram can be found for chain " + chainid);
129740
+
129741
+ return {'pairs': pairs, 'lw2pairs': lw2pairs};
129742
+ }
129743
+
129744
+ isCrossed(pair1, pair2) {
129745
+ let i = pair1[0], j = pair1[1];
129746
+ let k = pair2[0], l = pair2[1];
129747
+ return (i < k && k < j && j < l) || (k < i && i < l && l < j);
129748
+ }
129749
+
129750
+ // modified from a python script by Eugene Baulin (https://imol.institute/leaders/baulin-group/)
129751
+ // pairs: list of (i, j) with 0 <= i < j < length
129752
+ pairs2dotbracket(pairs, lw2pairs, chainid) { let ic = this.icn3d; ic.icn3dui;
129753
+ //Dot-bracket notation for RNA secondary structures with pseudoknots.
129754
+
129755
+ //Positions are 0-indexed. Crossing pairs require different bracket types.
129756
+ //Levels are minimized by greedy coloring of the crossing graph, with pairs
129757
+ //sorted by ascending conflict count so that pairs involved in fewer crossings
129758
+ //(which form larger conflict-free groups) occupy the lower bracket levels.
129759
+
129760
+ //Bracket levels: () [] {} <> Aa Bb Cc ... Zz (30 levels total).
129761
+
129762
+ let BRACKETS = ['()', '[]', '{}', '<>'];
129763
+ for(let ch of 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') {
129764
+ BRACKETS.push(ch + ch.toLowerCase());
129765
+ }
129766
+
129767
+ pairs.sort((a, b) => parseInt(a[0]) - parseInt(b[0]));
129768
+
129769
+ // Pairs with fewer crossings tend to belong to larger conflict-free groups
129770
+ // and should occupy lower levels. Sort ascending by crossing count so they
129771
+ // are placed at level 0 first; break ties by left endpoint for determinism.
129772
+ let pairstr2crosscnt = {};
129773
+ for(let i = 0, il = pairs.length; i < il; ++i) {
129774
+ let pairstr1 = pairs[i][0] + '_' + pairs[i][1];
129775
+ for(let j = i + 1; j < il; ++j) {
129776
+ let pairstr2 = pairs[j][0] + '_' + pairs[j][1];
129777
+ if(this.isCrossed(pairs[i], pairs[j])) {
129778
+ pairstr2crosscnt[pairstr1] = (pairstr2crosscnt[pairstr1] || 0) + 1;
129779
+ pairstr2crosscnt[pairstr2] = (pairstr2crosscnt[pairstr2] || 0) + 1;
129780
+ }
129781
+ }
129395
129782
  }
129783
+
129784
+ let pairsSortbyCross = pairs.sort((a, b) => {
129785
+ let pairstr1 = a[0] + '_' + a[1], pairstr2 = b[0] + '_' + b[1];
129786
+ let crosscnt1 = pairstr2crosscnt[pairstr1] || 0, crosscnt2 = pairstr2crosscnt[pairstr2] || 0;
129787
+ if(crosscnt1 != crosscnt2) {
129788
+ return crosscnt1 - crosscnt2;
129789
+ } else {
129790
+ return a[0] - b[0];
129791
+ }
129792
+ });
129793
+
129794
+ // Greedy level assignment: for each pair (in conflict-count order),
129795
+ // use the lowest level whose existing pairs do not cross it.
129796
+ let levels = []; // each level is an array of pairs
129797
+ for(let index = 0, indexl = pairsSortbyCross.length; index < indexl; ++index) {
129798
+ let pair = pairsSortbyCross[index];
129799
+
129800
+ if(levels.length == 0) {
129801
+ levels.push([pair]);
129802
+ continue;
129803
+ }
129804
+
129805
+ let bCrossed = false;
129806
+ for(let i = 0, il = levels.length; i < il; ++i) {
129807
+ bCrossed = false;
129808
+
129809
+ let level_pairs = levels[i];
129810
+
129811
+ for(let j = 0, jl = level_pairs.length; j < jl; ++j) {
129812
+ if(this.isCrossed(pair, level_pairs[j])) {
129813
+ bCrossed = true;
129814
+ break;
129815
+ }
129816
+ }
129817
+
129818
+ if(!bCrossed) {
129819
+ levels[i].push(pair);
129820
+ break;
129821
+ }
129822
+ }
129823
+
129824
+ if(bCrossed) {
129825
+ levels.push([pair]);
129826
+ }
129827
+ }
129828
+
129829
+ // Relabel so larger groups use lower-level brackets, minimising the total
129830
+ // number of characters at higher levels. Bracket types are just labels —
129831
+ // any permutation of levels is valid as long as pairs on the same level
129832
+ // do not cross.
129833
+ levels.sort((a, b) => b.length - a.length); // sort descending by group size
129834
+
129835
+ let dotb = [], seq = '';
129836
+ for(let i = 0; i < ic.chainsSeq[chainid].length; ++i) {
129837
+ dotb.push('.');
129838
+ seq += ic.chainsSeq[chainid][i].name;
129839
+ }
129840
+
129841
+ let type = 'cWW';
129842
+ if(!lw2pairs[type]) lw2pairs[type] = [];
129843
+
129844
+ for(let i = 0, il = levels.length; i < il; ++i) {
129845
+ let pairs = levels[i];
129846
+ for(let j = 0, jl = pairs.length; j < jl; ++j) {
129847
+ dotb[pairs[j][0]] = BRACKETS[i][0];
129848
+ dotb[pairs[j][1]] = BRACKETS[i][1];
129849
+
129850
+ if(i > 0) { // level 0 is for nested base pairs
129851
+ lw2pairs[type].push(pairs[j][0] + 1); // 1-based
129852
+ lw2pairs[type].push(pairs[j][1] + 1);
129853
+ }
129854
+ }
129855
+ }
129856
+
129857
+ return {'dotb': dotb.join(''), 'seq': seq, 'lw2pairs': lw2pairs};
129858
+ }
129859
+
129860
+ async drawRnacanvas(chainid) { let ic = this.icn3d, me = ic.icn3dui;
129861
+ ic.bAddedCursors = false;
129862
+
129863
+ ic.rnacanvas_chainid = chainid;
129864
+
129865
+ let pos = chainid.lastIndexOf('_');
129866
+ chainid.substr(0, pos);
129867
+
129868
+ let result = await this.getDotbracket(chainid);
129869
+
129870
+ ic.dot_bracket = result.dotb;
129871
+ ic.rnaseq = result.seq;
129872
+ ic.lw2pairs = result.lw2pairs;
129873
+
129874
+ let nonWC = '';
129875
+ this.updateRnacanvas(nonWC);
129876
+ //me.htmlCls.clickMenuCls.setLogCmd('update forna ' + nonWC, true);
129877
+
129878
+ me.htmlCls.dialogCls.openDlg('dl_rnacanvas', 'Show 2D Diagram for chain ' + chainid + ' with RNAcanvas');
129879
+ $("#" + me.pre + "basepairType").resizable();
129880
+ }
129881
+
129882
+ updateRnacanvas(nonWC) { let ic = this.icn3d, me = ic.icn3dui;
129883
+ let html = '';
129884
+
129885
+ html += "<div id='rnacanvasSvg'></div>\n";
129886
+
129887
+ html += "<script type='module'>\n";
129888
+ //html += " import 'https://cdn.jsdelivr.net/npm/@rnacanvas/embedded@3.1.0';\n";
129889
+ html += " import './script/rnacanvas-4.0.0.js';\n";
129890
+ html += "</script>\n";
129891
+
129892
+ html += "<script type='text/javascript'>\n";
129893
+ html += "var attempts = 0;\n";
129894
+ html += "var tick = () => {\n";
129895
+ html += " if (typeof RNAcanvas !== 'undefined') {\n";
129896
+
129897
+ // html += "<script type='text/javascript'>\n";
129898
+ // html += "setTimeout(function(){\n";
129899
+ html += " // create a new RNAcanvas app instance\n";
129900
+ html += " var rnaCanvas = new RNAcanvas();\n";
129901
+ html += " // Target your container and append the canvas element\n";
129902
+ html += " var container = document.getElementById('rnacanvasSvg');\n";
129903
+ html += " rnaCanvas.appendTo(container);\n";
129904
+ html += " // control the size of the component\n";
129905
+ html += " rnaCanvas.domNode.style.width = '" + ($(window).width() / 2 - 150) + "px';\n";
129906
+ html += " rnaCanvas.domNode.style.height = '" + ($(window).height() - 200) + "px';\n";
129907
+ //html += " rnaCanvas.domNode.style.width = '600px';\n";
129908
+ //html += " rnaCanvas.domNode.style.height = '600px';\n";
129909
+ html += " // Render the structure\n";
129910
+ html += " rnaCanvas.drawDotBracket('" + ic.rnaseq + "', '" + ic.dot_bracket + "');\n";
129911
+ html += " // add padding around the drawn structure\n";
129912
+ html += " rnaCanvas.drawing.setPadding(20);\n";
129913
+ //html += " rnaCanvas.drawing.setPadding(1000);\n";
129914
+ html += " // bring the drawn structure into view\n";
129915
+ html += " rnaCanvas.drawingView.fitToContent();\n";
129916
+ html += " $('.UDedZ1UaiPZJsRmm1yxA').hide();\n"; // hide the "Powered by RNAcanvas" label
129917
+
129918
+ html += "var pos2node = {};\n";
129919
+ html += "var nodes = rnaCanvas.drawing.bases;\n";
129920
+
129921
+ html += "for (var i = 0, il = nodes.length; i < il; i++) {\n";
129922
+ html += " pos2node[i + 1] = nodes[i];\n";
129923
+ html += " nodes[i].setAttribute('resi', i + 1);\n";
129924
+ html += "}\n";
129925
+
129926
+ html += "$(document).on('click', '#rnacanvasSvg svg text', function(e) {\n";
129927
+ html += " var id = $(this).attr('id');\n";
129928
+ html += " // clear all node color\n";
129929
+ html += " for (var i = 0, il = nodes.length; i < il; i++) {\n";
129930
+ html += " nodes[i].setAttribute('fill', '#000');\n";
129931
+ html += " }\n";
129932
+ html += " $(this)[0].setAttribute('fill', '#f8b84e');\n";
129933
+
129934
+ html += " var resn = $(this).text().split(' ')[0];\n"; //C Position 8
129935
+ html += " $(document).trigger('from_rnacanvas', $(this).attr('resi') + '_' + resn);\n";
129936
+ html += " document.dispatchEvent(event);\n";
129937
+ html += "});\n";
129938
+
129939
+ html += "$(document).on('mouseover', '#rnacanvasSvg svg text', function(e) {\n";
129940
+ html += " var id = $(this).attr('id');\n";
129941
+ html += " $(this)[0].setAttribute('fill', '#f8b84e');\n";
129942
+ html += " if(!$(this)[0].querySelector('title')) {\n";
129943
+ html += " var title = document.createElementNS('http://www.w3.org/2000/svg', 'title');\n";
129944
+ html += " title.textContent = ' Position ' + $(this).attr('resi');\n";
129945
+ html += " $(this)[0].appendChild(title);\n";
129946
+ html += " }\n";
129947
+ html += "});\n";
129948
+
129949
+ html += "$(document).on('mouseout', '#rnacanvasSvg svg text', function(e) {\n";
129950
+ html += " var id = $(this).attr('id');\n";
129951
+ html += " $(this)[0].setAttribute('fill', '#000');\n";
129952
+ html += "});\n";
129953
+
129954
+ // click 3D to highlight in 2D
129955
+ html += "$(document).on('icn3d.pick.click icn3d.pick.mouseover', function(ev, data) {\n";
129956
+ html += " // get the residues in the selection\n";
129957
+ html += " var ncbiresid = data;\n";
129958
+ html += " var pos = ncbiresid.substr(ncbiresid.lastIndexOf('_') + 1);\n";
129959
+
129960
+ html += " // clear all node color\n";
129961
+ html += " for (var i = 0, il = nodes.length; i < il; i++) {\n";
129962
+ html += " nodes[i].setAttribute('fill', '#000');\n";
129963
+ html += " }\n";
129964
+
129965
+ html += " var node = pos2node[parseInt(pos)];\n";
129966
+ html += " node.setAttribute('fill', '#f8b84e');\n";
129967
+ html += "});\n";
129968
+
129969
+ if(nonWC) {
129970
+ let lwTypesTmp = nonWC.split(',');
129971
+ let lwTypes = [...new Set(lwTypesTmp)]; // unique
129972
+
129973
+ for(let i = 0, il = lwTypes.length; i < il; ++i) {
129974
+ let type = lwTypes[i];
129975
+ let pairs = ic.lw2pairs[type];
129976
+ if(!pairs) continue;
129977
+
129978
+ for(let j = 0, jl = pairs.length; j < jl; j += 2) {
129979
+ let pos1 = pairs[j], pos2 = pairs[j + 1];
129980
+ html += "if(pos2node[" + pos1 + "] && pos2node[" + pos2 + "]) {\n";
129981
+ html += " var node1 = pos2node[" + pos1 + "].centerPoint;\n";
129982
+ html += " var node2 = pos2node[" + pos2 + "].centerPoint;\n";
129983
+ html += " const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n";
129984
+ html += " line.setAttribute('x1', node1.x);\n";
129985
+ html += " line.setAttribute('y1', node1.y);\n";
129986
+ html += " line.setAttribute('x2', node2.x);\n";
129987
+ html += " line.setAttribute('y2', node2.y);\n";
129988
+ html += " line.setAttribute('stroke', 'black');\n";
129989
+ html += " line.setAttribute('stroke-width', '1');\n";
129990
+ html += " line.setAttribute('title', '" + type + "');\n";
129991
+ html += " rnaCanvas.drawing.domNode.appendChild(line);";
129992
+ html += "}\n";
129993
+ }
129994
+ }
129995
+ }
129996
+
129997
+ // html += "}, 10000);\n";
129998
+
129999
+ html += " return;\n";
130000
+ html += " }\n";
130001
+ html += " if (attempts++ > 200) return;\n";
130002
+ html += " setTimeout(tick, 100);\n";
130003
+ html += "};\n";
130004
+ html += "tick();\n";
130005
+
130006
+ html += "</script>\n";
130007
+
130008
+ $("#" + me.pre + "rnacanvasDiv").html(html);
129396
130009
  }
129397
130010
 
129398
130011
  async drawIgdgm(chainid) { let ic = this.icn3d, me = ic.icn3dui;
@@ -131567,7 +132180,7 @@ class SaveFile {
131567
132180
  }
131568
132181
  }
131569
132182
 
131570
- saveSvg(id, filename, bContactmap, bLigplot) { let ic = this.icn3d, me = ic.icn3dui;
132183
+ saveSvg(id, filename, bContactmap, bLigplot, bClassName) { let ic = this.icn3d, me = ic.icn3dui;
131571
132184
  if(me.bNode) return '';
131572
132185
 
131573
132186
  let width = $("#" + id).width();
@@ -131580,17 +132193,24 @@ class SaveFile {
131580
132193
  height += ic.len4ang;
131581
132194
  }
131582
132195
 
131583
- let svgXml = this.getSvgXml(id, width, height, bContactmap, bLigplot);
132196
+ let svgXml = this.getSvgXml(id, width, height, bContactmap, bLigplot, bClassName);
132197
+
132198
+ if(id == me.rnacanvasid) { // replace the font to 8
132199
+ svgXml = svgXml.replace('font-size: 18px', 'font-size: 8px');
132200
+ }
131584
132201
 
131585
132202
  let blob = new Blob([svgXml], {type: "image/svg+xml"});
131586
132203
  saveAs(blob, filename);
131587
132204
  }
131588
132205
 
131589
- getSvgXml(id, width, height, bContactmap, bLigplot) { let ic = this.icn3d, me = ic.icn3dui;
132206
+ getSvgXml(id, width, height, bContactmap, bLigplot, bClassName) { let ic = this.icn3d, me = ic.icn3dui;
131590
132207
  if(me.bNode) return '';
131591
132208
 
131592
132209
  // font is not good
131593
- let svg_data = document.getElementById(id).innerHTML; //put id of your svg element here
132210
+ let svg_data = (!bClassName) ? document.getElementById(id).innerHTML : document.querySelector('.' + id).innerHTML; //put id of your svg element here
132211
+ svg_data = svg_data.replace(/ fill=" #ccc"=""/g, '" fill="#ccc"'); // fix some data
132212
+ svg_data = svg_data.replace(/style="cursor: pointer;"/g, '');
132213
+ svg_data = svg_data.replace(/ font-size="/g, ' style="font-size: ');
131594
132214
 
131595
132215
  let startX = (bLigplot) ? -30 : 0;
131596
132216
  let startY = (bLigplot) ? -30 : 0;
@@ -131880,10 +132500,10 @@ class SaveFile {
131880
132500
  for(let n = 0; n < 3; ++n) {
131881
132501
  let nNum = n + 1;
131882
132502
  stru2header[stru] += "REMARK 350 BIOMT" + nNum.toString() + " " + mNum.toString().padStart(2, ' ')
131883
- + " " + ic.biomtMatrices[m].elements[n + 0].toFixed(6).toString().padStart(9, ' ')
131884
- + " " + ic.biomtMatrices[m].elements[n + 4].toFixed(6).toString().padStart(9, ' ')
131885
- + " " + ic.biomtMatrices[m].elements[n + 8].toFixed(6).toString().padStart(9, ' ')
131886
- + " " + ic.biomtMatrices[m].elements[n + 12].toFixed(6).toString().padStart(14, ' ') + "\n";
132503
+ + " " + parseFloat(ic.biomtMatrices[m].elements[n + 0]).toFixed(6).toString().padStart(9, ' ')
132504
+ + " " + parseFloat(ic.biomtMatrices[m].elements[n + 4]).toFixed(6).toString().padStart(9, ' ')
132505
+ + " " + parseFloat(ic.biomtMatrices[m].elements[n + 8]).toFixed(6).toString().padStart(9, ' ')
132506
+ + " " + parseFloat(ic.biomtMatrices[m].elements[n + 12]).toFixed(6).toString().padStart(14, ' ') + "\n";
131887
132507
  }
131888
132508
  }
131889
132509
  }
@@ -133324,7 +133944,7 @@ class Export3D {
133324
133944
  let mat = ic.biomtMatrices[i];
133325
133945
  if(mat === undefined) continue;
133326
133946
  // skip itself
133327
- if(mat.equals(identity)) continue;
133947
+ if(me.utilsCls.compMatrix(mat, identity, 16)) continue;
133328
133948
  let time =(i + 1) * 100;
133329
133949
  //https://stackoverflow.com/questions/1190642/how-can-i-pass-a-parameter-to-a-settimeout-callback
133330
133950
  setTimeout(function(mat, index){
@@ -133366,7 +133986,7 @@ class Export3D {
133366
133986
  let mat = ic.biomtMatrices[i];
133367
133987
  if(mat === undefined) continue;
133368
133988
  // skip itself
133369
- if(mat.equals(identity)) continue;
133989
+ if(me.utilsCls.compMatrix(mat, identity, 16)) continue;
133370
133990
  let time =(i + 1) * 100;
133371
133991
  //https://stackoverflow.com/questions/1190642/how-can-i-pass-a-parameter-to-a-settimeout-callback
133372
133992
  setTimeout(function(mat, index){
@@ -133483,7 +134103,7 @@ class Export3D {
133483
134103
  if(mat1 === undefined) continue;
133484
134104
 
133485
134105
  // skip itself
133486
- if(mat1.equals(identity)) continue;
134106
+ if(me.utilsCls.compMatrix(mat1, identity, 16)) continue;
133487
134107
 
133488
134108
  blobArray = this.processStlMeshGroup( ic.mdl, blobArray, mat1 );
133489
134109
 
@@ -133582,7 +134202,7 @@ class Export3D {
133582
134202
 
133583
134203
  //http://gun.teipir.gr/VRML-amgem/spec/part1/examples.html
133584
134204
  //Save the VRML file for 3D color printing.
133585
- saveVrmlFile( mat ){ let ic = this.icn3d; ic.icn3dui;
134205
+ saveVrmlFile( mat ){ let ic = this.icn3d, me = ic.icn3dui;
133586
134206
  if(Object.keys(ic.dAtoms).length > 50000) {
133587
134207
  var aaa = 1; //alert('Please display a subset of the structure to export 3D files. Then merge the files for 3D printing...');
133588
134208
  return [''];
@@ -133613,7 +134233,7 @@ class Export3D {
133613
134233
  if(mat1 === undefined) continue;
133614
134234
 
133615
134235
  // skip itself
133616
- if(mat1.equals(identity)) continue;
134236
+ if(me.utilsCls.compMatrix(mat1, identity, 16)) continue;
133617
134237
 
133618
134238
  result = this.processVrmlMeshGroup( ic.mdl, vrmlStrArray, vertexCnt, mat1 );
133619
134239
  vrmlStrArray = result.vrmlStrArray;
@@ -134263,6 +134883,9 @@ class Picking {
134263
134883
  this.showPickingBase(atom, x, y);
134264
134884
 
134265
134885
  if(ic.pk != 0) {
134886
+ let resid = atom.structure + '_' + atom.chain + '_' + atom.resi;
134887
+ let ncbiresid = (ic.resid2ncbi[resid]) ? ic.resid2ncbi[resid] : resid;
134888
+
134266
134889
  if(x !== undefined && y !== undefined) { // mouse over
134267
134890
  if(me.cfg.showmenu != undefined && me.cfg.showmenu == true) {
134268
134891
  y += me.htmlCls.MENU_HEIGHT;
@@ -134289,6 +134912,8 @@ class Picking {
134289
134912
 
134290
134913
  $("#" + ic.pre + "popup").html(text);
134291
134914
  $("#" + ic.pre + "popup").css("top", y).css("left", x+20).show();
134915
+
134916
+ $(document).trigger('icn3d.pick.mouseover', ncbiresid);
134292
134917
  }
134293
134918
  else {
134294
134919
  // highlight the sequence background
@@ -134301,6 +134926,8 @@ class Picking {
134301
134926
  // update the interaction flag
134302
134927
  ic.bSphereCalc = false;
134303
134928
  ic.bHbondCalc = false;
134929
+
134930
+ $(document).trigger('icn3d.pick.click', ncbiresid);
134304
134931
  }
134305
134932
  }
134306
134933
  }
@@ -135797,7 +136424,7 @@ class iCn3DUI {
135797
136424
  //even when multiple iCn3D viewers are shown together.
135798
136425
  this.pre = this.cfg.divid + "_";
135799
136426
 
135800
- this.REVISION = '3.49.2';
136427
+ this.REVISION = '3.50.0';
135801
136428
 
135802
136429
  // In nodejs, iCn3D defines "window = {navigator: {}}", and added window = {navigator: {}, "__THREE__":"177"}
135803
136430
  this.bNode = (Object.keys(window).length < 3) ? true : false;