icn3d 3.46.1 → 3.47.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
@@ -55370,6 +55370,8 @@ class RmsdSuprCls {
55370
55370
  supr = undefined;
55371
55371
  }
55372
55372
 
55373
+ if(me.bNode) console.log("RMSD: " + supr);
55374
+
55373
55375
  return {'rot': rot, 'trans1': xc1, 'trans2': xc2, 'rmsd': supr};
55374
55376
 
55375
55377
  }; // end rmsd_supr
@@ -56165,11 +56167,12 @@ class ClickMenu {
56165
56167
  }
56166
56168
  }
56167
56169
 
56168
- setSetsMenus(id, bOneset) { let me = this.icn3dui, ic = me.icn3d;
56170
+ setSetsMenus(id, bOneset, bThreeset) { let me = this.icn3dui, ic = me.icn3d;
56169
56171
  this.SetChainsAdvancedMenu();
56170
56172
 
56171
56173
  let id1 = id;
56172
56174
  let id2 = id + '2';
56175
+ let id3 = id + '3';
56173
56176
 
56174
56177
  let definedAtomsHtml = ic.definedSetsCls.setAtomMenu(['protein']);
56175
56178
  if($("#" + me.pre + id1).length) {
@@ -56178,9 +56181,13 @@ class ClickMenu {
56178
56181
  if(!bOneset && $("#" + me.pre + id2).length) {
56179
56182
  $("#" + me.pre + id2).html(" <option value='selected' selected>selected</option>" + definedAtomsHtml);
56180
56183
  }
56184
+ if(bThreeset && $("#" + me.pre + id3).length) {
56185
+ $("#" + me.pre + id3).html(" <option value='selected' selected>selected</option>" + definedAtomsHtml);
56186
+ }
56181
56187
 
56182
56188
  $("#" + me.pre + id1).resizable();
56183
56189
  if(!bOneset) $("#" + me.pre + id2).resizable();
56190
+ if(bThreeset) $("#" + me.pre + id3).resizable();
56184
56191
  }
56185
56192
 
56186
56193
  applyShownMenus(bNoSave) { let me = this.icn3dui; me.icn3d;
@@ -56397,27 +56404,31 @@ class ClickMenu {
56397
56404
 
56398
56405
  me.myEventCls.onIds("#" + me.pre + "mn1_pdbfile", "click", function(e) { me.icn3d; //e.preventDefault();
56399
56406
  //me = me.setIcn3dui($(this).attr('id'));
56400
- me.htmlCls.dialogCls.openDlg('dl_pdbfile', 'Please input PDB File');
56407
+ me.htmlCls.dialogCls.openDlg('dl_pdbfile', 'Please input PDB file');
56401
56408
  });
56402
56409
  me.myEventCls.onIds(["#" + me.pre + "mn1_pdbfile_app", "#" + me.pre + "tool_pdbfile"], "click", function(e) { me.icn3d; //e.preventDefault();
56403
56410
  //me = me.setIcn3dui($(this).attr('id'));
56404
- me.htmlCls.dialogCls.openDlg('dl_pdbfile_app', 'Please append PDB Files');
56411
+ me.htmlCls.dialogCls.openDlg('dl_pdbfile_app', 'Please append PDB files');
56405
56412
  });
56406
56413
 
56407
56414
  me.myEventCls.onIds("#" + me.pre + "mn1_mol2file", "click", function(e) { me.icn3d; //e.preventDefault();
56408
- me.htmlCls.dialogCls.openDlg('dl_mol2file', 'Please input Mol2 File');
56415
+ me.htmlCls.dialogCls.openDlg('dl_mol2file', 'Please input Mol2 file');
56409
56416
  });
56410
56417
 
56411
56418
  me.myEventCls.onIds("#" + me.pre + "mn1_sdffile", "click", function(e) { me.icn3d; //e.preventDefault();
56412
- me.htmlCls.dialogCls.openDlg('dl_sdffile', 'Please input SDF File');
56419
+ me.htmlCls.dialogCls.openDlg('dl_sdffile', 'Please input SDF file');
56413
56420
  });
56414
56421
 
56415
56422
  me.myEventCls.onIds("#" + me.pre + "mn1_xyzfile", "click", function(e) { me.icn3d; //e.preventDefault();
56416
- me.htmlCls.dialogCls.openDlg('dl_xyzfile', 'Please input XYZ File');
56423
+ me.htmlCls.dialogCls.openDlg('dl_xyzfile', 'Please input XYZ file');
56424
+ });
56425
+
56426
+ me.myEventCls.onIds("#" + me.pre + "mn1_dcdfile", "click", function(e) { me.icn3d; //e.preventDefault();
56427
+ me.htmlCls.dialogCls.openDlg('dl_dcdfile', 'Please input MD trajectory file');
56417
56428
  });
56418
56429
 
56419
56430
  me.myEventCls.onIds("#" + me.pre + "mn1_afmapfile", "click", function(e) { me.icn3d; //e.preventDefault();
56420
- me.htmlCls.dialogCls.openDlg('dl_afmapfile', 'Please input AlphaFold PAE File');
56431
+ me.htmlCls.dialogCls.openDlg('dl_afmapfile', 'Please input AlphaFold PAE file');
56421
56432
  });
56422
56433
 
56423
56434
  me.myEventCls.onIds("#" + me.pre + "mn1_urlfile", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -56425,11 +56436,11 @@ class ClickMenu {
56425
56436
  });
56426
56437
 
56427
56438
  me.myEventCls.onIds("#" + me.pre + "mn1_clustalwfile", "click", function(e) { me.icn3d; //e.preventDefault();
56428
- me.htmlCls.dialogCls.openDlg('dl_clustalwfile', 'Please input CLUSTALW MSA File');
56439
+ me.htmlCls.dialogCls.openDlg('dl_clustalwfile', 'Please input CLUSTALW MSA file');
56429
56440
  });
56430
56441
 
56431
56442
  me.myEventCls.onIds("#" + me.pre + "mn1_fastafile", "click", function(e) { me.icn3d; //e.preventDefault();
56432
- me.htmlCls.dialogCls.openDlg('dl_fastafile', 'Please input FASTA MSA File');
56443
+ me.htmlCls.dialogCls.openDlg('dl_fastafile', 'Please input FASTA MSA file');
56433
56444
  });
56434
56445
 
56435
56446
  me.myEventCls.onIds("#" + me.pre + "mn1_fixedversion", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -58303,6 +58314,13 @@ class ClickMenu {
58303
58314
  ic.bLinebtwsets = true;
58304
58315
  });
58305
58316
 
58317
+ me.myEventCls.onIds("#" + me.pre + "mn5_plane3sets", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
58318
+ me.htmlCls.dialogCls.openDlg('dl_plane3sets', 'Draw a plane among three sets');
58319
+
58320
+ thisClass.setSetsMenus('plane3sets', undefined, true);
58321
+
58322
+ ic.bPlane3sets = true;
58323
+ });
58306
58324
 
58307
58325
  me.myEventCls.onIds(["#" + me.pre + "mn2_selectedcenter", "#" + me.pre + "zoomin_selection", "#" + me.pre + "tool_selectedcenter"], "click", function(e) { let ic = me.icn3d; //e.preventDefault();
58308
58326
  //thisClass.setLogCmd('zoom selection', true);
@@ -59391,6 +59409,7 @@ class SetMenu {
59391
59409
  html += this.getLink('mn1_mol2file', 'Mol2 File', undefined, 2);
59392
59410
  html += this.getLink('mn1_sdffile', 'SDF File', undefined, 2);
59393
59411
  html += this.getLink('mn1_xyzfile', 'XYZ File', undefined, 2);
59412
+ html += this.getLink('mn1_dcdfile', 'MD Trajectory File', undefined, 2);
59394
59413
 
59395
59414
  html += this.getMenuSep();
59396
59415
 
@@ -60024,6 +60043,7 @@ class SetMenu {
60024
60043
 
60025
60044
  html += this.getLink('mn5_cartoonshape', 'Cartoon for a Set', undefined, 1);
60026
60045
  html += this.getLink('mn5_linebtwsets', 'Line btw. Two Sets', undefined, 1);
60046
+ html += this.getLink('mn5_plane3sets', 'Plane among 3 Sets', undefined, 1);
60027
60047
 
60028
60048
  if(me.cfg.cid === undefined && me.cfg.align === undefined && me.cfg.chainalign === undefined && me.cfg.mmdbaf === undefined) {
60029
60049
  html += this.getMenuSep();
@@ -60894,6 +60914,7 @@ class Dialog {
60894
60914
  let bGraph = $('#' + me.pre + 'dl_graph').hasClass('ui-dialog-content'); // initialized
60895
60915
  let bLineGraph = $('#' + me.pre + 'dl_linegraph').hasClass('ui-dialog-content'); // initialized
60896
60916
  let bScatterplot = $('#' + me.pre + 'dl_scatterplot').hasClass('ui-dialog-content'); // initialized
60917
+ let bRmsdplot = $('#' + me.pre + 'dl_rmsdplot').hasClass('ui-dialog-content'); // initialized
60897
60918
  let bLigplot = $('#' + me.pre + 'dl_ligplot').hasClass('ui-dialog-content'); // initialized
60898
60919
  let bContactmap = $('#' + me.pre + 'dl_contactmap').hasClass('ui-dialog-content'); // initialized
60899
60920
  let bAlignerrormap = $('#' + me.pre + 'dl_alignerrormap').hasClass('ui-dialog-content'); // initialized
@@ -60911,6 +60932,7 @@ class Dialog {
60911
60932
  id2flag.dl_graph = 'bGraph2';
60912
60933
  id2flag.dl_linegraph = 'bLineGraph2';
60913
60934
  id2flag.dl_scatterplot = 'bScatterplot2';
60935
+ id2flag.dl_rmsdplot = 'bRmsdplot2';
60914
60936
  id2flag.dl_ligplot = 'bLigplot2';
60915
60937
  id2flag.dl_contactmap = 'bContactmap2';
60916
60938
  id2flag.dl_alignerrormap = 'bAlignerrormap2';
@@ -60924,6 +60946,7 @@ class Dialog {
60924
60946
  if(bGraph) status.bGraph2 = $('#' + me.pre + 'dl_graph').dialog( 'isOpen' );
60925
60947
  if(bLineGraph) status.bLineGraph2 = $('#' + me.pre + 'dl_linegraph').dialog( 'isOpen' );
60926
60948
  if(bScatterplot) status.bScatterplot2 = $('#' + me.pre + 'dl_scatterplot').dialog( 'isOpen' );
60949
+ if(bRmsdplot) status.bRmsdplot2 = $('#' + me.pre + 'dl_rmsdplot').dialog( 'isOpen' );
60927
60950
  if(bLigplot) status.bLigplot2 = $('#' + me.pre + 'dl_ligplot').dialog( 'isOpen' );
60928
60951
  if(bContactmap) status.bContactmap2 = $('#' + me.pre + 'dl_contactmap').dialog( 'isOpen' );
60929
60952
  if(bAlignerrormap) status.bAlignerror2 = $('#' + me.pre + 'dl_alignerrormap').dialog( 'isOpen' );
@@ -61113,7 +61136,7 @@ class Dialog {
61113
61136
 
61114
61137
  let status = this.getDialogStatus().status;
61115
61138
 
61116
- 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_ligplot' || id === me.pre + 'dl_contactmap' || id === me.pre + 'dl_alignerrormap' || id === me.pre + 'dl_interactionsorted' || id === me.pre + 'dl_alignment') {
61139
+ 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_ligplot' || id === me.pre + 'dl_contactmap' || id === me.pre + 'dl_alignerrormap' || id === me.pre + 'dl_interactionsorted' || id === me.pre + 'dl_alignment') {
61117
61140
  //var dialogWidth = 0.5 *(me.htmlCls.WIDTH - me.htmlCls.LESSWIDTH) - twoddgmWidth * 0.5;
61118
61141
  let dialogWidth = 0.5 *(me.htmlCls.WIDTH) - twoddgmWidth * 0.5;
61119
61142
 
@@ -61339,7 +61362,7 @@ class Dialog {
61339
61362
  let width = 400, height = 150;
61340
61363
  let twoddgmWidth = me.htmlCls.width2d + 20;
61341
61364
 
61342
- 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_ligplot' || id === me.pre + 'dl_contactmap' || id === me.pre + 'dl_alignerrormap' || id === me.pre + 'dl_interactionsorted' || id === me.pre + 'dl_alignment') {
61365
+ 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_ligplot' || id === me.pre + 'dl_contactmap' || id === me.pre + 'dl_alignerrormap' || id === me.pre + 'dl_interactionsorted' || id === me.pre + 'dl_alignment') {
61343
61366
  $( "#" + id ).show();
61344
61367
  $( "#" + id + "_nb").show();
61345
61368
  $( "#" + id + "_title").html(title);
@@ -61770,6 +61793,23 @@ class SetDialog {
61770
61793
  html += me.htmlCls.buttonStr + "reload_xyzfile'>Load</button>";
61771
61794
  html += "</div>";
61772
61795
 
61796
+ html += me.htmlCls.divStr + "dl_dcdfile' class='" + dialogClass + "'>";
61797
+ html += this.addNotebookTitle('dl_dcdfile', 'Please input an MD trajectory file');
61798
+ html += "Step 1. <b>PDB File</b>: " + me.htmlCls.inputFileStr + "id='" + me.pre + "dcdpdbfile' size=8> ";
61799
+ html += me.htmlCls.buttonStr + "reload_dcdpdbfile'>Load PDB File</button><br><br>";
61800
+
61801
+ html += "Step 2. <b>DCD File</b>: " + me.htmlCls.inputFileStr + "id='" + me.pre + "dcdfile' size=8> ";
61802
+ html += me.htmlCls.buttonStr + "reload_dcdfile'>Load DCD File</button><br>";
61803
+
61804
+ html += "or <b>XTC File</b>: " + me.htmlCls.inputFileStr + "id='" + me.pre + "xtcfile' size=8> ";
61805
+ html += me.htmlCls.buttonStr + "reload_xtcfile' style='margin-left:28px'>Load XTC File</button><br><br>";
61806
+
61807
+ html += "<hr><br>";
61808
+ html += "<b>Analysis</b>: " + me.htmlCls.buttonStr + "rmsd_plot'>RMSD Plot</button><br><br>";
61809
+ html += "<b>Video from Frames</b>: " + me.htmlCls.buttonStr + "video_frame'>Make Video</button> with " + me.htmlCls.inputTextStr + "id='" + me.pre + "videofps' value='2' size=2> FPS (Frame per Sec)<br><br>";
61810
+
61811
+ html += "</div>";
61812
+
61773
61813
  html += me.htmlCls.divStr + "dl_clustalwfile' class='" + dialogClass + "' style='max-width:500px'>";
61774
61814
  html += this.addNotebookTitle('dl_clustalwfile', 'Please input a CLUSTALW MSA file');
61775
61815
  html += "Note the sequence names are either UniProt ID (e.g., A4D1S0 or A4D1S0_A), RefSeq ID (e.g., NP_001743), or PDB chain ID (e.g., 1HHO_A).<br><br>";
@@ -62300,6 +62340,15 @@ class SetDialog {
62300
62340
 
62301
62341
  html += "</div>";
62302
62342
 
62343
+ html += me.htmlCls.divStr + "dl_rmsdplot' style='background-color:white' class='" + dialogClass + "'>";
62344
+ html += this.addNotebookTitle('dl_rmsdplot', 'RMSD Plot');
62345
+
62346
+ me.rmsdplotid = me.pre + 'rmsdplot';
62347
+ html += me.htmlCls.divNowrapStr + buttonStrTmp + me.rmsdplotid + '_json">JSON</button>' + me.htmlCls.space2 + " The image below can be saved via right click.<br></div>";
62348
+
62349
+ html += '<canvas id="' + me.rmsdplotid + '"></canvas>';
62350
+
62351
+ html += "</div>";
62303
62352
 
62304
62353
  html += me.htmlCls.divStr + "dl_ligplot' style='background-color:white' class='" + dialogClass + "'>";
62305
62354
 
@@ -62557,6 +62606,42 @@ class SetDialog {
62557
62606
  html += "</div>";
62558
62607
 
62559
62608
 
62609
+ html += me.htmlCls.divStr + "dl_plane3sets' class='" + dialogClass + "'>";
62610
+ html += this.addNotebookTitle('dl_plane3sets', 'Add a plane among three sets');
62611
+ html += me.htmlCls.spanNowrapStr + "1. Select three sets</span><br/>";
62612
+ html += "<table border=0 width=400 cellspacing=10><tr><td>";
62613
+
62614
+ html += me.htmlCls.divNowrapStr + "First set:</div>";
62615
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "plane3sets' multiple size='5' style='min-width:130px;'>";
62616
+ html += "</select></div>";
62617
+
62618
+ html += "</td><td>";
62619
+
62620
+ html += me.htmlCls.divNowrapStr + "Second set:</div>";
62621
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "plane3sets2' multiple size='5' style='min-width:130px;'>";
62622
+ html += "</select></div>";
62623
+
62624
+ html += "</td><td>";
62625
+
62626
+ html += me.htmlCls.divNowrapStr + "Third set:</div>";
62627
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "plane3sets3' multiple size='5' style='min-width:130px;'>";
62628
+ html += "</select></div>";
62629
+
62630
+ html += "</td></tr></table>";
62631
+
62632
+ html += "2. Thickness (&#197;): " + me.htmlCls.inputTextStr + "id='" + me.pre + "plane3sets_thickness' value='2' size=4><br/><br/>";
62633
+
62634
+ html += "3. Color: " + me.htmlCls.inputTextStr + "id='" + me.pre + "plane3sets_customcolor' value='" + defaultColor + "' size=4><br/><br/>";
62635
+
62636
+ html += me.htmlCls.divNowrapStr + "4. Opacity: <select id='" + me.pre + "plane3sets_opacity'>";
62637
+ html += me.htmlCls.setHtmlCls.getOptionHtml(['1.0', '0.9', '0.8', '0.7', '0.6', '0.5', '0.4', '0.3', '0.2', '0.1'], 7);
62638
+ html += "</select></div><br>";
62639
+
62640
+ html += me.htmlCls.spanNowrapStr + "5. " + me.htmlCls.buttonStr + "applyplane3sets'>Display</button></span>";
62641
+ html += me.htmlCls.space3 + me.htmlCls.spanNowrapStr + me.htmlCls.buttonStr + "clearplane3sets'>Clear</button></span>";
62642
+ html += "</div>";
62643
+
62644
+
62560
62645
  html += me.htmlCls.divStr + "dl_cartoonshape' class='" + dialogClass + "'>";
62561
62646
  html += this.addNotebookTitle('dl_cartoonshape', 'Cartoon Shape');
62562
62647
  html += me.htmlCls.spanNowrapStr + "1. Select a set:</span><br/>";
@@ -63273,10 +63358,10 @@ class Events {
63273
63358
  }
63274
63359
  }
63275
63360
 
63276
- async loadPdbFile(bAppend, fileId, bmmCIF) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
63361
+ async loadPdbFile(bAppend, fileId, bmmCIF, bOpenDialog) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
63277
63362
  //me = ic.setIcn3dui(this.id);
63278
63363
  ic.bInitial = true;
63279
- thisClass.iniFileLoad();
63364
+ if(!bOpenDialog) thisClass.iniFileLoad();
63280
63365
  let files = $("#" + me.pre + fileId)[0].files;
63281
63366
  if(!files[0]) {
63282
63367
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
@@ -63594,7 +63679,7 @@ class Events {
63594
63679
 
63595
63680
  me.myEventCls.onIds(["#" + me.pre + "alternate", "#" + me.pre + "mn2_alternate", "#" + me.pre + "alternate2"], "click", async function(e) { let ic = me.icn3d;
63596
63681
  ic.bAlternate = true;
63597
- await ic.alternateCls.alternateStructures();
63682
+ ic.alternateCls.alternateStructures();
63598
63683
  ic.bAlternate = false;
63599
63684
 
63600
63685
  thisClass.setLogCmd("alternate structures", false);
@@ -64516,14 +64601,53 @@ class Events {
64516
64601
 
64517
64602
  // Start recording
64518
64603
  ic.videoRecorder.start();
64519
- thisClass.setLogCmd('Video revording started', false);
64604
+ thisClass.setLogCmd('Video recording started', false);
64520
64605
  });
64521
64606
 
64522
64607
  me.myEventCls.onIds("#" + me.pre + "video_end", "click", function(e) { let ic = me.icn3d;
64523
64608
  e.preventDefault();
64524
64609
 
64525
64610
  ic.videoRecorder.stop();
64526
- thisClass.setLogCmd('Video revording ended', false);
64611
+ thisClass.setLogCmd('Video recording ended', false);
64612
+ });
64613
+
64614
+ me.myEventCls.onIds("#" + me.pre + "video_frame", "click", function(e) { let ic = me.icn3d;
64615
+ e.preventDefault();
64616
+
64617
+ let fps = $("#" + me.pre + "videofps").val();
64618
+ let interval = 1000 / fps; // ms
64619
+ let duratinon = (ic.frames + 3) * interval; // make the video a little longer than the number of frames
64620
+
64621
+ const canvas = document.getElementById(ic.pre + "canvas");
64622
+ // ic.videoFrameRecorder = new MediaRecorder(canvas.captureStream(fps));
64623
+ ic.videoFrameRecorder = new MediaRecorder(canvas.captureStream());
64624
+ const recordedChunks = [];
64625
+
64626
+ // Collect data chunks
64627
+ ic.videoFrameRecorder.ondataavailable = event => {
64628
+ recordedChunks.push(event.data);
64629
+ };
64630
+
64631
+ ic.videoFrameRecorder.onstop = event => {
64632
+ // Code to save the recordedChunks as a video file
64633
+ const blob = new Blob(recordedChunks, {type: ic.videoFrameRecorder.mimeType});
64634
+ let fileName = ic.inputid + '_video_frame';
64635
+ saveAs(blob, fileName);
64636
+ };
64637
+
64638
+ // Start recording
64639
+ ic.videoFrameRecorder.start();
64640
+ thisClass.setLogCmd('Video recording started', false);
64641
+
64642
+ const intervalId = setInterval(function() {
64643
+ ic.alternateCls.alternateStructures();
64644
+ }, interval);
64645
+
64646
+ setTimeout(() => {
64647
+ clearInterval(intervalId);
64648
+ ic.videoFrameRecorder.stop();
64649
+ thisClass.setLogCmd('Video recording ended', false);
64650
+ }, duratinon);
64527
64651
  });
64528
64652
 
64529
64653
  me.myEventCls.onIds("#" + me.pre + "reload_state", "click", function(e) { let ic = me.icn3d;
@@ -65145,6 +65269,22 @@ class Events {
65145
65269
  await thisClass.loadPdbFile(ic.bAppend, 'pdbfile_app');
65146
65270
  });
65147
65271
 
65272
+ me.myEventCls.onIds("#" + me.pre + "reload_dcdpdbfile", "click", async function(e) { me.icn3d;
65273
+ e.preventDefault();
65274
+
65275
+ let bAppend = false;
65276
+ // ic.bRender = false;
65277
+ await thisClass.loadPdbFile(bAppend, 'dcdpdbfile', undefined, true);
65278
+ });
65279
+
65280
+ me.myEventCls.onIds("#" + me.pre + "reload_xtcpdbfile", "click", async function(e) { me.icn3d;
65281
+ e.preventDefault();
65282
+
65283
+ let bAppend = false;
65284
+ // ic.bRender = false;
65285
+ await thisClass.loadPdbFile(bAppend, 'xtcpdbfile', undefined, true);
65286
+ });
65287
+
65148
65288
  me.myEventCls.onIds("#" + me.pre + "reload_mol2file", "click", function(e) { let ic = me.icn3d;
65149
65289
  e.preventDefault();
65150
65290
  ic.bInitial = true;
@@ -65226,6 +65366,62 @@ class Events {
65226
65366
  }
65227
65367
  });
65228
65368
 
65369
+ me.myEventCls.onIds("#" + me.pre + "reload_dcdfile", "click", async function(e) { let ic = me.icn3d;
65370
+ e.preventDefault();
65371
+ ic.bInitial = true;
65372
+
65373
+ //thisClass.iniFileLoad();
65374
+ let file = $("#" + me.pre + "dcdfile")[0].files[0];
65375
+ if(!file) {
65376
+ var aaa = 1; //alert("Please select a file before clicking 'Load'");
65377
+ }
65378
+ else {
65379
+ me.htmlCls.setHtmlCls.fileSupport();
65380
+ let reader = new FileReader();
65381
+ reader.onload = async function(e) {
65382
+ let arrayBuffer = e.target.result;
65383
+ thisClass.setLogCmd('load dcd file ' + $("#" + me.pre + "dcdfile").val(), false);
65384
+ ic.molTitle = "";
65385
+ ic.inputid = undefined;
65386
+
65387
+ // ic.init();
65388
+ ic.bInputfile = true;
65389
+ ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + arrayBuffer : arrayBuffer;
65390
+ ic.InputfileType = 'dcd';
65391
+ await ic.dcdParserCls.loadDcdData(arrayBuffer);
65392
+ };
65393
+ reader.readAsArrayBuffer(file);
65394
+ }
65395
+ });
65396
+
65397
+ me.myEventCls.onIds("#" + me.pre + "reload_xtcfile", "click", async function(e) { let ic = me.icn3d;
65398
+ e.preventDefault();
65399
+ ic.bInitial = true;
65400
+
65401
+ //thisClass.iniFileLoad();
65402
+ let file = $("#" + me.pre + "xtcfile")[0].files[0];
65403
+ if(!file) {
65404
+ var aaa = 1; //alert("Please select a file before clicking 'Load'");
65405
+ }
65406
+ else {
65407
+ me.htmlCls.setHtmlCls.fileSupport();
65408
+ let reader = new FileReader();
65409
+ reader.onload = async function(e) {
65410
+ let arrayBuffer = e.target.result;
65411
+ thisClass.setLogCmd('load xtc file ' + $("#" + me.pre + "xtcfile").val(), false);
65412
+ ic.molTitle = "";
65413
+ ic.inputid = undefined;
65414
+
65415
+ // ic.init();
65416
+ ic.bInputfile = true;
65417
+ ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + arrayBuffer : arrayBuffer;
65418
+ ic.InputfileType = 'xtc';
65419
+ await ic.xtcParserCls.loadXtcData(arrayBuffer);
65420
+ };
65421
+ reader.readAsArrayBuffer(file);
65422
+ }
65423
+ });
65424
+
65229
65425
  me.myEventCls.onIds("#" + me.pre + "reload_clustalwfile", "click", function(e) { let ic = me.icn3d;
65230
65426
  e.preventDefault();
65231
65427
  ic.bInitial = true;
@@ -65478,6 +65674,11 @@ class Events {
65478
65674
 
65479
65675
  await ic.showInterCls.showInteractions('graph');
65480
65676
  });
65677
+ me.myEventCls.onIds("#" + me.pre + "rmsd_plot", "click", async function(e) { let ic = me.icn3d;
65678
+ e.preventDefault();
65679
+
65680
+ await ic.dcdParserCls.showRmsdPlot();
65681
+ });
65481
65682
  me.myEventCls.onIds("#" + me.pre + "hbondLineGraph", "click", async function(e) { let ic = me.icn3d;
65482
65683
  e.preventDefault();
65483
65684
 
@@ -65623,6 +65824,12 @@ class Events {
65623
65824
  thisClass.setLogCmd("scatterplot scale " + scale, true);
65624
65825
  });
65625
65826
 
65827
+ me.myEventCls.onIds("#" + me.rmsdplotid + "_json", "click", function(e) { let ic = me.icn3d;
65828
+ e.preventDefault();
65829
+
65830
+ ic.saveFileCls.saveFile(ic.inputid + "_rmsdplot.json", "text", [JSON.stringify(ic.mdDataSet)]);
65831
+ });
65832
+
65626
65833
  me.myEventCls.onIds("#" + me.ligplotid + "_svg", "click", function(e) { let ic = me.icn3d;
65627
65834
  e.preventDefault();
65628
65835
 
@@ -66019,6 +66226,39 @@ class Events {
66019
66226
  ic.drawCls.draw();
66020
66227
  });
66021
66228
 
66229
+ me.myEventCls.onIds("#" + me.pre + "applyplane3sets", "click", function(e) { let ic = me.icn3d;
66230
+ e.preventDefault();
66231
+
66232
+ ic.bLinebtwsets = false;
66233
+
66234
+ let nameArray = $("#" + me.pre + "plane3sets").val();
66235
+ let nameArray2 = $("#" + me.pre + "plane3sets2").val();
66236
+ let nameArray3 = $("#" + me.pre + "plane3sets3").val();
66237
+
66238
+ let atomSet1 = ic.definedSetsCls.getAtomsFromNameArray(nameArray);
66239
+ let atomSet2 = ic.definedSetsCls.getAtomsFromNameArray(nameArray2);
66240
+ let atomSet3 = ic.definedSetsCls.getAtomsFromNameArray(nameArray3);
66241
+
66242
+ let posArray1 = ic.contactCls.getExtent(atomSet1);
66243
+ let posArray2 = ic.contactCls.getExtent(atomSet2);
66244
+ let posArray3 = ic.contactCls.getExtent(atomSet3);
66245
+
66246
+ let pos1 = new Vector3$1(posArray1[2][0], posArray1[2][1], posArray1[2][2]);
66247
+ let pos2 = new Vector3$1(posArray2[2][0], posArray2[2][1], posArray2[2][2]);
66248
+ let pos3 = new Vector3$1(posArray3[2][0], posArray3[2][1], posArray3[2][2]);
66249
+
66250
+ let thickness = $("#" + me.pre + "plane3sets_thickness").val();
66251
+ let color = $("#" + me.pre + "plane3sets_customcolor").val();
66252
+ let opacity = $("#" + me.pre + "plane3sets_opacity").val();
66253
+
66254
+ let command = 'add plane | x1 ' + pos1.x.toPrecision(4) + ' y1 ' + pos1.y.toPrecision(4) + ' z1 ' + pos1.z.toPrecision(4) + ' | x2 ' + pos2.x.toPrecision(4) + ' y2 ' + pos2.y.toPrecision(4) + ' z2 ' + pos2.z.toPrecision(4) + ' | x3 ' + pos3.x.toPrecision(4) + ' y3 ' + pos3.y.toPrecision(4) + ' z3 ' + pos3.z.toPrecision(4) + ' | color ' + color + ' | thickness ' + thickness + ' | opacity ' + opacity;
66255
+
66256
+ thisClass.setLogCmd(command, true);
66257
+
66258
+ ic.analysisCls.addPlane(pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z, pos3.x, pos3.y, pos3.z, color, thickness, opacity);
66259
+ ic.drawCls.draw();
66260
+ });
66261
+
66022
66262
  me.myEventCls.onIds("#" + me.pre + "applycartoonshape", "click", function(e) { let ic = me.icn3d;
66023
66263
  e.preventDefault();
66024
66264
 
@@ -66066,6 +66306,16 @@ class Events {
66066
66306
  ic.drawCls.draw();
66067
66307
  });
66068
66308
 
66309
+ me.myEventCls.onIds("#" + me.pre + "clearplane3sets", "click", function(e) { let ic = me.icn3d;
66310
+ e.preventDefault();
66311
+
66312
+
66313
+ ic.planes = [];
66314
+ thisClass.setLogCmd('clear plane among sets', true);
66315
+
66316
+ ic.drawCls.draw();
66317
+ });
66318
+
66069
66319
  me.myEventCls.onIds("#" + me.pre + "clearcartoonshape", "click", function(e) { let ic = me.icn3d;
66070
66320
  e.preventDefault();
66071
66321
 
@@ -67562,6 +67812,12 @@ class SetHtml {
67562
67812
  else if(type === 'xyz') {
67563
67813
  await ic.xyzParserCls.loadXyzData(data);
67564
67814
  }
67815
+ else if(type === 'dcd') {
67816
+ await ic.dcdParserCls.loadDcdData(data);
67817
+ }
67818
+ else if(type === 'xtc') {
67819
+ await ic.xtcParserCls.loadXtcData(data);
67820
+ }
67565
67821
  else if(type === 'mmcif') {
67566
67822
  await ic.mmcifParserCls.loadMmcifData(data);
67567
67823
  }
@@ -77241,6 +77497,37 @@ class Cylinder {
77241
77497
  }
77242
77498
  }
77243
77499
 
77500
+ //Create planes for a list of "planes", each of which has the properties 'position1', 'position2', 'position2', 'color', 'thickness', 'opacity',
77501
+ createPlanes(planes) { let ic = this.icn3d, me = ic.icn3dui;
77502
+ if(me.bNode) return;
77503
+
77504
+ for(let i = 0, il = planes.length; i < il; ++i) {
77505
+ let plane = planes[i];
77506
+
77507
+ let p1 = plane.position1;
77508
+ let p2 = plane.position2;
77509
+ let p3 = plane.position3;
77510
+
77511
+ let thickness = (plane.thickness) ? plane.thickness : 2;
77512
+ let opacity = (plane.opacity) ? plane.opacity : 0.3;
77513
+ let colorStr = '#' + plane.color.replace(/\#/g, '');
77514
+ let color = me.parasCls.thr(colorStr);
77515
+
77516
+ let planeGeo = new Plane();
77517
+ planeGeo.setFromCoplanarPoints(p1, p2, p3);
77518
+ let planeNormal = planeGeo.normal;
77519
+
77520
+ const projectedPoint = new Vector3$1();
77521
+ // Project the center onto the plane
77522
+ planeGeo.projectPoint(ic.center, projectedPoint);
77523
+
77524
+ let c0 = projectedPoint.clone().sub(planeNormal.clone().multiplyScalar(thickness * 0.5));
77525
+ let c1 = projectedPoint.clone().add(planeNormal.clone().multiplyScalar(thickness * 0.5));
77526
+ let radius = ic.maxD / 2;
77527
+ ic.cylinderCls.createCylinder(c0, c1, radius, color, undefined, color, undefined, undefined, opacity);
77528
+ }
77529
+ }
77530
+
77244
77531
  createCylinder_base(p0, p1, radius, color, bHighlight, color2, bPicking) { let ic = this.icn3d, me = ic.icn3dui;
77245
77532
  if(me.bNode) return;
77246
77533
 
@@ -77652,7 +77939,7 @@ class Line$1 {
77652
77939
  }
77653
77940
 
77654
77941
  // do not add the artificial lines to raycasting objects
77655
- };
77942
+ }
77656
77943
 
77657
77944
  }
77658
77945
 
@@ -78130,7 +78417,7 @@ class FirstAtomObj {
78130
78417
  let firstIndex;
78131
78418
 
78132
78419
  for(let i in atomsHash) {
78133
- if(ic.atoms[i].name == 'CA') {
78420
+ if(ic.atoms[i] && ic.atoms[i].name == 'CA') {
78134
78421
  firstIndex = i;
78135
78422
  break;
78136
78423
  }
@@ -78138,7 +78425,7 @@ class FirstAtomObj {
78138
78425
 
78139
78426
  if(!firstIndex) {
78140
78427
  for(let i in atomsHash) {
78141
- if(ic.atoms[i].name == "O3'" || ic.atoms[i].name == "O3*") {
78428
+ if(ic.atoms[i] && (ic.atoms[i].name == "O3'" || ic.atoms[i].name == "O3*")) {
78142
78429
  firstIndex = i;
78143
78430
  break;
78144
78431
  }
@@ -78217,7 +78504,7 @@ class FirstAtomObj {
78217
78504
  getAtomFromResi(resid, atomName) { let ic = this.icn3d; ic.icn3dui;
78218
78505
  if(ic.residues.hasOwnProperty(resid)) {
78219
78506
  for(let i in ic.residues[resid]) {
78220
- if(ic.atoms[i].name === atomName && !ic.atoms[i].het) {
78507
+ if(ic.atoms[i] && ic.atoms[i].name === atomName && !ic.atoms[i].het) {
78221
78508
  return ic.atoms[i];
78222
78509
  }
78223
78510
  }
@@ -84067,6 +84354,8 @@ class ApplyOther {
84067
84354
  }
84068
84355
 
84069
84356
  ic.lineCls.createLines(ic.lines);
84357
+ if(!ic.planes) ic.planes = [];
84358
+ ic.cylinderCls.createPlanes(ic.planes);
84070
84359
  // }
84071
84360
 
84072
84361
  // distance sets
@@ -86300,7 +86589,7 @@ class Alternate {
86300
86589
 
86301
86590
  // change the display atom when alternating
86302
86591
  //Show structures one by one.
86303
- async alternateStructures() { let ic = this.icn3d, me = ic.icn3dui;
86592
+ alternateStructures() { let ic = this.icn3d, me = ic.icn3dui;
86304
86593
  ic.bAlternate = true;
86305
86594
 
86306
86595
  //ic.transformCls.zoominSelection();
@@ -86445,7 +86734,7 @@ class Alternate {
86445
86734
 
86446
86735
  async alternateWrapper() { let ic = this.icn3d; ic.icn3dui;
86447
86736
  ic.bAlternate = true;
86448
- await this.alternateStructures();
86737
+ this.alternateStructures();
86449
86738
  ic.bAlternate = false;
86450
86739
  }
86451
86740
 
@@ -97134,6 +97423,8 @@ class ShowAnno {
97134
97423
  ic.seqAnnWidth = dialogWidth - 120 - 30*2 - 50; // title: 120px, start and end resi: 30px, extra space on the left and right: 50px
97135
97424
 
97136
97425
  for(let i = 0, il = chainArray.length; i < il; ++i) {
97426
+ if(!ic.chainsSeq[chainArray[i]]) continue; // skip empty chain
97427
+
97137
97428
  Math.round(chainArray[i].indexOf('_'));
97138
97429
  //if(pos > 4) continue; // NMR structures with structure id such as 2K042,2K043, ...
97139
97430
  // let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chainArray[i]]);
@@ -99856,7 +100147,7 @@ class LineGraph {
99856
100147
  }
99857
100148
 
99858
100149
  for(let i = 0, il = structureArray.length; i < il; ++i) {
99859
- let labelFinal = label;
100150
+ let labelFinal = (i+1).toString() + '. ' + label;
99860
100151
  if(bMutation) {
99861
100152
  if(i == 0) {
99862
100153
  labelFinal += "Wild Type ";
@@ -107564,6 +107855,12 @@ class PdbParser {
107564
107855
  else if(type === 'xyz') {
107565
107856
  await ic.xyzParserCls.loadXyzData(data);
107566
107857
  }
107858
+ else if(type === 'dcd') {
107859
+ await ic.dcdParserCls.loadDcdData(data);
107860
+ }
107861
+ else if(type === 'xtc') {
107862
+ await ic.xtcParserCls.loadXtcData(data);
107863
+ }
107567
107864
  else if(type === 'mmcif') {
107568
107865
  await ic.mmcifParserCls.loadMmcifData(data);
107569
107866
  }
@@ -108118,6 +108415,995 @@ class XyzParser {
108118
108415
  }
108119
108416
  }
108120
108417
 
108418
+ /**
108419
+ * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
108420
+ */
108421
+
108422
+ class DcdParser {
108423
+ constructor(icn3d) {
108424
+ this.icn3d = icn3d;
108425
+ icn3d.DELTA = 1;
108426
+ icn3d.TIMEOFFSET = 0;
108427
+ }
108428
+
108429
+ async loadDcdData(data) { let ic = this.icn3d, me = ic.icn3dui;
108430
+ let bResult = this.loadDcdAtomData(data);
108431
+
108432
+ if(me.cfg.align === undefined && Object.keys(ic.structures).length == 1) {
108433
+ $("#" + ic.pre + "alternateWrapper").hide();
108434
+ }
108435
+
108436
+ if(!bResult) {
108437
+ var aaa = 1; //alert('The DCD file has the wrong format...');
108438
+ }
108439
+ else {
108440
+ ic.setStyleCls.setAtomStyleByOptions(ic.opts);
108441
+ ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
108442
+
108443
+ // hide water, ions
108444
+ ic.dAtoms = me.hashUtilsCls.cloneHash(ic.proteins);
108445
+ ic.dAtoms = me.hashUtilsCls.unionHash(ic.dAtoms, ic.nucleotides);
108446
+ ic.dAtoms = me.hashUtilsCls.unionHash(ic.dAtoms, ic.chemicals);
108447
+ ic.hAtoms = me.hashUtilsCls.cloneHash(ic.dAtoms);
108448
+ ic.transformCls.zoominSelection();
108449
+
108450
+ // ic.bRender = true;
108451
+ await ic.ParserUtilsCls.renderStructure();
108452
+
108453
+ if(me.cfg.rotate !== undefined) ic.resizeCanvasCls.rotStruc(me.cfg.rotate, true);
108454
+
108455
+ //if(me.deferred !== undefined) me.deferred.resolve(); /// if(ic.deferred2 !== undefined) ic.deferred2.resolve();
108456
+ }
108457
+ }
108458
+
108459
+ // modified from https://github.com/molstar/molstar/blob/master/src/mol-io/reader/dcd/parser.ts
108460
+ loadDcdAtomData(data) { let ic = this.icn3d, me = ic.icn3dui;
108461
+ // http://www.ks.uiuc.edu/Research/vmd/plugins/molfile/dcdplugin.html
108462
+
108463
+ // The DCD format is structured as follows
108464
+ // (FORTRAN UNFORMATTED, with Fortran data type descriptions):
108465
+ // HDR NSET ISTRT NSAVC 5-ZEROS NATOM-NFREAT DELTA 9-ZEROS
108466
+ // `CORD' #files step 1 step zeroes (zero) timestep (zeroes)
108467
+ // interval
108468
+ // C*4 INT INT INT 5INT INT DOUBLE 9INT
108469
+ // ==========================================================================
108470
+ // NTITLE TITLE
108471
+ // INT (=2) C*MAXTITL
108472
+ // (=32)
108473
+ // ==========================================================================
108474
+ // NATOM
108475
+ // #atoms
108476
+ // INT
108477
+ // ==========================================================================
108478
+ // X(I), I=1,NATOM (DOUBLE)
108479
+ // Y(I), I=1,NATOM
108480
+ // Z(I), I=1,NATOM
108481
+ // ==========================================================================
108482
+
108483
+ let bin =(data.buffer && data.buffer instanceof ArrayBuffer) ? data.buffer : data;
108484
+ const dv = new DataView(bin);
108485
+
108486
+ // const header: Mutable<DcdHeader> = Object.create(null);
108487
+ // const frames: DcdFrame[] = [];
108488
+ const header = {};
108489
+
108490
+ let nextPos = 0;
108491
+
108492
+ // header block
108493
+
108494
+ const intView = new Int32Array(bin, 0, 23);
108495
+ const ef = intView[0] !== dv.getInt32(0); // endianess flag
108496
+ // swap byte order when big endian (84 indicates little endian)
108497
+ if (intView[0] !== 84) {
108498
+ const n = data.byteLength;
108499
+ for (let i = 0; i < n; i += 4) {
108500
+ dv.setFloat32(i, dv.getFloat32(i), true);
108501
+ }
108502
+ }
108503
+ if (intView[0] !== 84) {
108504
+ console.error('dcd bad format, header block start');
108505
+ return false;
108506
+ }
108507
+
108508
+ // format indicator, should read 'CORD'
108509
+ const formatString = String.fromCharCode(
108510
+ dv.getUint8(4), dv.getUint8(5),
108511
+ dv.getUint8(6), dv.getUint8(7)
108512
+ );
108513
+ if (formatString !== 'CORD') {
108514
+ console.error('dcd bad format, format string');
108515
+ return false;
108516
+ }
108517
+ let isCharmm = false;
108518
+ let extraBlock = false;
108519
+ let fourDims = false;
108520
+ // version field in charmm, unused in X-PLOR
108521
+ if (intView[22] !== 0) {
108522
+ isCharmm = true;
108523
+ if (intView[12] !== 0) extraBlock = true;
108524
+ if (intView[13] === 1) fourDims = true;
108525
+ }
108526
+ header.NSET = intView[2];
108527
+ header.ISTART = intView[3];
108528
+ header.NSAVC = intView[4];
108529
+ header.NAMNF = intView[10];
108530
+
108531
+ ic.frames = header.NSET;
108532
+
108533
+ if (isCharmm) {
108534
+ header.DELTA = dv.getFloat32(44, ef);
108535
+ } else {
108536
+ header.DELTA = dv.getFloat64(44, ef);
108537
+ }
108538
+ this.DELTA = header.DELTA;
108539
+
108540
+ if (intView[22] !== 84) {
108541
+ console.error('dcd bad format, header block end');
108542
+ return false;
108543
+ }
108544
+ nextPos = nextPos + 21 * 4 + 8;
108545
+
108546
+ // title block
108547
+
108548
+ const titleEnd = dv.getInt32(nextPos, ef);
108549
+ const titleStart = nextPos + 1;
108550
+ if ((titleEnd - 4) % 80 !== 0) {
108551
+ console.error('dcd bad format, title block start');
108552
+ return false;
108553
+ }
108554
+
108555
+ let byteView = new Uint8Array(bin);
108556
+ header.TITLE = String.fromCharCode.apply(null, byteView.subarray(titleStart, titleEnd));
108557
+ if (dv.getInt32(titleStart + titleEnd + 4 - 1, ef) !== titleEnd) {
108558
+ console.error('dcd bad format, title block end');
108559
+ return false;
108560
+ }
108561
+
108562
+ nextPos = nextPos + titleEnd + 8;
108563
+
108564
+ // natom block
108565
+
108566
+ if (dv.getInt32(nextPos, ef) !== 4) {
108567
+ console.error('dcd bad format, natom block start');
108568
+ return false;
108569
+ }
108570
+ header.NATOM = dv.getInt32(nextPos + 4, ef);
108571
+ if (dv.getInt32(nextPos + 8, ef) !== 4) {
108572
+ console.error('dcd bad format, natom block end');
108573
+ return false;
108574
+ }
108575
+ nextPos = nextPos + 4 + 8;
108576
+
108577
+ // fixed atoms block
108578
+
108579
+ if (header.NAMNF > 0) {
108580
+ // TODO read coordinates and indices of fixed atoms
108581
+ console.error('dcd format with fixed atoms unsupported, aborting');
108582
+ return false;
108583
+ }
108584
+
108585
+ // frames
108586
+ const natom = header.NATOM;
108587
+ const natom4 = natom * 4;
108588
+
108589
+ if(natom != Object.keys(ic.atoms).length) {
108590
+ var aaa = 1; //alert('The number of atoms in the DCD file does not match the number of atoms in the PDB file: ' + natom + ' != ' + Object.keys(ic.atoms).length);
108591
+ return false;
108592
+ }
108593
+
108594
+ let structuresOri = me.hashUtilsCls.cloneHash(ic.structures);
108595
+ let residuesOri = me.hashUtilsCls.cloneHash(ic.residues);
108596
+ let chainsOri = me.hashUtilsCls.cloneHash(ic.chains);
108597
+
108598
+ let proteinsOri = me.hashUtilsCls.cloneHash(ic.proteins);
108599
+ let nucleotidesOri = me.hashUtilsCls.cloneHash(ic.nucleotides);
108600
+ let waterOri = me.hashUtilsCls.cloneHash(ic.water);
108601
+ let ionsOri = me.hashUtilsCls.cloneHash(ic.ions);
108602
+ let chemicalsOri = me.hashUtilsCls.cloneHash(ic.chemicals);
108603
+
108604
+ let serial = natom + 1; // a preloaded PDB structure would have atom serial from 1 to natom
108605
+ for (let i = 0, n = header.NSET; i < n; ++i) {
108606
+ const frame = {};
108607
+ frame.elementCount = natom;
108608
+
108609
+ if (extraBlock) {
108610
+ nextPos += 4; // block start
108611
+ frame.cell = [
108612
+ dv.getFloat64(nextPos, ef),
108613
+ dv.getFloat64(nextPos + 1, ef),
108614
+ dv.getFloat64(nextPos + 2 * 8, ef),
108615
+ dv.getFloat64(nextPos + 3 * 8, ef),
108616
+ dv.getFloat64(nextPos + 4 * 8, ef),
108617
+ dv.getFloat64(nextPos + 5 * 8, ef)
108618
+ ];
108619
+ nextPos += 48;
108620
+ nextPos += 4; // block end
108621
+ }
108622
+
108623
+ // xyz coordinates
108624
+ for (let j = 0; j < 3; ++j) {
108625
+ if (dv.getInt32(nextPos, ef) !== natom4) {
108626
+ console.error(`dcd bad format, coord block start: ${i}, ${j}`);
108627
+ return false;
108628
+ }
108629
+ nextPos += 4; // block start
108630
+ const c = new Float32Array(bin, nextPos, natom);
108631
+ if (j === 0) frame.x = c;
108632
+ else if (j === 1) frame.y = c;
108633
+ else frame.z = c;
108634
+
108635
+ nextPos += natom4;
108636
+ if (dv.getInt32(nextPos, ef) !== natom4) {
108637
+ console.error(`dcd bad format, coord block end: ${i}, ${j}`);
108638
+ return false;
108639
+ }
108640
+ nextPos += 4; // block end
108641
+ }
108642
+
108643
+ if (fourDims) {
108644
+ const bytes = dv.getInt32(nextPos, ef);
108645
+ nextPos += 4 + bytes + 4; // block start + skip + block end
108646
+ }
108647
+
108648
+ // skip the first structure since it was read from PDB already
108649
+ if(i == 0) continue;
108650
+
108651
+ let molNum = i + 1; // to avoid the same molNum as the PDB structure
108652
+ for(let j = 0; j < natom; ++j) {
108653
+ let coord = new Vector3$1(frame.x[j], frame.y[j], frame.z[j]);
108654
+
108655
+ let atom = me.hashUtilsCls.cloneHash(ic.atoms[j + 1]);
108656
+
108657
+ atom.serial = serial;
108658
+ atom.structure = atom.structure + molNum;
108659
+ atom.coord = coord;
108660
+ atom.bonds = [].concat(ic.atoms[j + 1].bonds);
108661
+
108662
+ // update bonds
108663
+ for(let k = 0, kl = atom.bonds.length; k < kl; ++k) {
108664
+ atom.bonds[k] = parseInt(atom.bonds[k]) + natom * i;
108665
+ }
108666
+
108667
+ ic.atoms[serial] = atom;
108668
+
108669
+ // assign extra info
108670
+ ic.dAtoms[serial] = 1;
108671
+ ic.hAtoms[serial] = 1;
108672
+
108673
+ let chainid = atom.structure + '_' + atom.chain;
108674
+ let residid = chainid + '_' + atom.resi;
108675
+ ic.secondaries[residid] = atom.ss;
108676
+ ic.residueId2Name[residid] = me.utilsCls.residueName2Abbr(atom.resn);
108677
+
108678
+ ++serial;
108679
+ }
108680
+
108681
+ // update ic.structures, ic.residues and ic.chains
108682
+ for(let structure in structuresOri) {
108683
+ let structure2 = structure + molNum;
108684
+ ic.structures[structure2] = [];
108685
+
108686
+ for(let k = 0, kl = structuresOri[structure].length; k < kl; ++k) {
108687
+ let idArray = structuresOri[structure][k].split('_');
108688
+ ic.structures[structure2].push(structure2 + '_' + idArray[1]);
108689
+ }
108690
+ }
108691
+
108692
+ for(let j in residuesOri) {
108693
+ let idArray = j.split('_');
108694
+ let structure2 = idArray[0] + molNum;
108695
+ let residid2 = structure2 + '_' + idArray[1] + '_' + idArray[2];
108696
+ ic.residues[residid2] = {};
108697
+
108698
+ for(let k in residuesOri[j]) {
108699
+ ic.residues[residid2][parseInt(k) + natom * i] = 1;
108700
+ }
108701
+ }
108702
+
108703
+ for(let j in chainsOri) {
108704
+ let idArray = j.split('_');
108705
+ let structure2 = idArray[0] + molNum;
108706
+ let chainid2 = structure2 + '_' + idArray[1];
108707
+
108708
+ // ic.chainsSeq[chainid2] = [].concat(ic.chainsSeq[j]);
108709
+
108710
+ ic.chains[chainid2] = {};
108711
+ for(let k in chainsOri[j]) {
108712
+ ic.chains[chainid2][parseInt(k)+ natom * i] = 1;
108713
+ }
108714
+ }
108715
+
108716
+ // update ic.proteins, etc
108717
+ for(let j in proteinsOri) {
108718
+ ic.proteins[parseInt(j) + natom * i] = 1;
108719
+ }
108720
+ for(let j in nucleotidesOri) {
108721
+ ic.nucleotides[parseInt(j) + natom * i] = 1;
108722
+ }
108723
+ for(let j in waterOri) {
108724
+ ic.water[parseInt(j) + natom * i] = 1;
108725
+ }
108726
+ for(let j in ionsOri) {
108727
+ ic.ions[parseInt(j) + natom * i] = 1;
108728
+ }
108729
+ for(let j in chemicalsOri) {
108730
+ ic.chemicals[parseInt(j) + natom * i] = 1;
108731
+ }
108732
+
108733
+ // set ic.ncbi2resid and ic.resid2ncbi
108734
+ for(let chainid in chainsOri) {
108735
+ let idArray = chainid.split('_');
108736
+ let structure2 = idArray[0] + molNum;
108737
+ let chainid2 = structure2 + '_' + idArray[1];
108738
+
108739
+ for(let j = 0, jl = ic.chainsSeq[chainid].length; j < jl; ++j) {
108740
+ // NCBI residue number starts from 1 and increases continuously
108741
+ let residNCBI = chainid2 + '_' + (j+1).toString();
108742
+ let resid = chainid2 + '_' + ic.chainsSeq[chainid][j].resi;
108743
+ ic.ncbi2resid[residNCBI] = resid;
108744
+ ic.resid2ncbi[resid] = residNCBI;
108745
+ }
108746
+ }
108747
+ }
108748
+
108749
+ ic.molTitle = header.TITLE;
108750
+ ic.inputid = 'stru';
108751
+
108752
+ // ic.ParserUtilsCls.setMaxD();
108753
+
108754
+ ic.saveFileCls.showTitle();
108755
+
108756
+ return true;
108757
+ }
108758
+
108759
+ async showRmsdPlot() { let ic = this.icn3d, me = ic.icn3dui;
108760
+ if(ic.bChartjs === undefined) {
108761
+ let url = "https://cdn.jsdelivr.net/npm/chart.js";
108762
+ await me.getAjaxPromise(url, 'script');
108763
+
108764
+ ic.bChartjs = true;
108765
+ }
108766
+
108767
+ $("#" + me.rmsdplotid).empty();
108768
+ me.htmlCls.dialogCls.openDlg('dl_rmsdplot', 'RMSD Plot');
108769
+
108770
+ let dataSet = [];
108771
+ let structureArray = Object.keys(ic.structures);
108772
+ let coord1 = [], coord2 = [];
108773
+ for(let i = 0, il = structureArray.length; i < il; ++i) {
108774
+ let chainArray = ic.structures[structureArray[i]];
108775
+
108776
+ let coord = [];
108777
+ let nAtoms = 0;
108778
+ for(let j = 0, jl = chainArray.length; j < jl; ++j) {
108779
+ let chainid = chainArray[j];
108780
+ for(let k in ic.chains[chainid]) {
108781
+ let atom = ic.atoms[k];
108782
+ // only align proteins
108783
+ if(ic.proteins.hasOwnProperty(atom.serial)) {
108784
+ coord.push(atom.coord);
108785
+ ++nAtoms;
108786
+ }
108787
+ }
108788
+ }
108789
+
108790
+ if(i == 0) {
108791
+ coord1 = [].concat(coord);
108792
+ }
108793
+ else {
108794
+ coord2 = coord;
108795
+ }
108796
+
108797
+ if(i > 0) {
108798
+ let result = me.rmsdSuprCls.getRmsdSuprCls(coord1, coord2, nAtoms);
108799
+ let rmsd = (result.rmsd * 0.1).toPrecision(4); // convert from Å to nm
108800
+
108801
+ let time = ic.TIMEOFFSET + (i * ic.DELTA).toPrecision(4);
108802
+ dataSet.push({x: time, y: rmsd});
108803
+ }
108804
+ }
108805
+
108806
+ ic.mdDataSet = dataSet;
108807
+ if(me.bNode) console.log(dataSet);
108808
+
108809
+ let stepSize = (structureArray.length - 1) * ic.DELTA / 10; // 10 ticks
108810
+
108811
+ // https://www.chartjs.org/docs/latest/samples/line/line.html
108812
+ // const ctx = $("#" + me.rmsdplotid)[0].getContext('2d');
108813
+ const ctx = $("#" + me.rmsdplotid)[0];
108814
+
108815
+ new Chart(ctx, {
108816
+ type: 'line',
108817
+ data: {
108818
+ datasets: [{
108819
+ label: 'RMSD',
108820
+ data: dataSet
108821
+ }]
108822
+ },
108823
+ options: {
108824
+ responsive: true,
108825
+ scales: {
108826
+ x: { // X-axis configuration
108827
+ title: {
108828
+ display: true, // Show the X-axis label
108829
+ text: 'Time (ps)' // Text for the X-axis label
108830
+ },
108831
+ type: 'linear', // Required for numerical x-axis
108832
+ position: 'bottom',
108833
+ ticks: {
108834
+ stepSize: stepSize
108835
+ }
108836
+ },
108837
+ y: { // Y-axis configuration (defaults to numeric scale)
108838
+ title: {
108839
+ display: true, // Show the Y-axis label
108840
+ text: 'RMSD (nm)' // Text for the Y-axis label
108841
+ }
108842
+ }
108843
+ }
108844
+ }
108845
+ });
108846
+ }
108847
+ }
108848
+
108849
+ /**
108850
+ * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
108851
+ */
108852
+
108853
+ class XtcParser {
108854
+ constructor(icn3d) {
108855
+ this.icn3d = icn3d;
108856
+
108857
+ icn3d.DELTA = 1;
108858
+ icn3d.TIMEOFFSET = 0;
108859
+
108860
+ this.MagicInts = new Uint32Array([
108861
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 12, 16, 20, 25, 32, 40, 50, 64,
108862
+ 80, 101, 128, 161, 203, 256, 322, 406, 512, 645, 812, 1024, 1290,
108863
+ 1625, 2048, 2580, 3250, 4096, 5060, 6501, 8192, 10321, 13003,
108864
+ 16384, 20642, 26007, 32768, 41285, 52015, 65536, 82570, 104031,
108865
+ 131072, 165140, 208063, 262144, 330280, 416127, 524287, 660561,
108866
+ 832255, 1048576, 1321122, 1664510, 2097152, 2642245, 3329021,
108867
+ 4194304, 5284491, 6658042, 8388607, 10568983, 13316085, 16777216
108868
+ ]);
108869
+ this.FirstIdx = 9;
108870
+
108871
+ this._tmpBytes = new Uint8Array(32);
108872
+ let _buffer = new ArrayBuffer(8 * 3);
108873
+ this.buf = new Int32Array(_buffer);
108874
+ this.uint32view = new Uint32Array(_buffer);
108875
+ this.intBytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
108876
+ }
108877
+
108878
+ async loadXtcData(data) { let ic = this.icn3d, me = ic.icn3dui;
108879
+ let bResult = this.loadXtcAtomData(data);
108880
+
108881
+ if(me.cfg.align === undefined && Object.keys(ic.structures).length == 1) {
108882
+ $("#" + ic.pre + "alternateWrapper").hide();
108883
+ }
108884
+
108885
+ if(!bResult) {
108886
+ var aaa = 1; //alert('The XTC file has the wrong format...');
108887
+ }
108888
+ else {
108889
+ ic.setStyleCls.setAtomStyleByOptions(ic.opts);
108890
+ ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
108891
+
108892
+ // hide water, ions
108893
+ ic.dAtoms = me.hashUtilsCls.cloneHash(ic.proteins);
108894
+ ic.dAtoms = me.hashUtilsCls.unionHash(ic.dAtoms, ic.nucleotides);
108895
+ ic.dAtoms = me.hashUtilsCls.unionHash(ic.dAtoms, ic.chemicals);
108896
+ ic.hAtoms = me.hashUtilsCls.cloneHash(ic.dAtoms);
108897
+ ic.transformCls.zoominSelection();
108898
+
108899
+ // ic.bRender = true;
108900
+ await ic.ParserUtilsCls.renderStructure();
108901
+
108902
+ if(me.cfg.rotate !== undefined) ic.resizeCanvasCls.rotStruc(me.cfg.rotate, true);
108903
+
108904
+ //if(me.deferred !== undefined) me.deferred.resolve(); /// if(ic.deferred2 !== undefined) ic.deferred2.resolve();
108905
+ }
108906
+ }
108907
+
108908
+
108909
+ // modified from https://github.com/molstar/molstar/blob/master/src/mol-io/reader/xtc/parser.ts
108910
+ loadXtcAtomData(data) { let ic = this.icn3d, me = ic.icn3dui;
108911
+ // https://github.com/gromacs/gromacs/blob/master/src/gromacs/fileio/xtcio.cpp
108912
+ // https://github.com/gromacs/gromacs/blob/master/src/gromacs/fileio/libxdrf.cpp
108913
+
108914
+ let bin =(data.buffer && data.buffer instanceof ArrayBuffer) ? data.buffer : data;
108915
+
108916
+ // const dv = new DataView(bin, data.byteOffset);
108917
+ const dv = new DataView(bin);
108918
+
108919
+ data = new Uint8Array(bin);
108920
+
108921
+ // const f = {
108922
+ // frames: [],
108923
+ // boxes: [],
108924
+ // times: [],
108925
+ // timeOffset: 0,
108926
+ // deltaTime: 0
108927
+ // };
108928
+
108929
+ const coordinates = []; //f.frames;
108930
+ const times = []; //f.times;
108931
+
108932
+ const minMaxInt = [0, 0, 0, 0, 0, 0];
108933
+ const sizeint = [0, 0, 0];
108934
+ const bitsizeint = [0, 0, 0];
108935
+ const sizesmall = [0, 0, 0];
108936
+ const thiscoord = [0.1, 0.1, 0.1];
108937
+ const prevcoord = [0.1, 0.1, 0.1];
108938
+
108939
+ let offset = 0, natom;
108940
+
108941
+ while (true) {
108942
+ let frameCoords;
108943
+
108944
+ // const magicnum = dv.getInt32(offset)
108945
+ natom = dv.getInt32(offset + 4);
108946
+ // const step = dv.getInt32(offset + 8)
108947
+ offset += 12;
108948
+
108949
+ if(natom != Object.keys(ic.atoms).length) {
108950
+ var aaa = 1; //alert('The number of atoms in the XTC file does not match the number of atoms in the PDB file: ' + natom + ' != ' + Object.keys(ic.atoms).length);
108951
+ return false;
108952
+ }
108953
+
108954
+ times.push(dv.getFloat32(offset));
108955
+ offset += 4;
108956
+
108957
+ const box = new Float32Array(9);
108958
+ for (let i = 0; i < 9; ++i) {
108959
+ box[i] = dv.getFloat32(offset) * 10;
108960
+ offset += 4;
108961
+ }
108962
+
108963
+ if (natom <= 9) { // no compression
108964
+ frameCoords = { count: natom, x: new Float32Array(natom), y: new Float32Array(natom), z: new Float32Array(natom) };
108965
+ offset += 4;
108966
+ for (let i = 0; i < natom; ++i) {
108967
+ frameCoords.x[i] = dv.getFloat32(offset);
108968
+ frameCoords.y[i] = dv.getFloat32(offset + 4);
108969
+ frameCoords.z[i] = dv.getFloat32(offset + 8);
108970
+ offset += 12;
108971
+ }
108972
+ } else {
108973
+ this.buf[0] = this.buf[1] = this.buf[2] = 0;
108974
+ sizeint[0] = sizeint[1] = sizeint[2] = 0;
108975
+ sizesmall[0] = sizesmall[1] = sizesmall[2] = 0;
108976
+ bitsizeint[0] = bitsizeint[1] = bitsizeint[2] = 0;
108977
+ thiscoord[0] = thiscoord[1] = thiscoord[2] = 0;
108978
+ prevcoord[0] = prevcoord[1] = prevcoord[2] = 0;
108979
+
108980
+ frameCoords = { count: natom, x: new Float32Array(natom), y: new Float32Array(natom), z: new Float32Array(natom) };
108981
+ let lfp = 0;
108982
+
108983
+ const lsize = dv.getInt32(offset);
108984
+ offset += 4;
108985
+ const precision = dv.getFloat32(offset);
108986
+ offset += 4;
108987
+
108988
+ minMaxInt[0] = dv.getInt32(offset);
108989
+ minMaxInt[1] = dv.getInt32(offset + 4);
108990
+ minMaxInt[2] = dv.getInt32(offset + 8);
108991
+ minMaxInt[3] = dv.getInt32(offset + 12);
108992
+ minMaxInt[4] = dv.getInt32(offset + 16);
108993
+ minMaxInt[5] = dv.getInt32(offset + 20);
108994
+ sizeint[0] = minMaxInt[3] - minMaxInt[0] + 1;
108995
+ sizeint[1] = minMaxInt[4] - minMaxInt[1] + 1;
108996
+ sizeint[2] = minMaxInt[5] - minMaxInt[2] + 1;
108997
+ offset += 24;
108998
+
108999
+ let bitsize;
109000
+ if ((sizeint[0] | sizeint[1] | sizeint[2]) > 0xffffff) {
109001
+ bitsizeint[0] = this.sizeOfInt(sizeint[0]);
109002
+ bitsizeint[1] = this.sizeOfInt(sizeint[1]);
109003
+ bitsizeint[2] = this.sizeOfInt(sizeint[2]);
109004
+ bitsize = 0; // flag the use of large sizes
109005
+ } else {
109006
+ bitsize = this.sizeOfInts(3, sizeint);
109007
+ }
109008
+
109009
+ let smallidx = dv.getInt32(offset);
109010
+ offset += 4;
109011
+
109012
+ let tmpIdx = smallidx - 1;
109013
+ tmpIdx = (this.FirstIdx > tmpIdx) ? this.FirstIdx : tmpIdx;
109014
+ let smaller = (this.MagicInts[tmpIdx] / 2) | 0;
109015
+ let smallnum = (this.MagicInts[smallidx] / 2) | 0;
109016
+
109017
+ sizesmall[0] = sizesmall[1] = sizesmall[2] = this.MagicInts[smallidx];
109018
+
109019
+ const adz = Math.ceil(dv.getInt32(offset) / 4) * 4;
109020
+ offset += 4;
109021
+
109022
+ const invPrecision = 1.0 / precision;
109023
+ let run = 0;
109024
+ let i = 0;
109025
+
109026
+ // const this.buf8 = new Uint8Array(data.this.buffer, data.byteOffset + offset, 32 * 4); // 229...
109027
+
109028
+ thiscoord[0] = thiscoord[1] = thiscoord[2] = 0;
109029
+
109030
+ while (i < lsize) {
109031
+ if (bitsize === 0) {
109032
+ thiscoord[0] = this.decodeBits(data, offset, bitsizeint[0]);
109033
+ thiscoord[1] = this.decodeBits(data, offset, bitsizeint[1]);
109034
+ thiscoord[2] = this.decodeBits(data, offset, bitsizeint[2]);
109035
+ } else {
109036
+ this.decodeInts(data, offset, bitsize, sizeint, thiscoord);
109037
+ }
109038
+
109039
+ i++;
109040
+
109041
+ thiscoord[0] += minMaxInt[0];
109042
+ thiscoord[1] += minMaxInt[1];
109043
+ thiscoord[2] += minMaxInt[2];
109044
+
109045
+ prevcoord[0] = thiscoord[0];
109046
+ prevcoord[1] = thiscoord[1];
109047
+ prevcoord[2] = thiscoord[2];
109048
+
109049
+ const flag = this.decodeBits(data, offset, 1);
109050
+ let isSmaller = 0;
109051
+
109052
+ if (flag === 1) {
109053
+ run = this.decodeBits(data, offset, 5);
109054
+ isSmaller = run % 3;
109055
+ run -= isSmaller;
109056
+ isSmaller--;
109057
+ }
109058
+
109059
+ // if ((lfp-ptrstart)+run > size3){
109060
+ // fprintf(stderr, "(xdrfile error) Buffer overrun during decompression.\n");
109061
+ // return 0;
109062
+ // }
109063
+
109064
+ if (run > 0) {
109065
+ thiscoord[0] = thiscoord[1] = thiscoord[2] = 0;
109066
+
109067
+ for (let k = 0; k < run; k += 3) {
109068
+ this.decodeInts(data, offset, smallidx, sizesmall, thiscoord);
109069
+ i++;
109070
+
109071
+ thiscoord[0] += prevcoord[0] - smallnum;
109072
+ thiscoord[1] += prevcoord[1] - smallnum;
109073
+ thiscoord[2] += prevcoord[2] - smallnum;
109074
+
109075
+ if (k === 0) {
109076
+ // interchange first with second atom for
109077
+ // better compression of water molecules
109078
+ let tmpSwap = thiscoord[0];
109079
+ thiscoord[0] = prevcoord[0];
109080
+ prevcoord[0] = tmpSwap;
109081
+
109082
+ tmpSwap = thiscoord[1];
109083
+ thiscoord[1] = prevcoord[1];
109084
+ prevcoord[1] = tmpSwap;
109085
+
109086
+ tmpSwap = thiscoord[2];
109087
+ thiscoord[2] = prevcoord[2];
109088
+ prevcoord[2] = tmpSwap;
109089
+
109090
+ frameCoords.x[lfp] = prevcoord[0] * invPrecision;
109091
+ frameCoords.y[lfp] = prevcoord[1] * invPrecision;
109092
+ frameCoords.z[lfp] = prevcoord[2] * invPrecision;
109093
+ lfp++;
109094
+ } else {
109095
+ prevcoord[0] = thiscoord[0];
109096
+ prevcoord[1] = thiscoord[1];
109097
+ prevcoord[2] = thiscoord[2];
109098
+ }
109099
+ frameCoords.x[lfp] = thiscoord[0] * invPrecision;
109100
+ frameCoords.y[lfp] = thiscoord[1] * invPrecision;
109101
+ frameCoords.z[lfp] = thiscoord[2] * invPrecision;
109102
+ lfp++;
109103
+ }
109104
+ } else {
109105
+ frameCoords.x[lfp] = thiscoord[0] * invPrecision;
109106
+ frameCoords.y[lfp] = thiscoord[1] * invPrecision;
109107
+ frameCoords.z[lfp] = thiscoord[2] * invPrecision;
109108
+ lfp++;
109109
+ }
109110
+
109111
+ smallidx += isSmaller;
109112
+
109113
+ if (isSmaller < 0) {
109114
+ smallnum = smaller;
109115
+ if (smallidx > this.FirstIdx) {
109116
+ smaller = (this.MagicInts[smallidx - 1] / 2) | 0;
109117
+ } else {
109118
+ smaller = 0;
109119
+ }
109120
+ } else if (isSmaller > 0) {
109121
+ smaller = smallnum;
109122
+ smallnum = (this.MagicInts[smallidx] / 2) | 0;
109123
+ }
109124
+ sizesmall[0] = sizesmall[1] = sizesmall[2] = this.MagicInts[smallidx];
109125
+
109126
+ if (sizesmall[0] === 0 || sizesmall[1] === 0 || sizesmall[2] === 0) {
109127
+ undefinedError();
109128
+ }
109129
+ }
109130
+ offset += adz;
109131
+ }
109132
+
109133
+ let factor = 10;
109134
+ for (let c = 0; c < natom; c++) {
109135
+ frameCoords.x[c] *= factor;
109136
+ frameCoords.y[c] *= factor;
109137
+ frameCoords.z[c] *= factor;
109138
+ }
109139
+
109140
+ coordinates.push(frameCoords);
109141
+
109142
+ // if (ctx.shouldUpdate) {
109143
+ // await ctx.update({ current: offset, max: data.length });
109144
+ // }
109145
+
109146
+ // if (offset >= data.length) break;
109147
+ if (offset >= dv.byteLength) break;
109148
+ }
109149
+
109150
+ ic.frames = coordinates.length;
109151
+
109152
+ if (times.length >= 1) {
109153
+ ic.TIMEOFFSET = times[0];
109154
+ }
109155
+ if (times.length >= 2) {
109156
+ ic.DELTA = times[1] - times[0];
109157
+ }
109158
+
109159
+ // frames
109160
+ let structuresOri = me.hashUtilsCls.cloneHash(ic.structures);
109161
+ let residuesOri = me.hashUtilsCls.cloneHash(ic.residues);
109162
+ let chainsOri = me.hashUtilsCls.cloneHash(ic.chains);
109163
+
109164
+ let proteinsOri = me.hashUtilsCls.cloneHash(ic.proteins);
109165
+ let nucleotidesOri = me.hashUtilsCls.cloneHash(ic.nucleotides);
109166
+ let waterOri = me.hashUtilsCls.cloneHash(ic.water);
109167
+ let ionsOri = me.hashUtilsCls.cloneHash(ic.ions);
109168
+ let chemicalsOri = me.hashUtilsCls.cloneHash(ic.chemicals);
109169
+
109170
+ // let serial = natom + 1; // a preloaded PDB structure would have atom serial from 1 to natom
109171
+ let serial = 1;
109172
+
109173
+ for (let i = 0, n = coordinates.length; i < n; ++i) {
109174
+ // skip the first structure since it was read from PDB already
109175
+ // if(i == 0) continue;
109176
+
109177
+ // rewrite the coordinates of the first structure
109178
+ let frame = coordinates[i];
109179
+
109180
+ // let molNum = i + 1; // to avoid the same molNum as the PDB structure
109181
+ let molNum = (i == 0) ? '' : i;
109182
+ for(let j = 0; j < natom; ++j) {
109183
+ let coord = new Vector3$1(frame.x[j], frame.y[j], frame.z[j]);
109184
+ let atom = me.hashUtilsCls.cloneHash(ic.atoms[j + 1]);
109185
+
109186
+ atom.serial = serial;
109187
+ atom.structure = atom.structure + molNum;
109188
+ atom.coord = coord;
109189
+ atom.bonds = [].concat(ic.atoms[j + 1].bonds);
109190
+
109191
+ // update bonds
109192
+ for(let k = 0, kl = atom.bonds.length; k < kl; ++k) {
109193
+ atom.bonds[k] = parseInt(atom.bonds[k]) + natom * i;
109194
+ }
109195
+
109196
+ ic.atoms[serial] = atom;
109197
+
109198
+ // assign extra info
109199
+ ic.dAtoms[serial] = 1;
109200
+ ic.hAtoms[serial] = 1;
109201
+
109202
+ let chainid = atom.structure + '_' + atom.chain;
109203
+ let residid = chainid + '_' + atom.resi;
109204
+ ic.secondaries[residid] = atom.ss;
109205
+ ic.residueId2Name[residid] = me.utilsCls.residueName2Abbr(atom.resn);
109206
+
109207
+ ++serial;
109208
+ }
109209
+
109210
+ // update ic.structures, ic.residues and ic.chains
109211
+ for(let structure in structuresOri) {
109212
+ let structure2 = structure + molNum;
109213
+ ic.structures[structure2] = [];
109214
+
109215
+ for(let k = 0, kl = structuresOri[structure].length; k < kl; ++k) {
109216
+ let idArray = structuresOri[structure][k].split('_');
109217
+ ic.structures[structure2].push(structure2 + '_' + idArray[1]);
109218
+ }
109219
+ }
109220
+
109221
+ for(let j in residuesOri) {
109222
+ let idArray = j.split('_');
109223
+ let structure2 = idArray[0] + molNum;
109224
+ let residid2 = structure2 + '_' + idArray[1] + '_' + idArray[2];
109225
+ ic.residues[residid2] = {};
109226
+
109227
+ for(let k in residuesOri[j]) {
109228
+ ic.residues[residid2][parseInt(k) + natom * i] = 1;
109229
+ }
109230
+ }
109231
+
109232
+ for(let j in chainsOri) {
109233
+ let idArray = j.split('_');
109234
+ let structure2 = idArray[0] + molNum;
109235
+ let chainid2 = structure2 + '_' + idArray[1];
109236
+
109237
+ // ic.chainsSeq[chainid2] = [].concat(ic.chainsSeq[j]);
109238
+
109239
+ ic.chains[chainid2] = {};
109240
+ for(let k in chainsOri[j]) {
109241
+ ic.chains[chainid2][parseInt(k)+ natom * i] = 1;
109242
+ }
109243
+ }
109244
+
109245
+ // update ic.proteins, etc
109246
+ for(let j in proteinsOri) {
109247
+ ic.proteins[parseInt(j) + natom * i] = 1;
109248
+ }
109249
+ for(let j in nucleotidesOri) {
109250
+ ic.nucleotides[parseInt(j) + natom * i] = 1;
109251
+ }
109252
+ for(let j in waterOri) {
109253
+ ic.water[parseInt(j) + natom * i] = 1;
109254
+ }
109255
+ for(let j in ionsOri) {
109256
+ ic.ions[parseInt(j) + natom * i] = 1;
109257
+ }
109258
+ for(let j in chemicalsOri) {
109259
+ ic.chemicals[parseInt(j) + natom * i] = 1;
109260
+ }
109261
+
109262
+ // set ic.ncbi2resid and ic.resid2ncbi
109263
+ for(let chainid in chainsOri) {
109264
+ let idArray = chainid.split('_');
109265
+ let structure2 = idArray[0] + molNum;
109266
+ let chainid2 = structure2 + '_' + idArray[1];
109267
+
109268
+ for(let j = 0, jl = ic.chainsSeq[chainid].length; j < jl; ++j) {
109269
+ // NCBI residue number starts from 1 and increases continuously
109270
+ let residNCBI = chainid2 + '_' + (j+1).toString();
109271
+ let resid = chainid2 + '_' + ic.chainsSeq[chainid][j].resi;
109272
+ ic.ncbi2resid[residNCBI] = resid;
109273
+ ic.resid2ncbi[resid] = residNCBI;
109274
+ }
109275
+ }
109276
+ }
109277
+
109278
+ // ic.molTitle = header.TITLE;
109279
+ ic.inputid = 'stru';
109280
+
109281
+ // ic.ParserUtilsCls.setMaxD();
109282
+
109283
+ ic.saveFileCls.showTitle();
109284
+
109285
+ return true;
109286
+ }
109287
+
109288
+ sizeOfInt(size) { let ic = this.icn3d; ic.icn3dui;
109289
+ let num = 1;
109290
+ let numOfBits = 0;
109291
+ while (size >= num && numOfBits < 32) {
109292
+ numOfBits++;
109293
+ num <<= 1;
109294
+ }
109295
+ return numOfBits;
109296
+ }
109297
+
109298
+ sizeOfInts(numOfInts, sizes) { let ic = this.icn3d; ic.icn3dui;
109299
+ let numOfBytes = 1;
109300
+ let numOfBits = 0;
109301
+ this._tmpBytes[0] = 1;
109302
+ for (let i = 0; i < numOfInts; i++) {
109303
+ let bytecnt;
109304
+ let tmp = 0;
109305
+ for (bytecnt = 0; bytecnt < numOfBytes; bytecnt++) {
109306
+ tmp += this._tmpBytes[bytecnt] * sizes[i];
109307
+ this._tmpBytes[bytecnt] = tmp & 0xff;
109308
+ tmp >>= 8;
109309
+ }
109310
+ while (tmp !== 0) {
109311
+ this._tmpBytes[bytecnt++] = tmp & 0xff;
109312
+ tmp >>= 8;
109313
+ }
109314
+ numOfBytes = bytecnt;
109315
+ }
109316
+ let num = 1;
109317
+ numOfBytes--;
109318
+ while (this._tmpBytes[numOfBytes] >= num) {
109319
+ numOfBits++;
109320
+ num *= 2;
109321
+ }
109322
+ return numOfBits + numOfBytes * 8;
109323
+ }
109324
+
109325
+ decodeBits(cbuf, offset, numOfBits1) { let ic = this.icn3d; ic.icn3dui;
109326
+ let numOfBits = numOfBits1;
109327
+ const mask = (1 << numOfBits) - 1;
109328
+ let lastBB0 = this.uint32view[1];
109329
+ let lastBB1 = this.uint32view[2];
109330
+ let cnt = this.buf[0];
109331
+ let num = 0;
109332
+
109333
+ while (numOfBits >= 8) {
109334
+ lastBB1 = (lastBB1 << 8) | cbuf[offset + cnt++];
109335
+ num |= (lastBB1 >> lastBB0) << (numOfBits - 8);
109336
+ numOfBits -= 8;
109337
+ }
109338
+
109339
+ if (numOfBits > 0) {
109340
+ if (lastBB0 < numOfBits) {
109341
+ lastBB0 += 8;
109342
+ lastBB1 = (lastBB1 << 8) | cbuf[offset + cnt++];
109343
+ }
109344
+ lastBB0 -= numOfBits;
109345
+ num |= (lastBB1 >> lastBB0) & ((1 << numOfBits) - 1);
109346
+ }
109347
+
109348
+ num &= mask;
109349
+ this.buf[0] = cnt;
109350
+ this.buf[1] = lastBB0;
109351
+ this.buf[2] = lastBB1;
109352
+
109353
+ return num;
109354
+ }
109355
+
109356
+ decodeByte(cbuf, offset) { let ic = this.icn3d; ic.icn3dui;
109357
+ // special version of decodeBits with numOfBits = 8
109358
+
109359
+ // const mask = 0xff; // (1 << 8) - 1;
109360
+ // let lastBB0 = uint32view[1];
109361
+ let lastBB1 = this.uint32view[2];
109362
+ const cnt = this.buf[0];
109363
+
109364
+ lastBB1 = (lastBB1 << 8) | cbuf[offset + cnt];
109365
+
109366
+ this.buf[0] = cnt + 1;
109367
+ // this.buf[1] = lastBB0;
109368
+ this.buf[2] = lastBB1;
109369
+
109370
+ return (lastBB1 >> this.uint32view[1]) & 0xff;
109371
+ }
109372
+
109373
+ decodeInts(cbuf, offset, numOfBits1, sizes, nums) { let ic = this.icn3d; ic.icn3dui;
109374
+ let numOfBits = numOfBits1;
109375
+ let numOfBytes = 0;
109376
+
109377
+ this.intBytes[0] = 0;
109378
+ this.intBytes[1] = 0;
109379
+ this.intBytes[2] = 0;
109380
+ this.intBytes[3] = 0;
109381
+
109382
+ while (numOfBits > 8) {
109383
+ // this is inversed??? why??? because of the endiannness???
109384
+ this.intBytes[numOfBytes++] = this.decodeByte(cbuf, offset);
109385
+ numOfBits -= 8;
109386
+ }
109387
+
109388
+ if (numOfBits > 0) {
109389
+ this.intBytes[numOfBytes++] = this.decodeBits(cbuf, offset, numOfBits);
109390
+ }
109391
+
109392
+ for (let i = 2; i > 0; i--) {
109393
+ let num = 0;
109394
+ const s = sizes[i];
109395
+ for (let j = numOfBytes - 1; j >= 0; j--) {
109396
+ num = (num << 8) | this.intBytes[j];
109397
+ const t = (num / s) | 0;
109398
+ this.intBytes[j] = t;
109399
+ num = num - t * s;
109400
+ }
109401
+ nums[i] = num;
109402
+ }
109403
+ nums[0] = this.intBytes[0] | (this.intBytes[1] << 8) | (this.intBytes[2] << 16) | (this.intBytes[3] << 24);
109404
+ }
109405
+ }
109406
+
108121
109407
  /**
108122
109408
  * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
108123
109409
  */
@@ -114012,7 +115298,15 @@ class LoadPDB {
114012
115298
  prevCarbonArray.push(atom);
114013
115299
  }
114014
115300
 
114015
- if(!atom.het) {
115301
+ if(atom.resn === 'HOH' || atom.resn === 'WAT' || atom.resn === 'SOL') {
115302
+ ic.water[atom.serial] = 1;
115303
+ atom.color = me.parasCls.atomColors[atom.elem];
115304
+ }
115305
+ else if($.inArray(atom.resn.trim(), me.parasCls.ionsArray) !== -1 || atom.elem.trim() === atom.resn.trim()) {
115306
+ ic.ions[atom.serial] = 1;
115307
+ atom.color = me.parasCls.atomColors[atom.elem];
115308
+ }
115309
+ else if(!atom.het) {
114016
115310
  if($.inArray(atom.resn, me.parasCls.nucleotidesArray) !== -1) {
114017
115311
  ic.nucleotides[atom.serial] = 1;
114018
115312
  //if (atom.name === 'P') {
@@ -114037,19 +115331,7 @@ class LoadPDB {
114037
115331
  }
114038
115332
  }
114039
115333
  else if(atom.het) {
114040
- if(atom.resn === 'HOH' || atom.resn === 'WAT' || atom.resn === 'SOL') {
114041
- ic.water[atom.serial] = 1;
114042
- }
114043
- //else if(bOpm && atom.resn === 'DUM') {
114044
- // ic.mem[atom.serial] = 1;
114045
- //}
114046
- else if($.inArray(atom.resn, me.parasCls.ionsArray) !== -1 || atom.elem.trim() === atom.resn.trim()) {
114047
- ic.ions[atom.serial] = 1;
114048
- }
114049
- else {
114050
- ic.chemicals[atom.serial] = 1;
114051
- }
114052
-
115334
+ ic.chemicals[atom.serial] = 1;
114053
115335
  atom.color = me.parasCls.atomColors[atom.elem];
114054
115336
  }
114055
115337
 
@@ -116847,6 +118129,18 @@ class ApplyCommand {
116847
118129
  ic.analysisCls.addLine(parseFloat(p1Array[1]), parseFloat(p1Array[3]), parseFloat(p1Array[5]), parseFloat(p2Array[1]), parseFloat(p2Array[3]), parseFloat(p2Array[5]), color, dashed, type, parseFloat(radius), parseFloat(opacity));
116848
118130
  ic.drawCls.draw();
116849
118131
  }
118132
+ else if(command.indexOf('add plane') == 0) {
118133
+ let paraArray = command.split(' | ');
118134
+ let p1Array = paraArray[1].split(' ');
118135
+ let p2Array = paraArray[2].split(' ');
118136
+ let p3Array = paraArray[3].split(' ');
118137
+ let color = paraArray[4].substr(paraArray[4].lastIndexOf(' ') + 1);
118138
+ let thickness = (paraArray.length > 5) ? paraArray[5].substr(paraArray[5].lastIndexOf(' ') + 1) : 2;
118139
+ let opacity = (paraArray.length > 6) ? paraArray[6].substr(paraArray[6].lastIndexOf(' ') + 1) : 0.3;
118140
+
118141
+ ic.analysisCls.addPlane(parseFloat(p1Array[1]), parseFloat(p1Array[3]), parseFloat(p1Array[5]), parseFloat(p2Array[1]), parseFloat(p2Array[3]), parseFloat(p2Array[5]), parseFloat(p3Array[1]), parseFloat(p3Array[3]), parseFloat(p3Array[5]), color, parseFloat(thickness), parseFloat(opacity));
118142
+ ic.drawCls.draw();
118143
+ }
116850
118144
  else if(command.indexOf('add sphere') == 0) {
116851
118145
  this.addShape(commandOri, 'sphere');
116852
118146
  ic.shapeCmdHash[commandOri] = 1;
@@ -116865,6 +118159,10 @@ class ApplyCommand {
116865
118159
  ic.lines['cylinder'] = []; // reset
116866
118160
  //ic.drawCls.draw();
116867
118161
  }
118162
+ else if(command.indexOf('clear plane among sets') == 0) {
118163
+ ic.planes = []; // reset
118164
+ //ic.drawCls.draw();
118165
+ }
116868
118166
  else if(commandOri.indexOf('add label') == 0) {
116869
118167
  let paraArray = commandOri.split(' | ');
116870
118168
  let text = paraArray[0].substr(('add label').length + 1);
@@ -125618,6 +126916,21 @@ class Analysis {
125618
126916
  //ic.drawCls.draw();
125619
126917
  }
125620
126918
 
126919
+ //Add a plane among the positions (x1, y1, z1), (x2, y2, z2) and (x3, y3, z3) with the input "color".
126920
+ addPlane(x1, y1, z1, x2, y2, z2, x3, y3, z3, color, thickness, opacity) {var ic = this.icn3d; ic.icn3dui;
126921
+ let plane = {}; // Each plane contains 'position1', 'position2', 'position3', 'color', and 'thickness'
126922
+ plane.position1 = new Vector3$1(x1, y1, z1);
126923
+ plane.position2 = new Vector3$1(x2, y2, z2);
126924
+ plane.position3 = new Vector3$1(x3, y3, z3);
126925
+ plane.color = color;
126926
+ plane.thickness = thickness;
126927
+ plane.opacity = opacity;
126928
+ if(ic.planes === undefined) ic.planes = [];
126929
+ ic.planes.push(plane);
126930
+
126931
+ ic.hlObjectsCls.removeHlObjects();
126932
+ }
126933
+
125621
126934
  addLineFromPicking(type) {var ic = this.icn3d, me = ic.icn3dui;
125622
126935
  let color = $("#" + ic.pre + type + "color" ).val();
125623
126936
  (ic.pAtom.coord.x + ic.pAtom2.coord.x) / 2;
@@ -129404,12 +130717,13 @@ class SaveFile {
129404
130717
  let structureArray = Object.keys(me.utilsCls.getStructures(ic.dAtoms));
129405
130718
 
129406
130719
  if(structureArray.length > 1) {
129407
- title = 'Multiple structures: ';
129408
- for(let i = 0, il = structureArray.length; i < il; ++i) {
130720
+ title = structureArray.length + ' structures: ';
130721
+ for(let i = 0, il = structureArray.length; i < il && i < 5; ++i) {
129409
130722
  let url = (isNaN(structureArray[i]) && structureArray[i].length > 5) ? 'https://alphafold.ebi.ac.uk/entry/' + structureArray[i] : 'https://www.ncbi.nlm.nih.gov/structure/?term=' + structureArray[i];
129410
130723
  title += '<a href="' + url + '" style="color:' + titlelinkColor + '" target="_blank">' + structureArray[i] + '</a>';
129411
130724
  if(i < il - 1) title += ', ';
129412
130725
  }
130726
+ if(structureArray.length > 5) title += '...';
129413
130727
  $("#" + ic.pre + "title").html(title);
129414
130728
  }
129415
130729
  else if(structureArray.length == 1) {
@@ -131200,12 +132514,11 @@ class Control {
131200
132514
  ic.transformCls.setRotation(axis, angle);
131201
132515
  }
131202
132516
 
131203
- else if(e.keyCode === 65 ) { // A, alternate
132517
+ else if(e.keyCode === 65 ) { // A, alternate forward
131204
132518
  if(Object.keys(ic.structures).length > 1) {
131205
132519
  await ic.alternateCls.alternateWrapper();
131206
132520
  }
131207
132521
  }
131208
-
131209
132522
  }
131210
132523
  });
131211
132524
 
@@ -132655,6 +133968,8 @@ class iCn3D {
132655
133968
  this.pdbParserCls = new PdbParser(this);
132656
133969
  this.sdfParserCls = new SdfParser(this);
132657
133970
  this.xyzParserCls = new XyzParser(this);
133971
+ this.dcdParserCls = new DcdParser(this);
133972
+ this.xtcParserCls = new XtcParser(this);
132658
133973
  this.msaParserCls = new MsaParser(this);
132659
133974
  this.realignParserCls = new RealignParser(this);
132660
133975
  this.densityCifParserCls = new DensityCifParser(this);
@@ -132912,7 +134227,7 @@ class iCn3DUI {
132912
134227
  //even when multiple iCn3D viewers are shown together.
132913
134228
  this.pre = this.cfg.divid + "_";
132914
134229
 
132915
- this.REVISION = '3.46.0';
134230
+ this.REVISION = '3.47.0';
132916
134231
 
132917
134232
  // In nodejs, iCn3D defines "window = {navigator: {}}", and added window = {navigator: {}, "__THREE__":"177"}
132918
134233
  this.bNode = (Object.keys(window).length < 3) ? true : false;
@@ -133709,6 +135024,7 @@ exports.ConvertTypeCls = ConvertTypeCls;
133709
135024
  exports.Curve = Curve;
133710
135025
  exports.CurveStripArrow = CurveStripArrow;
133711
135026
  exports.Cylinder = Cylinder;
135027
+ exports.DcdParser = DcdParser;
133712
135028
  exports.DefinedSets = DefinedSets;
133713
135029
  exports.Delphi = Delphi;
133714
135030
  exports.DensityCifParser = DensityCifParser;
@@ -133794,6 +135110,7 @@ exports.UtilsCls = UtilsCls;
133794
135110
  exports.VRButton = VRButton;
133795
135111
  exports.Vastplus = Vastplus;
133796
135112
  exports.ViewInterPairs = ViewInterPairs;
135113
+ exports.XtcParser = XtcParser;
133797
135114
  exports.XyzParser = XyzParser;
133798
135115
  exports.iCn3D = iCn3D;
133799
135116
  exports.iCn3DUI = iCn3DUI;