icn3d 3.46.1 → 3.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/icn3d.module.js CHANGED
@@ -56271,6 +56271,8 @@ class RmsdSuprCls {
56271
56271
  supr = undefined;
56272
56272
  }
56273
56273
 
56274
+ if(me.bNode) console.log("RMSD: " + supr);
56275
+
56274
56276
  return {'rot': rot, 'trans1': xc1, 'trans2': xc2, 'rmsd': supr};
56275
56277
 
56276
56278
  }; // end rmsd_supr
@@ -57066,11 +57068,12 @@ class ClickMenu {
57066
57068
  }
57067
57069
  }
57068
57070
 
57069
- setSetsMenus(id, bOneset) { let me = this.icn3dui, ic = me.icn3d;
57071
+ setSetsMenus(id, bOneset, bThreeset) { let me = this.icn3dui, ic = me.icn3d;
57070
57072
  this.SetChainsAdvancedMenu();
57071
57073
 
57072
57074
  let id1 = id;
57073
57075
  let id2 = id + '2';
57076
+ let id3 = id + '3';
57074
57077
 
57075
57078
  let definedAtomsHtml = ic.definedSetsCls.setAtomMenu(['protein']);
57076
57079
  if($("#" + me.pre + id1).length) {
@@ -57079,9 +57082,13 @@ class ClickMenu {
57079
57082
  if(!bOneset && $("#" + me.pre + id2).length) {
57080
57083
  $("#" + me.pre + id2).html(" <option value='selected' selected>selected</option>" + definedAtomsHtml);
57081
57084
  }
57085
+ if(bThreeset && $("#" + me.pre + id3).length) {
57086
+ $("#" + me.pre + id3).html(" <option value='selected' selected>selected</option>" + definedAtomsHtml);
57087
+ }
57082
57088
 
57083
57089
  $("#" + me.pre + id1).resizable();
57084
57090
  if(!bOneset) $("#" + me.pre + id2).resizable();
57091
+ if(bThreeset) $("#" + me.pre + id3).resizable();
57085
57092
  }
57086
57093
 
57087
57094
  applyShownMenus(bNoSave) { let me = this.icn3dui; me.icn3d;
@@ -57298,27 +57305,31 @@ class ClickMenu {
57298
57305
 
57299
57306
  me.myEventCls.onIds("#" + me.pre + "mn1_pdbfile", "click", function(e) { me.icn3d; //e.preventDefault();
57300
57307
  //me = me.setIcn3dui($(this).attr('id'));
57301
- me.htmlCls.dialogCls.openDlg('dl_pdbfile', 'Please input PDB File');
57308
+ me.htmlCls.dialogCls.openDlg('dl_pdbfile', 'Please input PDB file');
57302
57309
  });
57303
57310
  me.myEventCls.onIds(["#" + me.pre + "mn1_pdbfile_app", "#" + me.pre + "tool_pdbfile"], "click", function(e) { me.icn3d; //e.preventDefault();
57304
57311
  //me = me.setIcn3dui($(this).attr('id'));
57305
- me.htmlCls.dialogCls.openDlg('dl_pdbfile_app', 'Please append PDB Files');
57312
+ me.htmlCls.dialogCls.openDlg('dl_pdbfile_app', 'Please append PDB files');
57306
57313
  });
57307
57314
 
57308
57315
  me.myEventCls.onIds("#" + me.pre + "mn1_mol2file", "click", function(e) { me.icn3d; //e.preventDefault();
57309
- me.htmlCls.dialogCls.openDlg('dl_mol2file', 'Please input Mol2 File');
57316
+ me.htmlCls.dialogCls.openDlg('dl_mol2file', 'Please input Mol2 file');
57310
57317
  });
57311
57318
 
57312
57319
  me.myEventCls.onIds("#" + me.pre + "mn1_sdffile", "click", function(e) { me.icn3d; //e.preventDefault();
57313
- me.htmlCls.dialogCls.openDlg('dl_sdffile', 'Please input SDF File');
57320
+ me.htmlCls.dialogCls.openDlg('dl_sdffile', 'Please input SDF file');
57314
57321
  });
57315
57322
 
57316
57323
  me.myEventCls.onIds("#" + me.pre + "mn1_xyzfile", "click", function(e) { me.icn3d; //e.preventDefault();
57317
- me.htmlCls.dialogCls.openDlg('dl_xyzfile', 'Please input XYZ File');
57324
+ me.htmlCls.dialogCls.openDlg('dl_xyzfile', 'Please input XYZ file');
57325
+ });
57326
+
57327
+ me.myEventCls.onIds("#" + me.pre + "mn1_dcdfile", "click", function(e) { me.icn3d; //e.preventDefault();
57328
+ me.htmlCls.dialogCls.openDlg('dl_dcdfile', 'Please input MD trajectory file');
57318
57329
  });
57319
57330
 
57320
57331
  me.myEventCls.onIds("#" + me.pre + "mn1_afmapfile", "click", function(e) { me.icn3d; //e.preventDefault();
57321
- me.htmlCls.dialogCls.openDlg('dl_afmapfile', 'Please input AlphaFold PAE File');
57332
+ me.htmlCls.dialogCls.openDlg('dl_afmapfile', 'Please input AlphaFold PAE file');
57322
57333
  });
57323
57334
 
57324
57335
  me.myEventCls.onIds("#" + me.pre + "mn1_urlfile", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -57326,11 +57337,11 @@ class ClickMenu {
57326
57337
  });
57327
57338
 
57328
57339
  me.myEventCls.onIds("#" + me.pre + "mn1_clustalwfile", "click", function(e) { me.icn3d; //e.preventDefault();
57329
- me.htmlCls.dialogCls.openDlg('dl_clustalwfile', 'Please input CLUSTALW MSA File');
57340
+ me.htmlCls.dialogCls.openDlg('dl_clustalwfile', 'Please input CLUSTALW MSA file');
57330
57341
  });
57331
57342
 
57332
57343
  me.myEventCls.onIds("#" + me.pre + "mn1_fastafile", "click", function(e) { me.icn3d; //e.preventDefault();
57333
- me.htmlCls.dialogCls.openDlg('dl_fastafile', 'Please input FASTA MSA File');
57344
+ me.htmlCls.dialogCls.openDlg('dl_fastafile', 'Please input FASTA MSA file');
57334
57345
  });
57335
57346
 
57336
57347
  me.myEventCls.onIds("#" + me.pre + "mn1_fixedversion", "click", function(e) { me.icn3d; //e.preventDefault();
@@ -59204,6 +59215,13 @@ class ClickMenu {
59204
59215
  ic.bLinebtwsets = true;
59205
59216
  });
59206
59217
 
59218
+ me.myEventCls.onIds("#" + me.pre + "mn5_plane3sets", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
59219
+ me.htmlCls.dialogCls.openDlg('dl_plane3sets', 'Draw a plane among three sets');
59220
+
59221
+ thisClass.setSetsMenus('plane3sets', undefined, true);
59222
+
59223
+ ic.bPlane3sets = true;
59224
+ });
59207
59225
 
59208
59226
  me.myEventCls.onIds(["#" + me.pre + "mn2_selectedcenter", "#" + me.pre + "zoomin_selection", "#" + me.pre + "tool_selectedcenter"], "click", function(e) { let ic = me.icn3d; //e.preventDefault();
59209
59227
  //thisClass.setLogCmd('zoom selection', true);
@@ -60292,6 +60310,7 @@ class SetMenu {
60292
60310
  html += this.getLink('mn1_mol2file', 'Mol2 File', undefined, 2);
60293
60311
  html += this.getLink('mn1_sdffile', 'SDF File', undefined, 2);
60294
60312
  html += this.getLink('mn1_xyzfile', 'XYZ File', undefined, 2);
60313
+ html += this.getLink('mn1_dcdfile', 'MD Trajectory File', undefined, 2);
60295
60314
 
60296
60315
  html += this.getMenuSep();
60297
60316
 
@@ -60925,6 +60944,7 @@ class SetMenu {
60925
60944
 
60926
60945
  html += this.getLink('mn5_cartoonshape', 'Cartoon for a Set', undefined, 1);
60927
60946
  html += this.getLink('mn5_linebtwsets', 'Line btw. Two Sets', undefined, 1);
60947
+ html += this.getLink('mn5_plane3sets', 'Plane among 3 Sets', undefined, 1);
60928
60948
 
60929
60949
  if(me.cfg.cid === undefined && me.cfg.align === undefined && me.cfg.chainalign === undefined && me.cfg.mmdbaf === undefined) {
60930
60950
  html += this.getMenuSep();
@@ -61795,6 +61815,7 @@ class Dialog {
61795
61815
  let bGraph = $('#' + me.pre + 'dl_graph').hasClass('ui-dialog-content'); // initialized
61796
61816
  let bLineGraph = $('#' + me.pre + 'dl_linegraph').hasClass('ui-dialog-content'); // initialized
61797
61817
  let bScatterplot = $('#' + me.pre + 'dl_scatterplot').hasClass('ui-dialog-content'); // initialized
61818
+ let bRmsdplot = $('#' + me.pre + 'dl_rmsdplot').hasClass('ui-dialog-content'); // initialized
61798
61819
  let bLigplot = $('#' + me.pre + 'dl_ligplot').hasClass('ui-dialog-content'); // initialized
61799
61820
  let bContactmap = $('#' + me.pre + 'dl_contactmap').hasClass('ui-dialog-content'); // initialized
61800
61821
  let bAlignerrormap = $('#' + me.pre + 'dl_alignerrormap').hasClass('ui-dialog-content'); // initialized
@@ -61812,6 +61833,7 @@ class Dialog {
61812
61833
  id2flag.dl_graph = 'bGraph2';
61813
61834
  id2flag.dl_linegraph = 'bLineGraph2';
61814
61835
  id2flag.dl_scatterplot = 'bScatterplot2';
61836
+ id2flag.dl_rmsdplot = 'bRmsdplot2';
61815
61837
  id2flag.dl_ligplot = 'bLigplot2';
61816
61838
  id2flag.dl_contactmap = 'bContactmap2';
61817
61839
  id2flag.dl_alignerrormap = 'bAlignerrormap2';
@@ -61825,6 +61847,7 @@ class Dialog {
61825
61847
  if(bGraph) status.bGraph2 = $('#' + me.pre + 'dl_graph').dialog( 'isOpen' );
61826
61848
  if(bLineGraph) status.bLineGraph2 = $('#' + me.pre + 'dl_linegraph').dialog( 'isOpen' );
61827
61849
  if(bScatterplot) status.bScatterplot2 = $('#' + me.pre + 'dl_scatterplot').dialog( 'isOpen' );
61850
+ if(bRmsdplot) status.bRmsdplot2 = $('#' + me.pre + 'dl_rmsdplot').dialog( 'isOpen' );
61828
61851
  if(bLigplot) status.bLigplot2 = $('#' + me.pre + 'dl_ligplot').dialog( 'isOpen' );
61829
61852
  if(bContactmap) status.bContactmap2 = $('#' + me.pre + 'dl_contactmap').dialog( 'isOpen' );
61830
61853
  if(bAlignerrormap) status.bAlignerror2 = $('#' + me.pre + 'dl_alignerrormap').dialog( 'isOpen' );
@@ -62014,7 +62037,7 @@ class Dialog {
62014
62037
 
62015
62038
  let status = this.getDialogStatus().status;
62016
62039
 
62017
- 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') {
62040
+ 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') {
62018
62041
  //var dialogWidth = 0.5 *(me.htmlCls.WIDTH - me.htmlCls.LESSWIDTH) - twoddgmWidth * 0.5;
62019
62042
  let dialogWidth = 0.5 *(me.htmlCls.WIDTH) - twoddgmWidth * 0.5;
62020
62043
 
@@ -62240,7 +62263,7 @@ class Dialog {
62240
62263
  let width = 400, height = 150;
62241
62264
  let twoddgmWidth = me.htmlCls.width2d + 20;
62242
62265
 
62243
- 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') {
62266
+ 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') {
62244
62267
  $( "#" + id ).show();
62245
62268
  $( "#" + id + "_nb").show();
62246
62269
  $( "#" + id + "_title").html(title);
@@ -62671,6 +62694,23 @@ class SetDialog {
62671
62694
  html += me.htmlCls.buttonStr + "reload_xyzfile'>Load</button>";
62672
62695
  html += "</div>";
62673
62696
 
62697
+ html += me.htmlCls.divStr + "dl_dcdfile' class='" + dialogClass + "'>";
62698
+ html += this.addNotebookTitle('dl_dcdfile', 'Please input an MD trajectory file');
62699
+ html += "Step 1. <b>PDB File</b>: " + me.htmlCls.inputFileStr + "id='" + me.pre + "dcdpdbfile' size=8> ";
62700
+ html += me.htmlCls.buttonStr + "reload_dcdpdbfile'>Load PDB File</button><br><br>";
62701
+
62702
+ html += "Step 2. <b>DCD File</b>: " + me.htmlCls.inputFileStr + "id='" + me.pre + "dcdfile' size=8> ";
62703
+ html += me.htmlCls.buttonStr + "reload_dcdfile'>Load DCD File</button><br>";
62704
+
62705
+ html += "or <b>XTC File</b>: " + me.htmlCls.inputFileStr + "id='" + me.pre + "xtcfile' size=8> ";
62706
+ html += me.htmlCls.buttonStr + "reload_xtcfile' style='margin-left:28px'>Load XTC File</button><br><br>";
62707
+
62708
+ html += "<hr><br>";
62709
+ html += "<b>Analysis</b>: " + me.htmlCls.buttonStr + "rmsd_plot'>RMSD Plot</button><br><br>";
62710
+ 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>";
62711
+
62712
+ html += "</div>";
62713
+
62674
62714
  html += me.htmlCls.divStr + "dl_clustalwfile' class='" + dialogClass + "' style='max-width:500px'>";
62675
62715
  html += this.addNotebookTitle('dl_clustalwfile', 'Please input a CLUSTALW MSA file');
62676
62716
  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>";
@@ -63201,6 +63241,15 @@ class SetDialog {
63201
63241
 
63202
63242
  html += "</div>";
63203
63243
 
63244
+ html += me.htmlCls.divStr + "dl_rmsdplot' style='background-color:white' class='" + dialogClass + "'>";
63245
+ html += this.addNotebookTitle('dl_rmsdplot', 'RMSD Plot');
63246
+
63247
+ me.rmsdplotid = me.pre + 'rmsdplot';
63248
+ html += me.htmlCls.divNowrapStr + buttonStrTmp + me.rmsdplotid + '_json">JSON</button>' + me.htmlCls.space2 + " The image below can be saved via right click.<br></div>";
63249
+
63250
+ html += '<canvas id="' + me.rmsdplotid + '"></canvas>';
63251
+
63252
+ html += "</div>";
63204
63253
 
63205
63254
  html += me.htmlCls.divStr + "dl_ligplot' style='background-color:white' class='" + dialogClass + "'>";
63206
63255
 
@@ -63458,6 +63507,42 @@ class SetDialog {
63458
63507
  html += "</div>";
63459
63508
 
63460
63509
 
63510
+ html += me.htmlCls.divStr + "dl_plane3sets' class='" + dialogClass + "'>";
63511
+ html += this.addNotebookTitle('dl_plane3sets', 'Add a plane among three sets');
63512
+ html += me.htmlCls.spanNowrapStr + "1. Select three sets</span><br/>";
63513
+ html += "<table border=0 width=400 cellspacing=10><tr><td>";
63514
+
63515
+ html += me.htmlCls.divNowrapStr + "First set:</div>";
63516
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "plane3sets' multiple size='5' style='min-width:130px;'>";
63517
+ html += "</select></div>";
63518
+
63519
+ html += "</td><td>";
63520
+
63521
+ html += me.htmlCls.divNowrapStr + "Second set:</div>";
63522
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "plane3sets2' multiple size='5' style='min-width:130px;'>";
63523
+ html += "</select></div>";
63524
+
63525
+ html += "</td><td>";
63526
+
63527
+ html += me.htmlCls.divNowrapStr + "Third set:</div>";
63528
+ html += "<div style='text-indent:1.1em'><select style='max-width:200px' id='" + me.pre + "plane3sets3' multiple size='5' style='min-width:130px;'>";
63529
+ html += "</select></div>";
63530
+
63531
+ html += "</td></tr></table>";
63532
+
63533
+ html += "2. Thickness (&#197;): " + me.htmlCls.inputTextStr + "id='" + me.pre + "plane3sets_thickness' value='2' size=4><br/><br/>";
63534
+
63535
+ html += "3. Color: " + me.htmlCls.inputTextStr + "id='" + me.pre + "plane3sets_customcolor' value='" + defaultColor + "' size=4><br/><br/>";
63536
+
63537
+ html += me.htmlCls.divNowrapStr + "4. Opacity: <select id='" + me.pre + "plane3sets_opacity'>";
63538
+ 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);
63539
+ html += "</select></div><br>";
63540
+
63541
+ html += me.htmlCls.spanNowrapStr + "5. " + me.htmlCls.buttonStr + "applyplane3sets'>Display</button></span>";
63542
+ html += me.htmlCls.space3 + me.htmlCls.spanNowrapStr + me.htmlCls.buttonStr + "clearplane3sets'>Clear</button></span>";
63543
+ html += "</div>";
63544
+
63545
+
63461
63546
  html += me.htmlCls.divStr + "dl_cartoonshape' class='" + dialogClass + "'>";
63462
63547
  html += this.addNotebookTitle('dl_cartoonshape', 'Cartoon Shape');
63463
63548
  html += me.htmlCls.spanNowrapStr + "1. Select a set:</span><br/>";
@@ -64174,10 +64259,10 @@ class Events {
64174
64259
  }
64175
64260
  }
64176
64261
 
64177
- async loadPdbFile(bAppend, fileId, bmmCIF) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
64262
+ async loadPdbFile(bAppend, fileId, bmmCIF, bOpenDialog) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
64178
64263
  //me = ic.setIcn3dui(this.id);
64179
64264
  ic.bInitial = true;
64180
- thisClass.iniFileLoad();
64265
+ if(!bOpenDialog) thisClass.iniFileLoad();
64181
64266
  let files = $("#" + me.pre + fileId)[0].files;
64182
64267
  if(!files[0]) {
64183
64268
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
@@ -64495,7 +64580,7 @@ class Events {
64495
64580
 
64496
64581
  me.myEventCls.onIds(["#" + me.pre + "alternate", "#" + me.pre + "mn2_alternate", "#" + me.pre + "alternate2"], "click", async function(e) { let ic = me.icn3d;
64497
64582
  ic.bAlternate = true;
64498
- await ic.alternateCls.alternateStructures();
64583
+ ic.alternateCls.alternateStructures();
64499
64584
  ic.bAlternate = false;
64500
64585
 
64501
64586
  thisClass.setLogCmd("alternate structures", false);
@@ -65417,14 +65502,53 @@ class Events {
65417
65502
 
65418
65503
  // Start recording
65419
65504
  ic.videoRecorder.start();
65420
- thisClass.setLogCmd('Video revording started', false);
65505
+ thisClass.setLogCmd('Video recording started', false);
65421
65506
  });
65422
65507
 
65423
65508
  me.myEventCls.onIds("#" + me.pre + "video_end", "click", function(e) { let ic = me.icn3d;
65424
65509
  e.preventDefault();
65425
65510
 
65426
65511
  ic.videoRecorder.stop();
65427
- thisClass.setLogCmd('Video revording ended', false);
65512
+ thisClass.setLogCmd('Video recording ended', false);
65513
+ });
65514
+
65515
+ me.myEventCls.onIds("#" + me.pre + "video_frame", "click", function(e) { let ic = me.icn3d;
65516
+ e.preventDefault();
65517
+
65518
+ let fps = $("#" + me.pre + "videofps").val();
65519
+ let interval = 1000 / fps; // ms
65520
+ let duratinon = (ic.frames + 3) * interval; // make the video a little longer than the number of frames
65521
+
65522
+ const canvas = document.getElementById(ic.pre + "canvas");
65523
+ // ic.videoFrameRecorder = new MediaRecorder(canvas.captureStream(fps));
65524
+ ic.videoFrameRecorder = new MediaRecorder(canvas.captureStream());
65525
+ const recordedChunks = [];
65526
+
65527
+ // Collect data chunks
65528
+ ic.videoFrameRecorder.ondataavailable = event => {
65529
+ recordedChunks.push(event.data);
65530
+ };
65531
+
65532
+ ic.videoFrameRecorder.onstop = event => {
65533
+ // Code to save the recordedChunks as a video file
65534
+ const blob = new Blob(recordedChunks, {type: ic.videoFrameRecorder.mimeType});
65535
+ let fileName = ic.inputid + '_video_frame';
65536
+ saveAs(blob, fileName);
65537
+ };
65538
+
65539
+ // Start recording
65540
+ ic.videoFrameRecorder.start();
65541
+ thisClass.setLogCmd('Video recording started', false);
65542
+
65543
+ const intervalId = setInterval(function() {
65544
+ ic.alternateCls.alternateStructures();
65545
+ }, interval);
65546
+
65547
+ setTimeout(() => {
65548
+ clearInterval(intervalId);
65549
+ ic.videoFrameRecorder.stop();
65550
+ thisClass.setLogCmd('Video recording ended', false);
65551
+ }, duratinon);
65428
65552
  });
65429
65553
 
65430
65554
  me.myEventCls.onIds("#" + me.pre + "reload_state", "click", function(e) { let ic = me.icn3d;
@@ -66046,6 +66170,22 @@ class Events {
66046
66170
  await thisClass.loadPdbFile(ic.bAppend, 'pdbfile_app');
66047
66171
  });
66048
66172
 
66173
+ me.myEventCls.onIds("#" + me.pre + "reload_dcdpdbfile", "click", async function(e) { me.icn3d;
66174
+ e.preventDefault();
66175
+
66176
+ let bAppend = false;
66177
+ // ic.bRender = false;
66178
+ await thisClass.loadPdbFile(bAppend, 'dcdpdbfile', undefined, true);
66179
+ });
66180
+
66181
+ me.myEventCls.onIds("#" + me.pre + "reload_xtcpdbfile", "click", async function(e) { me.icn3d;
66182
+ e.preventDefault();
66183
+
66184
+ let bAppend = false;
66185
+ // ic.bRender = false;
66186
+ await thisClass.loadPdbFile(bAppend, 'xtcpdbfile', undefined, true);
66187
+ });
66188
+
66049
66189
  me.myEventCls.onIds("#" + me.pre + "reload_mol2file", "click", function(e) { let ic = me.icn3d;
66050
66190
  e.preventDefault();
66051
66191
  ic.bInitial = true;
@@ -66127,6 +66267,62 @@ class Events {
66127
66267
  }
66128
66268
  });
66129
66269
 
66270
+ me.myEventCls.onIds("#" + me.pre + "reload_dcdfile", "click", async function(e) { let ic = me.icn3d;
66271
+ e.preventDefault();
66272
+ ic.bInitial = true;
66273
+
66274
+ //thisClass.iniFileLoad();
66275
+ let file = $("#" + me.pre + "dcdfile")[0].files[0];
66276
+ if(!file) {
66277
+ var aaa = 1; //alert("Please select a file before clicking 'Load'");
66278
+ }
66279
+ else {
66280
+ me.htmlCls.setHtmlCls.fileSupport();
66281
+ let reader = new FileReader();
66282
+ reader.onload = async function(e) {
66283
+ let arrayBuffer = e.target.result;
66284
+ thisClass.setLogCmd('load dcd file ' + $("#" + me.pre + "dcdfile").val(), false);
66285
+ ic.molTitle = "";
66286
+ ic.inputid = undefined;
66287
+
66288
+ // ic.init();
66289
+ ic.bInputfile = true;
66290
+ ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + arrayBuffer : arrayBuffer;
66291
+ ic.InputfileType = 'dcd';
66292
+ await ic.dcdParserCls.loadDcdData(arrayBuffer);
66293
+ };
66294
+ reader.readAsArrayBuffer(file);
66295
+ }
66296
+ });
66297
+
66298
+ me.myEventCls.onIds("#" + me.pre + "reload_xtcfile", "click", async function(e) { let ic = me.icn3d;
66299
+ e.preventDefault();
66300
+ ic.bInitial = true;
66301
+
66302
+ //thisClass.iniFileLoad();
66303
+ let file = $("#" + me.pre + "xtcfile")[0].files[0];
66304
+ if(!file) {
66305
+ var aaa = 1; //alert("Please select a file before clicking 'Load'");
66306
+ }
66307
+ else {
66308
+ me.htmlCls.setHtmlCls.fileSupport();
66309
+ let reader = new FileReader();
66310
+ reader.onload = async function(e) {
66311
+ let arrayBuffer = e.target.result;
66312
+ thisClass.setLogCmd('load xtc file ' + $("#" + me.pre + "xtcfile").val(), false);
66313
+ ic.molTitle = "";
66314
+ ic.inputid = undefined;
66315
+
66316
+ // ic.init();
66317
+ ic.bInputfile = true;
66318
+ ic.InputfileData = (ic.InputfileData) ? ic.InputfileData + '\nENDMDL\n' + arrayBuffer : arrayBuffer;
66319
+ ic.InputfileType = 'xtc';
66320
+ await ic.xtcParserCls.loadXtcData(arrayBuffer);
66321
+ };
66322
+ reader.readAsArrayBuffer(file);
66323
+ }
66324
+ });
66325
+
66130
66326
  me.myEventCls.onIds("#" + me.pre + "reload_clustalwfile", "click", function(e) { let ic = me.icn3d;
66131
66327
  e.preventDefault();
66132
66328
  ic.bInitial = true;
@@ -66379,6 +66575,11 @@ class Events {
66379
66575
 
66380
66576
  await ic.showInterCls.showInteractions('graph');
66381
66577
  });
66578
+ me.myEventCls.onIds("#" + me.pre + "rmsd_plot", "click", async function(e) { let ic = me.icn3d;
66579
+ e.preventDefault();
66580
+
66581
+ await ic.dcdParserCls.showRmsdPlot();
66582
+ });
66382
66583
  me.myEventCls.onIds("#" + me.pre + "hbondLineGraph", "click", async function(e) { let ic = me.icn3d;
66383
66584
  e.preventDefault();
66384
66585
 
@@ -66524,6 +66725,12 @@ class Events {
66524
66725
  thisClass.setLogCmd("scatterplot scale " + scale, true);
66525
66726
  });
66526
66727
 
66728
+ me.myEventCls.onIds("#" + me.rmsdplotid + "_json", "click", function(e) { let ic = me.icn3d;
66729
+ e.preventDefault();
66730
+
66731
+ ic.saveFileCls.saveFile(ic.inputid + "_rmsdplot.json", "text", [JSON.stringify(ic.mdDataSet)]);
66732
+ });
66733
+
66527
66734
  me.myEventCls.onIds("#" + me.ligplotid + "_svg", "click", function(e) { let ic = me.icn3d;
66528
66735
  e.preventDefault();
66529
66736
 
@@ -66920,6 +67127,39 @@ class Events {
66920
67127
  ic.drawCls.draw();
66921
67128
  });
66922
67129
 
67130
+ me.myEventCls.onIds("#" + me.pre + "applyplane3sets", "click", function(e) { let ic = me.icn3d;
67131
+ e.preventDefault();
67132
+
67133
+ ic.bLinebtwsets = false;
67134
+
67135
+ let nameArray = $("#" + me.pre + "plane3sets").val();
67136
+ let nameArray2 = $("#" + me.pre + "plane3sets2").val();
67137
+ let nameArray3 = $("#" + me.pre + "plane3sets3").val();
67138
+
67139
+ let atomSet1 = ic.definedSetsCls.getAtomsFromNameArray(nameArray);
67140
+ let atomSet2 = ic.definedSetsCls.getAtomsFromNameArray(nameArray2);
67141
+ let atomSet3 = ic.definedSetsCls.getAtomsFromNameArray(nameArray3);
67142
+
67143
+ let posArray1 = ic.contactCls.getExtent(atomSet1);
67144
+ let posArray2 = ic.contactCls.getExtent(atomSet2);
67145
+ let posArray3 = ic.contactCls.getExtent(atomSet3);
67146
+
67147
+ let pos1 = new Vector3$1(posArray1[2][0], posArray1[2][1], posArray1[2][2]);
67148
+ let pos2 = new Vector3$1(posArray2[2][0], posArray2[2][1], posArray2[2][2]);
67149
+ let pos3 = new Vector3$1(posArray3[2][0], posArray3[2][1], posArray3[2][2]);
67150
+
67151
+ let thickness = $("#" + me.pre + "plane3sets_thickness").val();
67152
+ let color = $("#" + me.pre + "plane3sets_customcolor").val();
67153
+ let opacity = $("#" + me.pre + "plane3sets_opacity").val();
67154
+
67155
+ 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;
67156
+
67157
+ thisClass.setLogCmd(command, true);
67158
+
67159
+ ic.analysisCls.addPlane(pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z, pos3.x, pos3.y, pos3.z, color, thickness, opacity);
67160
+ ic.drawCls.draw();
67161
+ });
67162
+
66923
67163
  me.myEventCls.onIds("#" + me.pre + "applycartoonshape", "click", function(e) { let ic = me.icn3d;
66924
67164
  e.preventDefault();
66925
67165
 
@@ -66967,6 +67207,16 @@ class Events {
66967
67207
  ic.drawCls.draw();
66968
67208
  });
66969
67209
 
67210
+ me.myEventCls.onIds("#" + me.pre + "clearplane3sets", "click", function(e) { let ic = me.icn3d;
67211
+ e.preventDefault();
67212
+
67213
+
67214
+ ic.planes = [];
67215
+ thisClass.setLogCmd('clear plane among sets', true);
67216
+
67217
+ ic.drawCls.draw();
67218
+ });
67219
+
66970
67220
  me.myEventCls.onIds("#" + me.pre + "clearcartoonshape", "click", function(e) { let ic = me.icn3d;
66971
67221
  e.preventDefault();
66972
67222
 
@@ -68463,6 +68713,12 @@ class SetHtml {
68463
68713
  else if(type === 'xyz') {
68464
68714
  await ic.xyzParserCls.loadXyzData(data);
68465
68715
  }
68716
+ else if(type === 'dcd') {
68717
+ await ic.dcdParserCls.loadDcdData(data);
68718
+ }
68719
+ else if(type === 'xtc') {
68720
+ await ic.xtcParserCls.loadXtcData(data);
68721
+ }
68466
68722
  else if(type === 'mmcif') {
68467
68723
  await ic.mmcifParserCls.loadMmcifData(data);
68468
68724
  }
@@ -78142,6 +78398,37 @@ class Cylinder {
78142
78398
  }
78143
78399
  }
78144
78400
 
78401
+ //Create planes for a list of "planes", each of which has the properties 'position1', 'position2', 'position2', 'color', 'thickness', 'opacity',
78402
+ createPlanes(planes) { let ic = this.icn3d, me = ic.icn3dui;
78403
+ if(me.bNode) return;
78404
+
78405
+ for(let i = 0, il = planes.length; i < il; ++i) {
78406
+ let plane = planes[i];
78407
+
78408
+ let p1 = plane.position1;
78409
+ let p2 = plane.position2;
78410
+ let p3 = plane.position3;
78411
+
78412
+ let thickness = (plane.thickness) ? plane.thickness : 2;
78413
+ let opacity = (plane.opacity) ? plane.opacity : 0.3;
78414
+ let colorStr = '#' + plane.color.replace(/\#/g, '');
78415
+ let color = me.parasCls.thr(colorStr);
78416
+
78417
+ let planeGeo = new Plane();
78418
+ planeGeo.setFromCoplanarPoints(p1, p2, p3);
78419
+ let planeNormal = planeGeo.normal;
78420
+
78421
+ const projectedPoint = new Vector3$1();
78422
+ // Project the center onto the plane
78423
+ planeGeo.projectPoint(ic.center, projectedPoint);
78424
+
78425
+ let c0 = projectedPoint.clone().sub(planeNormal.clone().multiplyScalar(thickness * 0.5));
78426
+ let c1 = projectedPoint.clone().add(planeNormal.clone().multiplyScalar(thickness * 0.5));
78427
+ let radius = ic.maxD / 2;
78428
+ ic.cylinderCls.createCylinder(c0, c1, radius, color, undefined, color, undefined, undefined, opacity);
78429
+ }
78430
+ }
78431
+
78145
78432
  createCylinder_base(p0, p1, radius, color, bHighlight, color2, bPicking) { let ic = this.icn3d, me = ic.icn3dui;
78146
78433
  if(me.bNode) return;
78147
78434
 
@@ -78553,7 +78840,7 @@ class Line$1 {
78553
78840
  }
78554
78841
 
78555
78842
  // do not add the artificial lines to raycasting objects
78556
- };
78843
+ }
78557
78844
 
78558
78845
  }
78559
78846
 
@@ -79031,7 +79318,7 @@ class FirstAtomObj {
79031
79318
  let firstIndex;
79032
79319
 
79033
79320
  for(let i in atomsHash) {
79034
- if(ic.atoms[i].name == 'CA') {
79321
+ if(ic.atoms[i] && ic.atoms[i].name == 'CA') {
79035
79322
  firstIndex = i;
79036
79323
  break;
79037
79324
  }
@@ -79039,7 +79326,7 @@ class FirstAtomObj {
79039
79326
 
79040
79327
  if(!firstIndex) {
79041
79328
  for(let i in atomsHash) {
79042
- if(ic.atoms[i].name == "O3'" || ic.atoms[i].name == "O3*") {
79329
+ if(ic.atoms[i] && (ic.atoms[i].name == "O3'" || ic.atoms[i].name == "O3*")) {
79043
79330
  firstIndex = i;
79044
79331
  break;
79045
79332
  }
@@ -79118,7 +79405,7 @@ class FirstAtomObj {
79118
79405
  getAtomFromResi(resid, atomName) { let ic = this.icn3d; ic.icn3dui;
79119
79406
  if(ic.residues.hasOwnProperty(resid)) {
79120
79407
  for(let i in ic.residues[resid]) {
79121
- if(ic.atoms[i].name === atomName && !ic.atoms[i].het) {
79408
+ if(ic.atoms[i] && ic.atoms[i].name === atomName && !ic.atoms[i].het) {
79122
79409
  return ic.atoms[i];
79123
79410
  }
79124
79411
  }
@@ -84968,6 +85255,8 @@ class ApplyOther {
84968
85255
  }
84969
85256
 
84970
85257
  ic.lineCls.createLines(ic.lines);
85258
+ if(!ic.planes) ic.planes = [];
85259
+ ic.cylinderCls.createPlanes(ic.planes);
84971
85260
  // }
84972
85261
 
84973
85262
  // distance sets
@@ -87201,7 +87490,7 @@ class Alternate {
87201
87490
 
87202
87491
  // change the display atom when alternating
87203
87492
  //Show structures one by one.
87204
- async alternateStructures() { let ic = this.icn3d, me = ic.icn3dui;
87493
+ alternateStructures() { let ic = this.icn3d, me = ic.icn3dui;
87205
87494
  ic.bAlternate = true;
87206
87495
 
87207
87496
  //ic.transformCls.zoominSelection();
@@ -87346,7 +87635,7 @@ class Alternate {
87346
87635
 
87347
87636
  async alternateWrapper() { let ic = this.icn3d; ic.icn3dui;
87348
87637
  ic.bAlternate = true;
87349
- await this.alternateStructures();
87638
+ this.alternateStructures();
87350
87639
  ic.bAlternate = false;
87351
87640
  }
87352
87641
 
@@ -98035,6 +98324,8 @@ class ShowAnno {
98035
98324
  ic.seqAnnWidth = dialogWidth - 120 - 30*2 - 50; // title: 120px, start and end resi: 30px, extra space on the left and right: 50px
98036
98325
 
98037
98326
  for(let i = 0, il = chainArray.length; i < il; ++i) {
98327
+ if(!ic.chainsSeq[chainArray[i]]) continue; // skip empty chain
98328
+
98038
98329
  Math.round(chainArray[i].indexOf('_'));
98039
98330
  //if(pos > 4) continue; // NMR structures with structure id such as 2K042,2K043, ...
98040
98331
  // let atom = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.chains[chainArray[i]]);
@@ -100757,7 +101048,7 @@ class LineGraph {
100757
101048
  }
100758
101049
 
100759
101050
  for(let i = 0, il = structureArray.length; i < il; ++i) {
100760
- let labelFinal = label;
101051
+ let labelFinal = (i+1).toString() + '. ' + label;
100761
101052
  if(bMutation) {
100762
101053
  if(i == 0) {
100763
101054
  labelFinal += "Wild Type ";
@@ -108465,6 +108756,12 @@ class PdbParser {
108465
108756
  else if(type === 'xyz') {
108466
108757
  await ic.xyzParserCls.loadXyzData(data);
108467
108758
  }
108759
+ else if(type === 'dcd') {
108760
+ await ic.dcdParserCls.loadDcdData(data);
108761
+ }
108762
+ else if(type === 'xtc') {
108763
+ await ic.xtcParserCls.loadXtcData(data);
108764
+ }
108468
108765
  else if(type === 'mmcif') {
108469
108766
  await ic.mmcifParserCls.loadMmcifData(data);
108470
108767
  }
@@ -109019,6 +109316,992 @@ class XyzParser {
109019
109316
  }
109020
109317
  }
109021
109318
 
109319
+ /**
109320
+ * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
109321
+ */
109322
+
109323
+ class DcdParser {
109324
+ constructor(icn3d) {
109325
+ this.icn3d = icn3d;
109326
+ icn3d.DELTA = 1;
109327
+ icn3d.TIMEOFFSET = 0;
109328
+ }
109329
+
109330
+ async loadDcdData(data) { let ic = this.icn3d, me = ic.icn3dui;
109331
+ let bResult = this.loadDcdAtomData(data);
109332
+
109333
+ if(me.cfg.align === undefined && Object.keys(ic.structures).length == 1) {
109334
+ $("#" + ic.pre + "alternateWrapper").hide();
109335
+ }
109336
+
109337
+ if(!bResult) {
109338
+ var aaa = 1; //alert('The DCD file has the wrong format...');
109339
+ }
109340
+ else {
109341
+ ic.setStyleCls.setAtomStyleByOptions(ic.opts);
109342
+ ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
109343
+
109344
+ // hide water, ions
109345
+ ic.dAtoms = me.hashUtilsCls.cloneHash(ic.proteins);
109346
+ ic.dAtoms = me.hashUtilsCls.unionHash(ic.dAtoms, ic.nucleotides);
109347
+ ic.dAtoms = me.hashUtilsCls.unionHash(ic.dAtoms, ic.chemicals);
109348
+ ic.hAtoms = me.hashUtilsCls.cloneHash(ic.dAtoms);
109349
+ ic.transformCls.zoominSelection();
109350
+
109351
+ // ic.bRender = true;
109352
+ await ic.ParserUtilsCls.renderStructure();
109353
+
109354
+ if(me.cfg.rotate !== undefined) ic.resizeCanvasCls.rotStruc(me.cfg.rotate, true);
109355
+
109356
+ //if(me.deferred !== undefined) me.deferred.resolve(); /// if(ic.deferred2 !== undefined) ic.deferred2.resolve();
109357
+ }
109358
+ }
109359
+
109360
+ // modified from https://github.com/molstar/molstar/blob/master/src/mol-io/reader/dcd/parser.ts
109361
+ loadDcdAtomData(data) { let ic = this.icn3d, me = ic.icn3dui;
109362
+ // http://www.ks.uiuc.edu/Research/vmd/plugins/molfile/dcdplugin.html
109363
+
109364
+ // The DCD format is structured as follows
109365
+ // (FORTRAN UNFORMATTED, with Fortran data type descriptions):
109366
+ // HDR NSET ISTRT NSAVC 5-ZEROS NATOM-NFREAT DELTA 9-ZEROS
109367
+ // `CORD' #files step 1 step zeroes (zero) timestep (zeroes)
109368
+ // interval
109369
+ // C*4 INT INT INT 5INT INT DOUBLE 9INT
109370
+ // ==========================================================================
109371
+ // NTITLE TITLE
109372
+ // INT (=2) C*MAXTITL
109373
+ // (=32)
109374
+ // ==========================================================================
109375
+ // NATOM
109376
+ // #atoms
109377
+ // INT
109378
+ // ==========================================================================
109379
+ // X(I), I=1,NATOM (DOUBLE)
109380
+ // Y(I), I=1,NATOM
109381
+ // Z(I), I=1,NATOM
109382
+ // ==========================================================================
109383
+
109384
+ let bin =(data.buffer && data.buffer instanceof ArrayBuffer) ? data.buffer : data;
109385
+ const dv = new DataView(bin);
109386
+
109387
+ // const header: Mutable<DcdHeader> = Object.create(null);
109388
+ // const frames: DcdFrame[] = [];
109389
+ const header = {};
109390
+
109391
+ let nextPos = 0;
109392
+
109393
+ // header block
109394
+
109395
+ const intView = new Int32Array(bin, 0, 23);
109396
+ const ef = intView[0] !== dv.getInt32(0); // endianess flag
109397
+ // swap byte order when big endian (84 indicates little endian)
109398
+ if (intView[0] !== 84) {
109399
+ const n = data.byteLength;
109400
+ for (let i = 0; i < n; i += 4) {
109401
+ dv.setFloat32(i, dv.getFloat32(i), true);
109402
+ }
109403
+ }
109404
+ if (intView[0] !== 84) {
109405
+ console.error('dcd bad format, header block start');
109406
+ return false;
109407
+ }
109408
+
109409
+ // format indicator, should read 'CORD'
109410
+ const formatString = String.fromCharCode(
109411
+ dv.getUint8(4), dv.getUint8(5),
109412
+ dv.getUint8(6), dv.getUint8(7)
109413
+ );
109414
+ if (formatString !== 'CORD') {
109415
+ console.error('dcd bad format, format string');
109416
+ return false;
109417
+ }
109418
+ let isCharmm = false;
109419
+ let extraBlock = false;
109420
+ let fourDims = false;
109421
+ // version field in charmm, unused in X-PLOR
109422
+ if (intView[22] !== 0) {
109423
+ isCharmm = true;
109424
+ if (intView[12] !== 0) extraBlock = true;
109425
+ if (intView[13] === 1) fourDims = true;
109426
+ }
109427
+ header.NSET = intView[2];
109428
+ header.ISTART = intView[3];
109429
+ header.NSAVC = intView[4];
109430
+ header.NAMNF = intView[10];
109431
+
109432
+ ic.frames = header.NSET;
109433
+
109434
+ if (isCharmm) {
109435
+ header.DELTA = dv.getFloat32(44, ef);
109436
+ } else {
109437
+ header.DELTA = dv.getFloat64(44, ef);
109438
+ }
109439
+ this.DELTA = header.DELTA;
109440
+
109441
+ if (intView[22] !== 84) {
109442
+ console.error('dcd bad format, header block end');
109443
+ return false;
109444
+ }
109445
+ nextPos = nextPos + 21 * 4 + 8;
109446
+
109447
+ // title block
109448
+
109449
+ const titleEnd = dv.getInt32(nextPos, ef);
109450
+ const titleStart = nextPos + 1;
109451
+ if ((titleEnd - 4) % 80 !== 0) {
109452
+ console.error('dcd bad format, title block start');
109453
+ return false;
109454
+ }
109455
+
109456
+ let byteView = new Uint8Array(bin);
109457
+ header.TITLE = String.fromCharCode.apply(null, byteView.subarray(titleStart, titleEnd));
109458
+ if (dv.getInt32(titleStart + titleEnd + 4 - 1, ef) !== titleEnd) {
109459
+ console.error('dcd bad format, title block end');
109460
+ return false;
109461
+ }
109462
+
109463
+ nextPos = nextPos + titleEnd + 8;
109464
+
109465
+ // natom block
109466
+
109467
+ if (dv.getInt32(nextPos, ef) !== 4) {
109468
+ console.error('dcd bad format, natom block start');
109469
+ return false;
109470
+ }
109471
+ header.NATOM = dv.getInt32(nextPos + 4, ef);
109472
+ if (dv.getInt32(nextPos + 8, ef) !== 4) {
109473
+ console.error('dcd bad format, natom block end');
109474
+ return false;
109475
+ }
109476
+ nextPos = nextPos + 4 + 8;
109477
+
109478
+ // fixed atoms block
109479
+
109480
+ if (header.NAMNF > 0) {
109481
+ // TODO read coordinates and indices of fixed atoms
109482
+ console.error('dcd format with fixed atoms unsupported, aborting');
109483
+ return false;
109484
+ }
109485
+
109486
+ // frames
109487
+ const natom = header.NATOM;
109488
+ const natom4 = natom * 4;
109489
+
109490
+ if(natom != Object.keys(ic.atoms).length) {
109491
+ 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);
109492
+ return false;
109493
+ }
109494
+
109495
+ let structuresOri = me.hashUtilsCls.cloneHash(ic.structures);
109496
+ let residuesOri = me.hashUtilsCls.cloneHash(ic.residues);
109497
+ let chainsOri = me.hashUtilsCls.cloneHash(ic.chains);
109498
+
109499
+ let proteinsOri = me.hashUtilsCls.cloneHash(ic.proteins);
109500
+ let nucleotidesOri = me.hashUtilsCls.cloneHash(ic.nucleotides);
109501
+ let waterOri = me.hashUtilsCls.cloneHash(ic.water);
109502
+ let ionsOri = me.hashUtilsCls.cloneHash(ic.ions);
109503
+ let chemicalsOri = me.hashUtilsCls.cloneHash(ic.chemicals);
109504
+
109505
+ let serial = natom + 1; // a preloaded PDB structure would have atom serial from 1 to natom
109506
+ for (let i = 0, n = header.NSET; i < n; ++i) {
109507
+ const frame = {};
109508
+ frame.elementCount = natom;
109509
+
109510
+ if (extraBlock) {
109511
+ nextPos += 4; // block start
109512
+ frame.cell = [
109513
+ dv.getFloat64(nextPos, ef),
109514
+ dv.getFloat64(nextPos + 1, ef),
109515
+ dv.getFloat64(nextPos + 2 * 8, ef),
109516
+ dv.getFloat64(nextPos + 3 * 8, ef),
109517
+ dv.getFloat64(nextPos + 4 * 8, ef),
109518
+ dv.getFloat64(nextPos + 5 * 8, ef)
109519
+ ];
109520
+ nextPos += 48;
109521
+ nextPos += 4; // block end
109522
+ }
109523
+
109524
+ // xyz coordinates
109525
+ for (let j = 0; j < 3; ++j) {
109526
+ if (dv.getInt32(nextPos, ef) !== natom4) {
109527
+ console.error(`dcd bad format, coord block start: ${i}, ${j}`);
109528
+ return false;
109529
+ }
109530
+ nextPos += 4; // block start
109531
+ const c = new Float32Array(bin, nextPos, natom);
109532
+ if (j === 0) frame.x = c;
109533
+ else if (j === 1) frame.y = c;
109534
+ else frame.z = c;
109535
+
109536
+ nextPos += natom4;
109537
+ if (dv.getInt32(nextPos, ef) !== natom4) {
109538
+ console.error(`dcd bad format, coord block end: ${i}, ${j}`);
109539
+ return false;
109540
+ }
109541
+ nextPos += 4; // block end
109542
+ }
109543
+
109544
+ if (fourDims) {
109545
+ const bytes = dv.getInt32(nextPos, ef);
109546
+ nextPos += 4 + bytes + 4; // block start + skip + block end
109547
+ }
109548
+
109549
+ // skip the first structure since it was read from PDB already
109550
+ if(i == 0) continue;
109551
+
109552
+ let molNum = i + 1; // to avoid the same molNum as the PDB structure
109553
+ for(let j = 0; j < natom; ++j) {
109554
+ let coord = new Vector3$1(frame.x[j], frame.y[j], frame.z[j]);
109555
+
109556
+ let atom = me.hashUtilsCls.cloneHash(ic.atoms[j + 1]);
109557
+
109558
+ atom.serial = serial;
109559
+ atom.structure = atom.structure + molNum;
109560
+ atom.coord = coord;
109561
+ atom.bonds = [].concat(ic.atoms[j + 1].bonds);
109562
+
109563
+ // update bonds
109564
+ for(let k = 0, kl = atom.bonds.length; k < kl; ++k) {
109565
+ atom.bonds[k] = parseInt(atom.bonds[k]) + natom * i;
109566
+ }
109567
+
109568
+ ic.atoms[serial] = atom;
109569
+
109570
+ // assign extra info
109571
+ ic.dAtoms[serial] = 1;
109572
+ ic.hAtoms[serial] = 1;
109573
+
109574
+ let chainid = atom.structure + '_' + atom.chain;
109575
+ let residid = chainid + '_' + atom.resi;
109576
+ ic.secondaries[residid] = atom.ss;
109577
+ ic.residueId2Name[residid] = me.utilsCls.residueName2Abbr(atom.resn);
109578
+
109579
+ ++serial;
109580
+ }
109581
+
109582
+ // update ic.structures, ic.residues and ic.chains
109583
+ for(let structure in structuresOri) {
109584
+ let structure2 = structure + molNum;
109585
+ ic.structures[structure2] = [];
109586
+
109587
+ for(let k = 0, kl = structuresOri[structure].length; k < kl; ++k) {
109588
+ let idArray = structuresOri[structure][k].split('_');
109589
+ ic.structures[structure2].push(structure2 + '_' + idArray[1]);
109590
+ }
109591
+ }
109592
+
109593
+ for(let j in residuesOri) {
109594
+ let idArray = j.split('_');
109595
+ let structure2 = idArray[0] + molNum;
109596
+ let residid2 = structure2 + '_' + idArray[1] + '_' + idArray[2];
109597
+ ic.residues[residid2] = {};
109598
+
109599
+ for(let k in residuesOri[j]) {
109600
+ ic.residues[residid2][parseInt(k) + natom * i] = 1;
109601
+ }
109602
+ }
109603
+
109604
+ for(let j in chainsOri) {
109605
+ let idArray = j.split('_');
109606
+ let structure2 = idArray[0] + molNum;
109607
+ let chainid2 = structure2 + '_' + idArray[1];
109608
+
109609
+ // ic.chainsSeq[chainid2] = [].concat(ic.chainsSeq[j]);
109610
+
109611
+ ic.chains[chainid2] = {};
109612
+ for(let k in chainsOri[j]) {
109613
+ ic.chains[chainid2][parseInt(k)+ natom * i] = 1;
109614
+ }
109615
+ }
109616
+
109617
+ // update ic.proteins, etc
109618
+ for(let j in proteinsOri) {
109619
+ ic.proteins[parseInt(j) + natom * i] = 1;
109620
+ }
109621
+ for(let j in nucleotidesOri) {
109622
+ ic.nucleotides[parseInt(j) + natom * i] = 1;
109623
+ }
109624
+ for(let j in waterOri) {
109625
+ ic.water[parseInt(j) + natom * i] = 1;
109626
+ }
109627
+ for(let j in ionsOri) {
109628
+ ic.ions[parseInt(j) + natom * i] = 1;
109629
+ }
109630
+ for(let j in chemicalsOri) {
109631
+ ic.chemicals[parseInt(j) + natom * i] = 1;
109632
+ }
109633
+
109634
+ // set ic.ncbi2resid and ic.resid2ncbi
109635
+ for(let chainid in chainsOri) {
109636
+ let idArray = chainid.split('_');
109637
+ let structure2 = idArray[0] + molNum;
109638
+ let chainid2 = structure2 + '_' + idArray[1];
109639
+
109640
+ for(let j = 0, jl = ic.chainsSeq[chainid].length; j < jl; ++j) {
109641
+ // NCBI residue number starts from 1 and increases continuously
109642
+ let residNCBI = chainid2 + '_' + (j+1).toString();
109643
+ let resid = chainid2 + '_' + ic.chainsSeq[chainid][j].resi;
109644
+ ic.ncbi2resid[residNCBI] = resid;
109645
+ ic.resid2ncbi[resid] = residNCBI;
109646
+ }
109647
+ }
109648
+ }
109649
+
109650
+ ic.molTitle = header.TITLE;
109651
+ ic.inputid = 'stru';
109652
+
109653
+ // ic.ParserUtilsCls.setMaxD();
109654
+
109655
+ ic.saveFileCls.showTitle();
109656
+
109657
+ return true;
109658
+ }
109659
+
109660
+ async showRmsdPlot() { let ic = this.icn3d, me = ic.icn3dui;
109661
+ if(ic.bChartjs === undefined) {
109662
+ let url = "https://cdn.jsdelivr.net/npm/chart.js";
109663
+ await me.getAjaxPromise(url, 'script');
109664
+
109665
+ ic.bChartjs = true;
109666
+ }
109667
+
109668
+ $("#" + me.rmsdplotid).empty();
109669
+ me.htmlCls.dialogCls.openDlg('dl_rmsdplot', 'RMSD Plot');
109670
+
109671
+ let dataSet = [];
109672
+ let structureArray = Object.keys(ic.structures);
109673
+ let coord1 = [], coord2 = [];
109674
+ for(let i = 0, il = structureArray.length; i < il; ++i) {
109675
+ let chainArray = ic.structures[structureArray[i]];
109676
+
109677
+ let coord = [];
109678
+ let nAtoms = 0;
109679
+ for(let j = 0, jl = chainArray.length; j < jl; ++j) {
109680
+ let chainid = chainArray[j];
109681
+ for(let k in ic.chains[chainid]) {
109682
+ let atom = ic.atoms[k];
109683
+ coord.push(atom.coord);
109684
+ ++nAtoms;
109685
+ }
109686
+ }
109687
+
109688
+ if(i == 0) {
109689
+ coord1 = [].concat(coord);
109690
+ }
109691
+ else {
109692
+ coord2 = coord;
109693
+ }
109694
+
109695
+ if(i > 0) {
109696
+ let result = me.rmsdSuprCls.getRmsdSuprCls(coord1, coord2, nAtoms);
109697
+ let rmsd = (result.rmsd * 0.1).toPrecision(4); // convert from Å to nm
109698
+
109699
+ let time = ic.TIMEOFFSET + (i * ic.DELTA).toPrecision(4);
109700
+ dataSet.push({x: time, y: rmsd});
109701
+ }
109702
+ }
109703
+
109704
+ ic.mdDataSet = dataSet;
109705
+ if(me.bNode) console.log(dataSet);
109706
+
109707
+ let stepSize = (structureArray.length - 1) * ic.DELTA / 10; // 10 ticks
109708
+
109709
+ // https://www.chartjs.org/docs/latest/samples/line/line.html
109710
+ // const ctx = $("#" + me.rmsdplotid)[0].getContext('2d');
109711
+ const ctx = $("#" + me.rmsdplotid)[0];
109712
+
109713
+ new Chart(ctx, {
109714
+ type: 'line',
109715
+ data: {
109716
+ datasets: [{
109717
+ label: 'RMSD',
109718
+ data: dataSet
109719
+ }]
109720
+ },
109721
+ options: {
109722
+ responsive: true,
109723
+ scales: {
109724
+ x: { // X-axis configuration
109725
+ title: {
109726
+ display: true, // Show the X-axis label
109727
+ text: 'Time (ps)' // Text for the X-axis label
109728
+ },
109729
+ type: 'linear', // Required for numerical x-axis
109730
+ position: 'bottom',
109731
+ ticks: {
109732
+ stepSize: stepSize
109733
+ }
109734
+ },
109735
+ y: { // Y-axis configuration (defaults to numeric scale)
109736
+ title: {
109737
+ display: true, // Show the Y-axis label
109738
+ text: 'RMSD (nm)' // Text for the Y-axis label
109739
+ }
109740
+ }
109741
+ }
109742
+ }
109743
+ });
109744
+ }
109745
+ }
109746
+
109747
+ /**
109748
+ * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
109749
+ */
109750
+
109751
+ class XtcParser {
109752
+ constructor(icn3d) {
109753
+ this.icn3d = icn3d;
109754
+
109755
+ icn3d.DELTA = 1;
109756
+ icn3d.TIMEOFFSET = 0;
109757
+
109758
+ this.MagicInts = new Uint32Array([
109759
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 12, 16, 20, 25, 32, 40, 50, 64,
109760
+ 80, 101, 128, 161, 203, 256, 322, 406, 512, 645, 812, 1024, 1290,
109761
+ 1625, 2048, 2580, 3250, 4096, 5060, 6501, 8192, 10321, 13003,
109762
+ 16384, 20642, 26007, 32768, 41285, 52015, 65536, 82570, 104031,
109763
+ 131072, 165140, 208063, 262144, 330280, 416127, 524287, 660561,
109764
+ 832255, 1048576, 1321122, 1664510, 2097152, 2642245, 3329021,
109765
+ 4194304, 5284491, 6658042, 8388607, 10568983, 13316085, 16777216
109766
+ ]);
109767
+ this.FirstIdx = 9;
109768
+
109769
+ this._tmpBytes = new Uint8Array(32);
109770
+ let _buffer = new ArrayBuffer(8 * 3);
109771
+ this.buf = new Int32Array(_buffer);
109772
+ this.uint32view = new Uint32Array(_buffer);
109773
+ 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];
109774
+ }
109775
+
109776
+ async loadXtcData(data) { let ic = this.icn3d, me = ic.icn3dui;
109777
+ let bResult = this.loadXtcAtomData(data);
109778
+
109779
+ if(me.cfg.align === undefined && Object.keys(ic.structures).length == 1) {
109780
+ $("#" + ic.pre + "alternateWrapper").hide();
109781
+ }
109782
+
109783
+ if(!bResult) {
109784
+ var aaa = 1; //alert('The XTC file has the wrong format...');
109785
+ }
109786
+ else {
109787
+ ic.setStyleCls.setAtomStyleByOptions(ic.opts);
109788
+ ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
109789
+
109790
+ // hide water, ions
109791
+ ic.dAtoms = me.hashUtilsCls.cloneHash(ic.proteins);
109792
+ ic.dAtoms = me.hashUtilsCls.unionHash(ic.dAtoms, ic.nucleotides);
109793
+ ic.dAtoms = me.hashUtilsCls.unionHash(ic.dAtoms, ic.chemicals);
109794
+ ic.hAtoms = me.hashUtilsCls.cloneHash(ic.dAtoms);
109795
+ ic.transformCls.zoominSelection();
109796
+
109797
+ // ic.bRender = true;
109798
+ await ic.ParserUtilsCls.renderStructure();
109799
+
109800
+ if(me.cfg.rotate !== undefined) ic.resizeCanvasCls.rotStruc(me.cfg.rotate, true);
109801
+
109802
+ //if(me.deferred !== undefined) me.deferred.resolve(); /// if(ic.deferred2 !== undefined) ic.deferred2.resolve();
109803
+ }
109804
+ }
109805
+
109806
+
109807
+ // modified from https://github.com/molstar/molstar/blob/master/src/mol-io/reader/xtc/parser.ts
109808
+ loadXtcAtomData(data) { let ic = this.icn3d, me = ic.icn3dui;
109809
+ // https://github.com/gromacs/gromacs/blob/master/src/gromacs/fileio/xtcio.cpp
109810
+ // https://github.com/gromacs/gromacs/blob/master/src/gromacs/fileio/libxdrf.cpp
109811
+
109812
+ let bin =(data.buffer && data.buffer instanceof ArrayBuffer) ? data.buffer : data;
109813
+
109814
+ // const dv = new DataView(bin, data.byteOffset);
109815
+ const dv = new DataView(bin);
109816
+
109817
+ data = new Uint8Array(bin);
109818
+
109819
+ // const f = {
109820
+ // frames: [],
109821
+ // boxes: [],
109822
+ // times: [],
109823
+ // timeOffset: 0,
109824
+ // deltaTime: 0
109825
+ // };
109826
+
109827
+ const coordinates = []; //f.frames;
109828
+ const times = []; //f.times;
109829
+
109830
+ const minMaxInt = [0, 0, 0, 0, 0, 0];
109831
+ const sizeint = [0, 0, 0];
109832
+ const bitsizeint = [0, 0, 0];
109833
+ const sizesmall = [0, 0, 0];
109834
+ const thiscoord = [0.1, 0.1, 0.1];
109835
+ const prevcoord = [0.1, 0.1, 0.1];
109836
+
109837
+ let offset = 0, natom;
109838
+
109839
+ while (true) {
109840
+ let frameCoords;
109841
+
109842
+ // const magicnum = dv.getInt32(offset)
109843
+ natom = dv.getInt32(offset + 4);
109844
+ // const step = dv.getInt32(offset + 8)
109845
+ offset += 12;
109846
+
109847
+ if(natom != Object.keys(ic.atoms).length) {
109848
+ 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);
109849
+ return false;
109850
+ }
109851
+
109852
+ times.push(dv.getFloat32(offset));
109853
+ offset += 4;
109854
+
109855
+ const box = new Float32Array(9);
109856
+ for (let i = 0; i < 9; ++i) {
109857
+ box[i] = dv.getFloat32(offset) * 10;
109858
+ offset += 4;
109859
+ }
109860
+
109861
+ if (natom <= 9) { // no compression
109862
+ frameCoords = { count: natom, x: new Float32Array(natom), y: new Float32Array(natom), z: new Float32Array(natom) };
109863
+ offset += 4;
109864
+ for (let i = 0; i < natom; ++i) {
109865
+ frameCoords.x[i] = dv.getFloat32(offset);
109866
+ frameCoords.y[i] = dv.getFloat32(offset + 4);
109867
+ frameCoords.z[i] = dv.getFloat32(offset + 8);
109868
+ offset += 12;
109869
+ }
109870
+ } else {
109871
+ this.buf[0] = this.buf[1] = this.buf[2] = 0;
109872
+ sizeint[0] = sizeint[1] = sizeint[2] = 0;
109873
+ sizesmall[0] = sizesmall[1] = sizesmall[2] = 0;
109874
+ bitsizeint[0] = bitsizeint[1] = bitsizeint[2] = 0;
109875
+ thiscoord[0] = thiscoord[1] = thiscoord[2] = 0;
109876
+ prevcoord[0] = prevcoord[1] = prevcoord[2] = 0;
109877
+
109878
+ frameCoords = { count: natom, x: new Float32Array(natom), y: new Float32Array(natom), z: new Float32Array(natom) };
109879
+ let lfp = 0;
109880
+
109881
+ const lsize = dv.getInt32(offset);
109882
+ offset += 4;
109883
+ const precision = dv.getFloat32(offset);
109884
+ offset += 4;
109885
+
109886
+ minMaxInt[0] = dv.getInt32(offset);
109887
+ minMaxInt[1] = dv.getInt32(offset + 4);
109888
+ minMaxInt[2] = dv.getInt32(offset + 8);
109889
+ minMaxInt[3] = dv.getInt32(offset + 12);
109890
+ minMaxInt[4] = dv.getInt32(offset + 16);
109891
+ minMaxInt[5] = dv.getInt32(offset + 20);
109892
+ sizeint[0] = minMaxInt[3] - minMaxInt[0] + 1;
109893
+ sizeint[1] = minMaxInt[4] - minMaxInt[1] + 1;
109894
+ sizeint[2] = minMaxInt[5] - minMaxInt[2] + 1;
109895
+ offset += 24;
109896
+
109897
+ let bitsize;
109898
+ if ((sizeint[0] | sizeint[1] | sizeint[2]) > 0xffffff) {
109899
+ bitsizeint[0] = this.sizeOfInt(sizeint[0]);
109900
+ bitsizeint[1] = this.sizeOfInt(sizeint[1]);
109901
+ bitsizeint[2] = this.sizeOfInt(sizeint[2]);
109902
+ bitsize = 0; // flag the use of large sizes
109903
+ } else {
109904
+ bitsize = this.sizeOfInts(3, sizeint);
109905
+ }
109906
+
109907
+ let smallidx = dv.getInt32(offset);
109908
+ offset += 4;
109909
+
109910
+ let tmpIdx = smallidx - 1;
109911
+ tmpIdx = (this.FirstIdx > tmpIdx) ? this.FirstIdx : tmpIdx;
109912
+ let smaller = (this.MagicInts[tmpIdx] / 2) | 0;
109913
+ let smallnum = (this.MagicInts[smallidx] / 2) | 0;
109914
+
109915
+ sizesmall[0] = sizesmall[1] = sizesmall[2] = this.MagicInts[smallidx];
109916
+
109917
+ const adz = Math.ceil(dv.getInt32(offset) / 4) * 4;
109918
+ offset += 4;
109919
+
109920
+ const invPrecision = 1.0 / precision;
109921
+ let run = 0;
109922
+ let i = 0;
109923
+
109924
+ // const this.buf8 = new Uint8Array(data.this.buffer, data.byteOffset + offset, 32 * 4); // 229...
109925
+
109926
+ thiscoord[0] = thiscoord[1] = thiscoord[2] = 0;
109927
+
109928
+ while (i < lsize) {
109929
+ if (bitsize === 0) {
109930
+ thiscoord[0] = this.decodeBits(data, offset, bitsizeint[0]);
109931
+ thiscoord[1] = this.decodeBits(data, offset, bitsizeint[1]);
109932
+ thiscoord[2] = this.decodeBits(data, offset, bitsizeint[2]);
109933
+ } else {
109934
+ this.decodeInts(data, offset, bitsize, sizeint, thiscoord);
109935
+ }
109936
+
109937
+ i++;
109938
+
109939
+ thiscoord[0] += minMaxInt[0];
109940
+ thiscoord[1] += minMaxInt[1];
109941
+ thiscoord[2] += minMaxInt[2];
109942
+
109943
+ prevcoord[0] = thiscoord[0];
109944
+ prevcoord[1] = thiscoord[1];
109945
+ prevcoord[2] = thiscoord[2];
109946
+
109947
+ const flag = this.decodeBits(data, offset, 1);
109948
+ let isSmaller = 0;
109949
+
109950
+ if (flag === 1) {
109951
+ run = this.decodeBits(data, offset, 5);
109952
+ isSmaller = run % 3;
109953
+ run -= isSmaller;
109954
+ isSmaller--;
109955
+ }
109956
+
109957
+ // if ((lfp-ptrstart)+run > size3){
109958
+ // fprintf(stderr, "(xdrfile error) Buffer overrun during decompression.\n");
109959
+ // return 0;
109960
+ // }
109961
+
109962
+ if (run > 0) {
109963
+ thiscoord[0] = thiscoord[1] = thiscoord[2] = 0;
109964
+
109965
+ for (let k = 0; k < run; k += 3) {
109966
+ this.decodeInts(data, offset, smallidx, sizesmall, thiscoord);
109967
+ i++;
109968
+
109969
+ thiscoord[0] += prevcoord[0] - smallnum;
109970
+ thiscoord[1] += prevcoord[1] - smallnum;
109971
+ thiscoord[2] += prevcoord[2] - smallnum;
109972
+
109973
+ if (k === 0) {
109974
+ // interchange first with second atom for
109975
+ // better compression of water molecules
109976
+ let tmpSwap = thiscoord[0];
109977
+ thiscoord[0] = prevcoord[0];
109978
+ prevcoord[0] = tmpSwap;
109979
+
109980
+ tmpSwap = thiscoord[1];
109981
+ thiscoord[1] = prevcoord[1];
109982
+ prevcoord[1] = tmpSwap;
109983
+
109984
+ tmpSwap = thiscoord[2];
109985
+ thiscoord[2] = prevcoord[2];
109986
+ prevcoord[2] = tmpSwap;
109987
+
109988
+ frameCoords.x[lfp] = prevcoord[0] * invPrecision;
109989
+ frameCoords.y[lfp] = prevcoord[1] * invPrecision;
109990
+ frameCoords.z[lfp] = prevcoord[2] * invPrecision;
109991
+ lfp++;
109992
+ } else {
109993
+ prevcoord[0] = thiscoord[0];
109994
+ prevcoord[1] = thiscoord[1];
109995
+ prevcoord[2] = thiscoord[2];
109996
+ }
109997
+ frameCoords.x[lfp] = thiscoord[0] * invPrecision;
109998
+ frameCoords.y[lfp] = thiscoord[1] * invPrecision;
109999
+ frameCoords.z[lfp] = thiscoord[2] * invPrecision;
110000
+ lfp++;
110001
+ }
110002
+ } else {
110003
+ frameCoords.x[lfp] = thiscoord[0] * invPrecision;
110004
+ frameCoords.y[lfp] = thiscoord[1] * invPrecision;
110005
+ frameCoords.z[lfp] = thiscoord[2] * invPrecision;
110006
+ lfp++;
110007
+ }
110008
+
110009
+ smallidx += isSmaller;
110010
+
110011
+ if (isSmaller < 0) {
110012
+ smallnum = smaller;
110013
+ if (smallidx > this.FirstIdx) {
110014
+ smaller = (this.MagicInts[smallidx - 1] / 2) | 0;
110015
+ } else {
110016
+ smaller = 0;
110017
+ }
110018
+ } else if (isSmaller > 0) {
110019
+ smaller = smallnum;
110020
+ smallnum = (this.MagicInts[smallidx] / 2) | 0;
110021
+ }
110022
+ sizesmall[0] = sizesmall[1] = sizesmall[2] = this.MagicInts[smallidx];
110023
+
110024
+ if (sizesmall[0] === 0 || sizesmall[1] === 0 || sizesmall[2] === 0) {
110025
+ undefinedError();
110026
+ }
110027
+ }
110028
+ offset += adz;
110029
+ }
110030
+
110031
+ let factor = 10;
110032
+ for (let c = 0; c < natom; c++) {
110033
+ frameCoords.x[c] *= factor;
110034
+ frameCoords.y[c] *= factor;
110035
+ frameCoords.z[c] *= factor;
110036
+ }
110037
+
110038
+ coordinates.push(frameCoords);
110039
+
110040
+ // if (ctx.shouldUpdate) {
110041
+ // await ctx.update({ current: offset, max: data.length });
110042
+ // }
110043
+
110044
+ // if (offset >= data.length) break;
110045
+ if (offset >= dv.byteLength) break;
110046
+ }
110047
+
110048
+ ic.frames = coordinates.length;
110049
+
110050
+ if (times.length >= 1) {
110051
+ ic.TIMEOFFSET = times[0];
110052
+ }
110053
+ if (times.length >= 2) {
110054
+ ic.DELTA = times[1] - times[0];
110055
+ }
110056
+
110057
+ // frames
110058
+ let structuresOri = me.hashUtilsCls.cloneHash(ic.structures);
110059
+ let residuesOri = me.hashUtilsCls.cloneHash(ic.residues);
110060
+ let chainsOri = me.hashUtilsCls.cloneHash(ic.chains);
110061
+
110062
+ let proteinsOri = me.hashUtilsCls.cloneHash(ic.proteins);
110063
+ let nucleotidesOri = me.hashUtilsCls.cloneHash(ic.nucleotides);
110064
+ let waterOri = me.hashUtilsCls.cloneHash(ic.water);
110065
+ let ionsOri = me.hashUtilsCls.cloneHash(ic.ions);
110066
+ let chemicalsOri = me.hashUtilsCls.cloneHash(ic.chemicals);
110067
+
110068
+ // let serial = natom + 1; // a preloaded PDB structure would have atom serial from 1 to natom
110069
+ let serial = 1;
110070
+
110071
+ for (let i = 0, n = coordinates.length; i < n; ++i) {
110072
+ // skip the first structure since it was read from PDB already
110073
+ // if(i == 0) continue;
110074
+
110075
+ // rewrite the coordinates of the first structure
110076
+ let frame = coordinates[i];
110077
+
110078
+ // let molNum = i + 1; // to avoid the same molNum as the PDB structure
110079
+ let molNum = (i == 0) ? '' : i;
110080
+ for(let j = 0; j < natom; ++j) {
110081
+ let coord = new Vector3$1(frame.x[j], frame.y[j], frame.z[j]);
110082
+ let atom = me.hashUtilsCls.cloneHash(ic.atoms[j + 1]);
110083
+
110084
+ atom.serial = serial;
110085
+ atom.structure = atom.structure + molNum;
110086
+ atom.coord = coord;
110087
+ atom.bonds = [].concat(ic.atoms[j + 1].bonds);
110088
+
110089
+ // update bonds
110090
+ for(let k = 0, kl = atom.bonds.length; k < kl; ++k) {
110091
+ atom.bonds[k] = parseInt(atom.bonds[k]) + natom * i;
110092
+ }
110093
+
110094
+ ic.atoms[serial] = atom;
110095
+
110096
+ // assign extra info
110097
+ ic.dAtoms[serial] = 1;
110098
+ ic.hAtoms[serial] = 1;
110099
+
110100
+ let chainid = atom.structure + '_' + atom.chain;
110101
+ let residid = chainid + '_' + atom.resi;
110102
+ ic.secondaries[residid] = atom.ss;
110103
+ ic.residueId2Name[residid] = me.utilsCls.residueName2Abbr(atom.resn);
110104
+
110105
+ ++serial;
110106
+ }
110107
+
110108
+ // update ic.structures, ic.residues and ic.chains
110109
+ for(let structure in structuresOri) {
110110
+ let structure2 = structure + molNum;
110111
+ ic.structures[structure2] = [];
110112
+
110113
+ for(let k = 0, kl = structuresOri[structure].length; k < kl; ++k) {
110114
+ let idArray = structuresOri[structure][k].split('_');
110115
+ ic.structures[structure2].push(structure2 + '_' + idArray[1]);
110116
+ }
110117
+ }
110118
+
110119
+ for(let j in residuesOri) {
110120
+ let idArray = j.split('_');
110121
+ let structure2 = idArray[0] + molNum;
110122
+ let residid2 = structure2 + '_' + idArray[1] + '_' + idArray[2];
110123
+ ic.residues[residid2] = {};
110124
+
110125
+ for(let k in residuesOri[j]) {
110126
+ ic.residues[residid2][parseInt(k) + natom * i] = 1;
110127
+ }
110128
+ }
110129
+
110130
+ for(let j in chainsOri) {
110131
+ let idArray = j.split('_');
110132
+ let structure2 = idArray[0] + molNum;
110133
+ let chainid2 = structure2 + '_' + idArray[1];
110134
+
110135
+ // ic.chainsSeq[chainid2] = [].concat(ic.chainsSeq[j]);
110136
+
110137
+ ic.chains[chainid2] = {};
110138
+ for(let k in chainsOri[j]) {
110139
+ ic.chains[chainid2][parseInt(k)+ natom * i] = 1;
110140
+ }
110141
+ }
110142
+
110143
+ // update ic.proteins, etc
110144
+ for(let j in proteinsOri) {
110145
+ ic.proteins[parseInt(j) + natom * i] = 1;
110146
+ }
110147
+ for(let j in nucleotidesOri) {
110148
+ ic.nucleotides[parseInt(j) + natom * i] = 1;
110149
+ }
110150
+ for(let j in waterOri) {
110151
+ ic.water[parseInt(j) + natom * i] = 1;
110152
+ }
110153
+ for(let j in ionsOri) {
110154
+ ic.ions[parseInt(j) + natom * i] = 1;
110155
+ }
110156
+ for(let j in chemicalsOri) {
110157
+ ic.chemicals[parseInt(j) + natom * i] = 1;
110158
+ }
110159
+
110160
+ // set ic.ncbi2resid and ic.resid2ncbi
110161
+ for(let chainid in chainsOri) {
110162
+ let idArray = chainid.split('_');
110163
+ let structure2 = idArray[0] + molNum;
110164
+ let chainid2 = structure2 + '_' + idArray[1];
110165
+
110166
+ for(let j = 0, jl = ic.chainsSeq[chainid].length; j < jl; ++j) {
110167
+ // NCBI residue number starts from 1 and increases continuously
110168
+ let residNCBI = chainid2 + '_' + (j+1).toString();
110169
+ let resid = chainid2 + '_' + ic.chainsSeq[chainid][j].resi;
110170
+ ic.ncbi2resid[residNCBI] = resid;
110171
+ ic.resid2ncbi[resid] = residNCBI;
110172
+ }
110173
+ }
110174
+ }
110175
+
110176
+ // ic.molTitle = header.TITLE;
110177
+ ic.inputid = 'stru';
110178
+
110179
+ // ic.ParserUtilsCls.setMaxD();
110180
+
110181
+ ic.saveFileCls.showTitle();
110182
+
110183
+ return true;
110184
+ }
110185
+
110186
+ sizeOfInt(size) { let ic = this.icn3d; ic.icn3dui;
110187
+ let num = 1;
110188
+ let numOfBits = 0;
110189
+ while (size >= num && numOfBits < 32) {
110190
+ numOfBits++;
110191
+ num <<= 1;
110192
+ }
110193
+ return numOfBits;
110194
+ }
110195
+
110196
+ sizeOfInts(numOfInts, sizes) { let ic = this.icn3d; ic.icn3dui;
110197
+ let numOfBytes = 1;
110198
+ let numOfBits = 0;
110199
+ this._tmpBytes[0] = 1;
110200
+ for (let i = 0; i < numOfInts; i++) {
110201
+ let bytecnt;
110202
+ let tmp = 0;
110203
+ for (bytecnt = 0; bytecnt < numOfBytes; bytecnt++) {
110204
+ tmp += this._tmpBytes[bytecnt] * sizes[i];
110205
+ this._tmpBytes[bytecnt] = tmp & 0xff;
110206
+ tmp >>= 8;
110207
+ }
110208
+ while (tmp !== 0) {
110209
+ this._tmpBytes[bytecnt++] = tmp & 0xff;
110210
+ tmp >>= 8;
110211
+ }
110212
+ numOfBytes = bytecnt;
110213
+ }
110214
+ let num = 1;
110215
+ numOfBytes--;
110216
+ while (this._tmpBytes[numOfBytes] >= num) {
110217
+ numOfBits++;
110218
+ num *= 2;
110219
+ }
110220
+ return numOfBits + numOfBytes * 8;
110221
+ }
110222
+
110223
+ decodeBits(cbuf, offset, numOfBits1) { let ic = this.icn3d; ic.icn3dui;
110224
+ let numOfBits = numOfBits1;
110225
+ const mask = (1 << numOfBits) - 1;
110226
+ let lastBB0 = this.uint32view[1];
110227
+ let lastBB1 = this.uint32view[2];
110228
+ let cnt = this.buf[0];
110229
+ let num = 0;
110230
+
110231
+ while (numOfBits >= 8) {
110232
+ lastBB1 = (lastBB1 << 8) | cbuf[offset + cnt++];
110233
+ num |= (lastBB1 >> lastBB0) << (numOfBits - 8);
110234
+ numOfBits -= 8;
110235
+ }
110236
+
110237
+ if (numOfBits > 0) {
110238
+ if (lastBB0 < numOfBits) {
110239
+ lastBB0 += 8;
110240
+ lastBB1 = (lastBB1 << 8) | cbuf[offset + cnt++];
110241
+ }
110242
+ lastBB0 -= numOfBits;
110243
+ num |= (lastBB1 >> lastBB0) & ((1 << numOfBits) - 1);
110244
+ }
110245
+
110246
+ num &= mask;
110247
+ this.buf[0] = cnt;
110248
+ this.buf[1] = lastBB0;
110249
+ this.buf[2] = lastBB1;
110250
+
110251
+ return num;
110252
+ }
110253
+
110254
+ decodeByte(cbuf, offset) { let ic = this.icn3d; ic.icn3dui;
110255
+ // special version of decodeBits with numOfBits = 8
110256
+
110257
+ // const mask = 0xff; // (1 << 8) - 1;
110258
+ // let lastBB0 = uint32view[1];
110259
+ let lastBB1 = this.uint32view[2];
110260
+ const cnt = this.buf[0];
110261
+
110262
+ lastBB1 = (lastBB1 << 8) | cbuf[offset + cnt];
110263
+
110264
+ this.buf[0] = cnt + 1;
110265
+ // this.buf[1] = lastBB0;
110266
+ this.buf[2] = lastBB1;
110267
+
110268
+ return (lastBB1 >> this.uint32view[1]) & 0xff;
110269
+ }
110270
+
110271
+ decodeInts(cbuf, offset, numOfBits1, sizes, nums) { let ic = this.icn3d; ic.icn3dui;
110272
+ let numOfBits = numOfBits1;
110273
+ let numOfBytes = 0;
110274
+
110275
+ this.intBytes[0] = 0;
110276
+ this.intBytes[1] = 0;
110277
+ this.intBytes[2] = 0;
110278
+ this.intBytes[3] = 0;
110279
+
110280
+ while (numOfBits > 8) {
110281
+ // this is inversed??? why??? because of the endiannness???
110282
+ this.intBytes[numOfBytes++] = this.decodeByte(cbuf, offset);
110283
+ numOfBits -= 8;
110284
+ }
110285
+
110286
+ if (numOfBits > 0) {
110287
+ this.intBytes[numOfBytes++] = this.decodeBits(cbuf, offset, numOfBits);
110288
+ }
110289
+
110290
+ for (let i = 2; i > 0; i--) {
110291
+ let num = 0;
110292
+ const s = sizes[i];
110293
+ for (let j = numOfBytes - 1; j >= 0; j--) {
110294
+ num = (num << 8) | this.intBytes[j];
110295
+ const t = (num / s) | 0;
110296
+ this.intBytes[j] = t;
110297
+ num = num - t * s;
110298
+ }
110299
+ nums[i] = num;
110300
+ }
110301
+ nums[0] = this.intBytes[0] | (this.intBytes[1] << 8) | (this.intBytes[2] << 16) | (this.intBytes[3] << 24);
110302
+ }
110303
+ }
110304
+
109022
110305
  /**
109023
110306
  * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
109024
110307
  */
@@ -114913,7 +116196,15 @@ class LoadPDB {
114913
116196
  prevCarbonArray.push(atom);
114914
116197
  }
114915
116198
 
114916
- if(!atom.het) {
116199
+ if(atom.resn === 'HOH' || atom.resn === 'WAT' || atom.resn === 'SOL') {
116200
+ ic.water[atom.serial] = 1;
116201
+ atom.color = me.parasCls.atomColors[atom.elem];
116202
+ }
116203
+ else if($.inArray(atom.resn.trim(), me.parasCls.ionsArray) !== -1 || atom.elem.trim() === atom.resn.trim()) {
116204
+ ic.ions[atom.serial] = 1;
116205
+ atom.color = me.parasCls.atomColors[atom.elem];
116206
+ }
116207
+ else if(!atom.het) {
114917
116208
  if($.inArray(atom.resn, me.parasCls.nucleotidesArray) !== -1) {
114918
116209
  ic.nucleotides[atom.serial] = 1;
114919
116210
  //if (atom.name === 'P') {
@@ -114938,19 +116229,7 @@ class LoadPDB {
114938
116229
  }
114939
116230
  }
114940
116231
  else if(atom.het) {
114941
- if(atom.resn === 'HOH' || atom.resn === 'WAT' || atom.resn === 'SOL') {
114942
- ic.water[atom.serial] = 1;
114943
- }
114944
- //else if(bOpm && atom.resn === 'DUM') {
114945
- // ic.mem[atom.serial] = 1;
114946
- //}
114947
- else if($.inArray(atom.resn, me.parasCls.ionsArray) !== -1 || atom.elem.trim() === atom.resn.trim()) {
114948
- ic.ions[atom.serial] = 1;
114949
- }
114950
- else {
114951
- ic.chemicals[atom.serial] = 1;
114952
- }
114953
-
116232
+ ic.chemicals[atom.serial] = 1;
114954
116233
  atom.color = me.parasCls.atomColors[atom.elem];
114955
116234
  }
114956
116235
 
@@ -117748,6 +119027,18 @@ class ApplyCommand {
117748
119027
  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));
117749
119028
  ic.drawCls.draw();
117750
119029
  }
119030
+ else if(command.indexOf('add plane') == 0) {
119031
+ let paraArray = command.split(' | ');
119032
+ let p1Array = paraArray[1].split(' ');
119033
+ let p2Array = paraArray[2].split(' ');
119034
+ let p3Array = paraArray[3].split(' ');
119035
+ let color = paraArray[4].substr(paraArray[4].lastIndexOf(' ') + 1);
119036
+ let thickness = (paraArray.length > 5) ? paraArray[5].substr(paraArray[5].lastIndexOf(' ') + 1) : 2;
119037
+ let opacity = (paraArray.length > 6) ? paraArray[6].substr(paraArray[6].lastIndexOf(' ') + 1) : 0.3;
119038
+
119039
+ 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));
119040
+ ic.drawCls.draw();
119041
+ }
117751
119042
  else if(command.indexOf('add sphere') == 0) {
117752
119043
  this.addShape(commandOri, 'sphere');
117753
119044
  ic.shapeCmdHash[commandOri] = 1;
@@ -117766,6 +119057,10 @@ class ApplyCommand {
117766
119057
  ic.lines['cylinder'] = []; // reset
117767
119058
  //ic.drawCls.draw();
117768
119059
  }
119060
+ else if(command.indexOf('clear plane among sets') == 0) {
119061
+ ic.planes = []; // reset
119062
+ //ic.drawCls.draw();
119063
+ }
117769
119064
  else if(commandOri.indexOf('add label') == 0) {
117770
119065
  let paraArray = commandOri.split(' | ');
117771
119066
  let text = paraArray[0].substr(('add label').length + 1);
@@ -126519,6 +127814,21 @@ class Analysis {
126519
127814
  //ic.drawCls.draw();
126520
127815
  }
126521
127816
 
127817
+ //Add a plane among the positions (x1, y1, z1), (x2, y2, z2) and (x3, y3, z3) with the input "color".
127818
+ addPlane(x1, y1, z1, x2, y2, z2, x3, y3, z3, color, thickness, opacity) {var ic = this.icn3d; ic.icn3dui;
127819
+ let plane = {}; // Each plane contains 'position1', 'position2', 'position3', 'color', and 'thickness'
127820
+ plane.position1 = new Vector3$1(x1, y1, z1);
127821
+ plane.position2 = new Vector3$1(x2, y2, z2);
127822
+ plane.position3 = new Vector3$1(x3, y3, z3);
127823
+ plane.color = color;
127824
+ plane.thickness = thickness;
127825
+ plane.opacity = opacity;
127826
+ if(ic.planes === undefined) ic.planes = [];
127827
+ ic.planes.push(plane);
127828
+
127829
+ ic.hlObjectsCls.removeHlObjects();
127830
+ }
127831
+
126522
127832
  addLineFromPicking(type) {var ic = this.icn3d, me = ic.icn3dui;
126523
127833
  let color = $("#" + ic.pre + type + "color" ).val();
126524
127834
  (ic.pAtom.coord.x + ic.pAtom2.coord.x) / 2;
@@ -130305,12 +131615,13 @@ class SaveFile {
130305
131615
  let structureArray = Object.keys(me.utilsCls.getStructures(ic.dAtoms));
130306
131616
 
130307
131617
  if(structureArray.length > 1) {
130308
- title = 'Multiple structures: ';
130309
- for(let i = 0, il = structureArray.length; i < il; ++i) {
131618
+ title = structureArray.length + ' structures: ';
131619
+ for(let i = 0, il = structureArray.length; i < il && i < 5; ++i) {
130310
131620
  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];
130311
131621
  title += '<a href="' + url + '" style="color:' + titlelinkColor + '" target="_blank">' + structureArray[i] + '</a>';
130312
131622
  if(i < il - 1) title += ', ';
130313
131623
  }
131624
+ if(structureArray.length > 5) title += '...';
130314
131625
  $("#" + ic.pre + "title").html(title);
130315
131626
  }
130316
131627
  else if(structureArray.length == 1) {
@@ -132101,12 +133412,11 @@ class Control {
132101
133412
  ic.transformCls.setRotation(axis, angle);
132102
133413
  }
132103
133414
 
132104
- else if(e.keyCode === 65 ) { // A, alternate
133415
+ else if(e.keyCode === 65 ) { // A, alternate forward
132105
133416
  if(Object.keys(ic.structures).length > 1) {
132106
133417
  await ic.alternateCls.alternateWrapper();
132107
133418
  }
132108
133419
  }
132109
-
132110
133420
  }
132111
133421
  });
132112
133422
 
@@ -133556,6 +134866,8 @@ class iCn3D {
133556
134866
  this.pdbParserCls = new PdbParser(this);
133557
134867
  this.sdfParserCls = new SdfParser(this);
133558
134868
  this.xyzParserCls = new XyzParser(this);
134869
+ this.dcdParserCls = new DcdParser(this);
134870
+ this.xtcParserCls = new XtcParser(this);
133559
134871
  this.msaParserCls = new MsaParser(this);
133560
134872
  this.realignParserCls = new RealignParser(this);
133561
134873
  this.densityCifParserCls = new DensityCifParser(this);
@@ -133813,7 +135125,7 @@ class iCn3DUI {
133813
135125
  //even when multiple iCn3D viewers are shown together.
133814
135126
  this.pre = this.cfg.divid + "_";
133815
135127
 
133816
- this.REVISION = '3.46.0';
135128
+ this.REVISION = '3.47.0';
133817
135129
 
133818
135130
  // In nodejs, iCn3D defines "window = {navigator: {}}", and added window = {navigator: {}, "__THREE__":"177"}
133819
135131
  this.bNode = (Object.keys(window).length < 3) ? true : false;
@@ -134574,4 +135886,4 @@ class printMsg {
134574
135886
  }
134575
135887
  }
134576
135888
 
134577
- export { ARButton, AddTrack, AlignParser, AlignSW, AlignSeq, Alternate, Analysis, AnnoCddSite, AnnoContact, AnnoCrossLink, AnnoDomain, AnnoSnpClinVar, AnnoSsbond, AnnoTransMem, Annotation, ApplyCenter, ApplyClbonds, ApplyCommand, ApplyDisplay, ApplyMap, ApplyOther, ApplySsbonds, ApplySymd, Axes, Box, Brick, Camera, CartoonNucl, ChainalignParser, ClickMenu, Contact, Control, ConvertTypeCls, Curve, CurveStripArrow, Cylinder, DefinedSets, Delphi, DensityCifParser, Diagram2d, Dialog, Domain3d, Draw, DrawGraph, Dsn6Parser, Dssp, ElectronMap, Events, Export3D, FirstAtomObj, Fog, GetGraph, Glycan, HBond, HashUtilsCls, HlObjects, HlSeq, HlUpdate, Html, Impostor, Instancing, Label, Line$1 as Line, LineGraph, LoadAtomData, LoadCIF, LoadPDB, LoadScript, MarchingCube, MmcifParser, MmdbParser, Mol2Parser, MsaParser, MyEventCls, OpmParser, ParasCls, ParserUtils, PdbParser, PiHalogen, Picking, ProteinSurface, Ray, RealignParser, Refnum, ReprSub, Resid2spec, ResidueLabels, ResizeCanvas, RmsdSuprCls, Saltbridge, SaveFile, Scap, Scene, SdfParser, SelectByCommand, Selection, SetColor, SetDialog, SetHtml, SetMenu, SetOption, SetSeqAlign, SetStyle, ShareLink, ShowAnno, ShowInter, ShowSeq, Sphere$1 as Sphere, Stick, Strand, Strip, SubdivideCls, Surface, Symd, ThreeDPrint, Transform, Tube, UtilsCls, VRButton, Vastplus, ViewInterPairs, XyzParser, iCn3D, iCn3DUI, printMsg };
135889
+ export { ARButton, AddTrack, AlignParser, AlignSW, AlignSeq, Alternate, Analysis, AnnoCddSite, AnnoContact, AnnoCrossLink, AnnoDomain, AnnoSnpClinVar, AnnoSsbond, AnnoTransMem, Annotation, ApplyCenter, ApplyClbonds, ApplyCommand, ApplyDisplay, ApplyMap, ApplyOther, ApplySsbonds, ApplySymd, Axes, Box, Brick, Camera, CartoonNucl, ChainalignParser, ClickMenu, Contact, Control, ConvertTypeCls, Curve, CurveStripArrow, Cylinder, DcdParser, DefinedSets, Delphi, DensityCifParser, Diagram2d, Dialog, Domain3d, Draw, DrawGraph, Dsn6Parser, Dssp, ElectronMap, Events, Export3D, FirstAtomObj, Fog, GetGraph, Glycan, HBond, HashUtilsCls, HlObjects, HlSeq, HlUpdate, Html, Impostor, Instancing, Label, Line$1 as Line, LineGraph, LoadAtomData, LoadCIF, LoadPDB, LoadScript, MarchingCube, MmcifParser, MmdbParser, Mol2Parser, MsaParser, MyEventCls, OpmParser, ParasCls, ParserUtils, PdbParser, PiHalogen, Picking, ProteinSurface, Ray, RealignParser, Refnum, ReprSub, Resid2spec, ResidueLabels, ResizeCanvas, RmsdSuprCls, Saltbridge, SaveFile, Scap, Scene, SdfParser, SelectByCommand, Selection, SetColor, SetDialog, SetHtml, SetMenu, SetOption, SetSeqAlign, SetStyle, ShareLink, ShowAnno, ShowInter, ShowSeq, Sphere$1 as Sphere, Stick, Strand, Strip, SubdivideCls, Surface, Symd, ThreeDPrint, Transform, Tube, UtilsCls, VRButton, Vastplus, ViewInterPairs, XtcParser, XyzParser, iCn3D, iCn3DUI, printMsg };