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.module.js CHANGED
@@ -2532,7 +2532,6 @@ THREE.TrackballControls = function ( object, domElement, icn3d ) {
2532
2532
  _this._panStart.add( mouseChange.subVectors( _this._panEnd, _this._panStart ).multiplyScalar( _this.dynamicDampingFactor ) );
2533
2533
 
2534
2534
  }
2535
-
2536
2535
  }
2537
2536
  }
2538
2537
 
@@ -3569,6 +3568,103 @@ THREE.OrthographicTrackballControls = function ( object, domElement, icn3d ) { v
3569
3568
  THREE.OrthographicTrackballControls.prototype = Object.create( THREE.EventDispatcher.prototype );
3570
3569
  THREE.OrthographicTrackballControls.prototype.constructor = THREE.OrthographicTrackballControls;
3571
3570
 
3571
+ /**
3572
+ * @author alteredq / http://alteredqualia.com/
3573
+ * @authod mrdoob / http://mrdoob.com/
3574
+ * @authod arodic / http://aleksandarrodic.com/
3575
+ * modified by Jiyao Wang
3576
+ */
3577
+
3578
+ THREE.StereoEffect = function ( renderer ) {
3579
+ var _this = this;
3580
+ // API
3581
+
3582
+ _this.separation = 3; // 1;
3583
+
3584
+ // internals
3585
+
3586
+ // _this._width, _this._height;
3587
+
3588
+ _this._position = new THREE.Vector3();
3589
+ _this._quaternion = new THREE.Quaternion();
3590
+ _this._scale = new THREE.Vector3();
3591
+
3592
+ _this._cameraL = new THREE.PerspectiveCamera();
3593
+ _this._cameraR = new THREE.PerspectiveCamera();
3594
+
3595
+ // initialization
3596
+
3597
+ renderer.autoClear = false;
3598
+
3599
+ _this.setSize = function ( width, height ) {
3600
+
3601
+ _this._width = width / 2;
3602
+ _this._height = height;
3603
+
3604
+ renderer.setSize( width, height );
3605
+
3606
+ };
3607
+
3608
+ _this.render = function ( scene, camera ) {
3609
+
3610
+ scene.updateMatrixWorld();
3611
+
3612
+ if ( camera.parent === undefined ) camera.updateMatrixWorld();
3613
+
3614
+ camera.matrixWorld.decompose( _this._position, _this._quaternion, _this._scale );
3615
+
3616
+ // left
3617
+ _this._cameraL.copy(camera);
3618
+ _this._cameraL.aspect = 0.5 * camera.aspect;
3619
+ _this._cameraL.updateProjectionMatrix();
3620
+
3621
+ /*
3622
+ _this._cameraL.fov = camera.fov;
3623
+ _this._cameraL.aspect = 0.5 * camera.aspect;
3624
+ _this._cameraL.near = camera.near;
3625
+ _this._cameraL.far = camera.far;
3626
+ _this._cameraL.updateProjectionMatrix();
3627
+
3628
+ _this._cameraL.position.copy( _this._position );
3629
+ // _this._cameraL.quaternion.copy( _this._quaternion );
3630
+ */
3631
+ _this._cameraL.translateX( - _this.separation );
3632
+
3633
+ // right
3634
+ _this._cameraR.copy(camera);
3635
+ _this._cameraR.aspect = 0.5 * camera.aspect;
3636
+ _this._cameraR.updateProjectionMatrix();
3637
+
3638
+ /*
3639
+ _this._cameraR.fov = camera.fov;
3640
+ _this._cameraR.aspect = 0.5 * camera.aspect;
3641
+ _this._cameraR.near = camera.near;
3642
+ _this._cameraR.far = camera.far;
3643
+ // _this._cameraR.projectionMatrix = _this._cameraL.projectionMatrix;
3644
+ _this._cameraR.updateProjectionMatrix();
3645
+
3646
+ _this._cameraR.position.copy( _this._position );
3647
+ // _this._cameraR.quaternion.copy( _this._quaternion );
3648
+ */
3649
+
3650
+ _this._cameraR.translateX( _this.separation );
3651
+
3652
+ //
3653
+
3654
+ renderer.setViewport( 0, 0, _this._width * 2, _this._height );
3655
+ renderer.clear();
3656
+
3657
+ renderer.setViewport( 0, 0, _this._width, _this._height );
3658
+ renderer.render( scene, _this._cameraL );
3659
+
3660
+ renderer.setViewport( _this._width, 0, _this._width, _this._height );
3661
+ renderer.render( scene, _this._cameraR );
3662
+
3663
+ };
3664
+
3665
+ };
3666
+
3667
+
3572
3668
 
3573
3669
  // ; var __CIFTools = function () {
3574
3670
  // 'use strict';
@@ -9706,6 +9802,7 @@ class ClickMenu {
9706
9802
 
9707
9803
  applyShownMenus(bNoSave) { let me = this.icn3dui; me.icn3d;
9708
9804
  let idArray = [];
9805
+
9709
9806
  for(let id in me.htmlCls.allMenus) {
9710
9807
  if(me.htmlCls.shownMenus.hasOwnProperty(id)) {
9711
9808
  $("#" + me.pre + id).parent().show();
@@ -9936,6 +10033,14 @@ class ClickMenu {
9936
10033
  me.htmlCls.dialogCls.openDlg('dl_urlfile', 'Load data by URL');
9937
10034
  });
9938
10035
 
10036
+ me.myEventCls.onIds("#" + me.pre + "mn1_clustalwfile", "click", function(e) { me.icn3d; //e.preventDefault();
10037
+ me.htmlCls.dialogCls.openDlg('dl_clustalwfile', 'Please input CLUSTALW MSA File');
10038
+ });
10039
+
10040
+ me.myEventCls.onIds("#" + me.pre + "mn1_fastafile", "click", function(e) { me.icn3d; //e.preventDefault();
10041
+ me.htmlCls.dialogCls.openDlg('dl_fastafile', 'Please input FASTA MSA File');
10042
+ });
10043
+
9939
10044
  me.myEventCls.onIds("#" + me.pre + "mn1_fixedversion", "click", function(e) { me.icn3d; //e.preventDefault();
9940
10045
  me.htmlCls.dialogCls.openDlg('dl_fixedversion', 'Open Share Link URL in the archived version of iCn3D');
9941
10046
  });
@@ -10037,6 +10142,11 @@ class ClickMenu {
10037
10142
  ic.saveFileCls.saveFile(file_pref + '_statefile.txt', 'command');
10038
10143
  });
10039
10144
 
10145
+ me.myEventCls.onIds("#" + me.pre + "mn1_exportVideo", "click", function(e) { me.icn3d; //e.preventDefault();
10146
+ thisClass.setLogCmd("export video", false);
10147
+ me.htmlCls.dialogCls.openDlg('dl_video', 'Save canvas changes in a video');
10148
+ });
10149
+
10040
10150
 
10041
10151
  me.myEventCls.onIds("#" + me.pre + "mn1_exportPdbRes", "click", function(e) { me.icn3d; //e.preventDefault();
10042
10152
  me.htmlCls.setHtmlCls.exportPdb();
@@ -11729,6 +11839,18 @@ class ClickMenu {
11729
11839
  //}
11730
11840
  });
11731
11841
 
11842
+ me.myEventCls.onIds("#" + me.pre + "mn6_stereoYes", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11843
+ ic.opts['effect'] = 'stereo';
11844
+ ic.drawCls.draw();
11845
+ thisClass.setLogCmd('stereo on', true);
11846
+ });
11847
+
11848
+ me.myEventCls.onIds("#" + me.pre + "mn6_stereoNo", "click", function(e) { let ic = me.icn3d; //e.preventDefault();
11849
+ ic.opts['effect'] = 'none';
11850
+ ic.drawCls.draw();
11851
+ thisClass.setLogCmd('stereo off', true);
11852
+ });
11853
+
11732
11854
  $(document).on("click", "#" + me.pre + "mn2_translate", function(e) { me.icn3d; //e.preventDefault();
11733
11855
  me.htmlCls.dialogCls.openDlg('dl_translate', 'Translate the X,Y,Z coordinates of the structure');
11734
11856
  });
@@ -12742,9 +12864,19 @@ class SetMenu {
12742
12864
  html += this.getLink('mn1_mol2file', 'Mol2 File', undefined, 2);
12743
12865
  html += this.getLink('mn1_sdffile', 'SDF File', undefined, 2);
12744
12866
  html += this.getLink('mn1_xyzfile', 'XYZ File', undefined, 2);
12867
+
12868
+ html += this.getMenuSep();
12869
+
12870
+ html += this.getMenuText('mn1_msawrap', 'Multiple Seq. Alignment', undefined, undefined, 2);
12871
+ html += "<ul>";
12872
+ html += this.getLink('mn1_clustalwfile', 'CLUSTALW Format', undefined, 3);
12873
+ html += this.getLink('mn1_fastafile', 'FASTA Format', undefined, 3);
12874
+ html += "</ul>";
12875
+
12745
12876
  html += this.getLink('mn1_afmapfile', 'AlphaFold PAE File', undefined, 2);
12746
12877
 
12747
12878
  html += this.getLink('mn1_urlfile', 'URL(CORS) ' + me.htmlCls.wifiStr, undefined, 2);
12879
+
12748
12880
  html += this.getMenuSep();
12749
12881
  html += this.getLink('mn1_pngimage', 'iCn3D PNG (appendable)', 1, 2);
12750
12882
  html += this.getLink('mn1_state', 'State/Script File', undefined, 2);
@@ -12851,6 +12983,7 @@ class SetMenu {
12851
12983
  html += "</ul>";
12852
12984
  html += "</li>";
12853
12985
 
12986
+ html += this.getLink('mn1_exportVideo', 'Video', undefined, 2);
12854
12987
  html += this.getLink('mn1_exportState', 'State File', undefined, 2);
12855
12988
  html += this.getLink('mn1_exportSelections', 'Selection File', undefined, 2);
12856
12989
  html += this.getLink('mn1_exportSelDetails', 'Selection Details', undefined, 2);
@@ -13068,6 +13201,13 @@ class SetMenu {
13068
13201
  html += "</ul>";
13069
13202
  html += "</li>";
13070
13203
 
13204
+ html += this.getMenuText('mn6_stereoWrapper', 'Stereo View', undefined, undefined, 1);
13205
+ html += "<ul>";
13206
+ html += this.getRadio('mn6_stereo', 'mn6_stereoYes', 'On', undefined, undefined, 2);
13207
+ html += this.getRadio('mn6_stereo', 'mn6_stereoNo', 'Off', true, undefined, 2);
13208
+ html += "</ul>";
13209
+ html += "</li>";
13210
+
13071
13211
  html += this.getLink('mn6_sidebyside', 'Side by Side', undefined, 1);
13072
13212
 
13073
13213
  html += this.getMenuText('mn2_rotate', 'Rotate', undefined, 1, 1);
@@ -15097,6 +15237,19 @@ class SetDialog {
15097
15237
  html += me.htmlCls.buttonStr + "reload_xyzfile'>Load</button>";
15098
15238
  html += "</div>";
15099
15239
 
15240
+ html += me.htmlCls.divStr + "dl_clustalwfile' class='" + dialogClass + "' style='max-width:500px'>";
15241
+ html += this.addNotebookTitle('dl_clustalwfile', 'Please input a CLUSTALW MSA file');
15242
+ 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>";
15243
+ html += "CLUSTALW File: " + me.htmlCls.inputFileStr + "id='" + me.pre + "clustalwfile' size=8> ";
15244
+ html += me.htmlCls.buttonStr + "reload_clustalwfile'>Load</button><br>";
15245
+ html += "</div>";
15246
+ html += me.htmlCls.divStr + "dl_fastafile' class='" + dialogClass + "' style='max-width:500px'>";
15247
+ html += this.addNotebookTitle('dl_fastafile', 'Please input a FASTA file');
15248
+ 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>";
15249
+ html += "FASTA File: " + me.htmlCls.inputFileStr + "id='" + me.pre + "fastafile' size=8> ";
15250
+ html += me.htmlCls.buttonStr + "reload_fastafile'>Load</button><br>";
15251
+ html += "</div>";
15252
+
15100
15253
  html += me.htmlCls.divStr + "dl_afmapfile' class='" + dialogClass + "'>";
15101
15254
  html += this.addNotebookTitle('dl_afmapfile', 'Please input an AlphaFold PAE file');
15102
15255
  html += "AlphaFold PAE File: " + me.htmlCls.inputFileStr + "id='" + me.pre + "afmapfile' size=8> <br><br>";
@@ -15216,6 +15369,12 @@ class SetDialog {
15216
15369
  html += me.htmlCls.buttonStr + "reload_state' style='margin-top: 6px;'>Load</button>";
15217
15370
  html += "</div>";
15218
15371
 
15372
+ html += me.htmlCls.divStr + "dl_video' class='" + dialogClass + "'>";
15373
+ html += this.addNotebookTitle('dl_video', 'Save canvas changes in a video');
15374
+ html += me.htmlCls.buttonStr + "video_start' style='margin-top: 6px;'>Video Start</button>";
15375
+ html += me.htmlCls.buttonStr + "video_end' style='margin: 6px 0px 0px 30px;'>Video End</button>";
15376
+ html += "</div>";
15377
+
15219
15378
  html += me.htmlCls.divStr + "dl_fixedversion' style='max-width:500px' class='" + dialogClass + "'>";
15220
15379
  html += this.addNotebookTitle('dl_fixedversion', 'Use fixed version of iCn3D');
15221
15380
  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>";
@@ -16575,17 +16734,10 @@ class Events {
16575
16734
  }
16576
16735
  }
16577
16736
 
16578
- async loadPdbFile(bAppend, fileId, bmmCIF) { let me = this.icn3dui, ic = me.icn3d;
16737
+ async loadPdbFile(bAppend, fileId, bmmCIF) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
16579
16738
  //me = ic.setIcn3dui(this.id);
16580
16739
  ic.bInitial = true;
16581
- if(!me.cfg.notebook) dialog.dialog( "close" );
16582
- //close all dialog
16583
- if(!me.cfg.notebook) {
16584
- $(".ui-dialog-content").dialog("close");
16585
- }
16586
- else {
16587
- ic.resizeCanvasCls.closeDialogs();
16588
- }
16740
+ thisClass.iniFileLoad();
16589
16741
  let files = $("#" + me.pre + fileId)[0].files;
16590
16742
  if(!files[0]) {
16591
16743
  alert("Please select a file before clicking 'Load'");
@@ -16631,11 +16783,22 @@ class Events {
16631
16783
 
16632
16784
  exportMsa(type) { let me = this.icn3dui, ic = me.icn3d;
16633
16785
  let text = ic.msa[type].join('\n\n');
16634
- let fileType = (type == 'fasta') ? '.fasta' : (type == 'clustal') ? '.aln' : '.txt';
16786
+ let fileType = (type == 'fasta') ? '.fasta' : (type == 'clustalw') ? '.aln' : '.txt';
16635
16787
 
16636
16788
  ic.saveFileCls.saveFile(ic.inputid + '_align' + fileType, 'text', [text]);
16637
16789
  }
16638
16790
 
16791
+ iniFileLoad() { let me = this.icn3dui, ic = me.icn3d;
16792
+ if(!me.cfg.notebook) dialog.dialog( "close" );
16793
+ //close all dialog
16794
+ if(!me.cfg.notebook) {
16795
+ $(".ui-dialog-content").dialog("close");
16796
+ }
16797
+ else {
16798
+ ic.resizeCanvasCls.closeDialogs();
16799
+ }
16800
+ }
16801
+
16639
16802
  async launchMmdb(ids, bBiounit, hostUrl, bAppend) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
16640
16803
  if(!me.cfg.notebook) dialog.dialog( "close" );
16641
16804
 
@@ -17731,16 +17894,40 @@ class Events {
17731
17894
 
17732
17895
  me.htmlCls.setHtmlCls.clickReload_pngimage();
17733
17896
 
17897
+ me.myEventCls.onIds("#" + me.pre + "video_start", "click", function(e) { let ic = me.icn3d;
17898
+ e.preventDefault();
17899
+
17900
+ const canvas = document.getElementById(ic.pre + "canvas");
17901
+ ic.videoRecorder = new MediaRecorder(canvas.captureStream());
17902
+ const recordedChunks = [];
17903
+
17904
+ // Collect data chunks
17905
+ ic.videoRecorder.ondataavailable = event => {
17906
+ recordedChunks.push(event.data);
17907
+ };
17908
+
17909
+ ic.videoRecorder.onstop = event => {
17910
+ // Code to save the recordedChunks as a video file
17911
+ const blob = new Blob(recordedChunks, {type: ic.videoRecorder.mimeType});
17912
+ let fileName = ic.inputid + '_video';
17913
+ saveAs(blob, fileName);
17914
+ };
17915
+
17916
+ // Start recording
17917
+ ic.videoRecorder.start();
17918
+ thisClass.setLogCmd('Video revording started', false);
17919
+ });
17920
+
17921
+ me.myEventCls.onIds("#" + me.pre + "video_end", "click", function(e) { let ic = me.icn3d;
17922
+ e.preventDefault();
17923
+
17924
+ ic.videoRecorder.stop();
17925
+ thisClass.setLogCmd('Video revording ended', false);
17926
+ });
17927
+
17734
17928
  me.myEventCls.onIds("#" + me.pre + "reload_state", "click", function(e) { let ic = me.icn3d;
17735
17929
  e.preventDefault();
17736
- if(!me.cfg.notebook) dialog.dialog( "close" );
17737
- //close all dialog
17738
- if(!me.cfg.notebook) {
17739
- $(".ui-dialog-content").dialog("close");
17740
- }
17741
- else {
17742
- ic.resizeCanvasCls.closeDialogs();
17743
- }
17930
+ thisClass.iniFileLoad();
17744
17931
  // initialize icn3dui
17745
17932
  //Do NOT clear data if iCn3D loads a pdb or other data file and then load a state file
17746
17933
  if(!ic.bInputfile) {
@@ -17792,12 +17979,7 @@ class Events {
17792
17979
  if (!file) {
17793
17980
  alert("Please select a file before clicking 'Load'");
17794
17981
  } else {
17795
- if (!me.cfg.notebook) dialog.dialog("close");
17796
- if (!me.cfg.notebook) {
17797
- $(".ui-dialog-content").dialog("close");
17798
- } else {
17799
- ic.resizeCanvasCls.closeDialogs();
17800
- }
17982
+ thisClass.iniFileLoad();
17801
17983
 
17802
17984
  ic.dAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
17803
17985
  ic.hAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
@@ -18352,14 +18534,7 @@ class Events {
18352
18534
  me.myEventCls.onIds("#" + me.pre + "reload_mol2file", "click", function(e) { let ic = me.icn3d;
18353
18535
  e.preventDefault();
18354
18536
  ic.bInitial = true;
18355
- if(!me.cfg.notebook) dialog.dialog( "close" );
18356
- //close all dialog
18357
- if(!me.cfg.notebook) {
18358
- $(".ui-dialog-content").dialog("close");
18359
- }
18360
- else {
18361
- ic.resizeCanvasCls.closeDialogs();
18362
- }
18537
+ thisClass.iniFileLoad();
18363
18538
  let file = $("#" + me.pre + "mol2file")[0].files[0];
18364
18539
  if(!file) {
18365
18540
  alert("Please select a file before clicking 'Load'");
@@ -18386,14 +18561,7 @@ class Events {
18386
18561
  me.myEventCls.onIds("#" + me.pre + "reload_sdffile", "click", function(e) { let ic = me.icn3d;
18387
18562
  e.preventDefault();
18388
18563
  ic.bInitial = true;
18389
- if(!me.cfg.notebook) dialog.dialog( "close" );
18390
- //close all dialog
18391
- if(!me.cfg.notebook) {
18392
- $(".ui-dialog-content").dialog("close");
18393
- }
18394
- else {
18395
- ic.resizeCanvasCls.closeDialogs();
18396
- }
18564
+ thisClass.iniFileLoad();
18397
18565
  let file = $("#" + me.pre + "sdffile")[0].files[0];
18398
18566
  if(!file) {
18399
18567
  alert("Please select a file before clicking 'Load'");
@@ -18420,14 +18588,7 @@ class Events {
18420
18588
  me.myEventCls.onIds("#" + me.pre + "reload_xyzfile", "click", function(e) { let ic = me.icn3d;
18421
18589
  e.preventDefault();
18422
18590
  ic.bInitial = true;
18423
- if(!me.cfg.notebook) dialog.dialog( "close" );
18424
- //close all dialog
18425
- if(!me.cfg.notebook) {
18426
- $(".ui-dialog-content").dialog("close");
18427
- }
18428
- else {
18429
- ic.resizeCanvasCls.closeDialogs();
18430
- }
18591
+ thisClass.iniFileLoad();
18431
18592
  let file = $("#" + me.pre + "xyzfile")[0].files[0];
18432
18593
  if(!file) {
18433
18594
  alert("Please select a file before clicking 'Load'");
@@ -18451,17 +18612,64 @@ class Events {
18451
18612
  }
18452
18613
  });
18453
18614
 
18454
- me.myEventCls.onIds("#" + me.pre + "reload_afmapfile", "click", function(e) { let ic = me.icn3d;
18615
+ me.myEventCls.onIds("#" + me.pre + "reload_clustalwfile", "click", function(e) { let ic = me.icn3d;
18455
18616
  e.preventDefault();
18456
18617
  ic.bInitial = true;
18457
- if(!me.cfg.notebook) dialog.dialog( "close" );
18458
- //close all dialog
18459
- if(!me.cfg.notebook) {
18460
- $(".ui-dialog-content").dialog("close");
18618
+ thisClass.iniFileLoad();
18619
+
18620
+ let file = $("#" + me.pre + "clustalwfile")[0].files[0];
18621
+ if(!file) {
18622
+ alert("Please select a file before clicking 'Load'");
18461
18623
  }
18462
18624
  else {
18463
- ic.resizeCanvasCls.closeDialogs();
18625
+ me.htmlCls.setHtmlCls.fileSupport();
18626
+ let reader = new FileReader();
18627
+ reader.onload = async function(e) {
18628
+ let dataStr = e.target.result; // or = reader.result;
18629
+ thisClass.setLogCmd('load CLUSTALW file ' + $("#" + me.pre + "clustalwfile").val(), false);
18630
+ ic.molTitle = "";
18631
+ ic.inputid = undefined;
18632
+ //ic.initUI();
18633
+ ic.init();
18634
+ ic.bInputfile = false; //true;
18635
+ ic.InputfileType = 'clustalw';
18636
+ await ic.msaParserCls.loadMsaData(dataStr, 'clustalw');
18637
+ };
18638
+ reader.readAsText(file);
18464
18639
  }
18640
+ });
18641
+
18642
+ me.myEventCls.onIds("#" + me.pre + "reload_fastafile", "click", function(e) { let ic = me.icn3d;
18643
+ e.preventDefault();
18644
+ ic.bInitial = true;
18645
+ thisClass.iniFileLoad();
18646
+
18647
+ let file = $("#" + me.pre + "fastafile")[0].files[0];
18648
+ if(!file) {
18649
+ alert("Please select a file before clicking 'Load'");
18650
+ }
18651
+ else {
18652
+ me.htmlCls.setHtmlCls.fileSupport();
18653
+ let reader = new FileReader();
18654
+ reader.onload = async function(e) {
18655
+ let dataStr = e.target.result; // or = reader.result;
18656
+ thisClass.setLogCmd('load FASTA file ' + $("#" + me.pre + "fastafile").val(), false);
18657
+ ic.molTitle = "";
18658
+ ic.inputid = undefined;
18659
+ //ic.initUI();
18660
+ ic.init();
18661
+ ic.bInputfile = false; //true;
18662
+ ic.InputfileType = 'fasta';
18663
+ await ic.msaParserCls.loadMsaData(dataStr, 'fasta');
18664
+ };
18665
+ reader.readAsText(file);
18666
+ }
18667
+ });
18668
+
18669
+ me.myEventCls.onIds("#" + me.pre + "reload_afmapfile", "click", function(e) { let ic = me.icn3d;
18670
+ e.preventDefault();
18671
+ ic.bInitial = true;
18672
+ thisClass.iniFileLoad();
18465
18673
  let file = $("#" + me.pre + "afmapfile")[0].files[0];
18466
18674
  if(!file) {
18467
18675
  alert("Please select a file before clicking 'Load'");
@@ -18483,14 +18691,7 @@ class Events {
18483
18691
  me.myEventCls.onIds("#" + me.pre + "reload_afmapfilefull", "click", function(e) { let ic = me.icn3d;
18484
18692
  e.preventDefault();
18485
18693
  ic.bInitial = true;
18486
- if(!me.cfg.notebook) dialog.dialog( "close" );
18487
- //close all dialog
18488
- if(!me.cfg.notebook) {
18489
- $(".ui-dialog-content").dialog("close");
18490
- }
18491
- else {
18492
- ic.resizeCanvasCls.closeDialogs();
18493
- }
18694
+ thisClass.iniFileLoad();
18494
18695
  let file = $("#" + me.pre + "afmapfile")[0].files[0];
18495
18696
  if(!file) {
18496
18697
  alert("Please select a file before clicking 'Load'");
@@ -18512,14 +18713,7 @@ class Events {
18512
18713
  me.myEventCls.onIds("#" + me.pre + "reload_urlfile", "click", async function(e) { let ic = me.icn3d;
18513
18714
  e.preventDefault();
18514
18715
  ic.bInitial = true;
18515
- if(!me.cfg.notebook) dialog.dialog( "close" );
18516
- //close all dialog
18517
- if(!me.cfg.notebook) {
18518
- $(".ui-dialog-content").dialog("close");
18519
- }
18520
- else {
18521
- ic.resizeCanvasCls.closeDialogs();
18522
- }
18716
+ thisClass.iniFileLoad();
18523
18717
  let type = $("#" + me.pre + "filetype").val();
18524
18718
  let url = $("#" + me.pre + "urlfile").val();
18525
18719
  ic.inputurl = 'type=' + type + '&url=' + encodeURIComponent(url);
@@ -19394,8 +19588,8 @@ class Events {
19394
19588
 
19395
19589
  me.myEventCls.onIds("#" + me.pre + "saveClustal", "click", function(e) { me.icn3d;
19396
19590
  e.stopImmediatePropagation();
19397
- thisClass.exportMsa('clustal');
19398
- thisClass.setLogCmd('Save alignment in CLUSTALW format', false);
19591
+ thisClass.exportMsa('clustalw');
19592
+ thisClass.setLogCmd('Save alignment in CLUSTALWW format', false);
19399
19593
  });
19400
19594
 
19401
19595
  me.myEventCls.onIds("#" + me.pre + "saveResbyres", "click", function(e) { me.icn3d;
@@ -20265,7 +20459,7 @@ class SetHtml {
20265
20459
 
20266
20460
  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/>";
20267
20461
 
20268
- 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/>";
20462
+ 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/>";
20269
20463
 
20270
20464
  sequencesHtml += me.htmlCls.divStr + "alignseqguide" + suffix + "' style='display:none; white-space:normal;' class='icn3d-box'>";
20271
20465
 
@@ -27521,7 +27715,12 @@ class Scene {
27521
27715
  ic.cams = {
27522
27716
  perspective: ic.perspectiveCamera,
27523
27717
  orthographic: ic.orthographicCamera,
27524
- };
27718
+ };
27719
+
27720
+ if(!me.bNode && ic.opts['effect'] == 'stereo' && !window.icn3duiHash) {
27721
+ ic.effect = ic.effects[options.effect];
27722
+ ic.effect.setSize(ic.container.width(), ic.container.height());
27723
+ }
27525
27724
  };
27526
27725
 
27527
27726
  setVrAr() { let ic = this.icn3d; ic.icn3dui;
@@ -31243,8 +31442,9 @@ class Strand {
31243
31442
  }
31244
31443
  }
31245
31444
 
31246
- // add one extra residue for coils between strands/helix
31247
- if(!isNaN(firstAtom.resi) && ic.pk === 3 && bHighlight === 1 && firstAtom.ss === 'coil') {
31445
+ // add one extra residue for coils between strands/helix if the style is NOT stick, ball and stick, lines, sphere, and dot
31446
+ // if(!isNaN(firstAtom.resi) && ic.pk === 3 && bHighlight === 1 && firstAtom.ss === 'coil') {
31447
+ 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') {
31248
31448
  let residueid = firstAtom.structure + '_' + firstAtom.chain + '_' + (parseInt(firstAtom.resi) - 1).toString();
31249
31449
  if(ic.residues.hasOwnProperty(residueid)) {
31250
31450
  atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, me.hashUtilsCls.hash2Atoms(ic.residues[residueid],
@@ -31279,8 +31479,8 @@ class Strand {
31279
31479
  }
31280
31480
  }
31281
31481
 
31282
- // add one extra residue for coils between strands/helix
31283
- if(ic.pk === 3 && bHighlight === 1 && lastAtom.ss === 'coil') {
31482
+ // add one extra residue for coils between strands/helix if the style is NOT stick, ball and stick, lines, sphere, and dot
31483
+ 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') {
31284
31484
  let residueid = lastAtom.structure + '_' + lastAtom.chain + '_' + (parseInt(lastAtom.resi) + 1).toString();
31285
31485
  if(ic.residues.hasOwnProperty(residueid)) {
31286
31486
  atomsAdjust = me.hashUtilsCls.unionHash(atomsAdjust, me.hashUtilsCls.hash2Atoms(ic.residues[residueid],
@@ -34130,6 +34330,7 @@ ElectronMap.prototype.fillvoxels = function(atoms, atomlist) { //(int seqinit,in
34130
34330
  }
34131
34331
  else {
34132
34332
  // let index2ori = {};
34333
+ let maxdist = this.maxdist;
34133
34334
  for(let serial in atomlist) {
34134
34335
  let atom = atoms[atomlist[serial]];
34135
34336
 
@@ -34146,11 +34347,11 @@ ElectronMap.prototype.fillvoxels = function(atoms, atomlist) { //(int seqinit,in
34146
34347
  }
34147
34348
 
34148
34349
  // show map near the structure
34149
- for(i = Math.floor(r.x) - this.maxdist, il = Math.ceil(r.x) + this.maxdist; i <= il; ++i) {
34350
+ for(i = Math.floor(r.x) - maxdist, il = Math.ceil(r.x) + maxdist; i <= il; ++i) {
34150
34351
  if(i < 0 || i > this.header.xExtent*this.scaleFactor - 1) continue;
34151
- for(j = Math.floor(r.y) - this.maxdist, jl = Math.ceil(r.y) + this.maxdist; j<= jl; ++j) {
34352
+ for(j = Math.floor(r.y) - maxdist, jl = Math.ceil(r.y) + maxdist; j<= jl; ++j) {
34152
34353
  if(j < 0 || j > this.header.yExtent*this.scaleFactor - 1) continue;
34153
- for(k = Math.floor(r.z) - this.maxdist, kl = Math.ceil(r.z) + this.maxdist; k<= kl; ++k) {
34354
+ for(k = Math.floor(r.z) - maxdist, kl = Math.ceil(r.z) + maxdist; k<= kl; ++k) {
34154
34355
  if(k < 0 || k > this.header.zExtent*this.scaleFactor - 1) continue;
34155
34356
  let index = i * widthHeight + j * height + k;
34156
34357
  indexArray.push(index);
@@ -34159,6 +34360,16 @@ ElectronMap.prototype.fillvoxels = function(atoms, atomlist) { //(int seqinit,in
34159
34360
  }
34160
34361
  }
34161
34362
 
34363
+ // show all
34364
+ // for(i = 0; i < this.pLength; ++i) {
34365
+ // for(j = 0; j < this.pWidth; ++j) {
34366
+ // for(k = 0; k < this.pHeight; ++k) {
34367
+ // let index = i * widthHeight + j * height + k;
34368
+ // indexArray.push(index);
34369
+ // }
34370
+ // }
34371
+ // }
34372
+
34162
34373
  for(i = 0, il = indexArray.length; i < il; ++i) {
34163
34374
  let index = indexArray[i];
34164
34375
 
@@ -35420,6 +35631,7 @@ class ApplyDisplay {
35420
35631
  for(let residueid in singletonResidueHash) {
35421
35632
  // get calpha
35422
35633
  let calpha = ic.firstAtomObjCls.getFirstCalphaAtomObj(ic.residues[residueid]);
35634
+ let sideAtom = ic.firstAtomObjCls.getFirstAtomObj(ic.selectionCls.getSideAtoms(ic.residues[residueid]));
35423
35635
  let atom = calpha;
35424
35636
 
35425
35637
  let prevResidueid = atom.structure + '_' + atom.chain + '_' + (parseInt(atom.resi) - 1).toString();
@@ -35436,7 +35648,7 @@ class ApplyDisplay {
35436
35648
  }
35437
35649
  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') ) {
35438
35650
  // do not add extra residue if the side chain is shown
35439
- if(calpha !== undefined && calpha.style2 !== undefined && calpha.style2 !== 'nothing') continue;
35651
+ if(sideAtom !== undefined && sideAtom.style2 !== undefined && sideAtom.style2 !== 'nothing') continue;
35440
35652
 
35441
35653
  let bAddResidue = false;
35442
35654
  // add the next residue with same style
@@ -35471,7 +35683,7 @@ class ApplyDisplay {
35471
35683
  }
35472
35684
  else if( (atom.style === 'ribbon' && atom.ss !== 'coil' && atom.ssend) || (atom.style === 'strand' && atom.ss !== 'coil' && atom.ssend)) {
35473
35685
  // do not add extra residue if the side chain is shown
35474
- if(calpha !== undefined && calpha.style2 !== undefined && calpha.style2 !== 'nothing') continue;
35686
+ if(sideAtom !== undefined && sideAtom.style2 !== undefined && sideAtom.style2 !== 'nothing') continue;
35475
35687
 
35476
35688
  let bAddResidue = false;
35477
35689
  // add the next residue with same style
@@ -38356,11 +38568,18 @@ class Alternate {
38356
38568
  }
38357
38569
 
38358
38570
  if(ic.scene) {
38571
+ ic.renderer.clear();
38572
+
38359
38573
  // https://github.com/gkjohnson/three-gpu-pathtracer/blob/main/example/basic.js
38360
38574
  ic.renderer.outputEncoding = THREE.sRGBEncoding;
38361
38575
  //ic.renderer.outputEncoding = THREE.LinearEncoding
38362
38576
 
38363
- ic.renderer.render(ic.scene, cam);
38577
+ if(ic.opts['effect'] == 'stereo' && !window.icn3duiHash) {
38578
+ ic.effect.render(ic.scene, cam);
38579
+ }
38580
+ else {
38581
+ ic.renderer.render(ic.scene, cam);
38582
+ }
38364
38583
  }
38365
38584
  }
38366
38585
 
@@ -52737,13 +52956,20 @@ class ShowInter {
52737
52956
  }
52738
52957
  // do not change the set of displaying atoms
52739
52958
  //ic.dAtoms = me.hashUtilsCls.cloneHash(ic.atoms);
52740
- let commandname, commanddesc;
52959
+ let commandname, commanddesc, commandname2;
52741
52960
  let firstAtom = ic.firstAtomObjCls.getFirstAtomObj(atomlistTarget);
52961
+
52742
52962
  if(firstAtom !== undefined) {
52743
52963
  commandname = "sphere." + firstAtom.chain + ":" + me.utilsCls.residueName2Abbr(firstAtom.resn.substr(0, 3)).trim() + firstAtom.resi + "-" + radius + "A";
52744
- if(bInteraction) commandname = "interactions." + firstAtom.chain + ":" + me.utilsCls.residueName2Abbr(firstAtom.resn.substr(0, 3)).trim() + firstAtom.resi + "-" + $("#" + ic.pre + "contactthreshold").val() + "A";
52964
+ //sometimes firstAtom.resi changed, thus we add a general name
52965
+ commandname2 = "sphere-" + radius + "A";
52966
+ if(bInteraction) {
52967
+ commandname = "interactions." + firstAtom.chain + ":" + me.utilsCls.residueName2Abbr(firstAtom.resn.substr(0, 3)).trim() + firstAtom.resi + "-" + $("#" + ic.pre + "contactthreshold").val() + "A";
52968
+ commandname2 = "interactions-" + $("#" + ic.pre + "contactthreshold").val() + "A";
52969
+ }
52745
52970
  commanddesc = commandname;
52746
52971
  ic.selectionCls.addCustomSelection(residueArray, commandname, commanddesc, select, true);
52972
+ ic.selectionCls.addCustomSelection(residueArray, commandname2, commanddesc, select, true);
52747
52973
  }
52748
52974
  ic.selectionCls.saveSelectionIfSelected();
52749
52975
  ic.drawCls.draw();
@@ -54921,6 +55147,7 @@ class ChainalignParser {
54921
55147
 
54922
55148
  ajaxArray.push(alignAjax);
54923
55149
  indexArray.push(index - 1);
55150
+ mmdbid_q = chainidArray[index].substr(0, chainidArray[index].indexOf('_'));
54924
55151
  struArray.push(mmdbid_q);
54925
55152
  }
54926
55153
 
@@ -54949,7 +55176,8 @@ class ChainalignParser {
54949
55176
  let mmdbid_q = struArray[i];
54950
55177
  let index = indexArray[i];
54951
55178
 
54952
- let bEqualMmdbid = (mmdbid_q == mmdbid_t);
55179
+ // let bEqualMmdbid = (mmdbid_q == mmdbid_t);
55180
+ let bEqualMmdbid = (mmdbid_q.substr(0,4) == mmdbid_t.substr(0,4));
54953
55181
  let bEqualChain = false;
54954
55182
 
54955
55183
  let queryData = {}; // check whether undefined
@@ -55199,7 +55427,7 @@ class ChainalignParser {
55199
55427
 
55200
55428
  transformStructure(mmdbid, index, alignType, bForce) { let ic = this.icn3d, me = ic.icn3dui;
55201
55429
  let chainidArray = ic.structures[mmdbid];
55202
-
55430
+
55203
55431
  for(let i = 0, il = chainidArray.length; i < il; ++i) {
55204
55432
  for(let serial in ic.chains[chainidArray[i]]) {
55205
55433
  let atm = ic.atoms[serial];
@@ -55331,6 +55559,26 @@ class ChainalignParser {
55331
55559
  return chainidArray;
55332
55560
  }
55333
55561
 
55562
+ addPostfixForStructureids(structArray) { let ic = this.icn3d; ic.icn3dui;
55563
+ let struct2cnt = {};
55564
+ for(let i = 0, il = structArray.length; i < il; ++i) {
55565
+ let struct = structArray[i].toUpperCase();
55566
+
55567
+ if(!struct2cnt.hasOwnProperty(struct)) {
55568
+ struct2cnt[struct] = 1;
55569
+ }
55570
+ else {
55571
+ ++struct2cnt[struct];
55572
+ }
55573
+
55574
+ struct = (struct2cnt[struct] == 1) ? struct : struct + struct2cnt[struct];
55575
+
55576
+ structArray[i] = struct;
55577
+ }
55578
+
55579
+ return structArray;
55580
+ }
55581
+
55334
55582
  async downloadChainalignment(chainalign) { let ic = this.icn3d, me = ic.icn3dui;
55335
55583
  let thisClass = this;
55336
55584
 
@@ -55372,6 +55620,7 @@ class ChainalignParser {
55372
55620
 
55373
55621
  ic.afChainIndexHash = {};
55374
55622
  ic.pdbChainIndexHash = {};
55623
+
55375
55624
  for(let index = 1, indexLen = alignArray.length; index < indexLen; ++index) {
55376
55625
  let pos2 = alignArray[index].indexOf('_');
55377
55626
  let mmdbid_q_tmp = alignArray[index].substr(0, pos2).toUpperCase();
@@ -55479,7 +55728,8 @@ class ChainalignParser {
55479
55728
 
55480
55729
  if(queryData !== undefined && JSON.stringify(queryData).indexOf('Oops there was a problem') === -1
55481
55730
  ) {
55482
- ic.mmdbidArray.push(mmdbid_q);
55731
+ // ic.mmdbidArray.push(mmdbid_q);
55732
+ ic.mmdbidArray.push(mmdbid_q.substr(0,4));
55483
55733
  queryDataArray.push(queryData);
55484
55734
  }
55485
55735
  else {
@@ -55518,7 +55768,8 @@ class ChainalignParser {
55518
55768
  // let align = (me.bNode) ? dataArray[index2 - missedChainCnt] : dataArray[index2 - missedChainCnt].value;//[0];
55519
55769
  let align = dataArray[index2 - missedChainCnt].value;//[0];
55520
55770
 
55521
- let bEqualMmdbid = (mmdbid_q == mmdbid_t);
55771
+ // let bEqualMmdbid = (mmdbid_q == mmdbid_t);
55772
+ let bEqualMmdbid = (mmdbid_q.substr(0,4) == mmdbid_t.substr(0,4));
55522
55773
  let bEqualChain = (chain_q == chain_t);
55523
55774
 
55524
55775
  me.htmlCls.clickMenuCls.setLogCmd("Align " + mmdbid_t + " with " + mmdbid_q, false);
@@ -55689,15 +55940,14 @@ class ChainalignParser {
55689
55940
 
55690
55941
  let structArray = [];
55691
55942
 
55692
- for(let i = 0, il = structArrayTmp.length; i < il; ++i) {
55693
- let id = structArrayTmp[i].toUpperCase();
55694
- // sometimes we want to load same structure multiple times
55695
- if(!ic.structures.hasOwnProperty(id) && structArray.indexOf(id) == -1) {
55696
- structArray.push(structArrayTmp[i]);
55697
- }
55698
- else {
55699
- // only when bNoDuplicate is undefined/false, it's allowed to load multiple copies of the same structure
55700
- if(!bNoDuplicate) structArray.push(structArrayTmp[i] + me.htmlCls.postfix);
55943
+ // only when bNoDuplicate is undefined/false, it's allowed to load multiple copies of the same structure
55944
+ if(!bNoDuplicate) {
55945
+ structArray = this.addPostfixForStructureids(structArrayTmp);
55946
+ }
55947
+ else {
55948
+ for(let i = 0, il = structArrayTmp.length; i < il; ++i) {
55949
+ let id = structArrayTmp[i].toUpperCase();
55950
+ if(!ic.structures.hasOwnProperty(id)) structArray.push(structArrayTmp[i]);
55701
55951
  }
55702
55952
  }
55703
55953
 
@@ -59692,6 +59942,283 @@ class XyzParser {
59692
59942
  }
59693
59943
  }
59694
59944
 
59945
+ /**
59946
+ * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
59947
+ */
59948
+
59949
+ class MsaParser {
59950
+ constructor(icn3d) {
59951
+ this.icn3d = icn3d;
59952
+ }
59953
+
59954
+ async loadMsaData(data, type) { let ic = this.icn3d, me = ic.icn3dui;
59955
+ let bResult = await this.loadMsaSeqData(data, type);
59956
+
59957
+ if(me.cfg.align === undefined && Object.keys(ic.structures).length == 1) {
59958
+ $("#" + ic.pre + "alternateWrapper").hide();
59959
+ }
59960
+
59961
+ let typeStr = type.toUpperCase();
59962
+
59963
+ if(!bResult) {
59964
+ alert('The ' + typeStr + ' file has the wrong format...');
59965
+ }
59966
+ else {
59967
+ // retrieve the structures
59968
+ me.cfg.bu = 0; // show all chains
59969
+ await ic.chainalignParserCls.downloadMmdbAf(ic.struArray.join(','));
59970
+ me.htmlCls.clickMenuCls.setLogCmd('load mmdbaf0 ' + ic.struArray.join(','), true);
59971
+
59972
+ // get the position of the first MSA residue in the full sequence
59973
+ let startPosArray = [];
59974
+ for(let i = 0, il = ic.inputChainidArray.length; i < il; ++i) {
59975
+ let chainid = ic.inputChainidArray[i];
59976
+ let inputSeqNoGap = ic.inputSeqArray[i].replace(/-/g, '');
59977
+
59978
+ // get the full seq
59979
+ let fullSeq = '';
59980
+ for(let j = 0, jl = ic.chainsSeq[chainid].length; j < jl; ++j) {
59981
+ fullSeq += ic.chainsSeq[chainid][j].name;
59982
+ }
59983
+
59984
+ // find the starting position of "inputSeq" in "fullSeq"
59985
+ let pos = fullSeq.toUpperCase().indexOf(inputSeqNoGap.substr(0, 20).toUpperCase());
59986
+ if(pos == -1) {
59987
+ 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...");
59988
+ pos = 0;
59989
+ }
59990
+ startPosArray.push(pos);
59991
+ }
59992
+
59993
+ // define residue mapping
59994
+ // The format is ": "-separated pairs: "1,5,10-50 | 1,5,10-50: 2,6,11-51 | 1,5,10-50"
59995
+ let predefinedres = '';
59996
+
59997
+ let chainid1 = ic.inputChainidArray[0], inputSeq1 = ic.inputSeqArray[0], pos1 = startPosArray[0];
59998
+ // loop through 2nd and forward
59999
+ for(let i = 1, il = ic.inputChainidArray.length; i < il; ++i) {
60000
+ let chainid2 = ic.inputChainidArray[i];
60001
+ let inputSeq2 = ic.inputSeqArray[i];
60002
+ let pos2 = startPosArray[i];
60003
+
60004
+ let index1 = pos1, index2 = pos2;
60005
+ let resiArray1 = [], resiArray2 = [];
60006
+ for(let j = 0, jl = inputSeq2.length; j < jl; ++j) {
60007
+ if(inputSeq1[j] != '-' && inputSeq2[j] != '-' && ic.chainsSeq[chainid1][index1] && ic.chainsSeq[chainid2][index2]) {
60008
+ let resi1 = ic.chainsSeq[chainid1][index1].resi;
60009
+ let resi2 = ic.chainsSeq[chainid2][index2].resi;
60010
+ if(ic.residues[chainid1 + '_' + resi1] && ic.residues[chainid2 + '_' + resi2]) {
60011
+ resiArray1.push(ic.chainsSeq[chainid1][index1].resi);
60012
+ resiArray2.push(ic.chainsSeq[chainid2][index2].resi);
60013
+ }
60014
+ }
60015
+
60016
+ if(inputSeq1[j] != '-') ++index1;
60017
+ if(inputSeq2[j] != '-') ++index2;
60018
+ }
60019
+ let resiRangeStr1 = ic.resid2specCls.resi2range(resiArray1, true);
60020
+ let resiRangeStr2 = ic.resid2specCls.resi2range(resiArray2, true);
60021
+
60022
+ predefinedres += resiRangeStr1 + ' | ' + resiRangeStr2;
60023
+ if(i < il -1) predefinedres += ': ';
60024
+ }
60025
+
60026
+ // realign based on residue by residue
60027
+ let alignment_final = ic.inputChainidArray.join(',');
60028
+
60029
+ if(predefinedres && (alignment_final.split(',').length - 1) != predefinedres.split(': ').length) {
60030
+ alert("Please make sure the number of chains and the lines of predefined residues are the same...");
60031
+ return;
60032
+ }
60033
+
60034
+ me.cfg.resdef = predefinedres.replace(/:/gi, ';');
60035
+
60036
+ let bRealign = true, bPredefined = true;
60037
+ let chainidArray = alignment_final.split(',');
60038
+ await ic.realignParserCls.realignChainOnSeqAlign(undefined, chainidArray, bRealign, bPredefined);
60039
+
60040
+ me.htmlCls.clickMenuCls.setLogCmd("realign predefined " + alignment_final + " " + predefinedres, true);
60041
+
60042
+
60043
+ ic.opts['color'] = 'identity';
60044
+ ic.setColorCls.setColorByOptions(ic.opts, ic.hAtoms);
60045
+ me.htmlCls.clickMenuCls.setLogCmd("color identity", true);
60046
+
60047
+ // show selection
60048
+ ic.selectionCls.showSelection();
60049
+ me.htmlCls.clickMenuCls.setLogCmd("show selection", true);
60050
+ }
60051
+ }
60052
+
60053
+ async loadMsaSeqData(data, type) { let ic = this.icn3d; ic.icn3dui;
60054
+ let lines = data.split(/\r?\n|\r/);
60055
+ if(lines.length < 2) return false;
60056
+
60057
+ ic.init();
60058
+
60059
+ ic.molTitle = "";
60060
+
60061
+ let seqHash = {};
60062
+
60063
+ let bStart = false, bSecBlock = false, chainid = '', seq = '', bFound = false;
60064
+
60065
+ if(type == 'clustalw' && lines[0].substr(0,7) != 'CLUSTAL') { // CLUSTAL W or CLUSTALW
60066
+ return false;
60067
+ }
60068
+
60069
+ let startLineNum = (type == 'clustalw') ? 1 : 0;
60070
+
60071
+ // 1. parse input msa
60072
+ for(let i = startLineNum, il = lines.length; i < il; ++i) {
60073
+ let line = lines[i].trim();
60074
+ if(line === '') {
60075
+ if(bStart) bSecBlock = true;
60076
+ bStart = false;
60077
+ continue;
60078
+ }
60079
+
60080
+ if(!bStart) { // first line
60081
+ if(type == 'fasta' && line.substr(0,1) != '>') {
60082
+ return false;
60083
+ }
60084
+ bStart = true;
60085
+ }
60086
+
60087
+ if(type == 'clustalw') {
60088
+ if(line.substr(0, 1) != ' ' && line.substr(0, 1) != '\t') {
60089
+ let chainid_seq = line.split(/\s+/);
60090
+ let idArray = chainid_seq[0].split('|');
60091
+ let result = this.getChainid(idArray, bStart && !bSecBlock);
60092
+ bFound = result.bFound;
60093
+ chainid = result.chainid;
60094
+
60095
+ if(bFound) {
60096
+ if(!seqHash.hasOwnProperty(chainid)) {
60097
+ seqHash[chainid] = chainid_seq[1];
60098
+ }
60099
+ else {
60100
+ seqHash[chainid] += chainid_seq[1];
60101
+ }
60102
+ }
60103
+ }
60104
+ }
60105
+ else if(type == 'fasta') {
60106
+ if(line.substr(0,1) == ">") {
60107
+ // add the previous seq
60108
+ if(chainid && seq && bFound) seqHash[chainid] = seq;
60109
+ chainid = '';
60110
+ seq = '';
60111
+
60112
+ let pos = line.indexOf(' ');
60113
+ let idArray = line.substr(1, pos).split('|');
60114
+
60115
+ if(idArray.length == 1) {
60116
+ chainid = idArray[0];
60117
+ }
60118
+ else {
60119
+ let result = this.getChainid(idArray, true);
60120
+ bFound = result.bFound;
60121
+ chainid = result.chainid;
60122
+ }
60123
+ }
60124
+ else {
60125
+ seq += line;
60126
+ }
60127
+ }
60128
+ }
60129
+
60130
+ // add the last seq
60131
+ if(type == 'fasta' && chainid && seq && bFound) seqHash[chainid] = seq;
60132
+
60133
+ // 2. get the PDB ID or RefSeqID or AlphaFold ID
60134
+ ic.inputChainidArray = [];
60135
+ ic.inputSeqArray = [];
60136
+ ic.struArray = [];
60137
+
60138
+ // find the tempate where the first residue is not gap
60139
+ let template = '';
60140
+ for(let chainid in seqHash) {
60141
+ let seq = seqHash[chainid];
60142
+ if(seq.substr(0,1) != '-') {
60143
+ template = chainid;
60144
+ await this.processOneChain(chainid, seqHash);
60145
+ break;
60146
+ }
60147
+ }
60148
+ if(!template) template = Object.keys(seqHash)[0];
60149
+
60150
+ for(let chainid in seqHash) {
60151
+ if(chainid != template) await this.processOneChain(chainid, seqHash);
60152
+ }
60153
+
60154
+ return true;
60155
+ }
60156
+
60157
+ async processOneChain(chainid, seqHash) { let ic = this.icn3d, me = ic.icn3dui;
60158
+ ic.inputSeqArray.push(seqHash[chainid]);
60159
+ // ic.inputSeqArray.push(seqHash[chainid].replace(/-/g, '')); // remove the gaps in seq
60160
+
60161
+ if(chainid.lastIndexOf('_') == 2) { // refseq ID
60162
+ // convert refseq to uniprot id
60163
+ let url = me.htmlCls.baseUrl + "vastdyn/vastdyn.cgi?refseq2uniprot=" + chainid;
60164
+
60165
+ let data = await me.getAjaxPromise(url, 'jsonp', false, 'The protein accession ' + chainid + ' can not be mapped to AlphaFold UniProt ID...');
60166
+ if(data && data.uniprot) {
60167
+ if(!ic.uniprot2acc) ic.uniprot2acc = {};
60168
+ let uniprot = data.uniprot;
60169
+ ic.uniprot2acc[uniprot] = chainid;
60170
+ ic.struArray.push(uniprot);
60171
+ ic.inputChainidArray.push(uniprot + '_A');
60172
+ }
60173
+ else {
60174
+ console.log('The accession ' + refseqid + ' can not be mapped to AlphaFold UniProt ID. It will be treated as a UniProt ID instead.');
60175
+ ic.struArray.push(chainid);
60176
+ ic.inputChainidArray.push(chainid + '_A');
60177
+ }
60178
+ }
60179
+ else if(chainid.indexOf('_') != -1) { // PDB ID
60180
+ let stru = chainid.substr(0, chainid.indexOf('_')).substr(0, 4);
60181
+ ic.struArray.push(stru);
60182
+ ic.inputChainidArray.push(chainid);
60183
+ }
60184
+ else if(chainid.length > 5) { // UniProt ID
60185
+ ic.struArray.push(chainid);
60186
+ ic.inputChainidArray.push(chainid + '_A');
60187
+ }
60188
+ }
60189
+
60190
+ getChainid(idArray, bWarning) { let ic = this.icn3d; ic.icn3dui;
60191
+ let bFound = false;
60192
+ let chainid = idArray[0];
60193
+
60194
+ for(let j = 0, jl = idArray.length; j < jl; ++j) {
60195
+ if(idArray[j] == 'pdb') {
60196
+ chainid = idArray[j+1] + '_' + idArray[j+2];
60197
+ bFound = true;
60198
+ break;
60199
+ }
60200
+ else if(idArray[j] == 'ref') { // refseq
60201
+ let refseq = idArray[j+1].split('.')[0];
60202
+ chainid = refseq; // + '_A';
60203
+ bFound = true;
60204
+ break;
60205
+ }
60206
+ else if(idArray[j] == 'sp' || idArray[j] == 'tr') { // uniprot
60207
+ let uniprot = idArray[j+1];
60208
+ chainid = uniprot;
60209
+ bFound = true;
60210
+ break;
60211
+ }
60212
+ }
60213
+
60214
+ if(!bFound && bWarning) {
60215
+ alert("The sequence ID " + idArray.join('|') + " does not have the correctly formatted PDB, UniProt or RefSeq ID...");
60216
+ }
60217
+
60218
+ return {chainid: chainid, bFound: bFound};
60219
+ }
60220
+ }
60221
+
59695
60222
  /**
59696
60223
  * @author Jiyao Wang <wangjiy@ncbi.nlm.nih.gov> / https://github.com/ncbi/icn3d
59697
60224
  */
@@ -59833,7 +60360,7 @@ class RealignParser {
59833
60360
  // If rmsd from vastsrv is too large, realign the chains
59834
60361
  //if(me.cfg.chainalign && !me.cfg.usepdbnum && me.cfg.resdef && rmsd > 5) {
59835
60362
  // redo algnment only for VAST serv page
59836
- if(!me.cfg.usepdbnum && me.cfg.resdef && rmsd > 5) {
60363
+ if(!me.cfg.usepdbnum && me.cfg.resdef && rmsd > 5 && me.cfg.chainalign) {
59837
60364
  console.log("RMSD from VAST is larger than 5. Realign the chains with TM-align.");
59838
60365
  //let nameArray = me.cfg.chainalign.split(',');
59839
60366
  let nameArray = Object.keys(chainidHash);
@@ -60289,7 +60816,8 @@ let resRangeArray = (me.cfg.resrange) ? decodeURIComponent(me.cfg.resrange).spli
60289
60816
  let predefinedResArray, predefinedResPair;
60290
60817
 
60291
60818
  if(bPredefined) {
60292
- predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split(': ');
60819
+ // predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split(': ');
60820
+ predefinedResArray = decodeURIComponent(me.cfg.resdef).trim().replace(/\+/gi, ' ').split('; ');
60293
60821
 
60294
60822
  if(predefinedResArray.length != chainidArray.length - 1) {
60295
60823
  alert("Please make sure the number of chains and the lines of predefined residues are the same...");
@@ -60566,7 +61094,7 @@ class DensityCifParser {
60566
61094
  let thisClass = this;
60567
61095
 
60568
61096
  let url;
60569
- let detail = (me.utilsCls.isMobile() || me.cfg.notebook) ? 2 : 4; //0 : 4;
61097
+ let detail = (me.utilsCls.isMobile() || me.cfg.notebook) ? 0 : 4; // max 6
60570
61098
 
60571
61099
  //https://www.ebi.ac.uk/pdbe/densities/doc.html
60572
61100
  if(type == '2fofc' || type == 'fofc') {
@@ -60577,6 +61105,7 @@ class DensityCifParser {
60577
61105
  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;
60578
61106
  }
60579
61107
  else if(type == 'em') {
61108
+ detail = (me.utilsCls.isMobile() || me.cfg.notebook) ? 0: 5; // max 6
60580
61109
  url = "https://www.ebi.ac.uk/pdbe/densities/emd/" + emd.toLowerCase() + "/cell?detail=" + detail;
60581
61110
  }
60582
61111
 
@@ -62150,11 +62679,12 @@ class ParserUtils {
62150
62679
 
62151
62680
  // set defined sets before loadScript
62152
62681
  if(ic.bInitial) {
62153
- if(me.cfg.mobilemenu) {
62154
- me.htmlCls.shownMenus = me.hashUtilsCls.cloneHash(me.htmlCls.simpleMenus);
62155
- let bNoSave = true;
62156
- me.htmlCls.clickMenuCls.applyShownMenus(bNoSave);
62157
- }
62682
+ // if(me.cfg.mobilemenu) {
62683
+ // me.htmlCls.shownMenus = me.hashUtilsCls.cloneHash(me.htmlCls.simpleMenus);
62684
+ // let bNoSave = true;
62685
+ // me.htmlCls.clickMenuCls.applyShownMenus(bNoSave);
62686
+ // }
62687
+
62158
62688
  // else {
62159
62689
  // me.htmlCls.shownMenus = me.hashUtilsCls.cloneHash(me.htmlCls.allMenus);
62160
62690
  // me.htmlCls.clickMenuCls.applyShownMenus();
@@ -64626,7 +65156,7 @@ class SetSeqAlign {
64626
65156
 
64627
65157
  setMsaFormat(chainidArray) { let ic = this.icn3d; ic.icn3dui;
64628
65158
  //set MSA
64629
- let fastaFormat = '', clustalFormat = 'CLUSTALW\n\n', resbyresFormat = '';
65159
+ let fastaFormat = '', clustalwFormat = 'CLUSTALWW\n\n', resbyresFormat = '';
64630
65160
  let chainArrayClustal = [];
64631
65161
 
64632
65162
  let consArray = [], resiArrayTemplate = [];
@@ -64635,8 +65165,8 @@ class SetSeqAlign {
64635
65165
  let chainid = chainidArray[i];
64636
65166
  fastaFormat += '>' + chainid + '\n';
64637
65167
 
64638
- let clustalArray = [];
64639
- let clustalLine = chainid.padEnd(20, ' ');
65168
+ let clustalwArray = [];
65169
+ let clustalwLine = chainid.padEnd(20, ' ');
64640
65170
  let consLine = ''.padEnd(20, ' ');
64641
65171
 
64642
65172
  let resiArrayTarget = [], resiArrayQuery = [];
@@ -64645,7 +65175,7 @@ class SetSeqAlign {
64645
65175
  for(let j = 0, jl = ic.alnChainsSeq[chainid].length; j < jl; ++j) {
64646
65176
  let resn = ic.alnChainsSeq[chainid][j].resn;
64647
65177
  fastaFormat += resn;
64648
- clustalLine += resn;
65178
+ clustalwLine += resn;
64649
65179
  if(i == il - 1) {
64650
65180
  let alignedClass = ic.alnChainsSeq[chainid][j].class;
64651
65181
  if(alignedClass == 'icn3d-cons') {
@@ -64664,7 +65194,8 @@ class SetSeqAlign {
64664
65194
  resiArrayTemplate.push(ic.alnChainsSeq[chainid][j].resi);
64665
65195
  }
64666
65196
  else {
64667
- if(ic.alnChainsSeq[chainid][j].aligned) {
65197
+ // if(ic.alnChainsSeq[chainid][j].aligned) {
65198
+ if(ic.alnChainsSeq[chainid][j].aligned && ic.alnChainsSeq[chainidTemplate][j] && ic.alnChainsSeq[chainid][j]) {
64668
65199
  resiArrayTarget.push(ic.alnChainsSeq[chainidTemplate][j].resi);
64669
65200
  resiArrayQuery.push(ic.alnChainsSeq[chainid][j].resi);
64670
65201
  }
@@ -64674,9 +65205,9 @@ class SetSeqAlign {
64674
65205
 
64675
65206
  if(cnt % 60 == 0) {
64676
65207
  fastaFormat += '\n';
64677
- clustalLine += ' ' + String(parseInt(cnt / 60) * 60);
64678
- clustalArray.push(clustalLine);
64679
- clustalLine = chainid.padEnd(20, ' ');
65208
+ clustalwLine += ' ' + String(parseInt(cnt / 60) * 60);
65209
+ clustalwArray.push(clustalwLine);
65210
+ clustalwLine = chainid.padEnd(20, ' ');
64680
65211
 
64681
65212
  if(i == il - 1) {
64682
65213
  consArray.push(consLine);
@@ -64687,7 +65218,7 @@ class SetSeqAlign {
64687
65218
 
64688
65219
  // add last line
64689
65220
  if(cnt % 60 != 0) {
64690
- clustalArray.push(clustalLine);
65221
+ clustalwArray.push(clustalwLine);
64691
65222
  if(i == il - 1) {
64692
65223
  consArray.push(consLine);
64693
65224
  }
@@ -64695,7 +65226,7 @@ class SetSeqAlign {
64695
65226
 
64696
65227
  fastaFormat += '\n';
64697
65228
 
64698
- chainArrayClustal.push(clustalArray);
65229
+ chainArrayClustal.push(clustalwArray);
64699
65230
  if(i == il - 1) chainArrayClustal.push(consArray);
64700
65231
 
64701
65232
  // residue by residue
@@ -64705,23 +65236,23 @@ class SetSeqAlign {
64705
65236
  if(i > 0) resbyresFormat += resiRangeStr1 + ' | ' + resiRangeStr2 + '\n';
64706
65237
  }
64707
65238
 
64708
- // CLUSTALW
65239
+ // CLUSTALWW
64709
65240
  for(let j = 0, jl = chainArrayClustal[0].length; j < jl; ++j) {
64710
65241
  for(let i = 0, il = chainArrayClustal.length; i < il; ++i) {
64711
- clustalFormat += chainArrayClustal[i][j] + '\n';
65242
+ clustalwFormat += chainArrayClustal[i][j] + '\n';
64712
65243
  }
64713
- clustalFormat += '\n';
65244
+ clustalwFormat += '\n';
64714
65245
  }
64715
65246
 
64716
65247
  // seq MSA
64717
65248
  if(!ic.msa) ic.msa = {};
64718
65249
 
64719
65250
  if(!ic.msa['fasta']) ic.msa['fasta'] = [];
64720
- if(!ic.msa['clustal']) ic.msa['clustal'] = [];
65251
+ if(!ic.msa['clustalw']) ic.msa['clustalw'] = [];
64721
65252
  if(!ic.msa['resbyres']) ic.msa['resbyres'] = [];
64722
65253
 
64723
65254
  ic.msa['fasta'].push(fastaFormat);
64724
- ic.msa['clustal'].push(clustalFormat);
65255
+ ic.msa['clustalw'].push(clustalwFormat);
64725
65256
  ic.msa['resbyres'].push(resbyresFormat);
64726
65257
  }
64727
65258
  }
@@ -67477,6 +68008,12 @@ class ApplyCommand {
67477
68008
  else if(command == 'set slab off') {
67478
68009
  ic.opts['slab'] = 'no';
67479
68010
  }
68011
+ else if(command == 'stereo on') {
68012
+ ic.opts['effect'] = 'stereo';
68013
+ }
68014
+ else if(command == 'stereo off') {
68015
+ ic.opts['effect'] = 'none';
68016
+ }
67480
68017
  else if(command == 'set assembly on') {
67481
68018
  ic.bAssembly = true;
67482
68019
  }
@@ -69550,16 +70087,26 @@ class DefinedSets {
69550
70087
  } // outer for
69551
70088
  }
69552
70089
 
69553
- setHAtomsFromSets(nameArray, type) { let ic = this.icn3d, me = ic.icn3dui;
70090
+ setHAtomsFromSets(nameArray, type) { let ic = this.icn3d; ic.icn3dui;
69554
70091
  for(let i = 0; i < nameArray.length; ++i) {
69555
70092
  let selectedSet = nameArray[i];
69556
70093
 
69557
- if((ic.defNames2Atoms === undefined || !ic.defNames2Atoms.hasOwnProperty(selectedSet)) &&(ic.defNames2Residues === undefined || !ic.defNames2Residues.hasOwnProperty(selectedSet)) ) continue;
70094
+ this.setHAtomsFromSets_base(selectedSet, type);
70095
+
70096
+ // sometimes the "resi" changed and thus the name changed
70097
+ //"sphere." + firstAtom.chain + ":" + me.utilsCls.residueName2Abbr(firstAtom.resn.substr(0, 3)).trim() + firstAtom.resi + "-" + radius + "A";
70098
+ if(Object.keys(ic.hAtoms).length == 0 && (selectedSet.split('.')[0] == 'sphere' || selectedSet.split('.')[0] == 'interactions')) {
70099
+ let pos = selectedSet.lastIndexOf('-');
70100
+ selectedSet = selectedSet.split('.')[0] + selectedSet.substr(pos);
70101
+ this.setHAtomsFromSets_base(selectedSet, type);
70102
+ }
70103
+ } // outer for
70104
+ }
69558
70105
 
70106
+ setHAtomsFromSets_base(selectedSet, type) { let ic = this.icn3d, me = ic.icn3dui;
69559
70107
  if(ic.defNames2Atoms !== undefined && ic.defNames2Atoms.hasOwnProperty(selectedSet)) {
69560
70108
 
69561
70109
  let atomArray = ic.defNames2Atoms[selectedSet];
69562
-
69563
70110
  if(type === 'or') {
69564
70111
  for(let j = 0, jl = atomArray.length; j < jl; ++j) {
69565
70112
  ic.hAtoms[atomArray[j]] = 1;
@@ -69605,7 +70152,6 @@ class DefinedSets {
69605
70152
  ic.hAtoms = me.hashUtilsCls.exclHash(ic.hAtoms, atomHash);
69606
70153
  }
69607
70154
  }
69608
- } // outer for
69609
70155
  }
69610
70156
 
69611
70157
  updateAdvancedCommands(nameArray, type) { let ic = this.icn3d; ic.icn3dui;
@@ -69628,6 +70174,7 @@ class DefinedSets {
69628
70174
 
69629
70175
  combineSets(orArray, andArray, notArray, commandname) { let ic = this.icn3d, me = ic.icn3dui;
69630
70176
  ic.hAtoms = {};
70177
+
69631
70178
  this.setHAtomsFromSets(orArray, 'or');
69632
70179
 
69633
70180
  if(Object.keys(ic.hAtoms).length == 0) {
@@ -71723,19 +72270,22 @@ class Selection {
71723
72270
  selectSideChains() { let ic = this.icn3d, me = ic.icn3dui;
71724
72271
  let currHAtoms = me.hashUtilsCls.cloneHash(ic.hAtoms);
71725
72272
 
71726
- //let nuclMainArray = ["C1'", "C1*", "C2'", "C2*", "C3'", "C3*", "C4'", "C4*", "C5'", "C5*", "O3'", "O3*", "O4'", "O4*", "O5'", "O5*", "P", "OP1", "O1P", "OP2", "O2P"];
72273
+ ic.hAtoms = this.getSideAtoms(currHAtoms);
72274
+ ic.hlUpdateCls.showHighlight();
72275
+ }
71727
72276
 
71728
- ic.hAtoms = {};
71729
- for(let i in currHAtoms) {
72277
+ getSideAtoms(atoms) { let ic = this.icn3d, me = ic.icn3dui;
72278
+ let sideAtoms = {};
72279
+ for(let i in atoms) {
71730
72280
  if((ic.proteins.hasOwnProperty(i) && ic.atoms[i].name !== "N" && ic.atoms[i].name !== "H"
71731
72281
  && ic.atoms[i].name !== "C" && ic.atoms[i].name !== "O"
71732
72282
  && !(ic.atoms[i].name === "CA" && ic.atoms[i].elem === "C") && ic.atoms[i].name !== "HA")
71733
72283
  ||(ic.nucleotides.hasOwnProperty(i) && me.parasCls.nuclMainArray.indexOf(ic.atoms[i].name) === -1) ) {
71734
- ic.hAtoms[i] = 1;
72284
+ sideAtoms[i] = 1;
71735
72285
  }
71736
72286
  }
71737
72287
 
71738
- ic.hlUpdateCls.showHighlight();
72288
+ return sideAtoms;
71739
72289
  }
71740
72290
 
71741
72291
  selectMainSideChains() { let ic = this.icn3d, me = ic.icn3dui;
@@ -72351,9 +72901,12 @@ class Resid2spec {
72351
72901
  resi2range(resiArray, bString) {var ic = this.icn3d; ic.icn3dui;
72352
72902
  let range = [], rangeStr = '';
72353
72903
 
72354
- let resiArraySorted = resiArray.sort(function(a, b) {
72355
- return parseInt(a) - parseInt(b);
72356
- });
72904
+ // some chains such as 3SN6_R start with residues with high residue numbers, then end with residues with low residue numbers
72905
+ // let resiArraySorted = resiArray.sort(function(a, b) {
72906
+ // return parseInt(a) - parseInt(b);
72907
+ // });
72908
+
72909
+ let resiArraySorted = resiArray;
72357
72910
 
72358
72911
  let startResi = resiArraySorted[0];
72359
72912
  let prevResi, resi;
@@ -73638,18 +74191,29 @@ class Dssp {
73638
74191
 
73639
74192
  ic.pdbDataArray = await this.promiseWithFixedJobs(pdbAjaxArray);
73640
74193
 
73641
- let bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template);
73642
74194
  let numRound = 0;
74195
+ let bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template, undefined, numRound);
74196
+ ++numRound;
73643
74197
 
73644
74198
  //while(!bNoMoreIg) {
73645
74199
  while(!bNoMoreIg && numRound < 15) {
73646
74200
  let bRerun = true;
73647
- bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template, bRerun);
74201
+ bNoMoreIg = await thisClass.parseRefPdbData(ic.pdbDataArray, template, bRerun, numRound);
73648
74202
  ++numRound;
73649
74203
  }
73650
74204
  }
73651
74205
  else {
73652
- await thisClass.parseRefPdbData(undefined, template);
74206
+ await thisClass.parseRefPdbData(undefined, template, undefined, numRound);
74207
+ }
74208
+
74209
+ // refnum should be adjusted after all Ig are detected since sometimes the sheet extension may affect another Ig domain
74210
+ if(!ic.chainid2igtrack) ic.chainid2igtrack = {};
74211
+ for(let chainid in ic.chains) {
74212
+ let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.chains[chainid]);
74213
+ if(ic.proteins.hasOwnProperty(atom.serial)) {
74214
+ let giSeq = ic.showSeqCls.getSeq(chainid);
74215
+ ic.chainid2igtrack[chainid] = this.ajdustRefnum(giSeq, chainid);
74216
+ }
73653
74217
  }
73654
74218
  // }
73655
74219
  // catch(err) {
@@ -73658,7 +74222,7 @@ class Dssp {
73658
74222
  // }
73659
74223
  }
73660
74224
 
73661
- async parseRefPdbData(dataArray, template, bRerun) { let ic = this.icn3d, me = ic.icn3dui;
74225
+ async parseRefPdbData(dataArray, template, bRerun, numRound) { let ic = this.icn3d, me = ic.icn3dui;
73662
74226
  let thisClass = this;
73663
74227
 
73664
74228
  let struArray = Object.keys(ic.structures);
@@ -73752,7 +74316,7 @@ class Dssp {
73752
74316
  dataArray2 = await this.promiseWithFixedJobs(ajaxArray);
73753
74317
 
73754
74318
  let bRound1 = true;
73755
- bNoMoreIg = await thisClass.parseAlignData(dataArray2, domainidpairArray, bRound1);
74319
+ bNoMoreIg = await thisClass.parseAlignData(dataArray2, domainidpairArray, bRound1, numRound);
73756
74320
 
73757
74321
  /// if(ic.deferredRefnum !== undefined) ic.deferredRefnum.resolve();
73758
74322
  }
@@ -73798,7 +74362,7 @@ class Dssp {
73798
74362
 
73799
74363
  dataArray3 = await this.promiseWithFixedJobs(ajaxArray);
73800
74364
 
73801
- bNoMoreIg = await thisClass.parseAlignData(dataArray3, domainidpairArray3);
74365
+ bNoMoreIg = await thisClass.parseAlignData(dataArray3, domainidpairArray3, undefined, numRound);
73802
74366
  }
73803
74367
 
73804
74368
  return bNoMoreIg;
@@ -74026,7 +74590,7 @@ class Dssp {
74026
74590
  delete ic.domainid2refpdbname[domainid];
74027
74591
  delete ic.domainid2score[domainid];
74028
74592
  }
74029
- continue;
74593
+ continue;
74030
74594
  }
74031
74595
  // }
74032
74596
  }
@@ -74090,7 +74654,7 @@ class Dssp {
74090
74654
  return domainid2segs; // only used in round 2
74091
74655
  }
74092
74656
 
74093
- async parseAlignData(dataArray, domainidpairArray, bRound1) { let ic = this.icn3d, me = ic.icn3dui;
74657
+ async parseAlignData(dataArray, domainidpairArray, bRound1, numRound) { let ic = this.icn3d, me = ic.icn3dui;
74094
74658
  let bNoMoreIg = false;
74095
74659
 
74096
74660
  let domainid2segs = this.parseAlignData_part1(dataArray, domainidpairArray, bRound1);
@@ -74115,7 +74679,8 @@ class Dssp {
74115
74679
  //let pdbid = domainid.substr(0, domainid.indexOf('_'));
74116
74680
  let chainid = domainid.substr(0, domainid.indexOf(','));
74117
74681
 
74118
- if(ic.refpdbHash.hasOwnProperty(chainid)) {
74682
+ // Adjusted refpdbname in the first try
74683
+ if(ic.refpdbHash.hasOwnProperty(chainid) && numRound == 0) {
74119
74684
  refpdbnameList = [chainid];
74120
74685
 
74121
74686
  if(!me.bNode) console.log("Adjusted refpdbname for domainid " + domainid + ": " + chainid);
@@ -74168,7 +74733,7 @@ class Dssp {
74168
74733
 
74169
74734
  dataArray3 = await this.promiseWithFixedJobs(ajaxArray);
74170
74735
 
74171
- bNoMoreIg = await this.parseAlignData(dataArray3, domainidpairArray3, false);
74736
+ bNoMoreIg = await this.parseAlignData(dataArray3, domainidpairArray3, false, numRound);
74172
74737
 
74173
74738
  // end of round 2
74174
74739
  return bNoMoreIg;
@@ -74413,6 +74978,8 @@ class Dssp {
74413
74978
  }
74414
74979
  }
74415
74980
 
74981
+ // refnum should be adjusted after all Ig are detected since sometimes the sheet extension may affect another Ig domain
74982
+ /*
74416
74983
  if(!ic.chainid2igtrack) ic.chainid2igtrack = {};
74417
74984
  for(let chainid in ic.chains) {
74418
74985
  let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.chains[chainid]);
@@ -74421,6 +74988,7 @@ class Dssp {
74421
74988
  ic.chainid2igtrack[chainid] = this.ajdustRefnum(giSeq, chainid);
74422
74989
  }
74423
74990
  }
74991
+ */
74424
74992
  }
74425
74993
 
74426
74994
  getStrandFromRefnum(oriRefnum, finalStrand) { let ic = this.icn3d; ic.icn3dui;
@@ -79353,7 +79921,7 @@ class ResizeCanvas {
79353
79921
  //let itemArray = ['dl_selectannotations', 'dl_alignment', 'dl_2ddgm', 'dl_definedsets', 'dl_graph',
79354
79922
  // 'dl_linegraph', 'dl_scatterplot', 'dl_contactmap', 'dl_allinteraction', 'dl_copyurl',
79355
79923
  // 'dl_symmetry', 'dl_symd', 'dl_rmsd', 'dl_legend', 'dl_disttable'];
79356
- 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'];
79924
+ 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'];
79357
79925
 
79358
79926
  for(let i in itemArray) {
79359
79927
  let item = itemArray[i];
@@ -80099,9 +80667,10 @@ class SaveFile {
80099
80667
  ssObj.resn = atom.resn;
80100
80668
  ssObj.resi = atom.resi;
80101
80669
 
80102
- if(parseInt(atom.resi) > parseInt(prevResi) + 1) {
80103
- ssObj.ss = ' ';
80104
- ssArray.push(ssObj);
80670
+ if(parseInt(atom.resi) > parseInt(prevResi) + 1 || atom.ssbegin) {
80671
+ let ssObj2 = me.hashUtilsCls.cloneHash(ssObj);
80672
+ ssObj2.ss = ' ';
80673
+ ssArray.push(ssObj2);
80105
80674
  }
80106
80675
 
80107
80676
  if(atom.ss == 'helix') {
@@ -80112,13 +80681,13 @@ class SaveFile {
80112
80681
  ssObj.ss = 'S';
80113
80682
  ssArray.push(ssObj);
80114
80683
  }
80115
-
80684
+ /*
80116
80685
  if(atom.ssend) {
80117
80686
  let ssObj2 = me.hashUtilsCls.cloneHash(ssObj);
80118
80687
  ssObj2.ss = ' ';
80119
80688
  ssArray.push(ssObj2);
80120
80689
  }
80121
-
80690
+ */
80122
80691
  prevResi = atom.resi;
80123
80692
  }
80124
80693
 
@@ -80126,9 +80695,9 @@ class SaveFile {
80126
80695
  for(let i = 0, il = ssArray.length; i < il; ++i) {
80127
80696
  let ssObj = ssArray[i];
80128
80697
 
80129
- if(ssObj.ss != prevSs || ssObj.ssbegin) {
80698
+ if(ssObj.ss != prevSs) {
80130
80699
  // print prev
80131
- stru2header[stru] += this.printPrevSecondary(bHelix, bSheet, prevRealSsObj, ssCnt);
80700
+ if(prevSs !== ' ') stru2header[stru] += this.printPrevSecondary(bHelix, bSheet, prevRealSsObj, ssCnt);
80132
80701
 
80133
80702
  // print current
80134
80703
  ssCnt = 0;
@@ -80136,7 +80705,7 @@ class SaveFile {
80136
80705
  bSheet = false;
80137
80706
  prevRealSsObj = undefined;
80138
80707
 
80139
- if(ssObj.ss != ' ') {
80708
+ if(ssObj.ss !== ' ') {
80140
80709
  if(ssObj.ss == 'H') {
80141
80710
  bHelix = true;
80142
80711
  prevRealSsObj = ssObj;
@@ -80152,7 +80721,7 @@ class SaveFile {
80152
80721
  }
80153
80722
  }
80154
80723
 
80155
- if(ssObj.ss != ' ') {
80724
+ if(ssObj.ss !== ' ') {
80156
80725
  ++ssCnt;
80157
80726
  prevRealSsObj = ssObj;
80158
80727
  }
@@ -82001,8 +82570,10 @@ class Ray {
82001
82570
  this.icn3d = icn3d;
82002
82571
  }
82003
82572
 
82004
- rayCaster(e, bClick) {
82573
+ rayCaster(e, bClick) { let ic = this.icn3d; ic.icn3dui;
82574
+ if(!ic.opts || ic.opts['effect'] == 'none') {
82005
82575
  this.rayCasterBase(e, bClick);
82576
+ }
82006
82577
  }
82007
82578
 
82008
82579
  rayCasterBase(e, bClick) { let ic = this.icn3d; ic.icn3dui;
@@ -83323,6 +83894,14 @@ class iCn3D {
83323
83894
  });
83324
83895
  }
83325
83896
 
83897
+ this.effects = {
83898
+ //'anaglyph': new THREE.AnaglyphEffect(this.renderer),
83899
+ //'parallax barrier': new THREE.ParallaxBarrierEffect(this.renderer),
83900
+ //'oculus rift': new THREE.OculusRiftEffect(this.renderer),
83901
+ 'stereo': new THREE.StereoEffect(this.renderer),
83902
+ 'none': this.renderer
83903
+ };
83904
+
83326
83905
  this.overdraw = 0;
83327
83906
  }
83328
83907
  else {
@@ -83469,14 +84048,6 @@ class iCn3D {
83469
84048
 
83470
84049
  this.bExtrude = true;
83471
84050
 
83472
- this.effects = {
83473
- //'anaglyph': new THREE.AnaglyphEffect(this.renderer),
83474
- //'parallax barrier': new THREE.ParallaxBarrierEffect(this.renderer),
83475
- //'oculus rift': new THREE.OculusRiftEffect(this.renderer),
83476
- //'stereo': new THREE.StereoEffect(this.renderer),
83477
- 'none': this.renderer
83478
- };
83479
-
83480
84051
  this.maxD = 500; // size of the molecule
83481
84052
  this.oriMaxD = this.maxD; // size of the molecule
83482
84053
  //this.cam_z = -150;
@@ -83529,6 +84100,7 @@ class iCn3D {
83529
84100
  //The default display options
83530
84101
  this.optsOri = {};
83531
84102
  this.optsOri['camera'] = 'perspective'; //perspective, orthographic
84103
+ this.optsOri['effect'] = 'none'; //stereo, none
83532
84104
  this.optsOri['background'] = 'black'; //transparent, black, grey, white
83533
84105
  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
83534
84106
  this.optsOri['proteins'] = 'ribbon'; //ribbon, strand, cylinder and plate, schematic, c alpha trace, backbone, b factor tube, lines, stick, ball and stick, sphere, nothing
@@ -83722,6 +84294,7 @@ class iCn3D {
83722
84294
  this.pdbParserCls = new PdbParser(this);
83723
84295
  this.sdfParserCls = new SdfParser(this);
83724
84296
  this.xyzParserCls = new XyzParser(this);
84297
+ this.msaParserCls = new MsaParser(this);
83725
84298
  this.realignParserCls = new RealignParser(this);
83726
84299
  this.densityCifParserCls = new DensityCifParser(this);
83727
84300
  this.ParserUtilsCls = new ParserUtils(this);
@@ -83978,7 +84551,7 @@ class iCn3DUI {
83978
84551
  //even when multiple iCn3D viewers are shown together.
83979
84552
  this.pre = this.cfg.divid + "_";
83980
84553
 
83981
- this.REVISION = '3.41.0';
84554
+ this.REVISION = '3.42.0';
83982
84555
 
83983
84556
  // In nodejs, iCn3D defines "window = {navigator: {}}"
83984
84557
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -84729,4 +85302,4 @@ class printMsg {
84729
85302
  }
84730
85303
  }
84731
85304
 
84732
- 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, 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 };
85305
+ 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 };