icn3d 3.41.0 → 3.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/icn3d.js CHANGED
@@ -2539,7 +2539,6 @@ THREE.TrackballControls = function ( object, domElement, icn3d ) {
2539
2539
  _this._panStart.add( mouseChange.subVectors( _this._panEnd, _this._panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
2540
2540
 
2541
2541
  }
2542
-
2543
2542
  }
2544
2543
  }
2545
2544
 
@@ -3576,6 +3575,103 @@ THREE.OrthographicTrackballControls = function ( object, domElement, icn3d ) { v
3576
3575
  THREE.OrthographicTrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
3577
3576
  THREE.OrthographicTrackballControls.prototype.constructor = THREE.OrthographicTrackballControls;
3578
3577
 
3578
+ /**
3579
+ * @author alteredq / http://alteredqualia.com/
3580
+ * @authod mrdoob / http://mrdoob.com/
3581
+ * @authod arodic / http://aleksandarrodic.com/
3582
+ * modified by Jiyao Wang
3583
+ */
3584
+
3585
+ THREE.StereoEffect = function ( renderer ) {
3586
+ var _this = this;
3587
+ // API
3588
+
3589
+ _this.separation = 3; // 1;
3590
+
3591
+ // internals
3592
+
3593
+ // _this._width, _this._height;
3594
+
3595
+ _this._position = new THREE.Vector3();
3596
+ _this._quaternion = new THREE.Quaternion();
3597
+ _this._scale = new THREE.Vector3();
3598
+
3599
+ _this._cameraL = new THREE.PerspectiveCamera();
3600
+ _this._cameraR = new THREE.PerspectiveCamera();
3601
+
3602
+ // initialization
3603
+
3604
+ renderer.autoClear = false;
3605
+
3606
+ _this.setSize = function ( width, height ) {
3607
+
3608
+ _this._width = width / 2;
3609
+ _this._height = height;
3610
+
3611
+ renderer.setSize( width, height );
3612
+
3613
+ };
3614
+
3615
+ _this.render = function ( scene, camera ) {
3616
+
3617
+ scene.updateMatrixWorld();
3618
+
3619
+ if ( camera.parent === undefined ) camera.updateMatrixWorld();
3620
+
3621
+ camera.matrixWorld.decompose( _this._position, _this._quaternion, _this._scale );
3622
+
3623
+ // left
3624
+ _this._cameraL.copy(camera);
3625
+ _this._cameraL.aspect = 0.5 * camera.aspect;
3626
+ _this._cameraL.updateProjectionMatrix();
3627
+
3628
+ /*
3629
+ _this._cameraL.fov = camera.fov;
3630
+ _this._cameraL.aspect = 0.5 * camera.aspect;
3631
+ _this._cameraL.near = camera.near;
3632
+ _this._cameraL.far = camera.far;
3633
+ _this._cameraL.updateProjectionMatrix();
3634
+
3635
+ _this._cameraL.position.copy( _this._position );
3636
+ // _this._cameraL.quaternion.copy( _this._quaternion );
3637
+ */
3638
+ _this._cameraL.translateX( - _this.separation );
3639
+
3640
+ // right
3641
+ _this._cameraR.copy(camera);
3642
+ _this._cameraR.aspect = 0.5 * camera.aspect;
3643
+ _this._cameraR.updateProjectionMatrix();
3644
+
3645
+ /*
3646
+ _this._cameraR.fov = camera.fov;
3647
+ _this._cameraR.aspect = 0.5 * camera.aspect;
3648
+ _this._cameraR.near = camera.near;
3649
+ _this._cameraR.far = camera.far;
3650
+ // _this._cameraR.projectionMatrix = _this._cameraL.projectionMatrix;
3651
+ _this._cameraR.updateProjectionMatrix();
3652
+
3653
+ _this._cameraR.position.copy( _this._position );
3654
+ // _this._cameraR.quaternion.copy( _this._quaternion );
3655
+ */
3656
+
3657
+ _this._cameraR.translateX( _this.separation );
3658
+
3659
+ //
3660
+
3661
+ renderer.setViewport( 0, 0, _this._width * 2, _this._height );
3662
+ renderer.clear();
3663
+
3664
+ renderer.setViewport( 0, 0, _this._width, _this._height );
3665
+ renderer.render( scene, _this._cameraL );
3666
+
3667
+ renderer.setViewport( _this._width, 0, _this._width, _this._height );
3668
+ renderer.render( scene, _this._cameraR );
3669
+
3670
+ };
3671
+
3672
+ };
3673
+
3674
+
3579
3675
 
3580
3676
  // ; var __CIFTools = function () {
3581
3677
  // 'use strict';
@@ -8805,6 +8901,7 @@ class ClickMenu {
8805
8901
 
8806
8902
  applyShownMenus(bNoSave) { let me = this.icn3dui; me.icn3d;
8807
8903
  let idArray = [];
8904
+
8808
8905
  for(let id in me.htmlCls.allMenus) {
8809
8906
  if(me.htmlCls.shownMenus.hasOwnProperty(id)) {
8810
8907
  $("#" + me.pre + id).parent().show();
@@ -9035,6 +9132,14 @@ class ClickMenu {
9035
9132
  me.htmlCls.dialogCls.openDlg('dl_urlfile', 'Load data by URL');
9036
9133
  });
9037
9134
 
9135
+ me.myEventCls.onIds("#" + me.pre + "mn1_clustalwfile", "click", function(e) { me.icn3d; //e.preventDefault();
9136
+ me.htmlCls.dialogCls.openDlg('dl_clustalwfile', 'Please input CLUSTALW MSA File');
9137
+ });
9138
+
9139
+ me.myEventCls.onIds("#" + me.pre + "mn1_fastafile", "click", function(e) { me.icn3d; //e.preventDefault();
9140
+ me.htmlCls.dialogCls.openDlg('dl_fastafile', 'Please input FASTA MSA File');
9141
+ });
9142
+
9038
9143
  me.myEventCls.onIds("#" + me.pre + "mn1_fixedversion", "click", function(e) { me.icn3d; //e.preventDefault();
9039
9144
  me.htmlCls.dialogCls.openDlg('dl_fixedversion', 'Open Share Link URL in the archived version of iCn3D');
9040
9145
  });
@@ -9136,6 +9241,11 @@ class ClickMenu {
9136
9241
  ic.saveFileCls.saveFile(file_pref + '_statefile.txt', 'command');
9137
9242
  });
9138
9243
 
9244
+ me.myEventCls.onIds("#" + me.pre + "mn1_exportVideo", "click", function(e) { me.icn3d; //e.preventDefault();
9245
+ thisClass.setLogCmd("export video", false);
9246
+ me.htmlCls.dialogCls.openDlg('dl_video', 'Save canvas changes in a video');
9247
+ });
9248
+
9139
9249
 
9140
9250
  me.myEventCls.onIds("#" + me.pre + "mn1_exportPdbRes", "click", function(e) { me.icn3d; //e.preventDefault();
9141
9251
  me.htmlCls.setHtmlCls.exportPdb();
@@ -10828,6 +10938,18 @@ class ClickMenu {
10828
10938
  //}
10829
10939
  });
10830
10940
 
10941
+ me.myEventCls.onIds("#" + me.pre + "mn6_stereoYes", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
10942
+ ic.opts['effect'] = 'stereo';
10943
+ ic.drawCls.draw();
10944
+ thisClass.setLogCmd('stereo on', true);
10945
+ });
10946
+
10947
+ me.myEventCls.onIds("#" + me.pre + "mn6_stereoNo", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
10948
+ ic.opts['effect'] = 'none';
10949
+ ic.drawCls.draw();
10950
+ thisClass.setLogCmd('stereo off', true);
10951
+ });
10952
+
10831
10953
  $(document).on("click", "#" + me.pre + "mn2_translate", function(e) { me.icn3d; //e.preventDefault();
10832
10954
  me.htmlCls.dialogCls.openDlg('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
10833
10955
  });
@@ -11841,9 +11963,19 @@ class SetMenu {
11841
11963
  html += this.getLink('mn1_mol2file', 'Mol2 File', undefined, 2);
11842
11964
  html += this.getLink('mn1_sdffile', 'SDF File', undefined, 2);
11843
11965
  html += this.getLink('mn1_xyzfile', 'XYZ File', undefined, 2);
11966
+
11967
+ html += this.getMenuSep();
11968
+
11969
+ html += this.getMenuText('mn1_msawrap', 'Multiple Seq. Alignment', undefined, undefined, 2);
11970
+ html += "<ul>";
11971
+ html += this.getLink('mn1_clustalwfile', 'CLUSTALW Format', undefined, 3);
11972
+ html += this.getLink('mn1_fastafile', 'FASTA Format', undefined, 3);
11973
+ html += "</ul>";
11974
+
11844
11975
  html += this.getLink('mn1_afmapfile', 'AlphaFold PAE File', undefined, 2);
11845
11976
 
11846
11977
  html += this.getLink('mn1_urlfile', 'URL(CORS) ' + me.htmlCls.wifiStr, undefined, 2);
11978
+
11847
11979
  html += this.getMenuSep();
11848
11980
  html += this.getLink('mn1_pngimage', 'iCn3D PNG (appendable)', 1, 2);
11849
11981
  html += this.getLink('mn1_state', 'State/Script File', undefined, 2);
@@ -11950,6 +12082,7 @@ class SetMenu {
11950
12082
  html += "</ul>";
11951
12083
  html += "</li>";
11952
12084
 
12085
+ html += this.getLink('mn1_exportVideo', 'Video', undefined, 2);
11953
12086
  html += this.getLink('mn1_exportState', 'State File', undefined, 2);
11954
12087
  html += this.getLink('mn1_exportSelections', 'Selection File', undefined, 2);
11955
12088
  html += this.getLink('mn1_exportSelDetails', 'Selection Details', undefined, 2);
@@ -12167,6 +12300,13 @@ class SetMenu {
12167
12300
  html += "</ul>";
12168
12301
  html += "</li>";
12169
12302
 
12303
+ html += this.getMenuText('mn6_stereoWrapper', 'Stereo View', undefined, undefined, 1);
12304
+ html += "<ul>";
12305
+ html += this.getRadio('mn6_stereo', 'mn6_stereoYes', 'On', undefined, undefined, 2);
12306
+ html += this.getRadio('mn6_stereo', 'mn6_stereoNo', 'Off', true, undefined, 2);
12307
+ html += "</ul>";
12308
+ html += "</li>";
12309
+
12170
12310
  html += this.getLink('mn6_sidebyside', 'Side by Side', undefined, 1);
12171
12311
 
12172
12312
  html += this.getMenuText('mn2_rotate', 'Rotate', undefined, 1, 1);
@@ -14196,6 +14336,19 @@ class SetDialog {
14196
14336
  html += me.htmlCls.buttonStr + "reload_xyzfile'>Load</button>";
14197
14337
  html += "</div>";
14198
14338
 
14339
+ html += me.htmlCls.divStr + "dl_clustalwfile' class='" + dialogClass + "' style='max-width:500px'>";
14340
+ html += this.addNotebookTitle('dl_clustalwfile', 'Please input a CLUSTALW MSA file');
14341
+ 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>";
14342
+ html += "CLUSTALW File: " + me.htmlCls.inputFileStr + "id='" + me.pre + "clustalwfile' size=8> ";
14343
+ html += me.htmlCls.buttonStr + "reload_clustalwfile'>Load</button><br>";
14344
+ html += "</div>";
14345
+ html += me.htmlCls.divStr + "dl_fastafile' class='" + dialogClass + "' style='max-width:500px'>";
14346
+ html += this.addNotebookTitle('dl_fastafile', 'Please input a FASTA file');
14347
+ html += "Note the sequence IDs following the symbol \">\" contain either UniProt ID (e.g., sp| or tr|), RefSeq ID (e.g., ref|), PDB chain ID (e.g., pdb|1HHO|A), or iCn3D chain ID (e.g., A4D1S0_A, 1HHO_A).<br><br>";
14348
+ html += "FASTA File: " + me.htmlCls.inputFileStr + "id='" + me.pre + "fastafile' size=8> ";
14349
+ html += me.htmlCls.buttonStr + "reload_fastafile'>Load</button><br>";
14350
+ html += "</div>";
14351
+
14199
14352
  html += me.htmlCls.divStr + "dl_afmapfile' class='" + dialogClass + "'>";
14200
14353
  html += this.addNotebookTitle('dl_afmapfile', 'Please input an AlphaFold PAE file');
14201
14354
  html += "AlphaFold PAE File: " + me.htmlCls.inputFileStr + "id='" + me.pre + "afmapfile' size=8> <br><br>";
@@ -14315,6 +14468,12 @@ class SetDialog {
14315
14468
  html += me.htmlCls.buttonStr + "reload_state' style='margin-top: 6px;'>Load</button>";
14316
14469
  html += "</div>";
14317
14470
 
14471
+ html += me.htmlCls.divStr + "dl_video' class='" + dialogClass + "'>";
14472
+ html += this.addNotebookTitle('dl_video', 'Save canvas changes in a video');
14473
+ html += me.htmlCls.buttonStr + "video_start' style='margin-top: 6px;'>Video Start</button>";
14474
+ html += me.htmlCls.buttonStr + "video_end' style='margin: 6px 0px 0px 30px;'>Video End</button>";
14475
+ html += "</div>";
14476
+
14318
14477
  html += me.htmlCls.divStr + "dl_fixedversion' style='max-width:500px' class='" + dialogClass + "'>";
14319
14478
  html += this.addNotebookTitle('dl_fixedversion', 'Use fixed version of iCn3D');
14320
14479
  html += "Since January 6, 2021, you can show the original view with the archived version of iCn3D by pasting your URL below and click \"Show Originial View\". Note the version in the parameter \"v\" was used to replace \"full.html\" with \"full_[v].html\" in the URL.<br><br>";
@@ -15674,17 +15833,10 @@ class Events {
15674
15833
  }
15675
15834
  }
15676
15835
 
15677
- async loadPdbFile(bAppend, fileId, bmmCIF) { let me = this.icn3dui, ic = me.icn3d;
15836
+ async loadPdbFile(bAppend, fileId, bmmCIF) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
15678
15837
  //me = ic.setIcn3dui(this.id);
15679
15838
  ic.bInitial = true;
15680
- if(!me.cfg.notebook) dialog.dialog( "close" );
15681
- //close all dialog
15682
- if(!me.cfg.notebook) {
15683
- $(".ui-dialog-content").dialog("close");
15684
- }
15685
- else {
15686
- ic.resizeCanvasCls.closeDialogs();
15687
- }
15839
+ thisClass.iniFileLoad();
15688
15840
  let files = $("#" + me.pre + fileId)[0].files;
15689
15841
  if(!files[0]) {
15690
15842
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
@@ -15730,11 +15882,22 @@ class Events {
15730
15882
 
15731
15883
  exportMsa(type) { let me = this.icn3dui, ic = me.icn3d;
15732
15884
  let text = ic.msa[type].join('\n\n');
15733
- let fileType = (type == 'fasta') ? '.fasta' : (type == 'clustal') ? '.aln' : '.txt';
15885
+ let fileType = (type == 'fasta') ? '.fasta' : (type == 'clustalw') ? '.aln' : '.txt';
15734
15886
 
15735
15887
  ic.saveFileCls.saveFile(ic.inputid + '_align' + fileType, 'text', [text]);
15736
15888
  }
15737
15889
 
15890
+ iniFileLoad() { let me = this.icn3dui, ic = me.icn3d;
15891
+ if(!me.cfg.notebook) dialog.dialog( "close" );
15892
+ //close all dialog
15893
+ if(!me.cfg.notebook) {
15894
+ $(".ui-dialog-content").dialog("close");
15895
+ }
15896
+ else {
15897
+ ic.resizeCanvasCls.closeDialogs();
15898
+ }
15899
+ }
15900
+
15738
15901
  async launchMmdb(ids, bBiounit, hostUrl, bAppend) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
15739
15902
  if(!me.cfg.notebook) dialog.dialog( "close" );
15740
15903
 
@@ -16830,16 +16993,40 @@ class Events {
16830
16993
 
16831
16994
  me.htmlCls.setHtmlCls.clickReload_pngimage();
16832
16995
 
16996
+ me.myEventCls.onIds("#" + me.pre + "video_start", "click", function(e) { let ic = me.icn3d;
16997
+ e.preventDefault();
16998
+
16999
+ const canvas = document.getElementById(ic.pre + "canvas");
17000
+ ic.videoRecorder = new MediaRecorder(canvas.captureStream());
17001
+ const recordedChunks = [];
17002
+
17003
+ // Collect data chunks
17004
+ ic.videoRecorder.ondataavailable = event => {
17005
+ recordedChunks.push(event.data);
17006
+ };
17007
+
17008
+ ic.videoRecorder.onstop = event => {
17009
+ // Code to save the recordedChunks as a video file
17010
+ const blob = new Blob(recordedChunks, {type: ic.videoRecorder.mimeType});
17011
+ let fileName = ic.inputid + '_video';
17012
+ saveAs(blob, fileName);
17013
+ };
17014
+
17015
+ // Start recording
17016
+ ic.videoRecorder.start();
17017
+ thisClass.setLogCmd('Video revording started', false);
17018
+ });
17019
+
17020
+ me.myEventCls.onIds("#" + me.pre + "video_end", "click", function(e) { let ic = me.icn3d;
17021
+ e.preventDefault();
17022
+
17023
+ ic.videoRecorder.stop();
17024
+ thisClass.setLogCmd('Video revording ended', false);
17025
+ });
17026
+
16833
17027
  me.myEventCls.onIds("#" + me.pre + "reload_state", "click", function(e) { let ic = me.icn3d;
16834
17028
  e.preventDefault();
16835
- if(!me.cfg.notebook) dialog.dialog( "close" );
16836
- //close all dialog
16837
- if(!me.cfg.notebook) {
16838
- $(".ui-dialog-content").dialog("close");
16839
- }
16840
- else {
16841
- ic.resizeCanvasCls.closeDialogs();
16842
- }
17029
+ thisClass.iniFileLoad();
16843
17030
  // initialize icn3dui
16844
17031
  //Do NOT clear data if iCn3D loads a pdb or other data file and then load a state file
16845
17032
  if(!ic.bInputfile) {
@@ -16891,12 +17078,7 @@ class Events {
16891
17078
  if (!file) {
16892
17079
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
16893
17080
  } else {
16894
- if (!me.cfg.notebook) dialog.dialog("close");
16895
- if (!me.cfg.notebook) {
16896
- $(".ui-dialog-content").dialog("close");
16897
- } else {
16898
- ic.resizeCanvasCls.closeDialogs();
16899
- }
17081
+ thisClass.iniFileLoad();
16900
17082
 
16901
17083
  ic.dAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
16902
17084
  ic.hAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
@@ -17451,14 +17633,7 @@ class Events {
17451
17633
  me.myEventCls.onIds("#" + me.pre + "reload_mol2file", "click", function(e) { let ic = me.icn3d;
17452
17634
  e.preventDefault();
17453
17635
  ic.bInitial = true;
17454
- if(!me.cfg.notebook) dialog.dialog( "close" );
17455
- //close all dialog
17456
- if(!me.cfg.notebook) {
17457
- $(".ui-dialog-content").dialog("close");
17458
- }
17459
- else {
17460
- ic.resizeCanvasCls.closeDialogs();
17461
- }
17636
+ thisClass.iniFileLoad();
17462
17637
  let file = $("#" + me.pre + "mol2file")[0].files[0];
17463
17638
  if(!file) {
17464
17639
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
@@ -17485,14 +17660,7 @@ class Events {
17485
17660
  me.myEventCls.onIds("#" + me.pre + "reload_sdffile", "click", function(e) { let ic = me.icn3d;
17486
17661
  e.preventDefault();
17487
17662
  ic.bInitial = true;
17488
- if(!me.cfg.notebook) dialog.dialog( "close" );
17489
- //close all dialog
17490
- if(!me.cfg.notebook) {
17491
- $(".ui-dialog-content").dialog("close");
17492
- }
17493
- else {
17494
- ic.resizeCanvasCls.closeDialogs();
17495
- }
17663
+ thisClass.iniFileLoad();
17496
17664
  let file = $("#" + me.pre + "sdffile")[0].files[0];
17497
17665
  if(!file) {
17498
17666
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
@@ -17519,14 +17687,7 @@ class Events {
17519
17687
  me.myEventCls.onIds("#" + me.pre + "reload_xyzfile", "click", function(e) { let ic = me.icn3d;
17520
17688
  e.preventDefault();
17521
17689
  ic.bInitial = true;
17522
- if(!me.cfg.notebook) dialog.dialog( "close" );
17523
- //close all dialog
17524
- if(!me.cfg.notebook) {
17525
- $(".ui-dialog-content").dialog("close");
17526
- }
17527
- else {
17528
- ic.resizeCanvasCls.closeDialogs();
17529
- }
17690
+ thisClass.iniFileLoad();
17530
17691
  let file = $("#" + me.pre + "xyzfile")[0].files[0];
17531
17692
  if(!file) {
17532
17693
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
@@ -17550,17 +17711,64 @@ class Events {
17550
17711
  }
17551
17712
  });
17552
17713
 
17553
- me.myEventCls.onIds("#" + me.pre + "reload_afmapfile", "click", function(e) { let ic = me.icn3d;
17714
+ me.myEventCls.onIds("#" + me.pre + "reload_clustalwfile", "click", function(e) { let ic = me.icn3d;
17554
17715
  e.preventDefault();
17555
17716
  ic.bInitial = true;
17556
- if(!me.cfg.notebook) dialog.dialog( "close" );
17557
- //close all dialog
17558
- if(!me.cfg.notebook) {
17559
- $(".ui-dialog-content").dialog("close");
17717
+ thisClass.iniFileLoad();
17718
+
17719
+ let file = $("#" + me.pre + "clustalwfile")[0].files[0];
17720
+ if(!file) {
17721
+ var aaa = 1; //alert("Please select a file before clicking 'Load'");
17560
17722
  }
17561
17723
  else {
17562
- ic.resizeCanvasCls.closeDialogs();
17724
+ me.htmlCls.setHtmlCls.fileSupport();
17725
+ let reader = new FileReader();
17726
+ reader.onload = async function(e) {
17727
+ let dataStr = e.target.result; // or = reader.result;
17728
+ thisClass.setLogCmd('load CLUSTALW file ' + $("#" + me.pre + "clustalwfile").val(), false);
17729
+ ic.molTitle = "";
17730
+ ic.inputid = undefined;
17731
+ //ic.initUI();
17732
+ ic.init();
17733
+ ic.bInputfile = false; //true;
17734
+ ic.InputfileType = 'clustalw';
17735
+ await ic.msaParserCls.loadMsaData(dataStr, 'clustalw');
17736
+ };
17737
+ reader.readAsText(file);
17563
17738
  }
17739
+ });
17740
+
17741
+ me.myEventCls.onIds("#" + me.pre + "reload_fastafile", "click", function(e) { let ic = me.icn3d;
17742
+ e.preventDefault();
17743
+ ic.bInitial = true;
17744
+ thisClass.iniFileLoad();
17745
+
17746
+ let file = $("#" + me.pre + "fastafile")[0].files[0];
17747
+ if(!file) {
17748
+ var aaa = 1; //alert("Please select a file before clicking 'Load'");
17749
+ }
17750
+ else {
17751
+ me.htmlCls.setHtmlCls.fileSupport();
17752
+ let reader = new FileReader();
17753
+ reader.onload = async function(e) {
17754
+ let dataStr = e.target.result; // or = reader.result;
17755
+ thisClass.setLogCmd('load FASTA file ' + $("#" + me.pre + "fastafile").val(), false);
17756
+ ic.molTitle = "";
17757
+ ic.inputid = undefined;
17758
+ //ic.initUI();
17759
+ ic.init();
17760
+ ic.bInputfile = false; //true;
17761
+ ic.InputfileType = 'fasta';
17762
+ await ic.msaParserCls.loadMsaData(dataStr, 'fasta');
17763
+ };
17764
+ reader.readAsText(file);
17765
+ }
17766
+ });
17767
+
17768
+ me.myEventCls.onIds("#" + me.pre + "reload_afmapfile", "click", function(e) { let ic = me.icn3d;
17769
+ e.preventDefault();
17770
+ ic.bInitial = true;
17771
+ thisClass.iniFileLoad();
17564
17772
  let file = $("#" + me.pre + "afmapfile")[0].files[0];
17565
17773
  if(!file) {
17566
17774
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
@@ -17582,14 +17790,7 @@ class Events {
17582
17790
  me.myEventCls.onIds("#" + me.pre + "reload_afmapfilefull", "click", function(e) { let ic = me.icn3d;
17583
17791
  e.preventDefault();
17584
17792
  ic.bInitial = true;
17585
- if(!me.cfg.notebook) dialog.dialog( "close" );
17586
- //close all dialog
17587
- if(!me.cfg.notebook) {
17588
- $(".ui-dialog-content").dialog("close");
17589
- }
17590
- else {
17591
- ic.resizeCanvasCls.closeDialogs();
17592
- }
17793
+ thisClass.iniFileLoad();
17593
17794
  let file = $("#" + me.pre + "afmapfile")[0].files[0];
17594
17795
  if(!file) {
17595
17796
  var aaa = 1; //alert("Please select a file before clicking 'Load'");
@@ -17611,14 +17812,7 @@ class Events {
17611
17812
  me.myEventCls.onIds("#" + me.pre + "reload_urlfile", "click", async function(e) { let ic = me.icn3d;
17612
17813
  e.preventDefault();
17613
17814
  ic.bInitial = true;
17614
- if(!me.cfg.notebook) dialog.dialog( "close" );
17615
- //close all dialog
17616
- if(!me.cfg.notebook) {
17617
- $(".ui-dialog-content").dialog("close");
17618
- }
17619
- else {
17620
- ic.resizeCanvasCls.closeDialogs();
17621
- }
17815
+ thisClass.iniFileLoad();
17622
17816
  let type = $("#" + me.pre + "filetype").val();
17623
17817
  let url = $("#" + me.pre + "urlfile").val();
17624
17818
  ic.inputurl = 'type=' + type + '&url=' + encodeURIComponent(url);
@@ -18493,8 +18687,8 @@ class Events {
18493
18687
 
18494
18688
  me.myEventCls.onIds("#" + me.pre + "saveClustal", "click", function(e) { me.icn3d;
18495
18689
  e.stopImmediatePropagation();
18496
- thisClass.exportMsa('clustal');
18497
- thisClass.setLogCmd('Save alignment in CLUSTALW format', false);
18690
+ thisClass.exportMsa('clustalw');
18691
+ thisClass.setLogCmd('Save alignment in CLUSTALWW format', false);
18498
18692
  });
18499
18693
 
18500
18694
  me.myEventCls.onIds("#" + me.pre + "saveResbyres", "click", function(e) { me.icn3d;
@@ -19364,7 +19558,7 @@ class SetHtml {
19364
19558
 
19365
19559
  sequencesHtml += "<div style='min-width:200px; display:inline-block;'><b>Selection:</b> Name: " + me.htmlCls.inputTextStr + "id='" + me.pre + "alignseq_command_name' value='alseq_" + index + "' size='10'> " + me.htmlCls.space2 + "<button style='white-space:nowrap;' id='" + me.pre + "alignseq_saveselection'>Save</button> <button style='white-space:nowrap; margin-left:20px;' id='" + me.pre + "alignseq_clearselection'>Clear</button></div><br/>";
19366
19560
 
19367
- sequencesHtml += "<div style='min-width:200px; display:inline-block; margin-top:3px'><b>Save Alignment</b>: " + "<button style='white-space:nowrap;' id='" + me.pre + "saveFasta'>FASTA</button> <button style='white-space:nowrap; margin-left:20px;' id='" + me.pre + "saveClustal'>CLUSTAL</button> <button style='white-space:nowrap; margin-left:20px;' id='" + me.pre + "saveResbyres'>Residue by Residue</button></div><br/>";
19561
+ sequencesHtml += "<div style='min-width:200px; display:inline-block; margin-top:3px'><b>Save Alignment</b>: " + "<button style='white-space:nowrap;' id='" + me.pre + "saveFasta'>FASTA</button> <button style='white-space:nowrap; margin-left:20px;' id='" + me.pre + "saveClustal'>CLUSTALW</button> <button style='white-space:nowrap; margin-left:20px;' id='" + me.pre + "saveResbyres'>Residue by Residue</button></div><br/>";
19368
19562
 
19369
19563
  sequencesHtml += me.htmlCls.divStr + "alignseqguide" + suffix + "' style='display:none; white-space:normal;' class='icn3d-box'>";
19370
19564
 
@@ -26620,7 +26814,12 @@ class Scene {
26620
26814
  ic.cams = {
26621
26815
  perspective: ic.perspectiveCamera,
26622
26816
  orthographic: ic.orthographicCamera,
26623
- };
26817
+ };
26818
+
26819
+ if(!me.bNode && ic.opts['effect'] == 'stereo' && !window.icn3duiHash) {
26820
+ ic.effect = ic.effects[options.effect];
26821
+ ic.effect.setSize(ic.container.width(), ic.container.height());
26822
+ }
26624
26823
  };
26625
26824
 
26626
26825
  setVrAr() { let ic = this.icn3d; ic.icn3dui;
@@ -30342,8 +30541,9 @@ class Strand {
30342
30541
  }
30343
30542
  }
30344
30543
 
30345
- // add one extra residue for coils between strands/helix
30346
- if(!isNaN(firstAtom.resi) && ic.pk === 3 && bHighlight === 1 && firstAtom.ss === 'coil') {
30544
+ // add one extra residue for coils between strands/helix if the style is NOT stick, ball and stick, lines, sphere, and dot
30545
+ // if(!isNaN(firstAtom.resi) && ic.pk === 3 && bHighlight === 1 && firstAtom.ss === 'coil') {
30546
+ if(!isNaN(firstAtom.resi) && ic.pk === 3 && bHighlight === 1 && firstAtom.ss === 'coil' && firstAtom.style != 'stick' && firstAtom.style != 'ball and stick' && firstAtom.style != 'lines' && firstAtom.style != 'sphere' && firstAtom.style != 'dot') {
30347
30547
  let residueid = firstAtom.structure + '_' + firstAtom.chain + '_' + (parseInt(firstAtom.resi) - 1).toString();
30348
30548
  if(ic.residues.hasOwnProperty(residueid)) {
30349
30549
  atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, me.hashUtilsCls.hash2Atoms(ic.residues[residueid],
@@ -30378,8 +30578,8 @@ class Strand {
30378
30578
  }
30379
30579
  }
30380
30580
 
30381
- // add one extra residue for coils between strands/helix
30382
- if(ic.pk === 3 && bHighlight === 1 && lastAtom.ss === 'coil') {
30581
+ // add one extra residue for coils between strands/helix if the style is NOT stick, ball and stick, lines, sphere, and dot
30582
+ if(ic.pk === 3 && bHighlight === 1 && lastAtom.ss === 'coil' && firstAtom.style != 'stick' && firstAtom.style != 'ball and stick' && firstAtom.style != 'lines' && firstAtom.style != 'sphere' && firstAtom.style != 'dot') {
30383
30583
  let residueid = lastAtom.structure + '_' + lastAtom.chain + '_' + (parseInt(lastAtom.resi) + 1).toString();
30384
30584
  if(ic.residues.hasOwnProperty(residueid)) {
30385
30585
  atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, me.hashUtilsCls.hash2Atoms(ic.residues[residueid],
@@ -33229,6 +33429,7 @@ ElectronMap.prototype.fillvoxels = function(atoms, atomlist) { //(int seqinit,in
33229
33429
  }
33230
33430
  else {
33231
33431
  // let index2ori = {};
33432
+ let maxdist = this.maxdist;
33232
33433
  for(let serial in atomlist) {
33233
33434
  let atom = atoms[atomlist[serial]];
33234
33435
 
@@ -33245,11 +33446,11 @@ ElectronMap.prototype.fillvoxels = function(atoms, atomlist) { //(int seqinit,in
33245
33446
  }
33246
33447
 
33247
33448
  // show map near the structure
33248
- for(i = Math.floor(r.x) - this.maxdist, il = Math.ceil(r.x) + this.maxdist; i <= il; ++i) {
33449
+ for(i = Math.floor(r.x) - maxdist, il = Math.ceil(r.x) + maxdist; i <= il; ++i) {
33249
33450
  if(i < 0 || i > this.header.xExtent*this.scaleFactor - 1) continue;
33250
- for(j = Math.floor(r.y) - this.maxdist, jl = Math.ceil(r.y) + this.maxdist; j<= jl; ++j) {
33451
+ for(j = Math.floor(r.y) - maxdist, jl = Math.ceil(r.y) + maxdist; j<= jl; ++j) {
33251
33452
  if(j < 0 || j > this.header.yExtent*this.scaleFactor - 1) continue;
33252
- for(k = Math.floor(r.z) - this.maxdist, kl = Math.ceil(r.z) + this.maxdist; k<= kl; ++k) {
33453
+ for(k = Math.floor(r.z) - maxdist, kl = Math.ceil(r.z) + maxdist; k<= kl; ++k) {
33253
33454
  if(k < 0 || k > this.header.zExtent*this.scaleFactor - 1) continue;
33254
33455
  let index = i * widthHeight + j * height + k;
33255
33456
  indexArray.push(index);
@@ -33258,6 +33459,16 @@ ElectronMap.prototype.fillvoxels = function(atoms, atomlist) { //(int seqinit,in
33258
33459
  }
33259
33460
  }
33260
33461
 
33462
+ // show all
33463
+ // for(i = 0; i < this.pLength; ++i) {
33464
+ // for(j = 0; j < this.pWidth; ++j) {
33465
+ // for(k = 0; k < this.pHeight; ++k) {
33466
+ // let index = i * widthHeight + j * height + k;
33467
+ // indexArray.push(index);
33468
+ // }
33469
+ // }
33470
+ // }
33471
+
33261
33472
  for(i = 0, il = indexArray.length; i < il; ++i) {
33262
33473
  let index = indexArray[i];
33263
33474
 
@@ -34519,6 +34730,7 @@ class ApplyDisplay {
34519
34730
  for(let residueid in singletonResidueHash) {
34520
34731
  // get calpha
34521
34732
  let calpha = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.residues[residueid]);
34733
+ let sideAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.selectionCls.getSideAtoms(ic.residues[residueid]));
34522
34734
  let atom = calpha;
34523
34735
 
34524
34736
  let prevResidueid = atom.structure + '_' + atom.chain + '_' + (parseInt(atom.resi) - 1).toString();
@@ -34535,7 +34747,7 @@ class ApplyDisplay {
34535
34747
  }
34536
34748
  else if( (atom.style === 'ribbon' && atom.ss === 'coil') || (atom.style === 'strand' && atom.ss === 'coil') || atom.style === 'o3 trace' || atom.style === 'schematic' || atom.style === 'c alpha trace' || atom.style === 'b factor tube' || (atom.style === 'cylinder and plate' && atom.ss !== 'helix') ) {
34537
34749
  // do not add extra residue if the side chain is shown
34538
- if(calpha !== undefined && calpha.style2 !== undefined && calpha.style2 !== 'nothing') continue;
34750
+ if(sideAtom !== undefined && sideAtom.style2 !== undefined && sideAtom.style2 !== 'nothing') continue;
34539
34751
 
34540
34752
  let bAddResidue = false;
34541
34753
  // add the next residue with same style
@@ -34570,7 +34782,7 @@ class ApplyDisplay {
34570
34782
  }
34571
34783
  else if( (atom.style === 'ribbon' && atom.ss !== 'coil' && atom.ssend) || (atom.style === 'strand' && atom.ss !== 'coil' && atom.ssend)) {
34572
34784
  // do not add extra residue if the side chain is shown
34573
- if(calpha !== undefined && calpha.style2 !== undefined && calpha.style2 !== 'nothing') continue;
34785
+ if(sideAtom !== undefined && sideAtom.style2 !== undefined && sideAtom.style2 !== 'nothing') continue;
34574
34786
 
34575
34787
  let bAddResidue = false;
34576
34788
  // add the next residue with same style
@@ -37455,11 +37667,18 @@ class Alternate {
37455
37667
  }
37456
37668
 
37457
37669
  if(ic.scene) {
37670
+ ic.renderer.clear();
37671
+
37458
37672
  // https://github.com/gkjohnson/three-gpu-pathtracer/blob/main/example/basic.js
37459
37673
  ic.renderer.outputEncoding = THREE.sRGBEncoding;
37460
37674
  //ic.renderer.outputEncoding = THREE.LinearEncoding
37461
37675
 
37462
- ic.renderer.render(ic.scene, cam);
37676
+ if(ic.opts['effect'] == 'stereo' && !window.icn3duiHash) {
37677
+ ic.effect.render(ic.scene, cam);
37678
+ }
37679
+ else {
37680
+ ic.renderer.render(ic.scene, cam);
37681
+ }
37463
37682
  }
37464
37683
  }
37465
37684
 
@@ -51836,13 +52055,20 @@ class ShowInter {
51836
52055
  }
51837
52056
  // do not change the set of displaying atoms
51838
52057
  //ic.dAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
51839
- let commandname, commanddesc;
52058
+ let commandname, commanddesc, commandname2;
51840
52059
  let firstAtom = ic.firstAtomObjCls.getFirstAtomObj(atomlistTarget);
52060
+
51841
52061
  if(firstAtom !== undefined) {
51842
52062
  commandname = "sphere." + firstAtom.chain + ":" + me.utilsCls.residueName2Abbr(firstAtom.resn.substr(0, 3)).trim() + firstAtom.resi + "-" + radius + "A";
51843
- if(bInteraction) commandname = "interactions." + firstAtom.chain + ":" + me.utilsCls.residueName2Abbr(firstAtom.resn.substr(0, 3)).trim() + firstAtom.resi + "-" + $("#" + ic.pre + "contactthreshold").val() + "A";
52063
+ //sometimes firstAtom.resi changed, thus we add a general name
52064
+ commandname2 = "sphere-" + radius + "A";
52065
+ if(bInteraction) {
52066
+ commandname = "interactions." + firstAtom.chain + ":" + me.utilsCls.residueName2Abbr(firstAtom.resn.substr(0, 3)).trim() + firstAtom.resi + "-" + $("#" + ic.pre + "contactthreshold").val() + "A";
52067
+ commandname2 = "interactions-" + $("#" + ic.pre + "contactthreshold").val() + "A";
52068
+ }
51844
52069
  commanddesc = commandname;
51845
52070
  ic.selectionCls.addCustomSelection(residueArray, commandname, commanddesc, select, true);
52071
+ ic.selectionCls.addCustomSelection(residueArray, commandname2, commanddesc, select, true);
51846
52072
  }
51847
52073
  ic.selectionCls.saveSelectionIfSelected();
51848
52074
  ic.drawCls.draw();
@@ -54020,6 +54246,7 @@ class ChainalignParser {
54020
54246
 
54021
54247
  ajaxArray.push(alignAjax);
54022
54248
  indexArray.push(index - 1);
54249
+ mmdbid_q = chainidArray[index].substr(0, chainidArray[index].indexOf('_'));
54023
54250
  struArray.push(mmdbid_q);
54024
54251
  }
54025
54252
 
@@ -54048,7 +54275,8 @@ class ChainalignParser {
54048
54275
  let mmdbid_q = struArray[i];
54049
54276
  let index = indexArray[i];
54050
54277
 
54051
- let bEqualMmdbid = (mmdbid_q == mmdbid_t);
54278
+ // let bEqualMmdbid = (mmdbid_q == mmdbid_t);
54279
+ let bEqualMmdbid = (mmdbid_q.substr(0,4) == mmdbid_t.substr(0,4));
54052
54280
  let bEqualChain = false;
54053
54281
 
54054
54282
  let queryData = {}; // check whether undefined
@@ -54298,7 +54526,7 @@ class ChainalignParser {
54298
54526
 
54299
54527
  transformStructure(mmdbid, index, alignType, bForce) { let ic = this.icn3d, me = ic.icn3dui;
54300
54528
  let chainidArray = ic.structures[mmdbid];
54301
-
54529
+
54302
54530
  for(let i = 0, il = chainidArray.length; i < il; ++i) {
54303
54531
  for(let serial in ic.chains[chainidArray[i]]) {
54304
54532
  let atm = ic.atoms[serial];
@@ -54430,6 +54658,26 @@ class ChainalignParser {
54430
54658
  return chainidArray;
54431
54659
  }
54432
54660
 
54661
+ addPostfixForStructureids(structArray) { let ic = this.icn3d; ic.icn3dui;
54662
+ let struct2cnt = {};
54663
+ for(let i = 0, il = structArray.length; i < il; ++i) {
54664
+ let struct = structArray[i].toUpperCase();
54665
+
54666
+ if(!struct2cnt.hasOwnProperty(struct)) {
54667
+ struct2cnt[struct] = 1;
54668
+ }
54669
+ else {
54670
+ ++struct2cnt[struct];
54671
+ }
54672
+
54673
+ struct = (struct2cnt[struct] == 1) ? struct : struct + struct2cnt[struct];
54674
+
54675
+ structArray[i] = struct;
54676
+ }
54677
+
54678
+ return structArray;
54679
+ }
54680
+
54433
54681
  async downloadChainalignment(chainalign) { let ic = this.icn3d, me = ic.icn3dui;
54434
54682
  let thisClass = this;
54435
54683
 
@@ -54471,6 +54719,7 @@ class ChainalignParser {
54471
54719
 
54472
54720
  ic.afChainIndexHash = {};
54473
54721
  ic.pdbChainIndexHash = {};
54722
+
54474
54723
  for(let index = 1, indexLen = alignArray.length; index < indexLen; ++index) {
54475
54724
  let pos2 = alignArray[index].indexOf('_');
54476
54725
  let mmdbid_q_tmp = alignArray[index].substr(0, pos2).toUpperCase();
@@ -54578,7 +54827,8 @@ class ChainalignParser {
54578
54827
 
54579
54828
  if(queryData !== undefined && JSON.stringify(queryData).indexOf('Oops there was a problem') === -1
54580
54829
  ) {
54581
- ic.mmdbidArray.push(mmdbid_q);
54830
+ // ic.mmdbidArray.push(mmdbid_q);
54831
+ ic.mmdbidArray.push(mmdbid_q.substr(0,4));
54582
54832
  queryDataArray.push(queryData);
54583
54833
  }
54584
54834
  else {
@@ -54617,7 +54867,8 @@ class ChainalignParser {
54617
54867
  // let align = (me.bNode) ? dataArray[index2 - missedChainCnt] : dataArray[index2 - missedChainCnt].value;//[0];
54618
54868
  let align = dataArray[index2 - missedChainCnt].value;//[0];
54619
54869
 
54620
- let bEqualMmdbid = (mmdbid_q == mmdbid_t);
54870
+ // let bEqualMmdbid = (mmdbid_q == mmdbid_t);
54871
+ let bEqualMmdbid = (mmdbid_q.substr(0,4) == mmdbid_t.substr(0,4));
54621
54872
  let bEqualChain = (chain_q == chain_t);
54622
54873
 
54623
54874
  me.htmlCls.clickMenuCls.setLogCmd("Align " + mmdbid_t + " with " + mmdbid_q, false);
@@ -54788,15 +55039,14 @@ class ChainalignParser {
54788
55039
 
54789
55040
  let structArray = [];
54790
55041
 
54791
- for(let i = 0, il = structArrayTmp.length; i < il; ++i) {
54792
- let id = structArrayTmp[i].toUpperCase();
54793
- // sometimes we want to load same structure multiple times
54794
- if(!ic.structures.hasOwnProperty(id) && structArray.indexOf(id) == -1) {
54795
- structArray.push(structArrayTmp[i]);
54796
- }
54797
- else {
54798
- // only when bNoDuplicate is undefined/false, it's allowed to load multiple copies of the same structure
54799
- if(!bNoDuplicate) structArray.push(structArrayTmp[i] + me.htmlCls.postfix);
55042
+ // only when bNoDuplicate is undefined/false, it's allowed to load multiple copies of the same structure
55043
+ if(!bNoDuplicate) {
55044
+ structArray = this.addPostfixForStructureids(structArrayTmp);
55045
+ }
55046
+ else {
55047
+ for(let i = 0, il = structArrayTmp.length; i < il; ++i) {
55048
+ let id = structArrayTmp[i].toUpperCase();
55049
+ if(!ic.structures.hasOwnProperty(id)) structArray.push(structArrayTmp[i]);
54800
55050
  }
54801
55051
  }
54802
55052
 
@@ -58791,6 +59041,283 @@ class XyzParser {
58791
59041
  }
58792
59042
  }
58793
59043
 
59044
+ /**
59045
+ * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
59046
+ */
59047
+
59048
+ class MsaParser {
59049
+ constructor(icn3d) {
59050
+ this.icn3d = icn3d;
59051
+ }
59052
+
59053
+ async loadMsaData(data, type) { let ic = this.icn3d, me = ic.icn3dui;
59054
+ let bResult = await this.loadMsaSeqData(data, type);
59055
+
59056
+ if(me.cfg.align === undefined && Object.keys(ic.structures).length == 1) {
59057
+ $("#" + ic.pre + "alternateWrapper").hide();
59058
+ }
59059
+
59060
+ let typeStr = type.toUpperCase();
59061
+
59062
+ if(!bResult) {
59063
+ var aaa = 1; //alert('The ' + typeStr + ' file has the wrong format...');
59064
+ }
59065
+ else {
59066
+ // retrieve the structures
59067
+ me.cfg.bu = 0; // show all chains
59068
+ await ic.chainalignParserCls.downloadMmdbAf(ic.struArray.join(','));
59069
+ me.htmlCls.clickMenuCls.setLogCmd('load mmdbaf0 ' + ic.struArray.join(','), true);
59070
+
59071
+ // get the position of the first MSA residue in the full sequence
59072
+ let startPosArray = [];
59073
+ for(let i = 0, il = ic.inputChainidArray.length; i < il; ++i) {
59074
+ let chainid = ic.inputChainidArray[i];
59075
+ let inputSeqNoGap = ic.inputSeqArray[i].replace(/-/g, '');
59076
+
59077
+ // get the full seq
59078
+ let fullSeq = '';
59079
+ for(let j = 0, jl = ic.chainsSeq[chainid].length; j < jl; ++j) {
59080
+ fullSeq += ic.chainsSeq[chainid][j].name;
59081
+ }
59082
+
59083
+ // find the starting position of "inputSeq" in "fullSeq"
59084
+ let pos = fullSeq.toUpperCase().indexOf(inputSeqNoGap.substr(0, 20).toUpperCase());
59085
+ if(pos == -1) {
59086
+ console.log("The sequence of the aligned chain " + chainid + " (" + inputSeqNoGap.toUpperCase() + ") is different from the sequence from the structure (" + fullSeq.toUpperCase() + "), and is thus not aligned correctly...");
59087
+ pos = 0;
59088
+ }
59089
+ startPosArray.push(pos);
59090
+ }
59091
+
59092
+ // define residue mapping
59093
+ // The format is ": "-separated pairs: "1,5,10-50 | 1,5,10-50: 2,6,11-51 | 1,5,10-50"
59094
+ let predefinedres = '';
59095
+
59096
+ let chainid1 = ic.inputChainidArray[0], inputSeq1 = ic.inputSeqArray[0], pos1 = startPosArray[0];
59097
+ // loop through 2nd and forward
59098
+ for(let i = 1, il = ic.inputChainidArray.length; i < il; ++i) {
59099
+ let chainid2 = ic.inputChainidArray[i];
59100
+ let inputSeq2 = ic.inputSeqArray[i];
59101
+ let pos2 = startPosArray[i];
59102
+
59103
+ let index1 = pos1, index2 = pos2;
59104
+ let resiArray1 = [], resiArray2 = [];
59105
+ for(let j = 0, jl = inputSeq2.length; j < jl; ++j) {
59106
+ if(inputSeq1[j] != '-' && inputSeq2[j] != '-' && ic.chainsSeq[chainid1][index1] && ic.chainsSeq[chainid2][index2]) {
59107
+ let resi1 = ic.chainsSeq[chainid1][index1].resi;
59108
+ let resi2 = ic.chainsSeq[chainid2][index2].resi;
59109
+ if(ic.residues[chainid1 + '_' + resi1] && ic.residues[chainid2 + '_' + resi2]) {
59110
+ resiArray1.push(ic.chainsSeq[chainid1][index1].resi);
59111
+ resiArray2.push(ic.chainsSeq[chainid2][index2].resi);
59112
+ }
59113
+ }
59114
+
59115
+ if(inputSeq1[j] != '-') ++index1;
59116
+ if(inputSeq2[j] != '-') ++index2;
59117
+ }
59118
+ let resiRangeStr1 = ic.resid2specCls.resi2range(resiArray1, true);
59119
+ let resiRangeStr2 = ic.resid2specCls.resi2range(resiArray2, true);
59120
+
59121
+ predefinedres += resiRangeStr1 + ' | ' + resiRangeStr2;
59122
+ if(i < il -1) predefinedres += ': ';
59123
+ }
59124
+
59125
+ // realign based on residue by residue
59126
+ let alignment_final = ic.inputChainidArray.join(',');
59127
+
59128
+ if(predefinedres && (alignment_final.split(',').length - 1) != predefinedres.split(': ').length) {
59129
+ var aaa = 1; //alert("Please make sure the number of chains and the lines of predefined residues are the same...");
59130
+ return;
59131
+ }
59132
+
59133
+ me.cfg.resdef = predefinedres.replace(/:/gi, ';');
59134
+
59135
+ let bRealign = true, bPredefined = true;
59136
+ let chainidArray = alignment_final.split(',');
59137
+ await ic.realignParserCls.realignChainOnSeqAlign(undefined, chainidArray, bRealign, bPredefined);
59138
+
59139
+ me.htmlCls.clickMenuCls.setLogCmd("realign predefined " + alignment_final + " " + predefinedres, true);
59140
+
59141
+
59142
+ ic.opts['color'] = 'identity';
59143
+ ic.setColorCls.setColorByOptions(ic.opts, ic.hAtoms);
59144
+ me.htmlCls.clickMenuCls.setLogCmd("color identity", true);
59145
+
59146
+ // show selection
59147
+ ic.selectionCls.showSelection();
59148
+ me.htmlCls.clickMenuCls.setLogCmd("show selection", true);
59149
+ }
59150
+ }
59151
+
59152
+ async loadMsaSeqData(data, type) { let ic = this.icn3d; ic.icn3dui;
59153
+ let lines = data.split(/\r?\n|\r/);
59154
+ if(lines.length < 2) return false;
59155
+
59156
+ ic.init();
59157
+
59158
+ ic.molTitle = "";
59159
+
59160
+ let seqHash = {};
59161
+
59162
+ let bStart = false, bSecBlock = false, chainid = '', seq = '', bFound = false;
59163
+
59164
+ if(type == 'clustalw' && lines[0].substr(0,7) != 'CLUSTAL') { // CLUSTAL W or CLUSTALW
59165
+ return false;
59166
+ }
59167
+
59168
+ let startLineNum = (type == 'clustalw') ? 1 : 0;
59169
+
59170
+ // 1. parse input msa
59171
+ for(let i = startLineNum, il = lines.length; i < il; ++i) {
59172
+ let line = lines[i].trim();
59173
+ if(line === '') {
59174
+ if(bStart) bSecBlock = true;
59175
+ bStart = false;
59176
+ continue;
59177
+ }
59178
+
59179
+ if(!bStart) { // first line
59180
+ if(type == 'fasta' && line.substr(0,1) != '>') {
59181
+ return false;
59182
+ }
59183
+ bStart = true;
59184
+ }
59185
+
59186
+ if(type == 'clustalw') {
59187
+ if(line.substr(0, 1) != ' ' && line.substr(0, 1) != '\t') {
59188
+ let chainid_seq = line.split(/\s+/);
59189
+ let idArray = chainid_seq[0].split('|');
59190
+ let result = this.getChainid(idArray, bStart && !bSecBlock);
59191
+ bFound = result.bFound;
59192
+ chainid = result.chainid;
59193
+
59194
+ if(bFound) {
59195
+ if(!seqHash.hasOwnProperty(chainid)) {
59196
+ seqHash[chainid] = chainid_seq[1];
59197
+ }
59198
+ else {
59199
+ seqHash[chainid] += chainid_seq[1];
59200
+ }
59201
+ }
59202
+ }
59203
+ }
59204
+ else if(type == 'fasta') {
59205
+ if(line.substr(0,1) == ">") {
59206
+ // add the previous seq
59207
+ if(chainid && seq && bFound) seqHash[chainid] = seq;
59208
+ chainid = '';
59209
+ seq = '';
59210
+
59211
+ let pos = line.indexOf(' ');
59212
+ let idArray = line.substr(1, pos).split('|');
59213
+
59214
+ if(idArray.length == 1) {
59215
+ chainid = idArray[0];
59216
+ }
59217
+ else {
59218
+ let result = this.getChainid(idArray, true);
59219
+ bFound = result.bFound;
59220
+ chainid = result.chainid;
59221
+ }
59222
+ }
59223
+ else {
59224
+ seq += line;
59225
+ }
59226
+ }
59227
+ }
59228
+
59229
+ // add the last seq
59230
+ if(type == 'fasta' && chainid && seq && bFound) seqHash[chainid] = seq;
59231
+
59232
+ // 2. get the PDB ID or RefSeqID or AlphaFold ID
59233
+ ic.inputChainidArray = [];
59234
+ ic.inputSeqArray = [];
59235
+ ic.struArray = [];
59236
+
59237
+ // find the tempate where the first residue is not gap
59238
+ let template = '';
59239
+ for(let chainid in seqHash) {
59240
+ let seq = seqHash[chainid];
59241
+ if(seq.substr(0,1) != '-') {
59242
+ template = chainid;
59243
+ await this.processOneChain(chainid, seqHash);
59244
+ break;
59245
+ }
59246
+ }
59247
+ if(!template) template = Object.keys(seqHash)[0];
59248
+
59249
+ for(let chainid in seqHash) {
59250
+ if(chainid != template) await this.processOneChain(chainid, seqHash);
59251
+ }
59252
+
59253
+ return true;
59254
+ }
59255
+
59256
+ async processOneChain(chainid, seqHash) { let ic = this.icn3d, me = ic.icn3dui;
59257
+ ic.inputSeqArray.push(seqHash[chainid]);
59258
+ // ic.inputSeqArray.push(seqHash[chainid].replace(/-/g, '')); // remove the gaps in seq
59259
+
59260
+ if(chainid.lastIndexOf('_') == 2) { // refseq ID
59261
+ // convert refseq to uniprot id
59262
+ let url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?refseq2uniprot=" + chainid;
59263
+
59264
+ let data = await me.getAjaxPromise(url, 'jsonp', false, 'The protein accession ' + chainid + ' can not be mapped to AlphaFold UniProt ID...');
59265
+ if(data && data.uniprot) {
59266
+ if(!ic.uniprot2acc) ic.uniprot2acc = {};
59267
+ let uniprot = data.uniprot;
59268
+ ic.uniprot2acc[uniprot] = chainid;
59269
+ ic.struArray.push(uniprot);
59270
+ ic.inputChainidArray.push(uniprot + '_A');
59271
+ }
59272
+ else {
59273
+ console.log('The accession ' + refseqid + ' can not be mapped to AlphaFold UniProt ID. It will be treated as a UniProt ID instead.');
59274
+ ic.struArray.push(chainid);
59275
+ ic.inputChainidArray.push(chainid + '_A');
59276
+ }
59277
+ }
59278
+ else if(chainid.indexOf('_') != -1) { // PDB ID
59279
+ let stru = chainid.substr(0, chainid.indexOf('_')).substr(0, 4);
59280
+ ic.struArray.push(stru);
59281
+ ic.inputChainidArray.push(chainid);
59282
+ }
59283
+ else if(chainid.length > 5) { // UniProt ID
59284
+ ic.struArray.push(chainid);
59285
+ ic.inputChainidArray.push(chainid + '_A');
59286
+ }
59287
+ }
59288
+
59289
+ getChainid(idArray, bWarning) { let ic = this.icn3d; ic.icn3dui;
59290
+ let bFound = false;
59291
+ let chainid = idArray[0];
59292
+
59293
+ for(let j = 0, jl = idArray.length; j < jl; ++j) {
59294
+ if(idArray[j] == 'pdb') {
59295
+ chainid = idArray[j+1] + '_' + idArray[j+2];
59296
+ bFound = true;
59297
+ break;
59298
+ }
59299
+ else if(idArray[j] == 'ref') { // refseq
59300
+ let refseq = idArray[j+1].split('.')[0];
59301
+ chainid = refseq; // + '_A';
59302
+ bFound = true;
59303
+ break;
59304
+ }
59305
+ else if(idArray[j] == 'sp' || idArray[j] == 'tr') { // uniprot
59306
+ let uniprot = idArray[j+1];
59307
+ chainid = uniprot;
59308
+ bFound = true;
59309
+ break;
59310
+ }
59311
+ }
59312
+
59313
+ if(!bFound && bWarning) {
59314
+ var aaa = 1; //alert("The sequence ID " + idArray.join('|') + " does not have the correctly formatted PDB, UniProt or RefSeq ID...");
59315
+ }
59316
+
59317
+ return {chainid: chainid, bFound: bFound};
59318
+ }
59319
+ }
59320
+
58794
59321
  /**
58795
59322
  * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
58796
59323
  */
@@ -58932,7 +59459,7 @@ class RealignParser {
58932
59459
  // If rmsd from vastsrv is too large, realign the chains
58933
59460
  //if(me.cfg.chainalign && !me.cfg.usepdbnum && me.cfg.resdef && rmsd > 5) {
58934
59461
  // redo algnment only for VAST serv page
58935
- if(!me.cfg.usepdbnum && me.cfg.resdef && rmsd > 5) {
59462
+ if(!me.cfg.usepdbnum && me.cfg.resdef && rmsd > 5 && me.cfg.chainalign) {
58936
59463
  console.log("RMSD from VAST is larger than 5. Realign the chains with TM-align.");
58937
59464
  //let nameArray = me.cfg.chainalign.split(',');
58938
59465
  let nameArray = Object.keys(chainidHash);
@@ -59388,7 +59915,8 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
59388
59915
  let predefinedResArray, predefinedResPair;
59389
59916
 
59390
59917
  if(bPredefined) {
59391
- predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split(': ');
59918
+ // predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split(': ');
59919
+ predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split('; ');
59392
59920
 
59393
59921
  if(predefinedResArray.length != chainidArray.length - 1) {
59394
59922
  var aaa = 1; //alert("Please make sure the number of chains and the lines of predefined residues are the same...");
@@ -59665,7 +60193,7 @@ class DensityCifParser {
59665
60193
  let thisClass = this;
59666
60194
 
59667
60195
  let url;
59668
- let detail = (me.utilsCls.isMobile() || me.cfg.notebook) ? 2 : 4; //0 : 4;
60196
+ let detail = (me.utilsCls.isMobile() || me.cfg.notebook) ? 0 : 4; // max 6
59669
60197
 
59670
60198
  //https://www.ebi.ac.uk/pdbe/densities/doc.html
59671
60199
  if(type == '2fofc' || type == 'fofc') {
@@ -59676,6 +60204,7 @@ class DensityCifParser {
59676
60204
  url = "https://www.ebi.ac.uk/pdbe/volume-server/x-ray/" + pdbid.toLowerCase() + "/box/" + min_max[0][0] + "," + min_max[0][1] + "," + min_max[0][2] + "/" + min_max[1][0] + "," + min_max[1][1] + "," + min_max[1][2] + "?detail=" + detail;
59677
60205
  }
59678
60206
  else if(type == 'em') {
60207
+ detail = (me.utilsCls.isMobile() || me.cfg.notebook) ? 0: 5; // max 6
59679
60208
  url = "https://www.ebi.ac.uk/pdbe/densities/emd/" + emd.toLowerCase() + "/cell?detail=" + detail;
59680
60209
  }
59681
60210
 
@@ -61249,11 +61778,12 @@ class ParserUtils {
61249
61778
 
61250
61779
  // set defined sets before loadScript
61251
61780
  if(ic.bInitial) {
61252
- if(me.cfg.mobilemenu) {
61253
- me.htmlCls.shownMenus = me.hashUtilsCls.cloneHash(me.htmlCls.simpleMenus);
61254
- let bNoSave = true;
61255
- me.htmlCls.clickMenuCls.applyShownMenus(bNoSave);
61256
- }
61781
+ // if(me.cfg.mobilemenu) {
61782
+ // me.htmlCls.shownMenus = me.hashUtilsCls.cloneHash(me.htmlCls.simpleMenus);
61783
+ // let bNoSave = true;
61784
+ // me.htmlCls.clickMenuCls.applyShownMenus(bNoSave);
61785
+ // }
61786
+
61257
61787
  // else {
61258
61788
  // me.htmlCls.shownMenus = me.hashUtilsCls.cloneHash(me.htmlCls.allMenus);
61259
61789
  // me.htmlCls.clickMenuCls.applyShownMenus();
@@ -63725,7 +64255,7 @@ class SetSeqAlign {
63725
64255
 
63726
64256
  setMsaFormat(chainidArray) { let ic = this.icn3d; ic.icn3dui;
63727
64257
  //set MSA
63728
- let fastaFormat = '', clustalFormat = 'CLUSTALW\n\n', resbyresFormat = '';
64258
+ let fastaFormat = '', clustalwFormat = 'CLUSTALWW\n\n', resbyresFormat = '';
63729
64259
  let chainArrayClustal = [];
63730
64260
 
63731
64261
  let consArray = [], resiArrayTemplate = [];
@@ -63734,8 +64264,8 @@ class SetSeqAlign {
63734
64264
  let chainid = chainidArray[i];
63735
64265
  fastaFormat += '>' + chainid + '\n';
63736
64266
 
63737
- let clustalArray = [];
63738
- let clustalLine = chainid.padEnd(20, ' ');
64267
+ let clustalwArray = [];
64268
+ let clustalwLine = chainid.padEnd(20, ' ');
63739
64269
  let consLine = ''.padEnd(20, ' ');
63740
64270
 
63741
64271
  let resiArrayTarget = [], resiArrayQuery = [];
@@ -63744,7 +64274,7 @@ class SetSeqAlign {
63744
64274
  for(let j = 0, jl = ic.alnChainsSeq[chainid].length; j < jl; ++j) {
63745
64275
  let resn = ic.alnChainsSeq[chainid][j].resn;
63746
64276
  fastaFormat += resn;
63747
- clustalLine += resn;
64277
+ clustalwLine += resn;
63748
64278
  if(i == il - 1) {
63749
64279
  let alignedClass = ic.alnChainsSeq[chainid][j].class;
63750
64280
  if(alignedClass == 'icn3d-cons') {
@@ -63763,7 +64293,8 @@ class SetSeqAlign {
63763
64293
  resiArrayTemplate.push(ic.alnChainsSeq[chainid][j].resi);
63764
64294
  }
63765
64295
  else {
63766
- if(ic.alnChainsSeq[chainid][j].aligned) {
64296
+ // if(ic.alnChainsSeq[chainid][j].aligned) {
64297
+ if(ic.alnChainsSeq[chainid][j].aligned && ic.alnChainsSeq[chainidTemplate][j] && ic.alnChainsSeq[chainid][j]) {
63767
64298
  resiArrayTarget.push(ic.alnChainsSeq[chainidTemplate][j].resi);
63768
64299
  resiArrayQuery.push(ic.alnChainsSeq[chainid][j].resi);
63769
64300
  }
@@ -63773,9 +64304,9 @@ class SetSeqAlign {
63773
64304
 
63774
64305
  if(cnt % 60 == 0) {
63775
64306
  fastaFormat += '\n';
63776
- clustalLine += ' ' + String(parseInt(cnt / 60) * 60);
63777
- clustalArray.push(clustalLine);
63778
- clustalLine = chainid.padEnd(20, ' ');
64307
+ clustalwLine += ' ' + String(parseInt(cnt / 60) * 60);
64308
+ clustalwArray.push(clustalwLine);
64309
+ clustalwLine = chainid.padEnd(20, ' ');
63779
64310
 
63780
64311
  if(i == il - 1) {
63781
64312
  consArray.push(consLine);
@@ -63786,7 +64317,7 @@ class SetSeqAlign {
63786
64317
 
63787
64318
  // add last line
63788
64319
  if(cnt % 60 != 0) {
63789
- clustalArray.push(clustalLine);
64320
+ clustalwArray.push(clustalwLine);
63790
64321
  if(i == il - 1) {
63791
64322
  consArray.push(consLine);
63792
64323
  }
@@ -63794,7 +64325,7 @@ class SetSeqAlign {
63794
64325
 
63795
64326
  fastaFormat += '\n';
63796
64327
 
63797
- chainArrayClustal.push(clustalArray);
64328
+ chainArrayClustal.push(clustalwArray);
63798
64329
  if(i == il - 1) chainArrayClustal.push(consArray);
63799
64330
 
63800
64331
  // residue by residue
@@ -63804,23 +64335,23 @@ class SetSeqAlign {
63804
64335
  if(i > 0) resbyresFormat += resiRangeStr1 + ' | ' + resiRangeStr2 + '\n';
63805
64336
  }
63806
64337
 
63807
- // CLUSTALW
64338
+ // CLUSTALWW
63808
64339
  for(let j = 0, jl = chainArrayClustal[0].length; j < jl; ++j) {
63809
64340
  for(let i = 0, il = chainArrayClustal.length; i < il; ++i) {
63810
- clustalFormat += chainArrayClustal[i][j] + '\n';
64341
+ clustalwFormat += chainArrayClustal[i][j] + '\n';
63811
64342
  }
63812
- clustalFormat += '\n';
64343
+ clustalwFormat += '\n';
63813
64344
  }
63814
64345
 
63815
64346
  // seq MSA
63816
64347
  if(!ic.msa) ic.msa = {};
63817
64348
 
63818
64349
  if(!ic.msa['fasta']) ic.msa['fasta'] = [];
63819
- if(!ic.msa['clustal']) ic.msa['clustal'] = [];
64350
+ if(!ic.msa['clustalw']) ic.msa['clustalw'] = [];
63820
64351
  if(!ic.msa['resbyres']) ic.msa['resbyres'] = [];
63821
64352
 
63822
64353
  ic.msa['fasta'].push(fastaFormat);
63823
- ic.msa['clustal'].push(clustalFormat);
64354
+ ic.msa['clustalw'].push(clustalwFormat);
63824
64355
  ic.msa['resbyres'].push(resbyresFormat);
63825
64356
  }
63826
64357
  }
@@ -66576,6 +67107,12 @@ class ApplyCommand {
66576
67107
  else if(command == 'set slab off') {
66577
67108
  ic.opts['slab'] = 'no';
66578
67109
  }
67110
+ else if(command == 'stereo on') {
67111
+ ic.opts['effect'] = 'stereo';
67112
+ }
67113
+ else if(command == 'stereo off') {
67114
+ ic.opts['effect'] = 'none';
67115
+ }
66579
67116
  else if(command == 'set assembly on') {
66580
67117
  ic.bAssembly = true;
66581
67118
  }
@@ -68649,16 +69186,26 @@ class DefinedSets {
68649
69186
  } // outer for
68650
69187
  }
68651
69188
 
68652
- setHAtomsFromSets(nameArray, type) { let ic = this.icn3d, me = ic.icn3dui;
69189
+ setHAtomsFromSets(nameArray, type) { let ic = this.icn3d; ic.icn3dui;
68653
69190
  for(let i = 0; i < nameArray.length; ++i) {
68654
69191
  let selectedSet = nameArray[i];
68655
69192
 
68656
- if((ic.defNames2Atoms === undefined || !ic.defNames2Atoms.hasOwnProperty(selectedSet)) &&(ic.defNames2Residues === undefined || !ic.defNames2Residues.hasOwnProperty(selectedSet)) ) continue;
69193
+ this.setHAtomsFromSets_base(selectedSet, type);
69194
+
69195
+ // sometimes the "resi" changed and thus the name changed
69196
+ //"sphere." + firstAtom.chain + ":" + me.utilsCls.residueName2Abbr(firstAtom.resn.substr(0, 3)).trim() + firstAtom.resi + "-" + radius + "A";
69197
+ if(Object.keys(ic.hAtoms).length == 0 && (selectedSet.split('.')[0] == 'sphere' || selectedSet.split('.')[0] == 'interactions')) {
69198
+ let pos = selectedSet.lastIndexOf('-');
69199
+ selectedSet = selectedSet.split('.')[0] + selectedSet.substr(pos);
69200
+ this.setHAtomsFromSets_base(selectedSet, type);
69201
+ }
69202
+ } // outer for
69203
+ }
68657
69204
 
69205
+ setHAtomsFromSets_base(selectedSet, type) { let ic = this.icn3d, me = ic.icn3dui;
68658
69206
  if(ic.defNames2Atoms !== undefined && ic.defNames2Atoms.hasOwnProperty(selectedSet)) {
68659
69207
 
68660
69208
  let atomArray = ic.defNames2Atoms[selectedSet];
68661
-
68662
69209
  if(type === 'or') {
68663
69210
  for(let j = 0, jl = atomArray.length; j < jl; ++j) {
68664
69211
  ic.hAtoms[atomArray[j]] = 1;
@@ -68704,7 +69251,6 @@ class DefinedSets {
68704
69251
  ic.hAtoms = me.hashUtilsCls.exclHash(ic.hAtoms, atomHash);
68705
69252
  }
68706
69253
  }
68707
- } // outer for
68708
69254
  }
68709
69255
 
68710
69256
  updateAdvancedCommands(nameArray, type) { let ic = this.icn3d; ic.icn3dui;
@@ -68727,6 +69273,7 @@ class DefinedSets {
68727
69273
 
68728
69274
  combineSets(orArray, andArray, notArray, commandname) { let ic = this.icn3d, me = ic.icn3dui;
68729
69275
  ic.hAtoms = {};
69276
+
68730
69277
  this.setHAtomsFromSets(orArray, 'or');
68731
69278
 
68732
69279
  if(Object.keys(ic.hAtoms).length == 0) {
@@ -70822,19 +71369,22 @@ class Selection {
70822
71369
  selectSideChains() { let ic = this.icn3d, me = ic.icn3dui;
70823
71370
  let currHAtoms = me.hashUtilsCls.cloneHash(ic.hAtoms);
70824
71371
 
70825
- //let nuclMainArray = ["C1'", "C1*", "C2'", "C2*", "C3'", "C3*", "C4'", "C4*", "C5'", "C5*", "O3'", "O3*", "O4'", "O4*", "O5'", "O5*", "P", "OP1", "O1P", "OP2", "O2P"];
71372
+ ic.hAtoms = this.getSideAtoms(currHAtoms);
71373
+ ic.hlUpdateCls.showHighlight();
71374
+ }
70826
71375
 
70827
- ic.hAtoms = {};
70828
- for(let i in currHAtoms) {
71376
+ getSideAtoms(atoms) { let ic = this.icn3d, me = ic.icn3dui;
71377
+ let sideAtoms = {};
71378
+ for(let i in atoms) {
70829
71379
  if((ic.proteins.hasOwnProperty(i) && ic.atoms[i].name !== "N" && ic.atoms[i].name !== "H"
70830
71380
  && ic.atoms[i].name !== "C" && ic.atoms[i].name !== "O"
70831
71381
  && !(ic.atoms[i].name === "CA" && ic.atoms[i].elem === "C") && ic.atoms[i].name !== "HA")
70832
71382
  ||(ic.nucleotides.hasOwnProperty(i) && me.parasCls.nuclMainArray.indexOf(ic.atoms[i].name) === -1) ) {
70833
- ic.hAtoms[i] = 1;
71383
+ sideAtoms[i] = 1;
70834
71384
  }
70835
71385
  }
70836
71386
 
70837
- ic.hlUpdateCls.showHighlight();
71387
+ return sideAtoms;
70838
71388
  }
70839
71389
 
70840
71390
  selectMainSideChains() { let ic = this.icn3d, me = ic.icn3dui;
@@ -71450,9 +72000,12 @@ class Resid2spec {
71450
72000
  resi2range(resiArray, bString) {var ic = this.icn3d; ic.icn3dui;
71451
72001
  let range = [], rangeStr = '';
71452
72002
 
71453
- let resiArraySorted = resiArray.sort(function(a, b) {
71454
- return parseInt(a) - parseInt(b);
71455
- });
72003
+ // some chains such as 3SN6_R start with residues with high residue numbers, then end with residues with low residue numbers
72004
+ // let resiArraySorted = resiArray.sort(function(a, b) {
72005
+ // return parseInt(a) - parseInt(b);
72006
+ // });
72007
+
72008
+ let resiArraySorted = resiArray;
71456
72009
 
71457
72010
  let startResi = resiArraySorted[0];
71458
72011
  let prevResi, resi;
@@ -72737,18 +73290,29 @@ class Dssp {
72737
73290
 
72738
73291
  ic.pdbDataArray = await this.promiseWithFixedJobs(pdbAjaxArray);
72739
73292
 
72740
- let bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template);
72741
73293
  let numRound = 0;
73294
+ let bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template, undefined, numRound);
73295
+ ++numRound;
72742
73296
 
72743
73297
  //while(!bNoMoreIg) {
72744
73298
  while(!bNoMoreIg && numRound < 15) {
72745
73299
  let bRerun = true;
72746
- bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template, bRerun);
73300
+ bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template, bRerun, numRound);
72747
73301
  ++numRound;
72748
73302
  }
72749
73303
  }
72750
73304
  else {
72751
- await thisClass.parseRefPdbData(undefined, template);
73305
+ await thisClass.parseRefPdbData(undefined, template, undefined, numRound);
73306
+ }
73307
+
73308
+ // refnum should be adjusted after all Ig are detected since sometimes the sheet extension may affect another Ig domain
73309
+ if(!ic.chainid2igtrack) ic.chainid2igtrack = {};
73310
+ for(let chainid in ic.chains) {
73311
+ let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.chains[chainid]);
73312
+ if(ic.proteins.hasOwnProperty(atom.serial)) {
73313
+ let giSeq = ic.showSeqCls.getSeq(chainid);
73314
+ ic.chainid2igtrack[chainid] = this.ajdustRefnum(giSeq, chainid);
73315
+ }
72752
73316
  }
72753
73317
  // }
72754
73318
  // catch(err) {
@@ -72757,7 +73321,7 @@ class Dssp {
72757
73321
  // }
72758
73322
  }
72759
73323
 
72760
- async parseRefPdbData(dataArray, template, bRerun) { let ic = this.icn3d, me = ic.icn3dui;
73324
+ async parseRefPdbData(dataArray, template, bRerun, numRound) { let ic = this.icn3d, me = ic.icn3dui;
72761
73325
  let thisClass = this;
72762
73326
 
72763
73327
  let struArray = Object.keys(ic.structures);
@@ -72851,7 +73415,7 @@ class Dssp {
72851
73415
  dataArray2 = await this.promiseWithFixedJobs(ajaxArray);
72852
73416
 
72853
73417
  let bRound1 = true;
72854
- bNoMoreIg = await thisClass.parseAlignData(dataArray2, domainidpairArray, bRound1);
73418
+ bNoMoreIg = await thisClass.parseAlignData(dataArray2, domainidpairArray, bRound1, numRound);
72855
73419
 
72856
73420
  /// if(ic.deferredRefnum !== undefined) ic.deferredRefnum.resolve();
72857
73421
  }
@@ -72897,7 +73461,7 @@ class Dssp {
72897
73461
 
72898
73462
  dataArray3 = await this.promiseWithFixedJobs(ajaxArray);
72899
73463
 
72900
- bNoMoreIg = await thisClass.parseAlignData(dataArray3, domainidpairArray3);
73464
+ bNoMoreIg = await thisClass.parseAlignData(dataArray3, domainidpairArray3, undefined, numRound);
72901
73465
  }
72902
73466
 
72903
73467
  return bNoMoreIg;
@@ -73125,7 +73689,7 @@ class Dssp {
73125
73689
  delete ic.domainid2refpdbname[domainid];
73126
73690
  delete ic.domainid2score[domainid];
73127
73691
  }
73128
- continue;
73692
+ continue;
73129
73693
  }
73130
73694
  // }
73131
73695
  }
@@ -73189,7 +73753,7 @@ class Dssp {
73189
73753
  return domainid2segs; // only used in round 2
73190
73754
  }
73191
73755
 
73192
- async parseAlignData(dataArray, domainidpairArray, bRound1) { let ic = this.icn3d, me = ic.icn3dui;
73756
+ async parseAlignData(dataArray, domainidpairArray, bRound1, numRound) { let ic = this.icn3d, me = ic.icn3dui;
73193
73757
  let bNoMoreIg = false;
73194
73758
 
73195
73759
  let domainid2segs = this.parseAlignData_part1(dataArray, domainidpairArray, bRound1);
@@ -73214,7 +73778,8 @@ class Dssp {
73214
73778
  //let pdbid = domainid.substr(0, domainid.indexOf('_'));
73215
73779
  let chainid = domainid.substr(0, domainid.indexOf(','));
73216
73780
 
73217
- if(ic.refpdbHash.hasOwnProperty(chainid)) {
73781
+ // Adjusted refpdbname in the first try
73782
+ if(ic.refpdbHash.hasOwnProperty(chainid) && numRound == 0) {
73218
73783
  refpdbnameList = [chainid];
73219
73784
 
73220
73785
  if(!me.bNode) console.log("Adjusted refpdbname for domainid " + domainid + ": " + chainid);
@@ -73267,7 +73832,7 @@ class Dssp {
73267
73832
 
73268
73833
  dataArray3 = await this.promiseWithFixedJobs(ajaxArray);
73269
73834
 
73270
- bNoMoreIg = await this.parseAlignData(dataArray3, domainidpairArray3, false);
73835
+ bNoMoreIg = await this.parseAlignData(dataArray3, domainidpairArray3, false, numRound);
73271
73836
 
73272
73837
  // end of round 2
73273
73838
  return bNoMoreIg;
@@ -73512,6 +74077,8 @@ class Dssp {
73512
74077
  }
73513
74078
  }
73514
74079
 
74080
+ // refnum should be adjusted after all Ig are detected since sometimes the sheet extension may affect another Ig domain
74081
+ /*
73515
74082
  if(!ic.chainid2igtrack) ic.chainid2igtrack = {};
73516
74083
  for(let chainid in ic.chains) {
73517
74084
  let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.chains[chainid]);
@@ -73520,6 +74087,7 @@ class Dssp {
73520
74087
  ic.chainid2igtrack[chainid] = this.ajdustRefnum(giSeq, chainid);
73521
74088
  }
73522
74089
  }
74090
+ */
73523
74091
  }
73524
74092
 
73525
74093
  getStrandFromRefnum(oriRefnum, finalStrand) { let ic = this.icn3d; ic.icn3dui;
@@ -78452,7 +79020,7 @@ class ResizeCanvas {
78452
79020
  //let itemArray = ['dl_selectannotations', 'dl_alignment', 'dl_2ddgm', 'dl_definedsets', 'dl_graph',
78453
79021
  // 'dl_linegraph', 'dl_scatterplot', 'dl_contactmap', 'dl_allinteraction', 'dl_copyurl',
78454
79022
  // 'dl_symmetry', 'dl_symd', 'dl_rmsd', 'dl_legend', 'dl_disttable'];
78455
- let itemArray = ['dl_2ddgm', 'dl_2dctn', 'dl_alignment', 'dl_sequence2', 'dl_definedsets', 'dl_setsmenu', 'dl_command', 'dl_setoperations', 'dl_vast', 'dl_foldseek', 'dl_mmtfid', 'dl_pdbid', 'dl_afid', 'dl_opmid', 'dl_pdbfile', 'dl_pdbfile_app', 'dl_rescolorfile', 'dl_customcolor', 'dl_align', 'dl_alignaf', 'dl_chainalign', 'dl_chainalign2', 'dl_chainalign3', 'dl_mutation', 'dl_mol2file', 'dl_sdffile', 'dl_xyzfile', 'dl_afmapfile', 'dl_urlfile', 'dl_mmciffile', 'dl_mmcifid', 'dl_mmdbid', 'dl_mmdbafid', 'dl_blast_rep_id', 'dl_yournote', 'dl_proteinname', 'dl_refseqid', 'dl_cid', 'dl_pngimage', 'dl_state', 'dl_fixedversion', 'dl_selection', 'dl_dsn6', 'dl_dsn6url', 'dl_clr', 'dl_symmetry', 'dl_symd', 'dl_contact', 'dl_hbonds', 'dl_realign', 'dl_realignbystruct', 'dl_allinteracton', 'dl_interactionsorted', 'dl_linegraph', 'dl_linegraphcolor', 'dl_scatterplot', 'dl_scatterploitcolor', 'dl_contactmap', 'dl_alignerrormap', 'dl_elecmap2fofc', 'dl_elecmapfofc', 'dl_emmap', 'dl_aroundsphere', 'dl_adjustmem', 'dl_selectplane', 'dl_addlabel', 'dl_addlabelselection', 'dl_labelColor', 'dl_distance', 'dl_stabilizer', 'dl_disttwosets', 'dl_distmanysets', 'dl_stabilizer_rm', 'dl_thickness', 'dl_thickness2', 'dl_addtrack', 'dl_addtrack_tabs', 'dl_saveselection', 'dl_copyurl', 'dl_selectannotations', 'dl_annotations_tabs', 'dl_anno_view_tabs', 'dl_annotations', 'dl_graph', 'dl_svgcolor', 'dl_area', 'dl_colorbyarea', 'dl_rmsd', 'dl_buriedarea', 'dl_propbypercentout', 'dl_propbybfactor', 'dl_legend', 'dl_disttable', 'dl_translate'];
79023
+ let itemArray = ['dl_2ddgm', 'dl_2dctn', 'dl_alignment', 'dl_sequence2', 'dl_definedsets', 'dl_setsmenu', 'dl_command', 'dl_setoperations', 'dl_vast', 'dl_foldseek', 'dl_mmtfid', 'dl_pdbid', 'dl_afid', 'dl_opmid', 'dl_pdbfile', 'dl_pdbfile_app', 'dl_rescolorfile', 'dl_customcolor', 'dl_align', 'dl_alignaf', 'dl_chainalign', 'dl_chainalign2', 'dl_chainalign3', 'dl_mutation', 'dl_mol2file', 'dl_sdffile', 'dl_xyzfile', 'dl_clustalwfile', 'dl_fastafile', 'dl_afmapfile', 'dl_urlfile', 'dl_mmciffile', 'dl_mmcifid', 'dl_mmdbid', 'dl_mmdbafid', 'dl_blast_rep_id', 'dl_yournote', 'dl_proteinname', 'dl_refseqid', 'dl_cid', 'dl_pngimage', 'dl_state', 'dl_fixedversion', 'dl_selection', 'dl_dsn6', 'dl_dsn6url', 'dl_clr', 'dl_symmetry', 'dl_symd', 'dl_contact', 'dl_hbonds', 'dl_realign', 'dl_realignbystruct', 'dl_allinteracton', 'dl_interactionsorted', 'dl_linegraph', 'dl_linegraphcolor', 'dl_scatterplot', 'dl_scatterploitcolor', 'dl_contactmap', 'dl_alignerrormap', 'dl_elecmap2fofc', 'dl_elecmapfofc', 'dl_emmap', 'dl_aroundsphere', 'dl_adjustmem', 'dl_selectplane', 'dl_addlabel', 'dl_addlabelselection', 'dl_labelColor', 'dl_distance', 'dl_stabilizer', 'dl_disttwosets', 'dl_distmanysets', 'dl_stabilizer_rm', 'dl_thickness', 'dl_thickness2', 'dl_addtrack', 'dl_addtrack_tabs', 'dl_saveselection', 'dl_copyurl', 'dl_selectannotations', 'dl_annotations_tabs', 'dl_anno_view_tabs', 'dl_annotations', 'dl_graph', 'dl_svgcolor', 'dl_area', 'dl_colorbyarea', 'dl_rmsd', 'dl_buriedarea', 'dl_propbypercentout', 'dl_propbybfactor', 'dl_legend', 'dl_disttable', 'dl_translate'];
78456
79024
 
78457
79025
  for(let i in itemArray) {
78458
79026
  let item = itemArray[i];
@@ -79198,9 +79766,10 @@ class SaveFile {
79198
79766
  ssObj.resn = atom.resn;
79199
79767
  ssObj.resi = atom.resi;
79200
79768
 
79201
- if(parseInt(atom.resi) > parseInt(prevResi) + 1) {
79202
- ssObj.ss = ' ';
79203
- ssArray.push(ssObj);
79769
+ if(parseInt(atom.resi) > parseInt(prevResi) + 1 || atom.ssbegin) {
79770
+ let ssObj2 = me.hashUtilsCls.cloneHash(ssObj);
79771
+ ssObj2.ss = ' ';
79772
+ ssArray.push(ssObj2);
79204
79773
  }
79205
79774
 
79206
79775
  if(atom.ss == 'helix') {
@@ -79211,13 +79780,13 @@ class SaveFile {
79211
79780
  ssObj.ss = 'S';
79212
79781
  ssArray.push(ssObj);
79213
79782
  }
79214
-
79783
+ /*
79215
79784
  if(atom.ssend) {
79216
79785
  let ssObj2 = me.hashUtilsCls.cloneHash(ssObj);
79217
79786
  ssObj2.ss = ' ';
79218
79787
  ssArray.push(ssObj2);
79219
79788
  }
79220
-
79789
+ */
79221
79790
  prevResi = atom.resi;
79222
79791
  }
79223
79792
 
@@ -79225,9 +79794,9 @@ class SaveFile {
79225
79794
  for(let i = 0, il = ssArray.length; i < il; ++i) {
79226
79795
  let ssObj = ssArray[i];
79227
79796
 
79228
- if(ssObj.ss != prevSs || ssObj.ssbegin) {
79797
+ if(ssObj.ss != prevSs) {
79229
79798
  // print prev
79230
- stru2header[stru] += this.printPrevSecondary(bHelix, bSheet, prevRealSsObj, ssCnt);
79799
+ if(prevSs !== ' ') stru2header[stru] += this.printPrevSecondary(bHelix, bSheet, prevRealSsObj, ssCnt);
79231
79800
 
79232
79801
  // print current
79233
79802
  ssCnt = 0;
@@ -79235,7 +79804,7 @@ class SaveFile {
79235
79804
  bSheet = false;
79236
79805
  prevRealSsObj = undefined;
79237
79806
 
79238
- if(ssObj.ss != ' ') {
79807
+ if(ssObj.ss !== ' ') {
79239
79808
  if(ssObj.ss == 'H') {
79240
79809
  bHelix = true;
79241
79810
  prevRealSsObj = ssObj;
@@ -79251,7 +79820,7 @@ class SaveFile {
79251
79820
  }
79252
79821
  }
79253
79822
 
79254
- if(ssObj.ss != ' ') {
79823
+ if(ssObj.ss !== ' ') {
79255
79824
  ++ssCnt;
79256
79825
  prevRealSsObj = ssObj;
79257
79826
  }
@@ -81100,8 +81669,10 @@ class Ray {
81100
81669
  this.icn3d = icn3d;
81101
81670
  }
81102
81671
 
81103
- rayCaster(e, bClick) {
81672
+ rayCaster(e, bClick) { let ic = this.icn3d; ic.icn3dui;
81673
+ if(!ic.opts || ic.opts['effect'] == 'none') {
81104
81674
  this.rayCasterBase(e, bClick);
81675
+ }
81105
81676
  }
81106
81677
 
81107
81678
  rayCasterBase(e, bClick) { let ic = this.icn3d; ic.icn3dui;
@@ -82422,6 +82993,14 @@ class iCn3D {
82422
82993
  });
82423
82994
  }
82424
82995
 
82996
+ this.effects = {
82997
+ //'anaglyph': new THREE.AnaglyphEffect(this.renderer),
82998
+ //'parallax barrier': new THREE.ParallaxBarrierEffect(this.renderer),
82999
+ //'oculus rift': new THREE.OculusRiftEffect(this.renderer),
83000
+ 'stereo': new THREE.StereoEffect(this.renderer),
83001
+ 'none': this.renderer
83002
+ };
83003
+
82425
83004
  this.overdraw = 0;
82426
83005
  }
82427
83006
  else {
@@ -82568,14 +83147,6 @@ class iCn3D {
82568
83147
 
82569
83148
  this.bExtrude = true;
82570
83149
 
82571
- this.effects = {
82572
- //'anaglyph': new THREE.AnaglyphEffect(this.renderer),
82573
- //'parallax barrier': new THREE.ParallaxBarrierEffect(this.renderer),
82574
- //'oculus rift': new THREE.OculusRiftEffect(this.renderer),
82575
- //'stereo': new THREE.StereoEffect(this.renderer),
82576
- 'none': this.renderer
82577
- };
82578
-
82579
83150
  this.maxD = 500; // size of the molecule
82580
83151
  this.oriMaxD = this.maxD; // size of the molecule
82581
83152
  //this.cam_z = -150;
@@ -82628,6 +83199,7 @@ class iCn3D {
82628
83199
  //The default display options
82629
83200
  this.optsOri = {};
82630
83201
  this.optsOri['camera'] = 'perspective'; //perspective, orthographic
83202
+ this.optsOri['effect'] = 'none'; //stereo, none
82631
83203
  this.optsOri['background'] = 'black'; //transparent, black, grey, white
82632
83204
  this.optsOri['color'] = 'chain'; //spectrum, secondary structure, charge, hydrophobic, conserved, chain, residue, atom, b factor, red, green, blue, magenta, yellow, cyan, white, grey, custom, ig strand
82633
83205
  this.optsOri['proteins'] = 'ribbon'; //ribbon, strand, cylinder and plate, schematic, c alpha trace, backbone, b factor tube, lines, stick, ball and stick, sphere, nothing
@@ -82821,6 +83393,7 @@ class iCn3D {
82821
83393
  this.pdbParserCls = new PdbParser(this);
82822
83394
  this.sdfParserCls = new SdfParser(this);
82823
83395
  this.xyzParserCls = new XyzParser(this);
83396
+ this.msaParserCls = new MsaParser(this);
82824
83397
  this.realignParserCls = new RealignParser(this);
82825
83398
  this.densityCifParserCls = new DensityCifParser(this);
82826
83399
  this.ParserUtilsCls = new ParserUtils(this);
@@ -83077,7 +83650,7 @@ class iCn3DUI {
83077
83650
  //even when multiple iCn3D viewers are shown together.
83078
83651
  this.pre = this.cfg.divid + "_";
83079
83652
 
83080
- this.REVISION = '3.41.0';
83653
+ this.REVISION = '3.42.0';
83081
83654
 
83082
83655
  // In nodejs, iCn3D defines "window = {navigator: {}}"
83083
83656
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -83900,6 +84473,7 @@ exports.MarchingCube = MarchingCube;
83900
84473
  exports.MmcifParser = MmcifParser;
83901
84474
  exports.MmdbParser = MmdbParser;
83902
84475
  exports.Mol2Parser = Mol2Parser;
84476
+ exports.MsaParser = MsaParser;
83903
84477
  exports.MyEventCls = MyEventCls;
83904
84478
  exports.OpmParser = OpmParser;
83905
84479
  exports.ParasCls = ParasCls;