icn3d 3.23.1 → 3.23.3

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
@@ -10602,7 +10602,7 @@ class SetDialog {
10602
10602
 
10603
10603
  html += me.htmlCls.divStr + "dl_mutation' class='" + dialogClass + "'>";
10604
10604
  html += "<div style='width:500px'>";
10605
- html += 'Please specify the mutations with a comma separated mutation list. Each mutation can be specified as "[<b>uppercase</b> PDB ID or AlphaFold UniProt ID]_[Chain ID]_[Residue Number]_[One Letter Mutant Residue]". E.g., the mutation of N501Y in the E chain of PDB 6M0J can be specified as "6M0J_E_501_Y". For AlphaFold structures, the "Chain ID" is "A".<br/><br/>';
10605
+ html += 'Please specify the mutations with a comma separated mutation list. Each mutation can be specified as "[<b>uppercase</b> PDB ID or AlphaFold UniProt ID]_[Chain Name]_[Residue Number]_[One Letter Mutant Residue]". E.g., the mutation of N501Y in the E chain of PDB 6M0J can be specified as "6M0J_E_501_Y". For AlphaFold structures, the "Chain ID" is "A".<br/>If you load a custom structure without PDB or UniProt ID, you can open "Seq. & Annotations" window and find the chain ID such as "stru_A". The part before the underscore is the structure ID, which can be used to specify the mutation such as "stru_A_...". Remember to choose "Show Mutation in: Current Page".<br/><br/>';
10606
10606
  html += "<div style='display:inline-block; width:110px'>Mutations: </div>" + me.htmlCls.inputTextStr + "id='" + me.pre + "mutationids' value='6M0J_E_484_K,6M0J_E_501_Y,6M0J_E_417_N' size=50><br/><br/>";
10607
10607
 
10608
10608
  html += '<b>ID Type</b>: ';
@@ -10675,8 +10675,9 @@ class SetDialog {
10675
10675
  html += "</div>";
10676
10676
 
10677
10677
  html += me.htmlCls.divStr + "dl_mmdbafid' class='" + dialogClass + "' style='max-width:600px'>";
10678
- html += "Append a list of PDB, MMDB, or AlphaFold UniProt structures: " + me.htmlCls.inputTextStr + "id='" + me.pre + "mmdbafid' placeholder='e.g., 1HHO,4N7N,P69905,P01942' size=30> <br><br>";
10679
- html += me.htmlCls.buttonStr + "reload_mmdbaf'>Append Biological Unit</button>" + me.htmlCls.buttonStr + "reload_mmdbaf_asym' style='margin-left:30px'>Append Asymmetric Unit (All Chains)</button>" + "<br/><br/>";
10678
+ html += "List of PDB, MMDB, or AlphaFold UniProt structures: " + me.htmlCls.inputTextStr + "id='" + me.pre + "mmdbafid' placeholder='e.g., 1HHO,4N7N,P69905,P01942' size=30> <br><br>";
10679
+ html += "<div style='display:inline-block; width:20px'></div>" + me.htmlCls.buttonStr + "reload_mmdbaf' style='width:150px'>Load Biological Unit</button>" + me.htmlCls.buttonStr + "reload_mmdbaf_asym' style='margin-left:30px; width:250px'>Load Asymmetric Unit (All Chains)</button>" + "<br/><br/>";
10680
+ html += "<div style='display:inline-block; width:20px'>or</div>" + me.htmlCls.buttonStr + "reload_mmdbaf_append' style='width:150px'>Append Biological Unit</button>" + me.htmlCls.buttonStr + "reload_mmdbaf_asym_append' style='margin-left:30px; width:250px'>Append Asymmetric ; Unit (All Chains)</button>" + "<br/><br/>";
10680
10681
 
10681
10682
  html += '<b>Note</b>: The "<b>biological unit</b>" is the <b>biochemically active form of a biomolecule</b>, <div style="width:20px; margin:6px 0 0 20px; display:inline-block;"><span id="'
10682
10683
  + me.pre + 'asu_bu2_expand" class="ui-icon ui-icon-plus icn3d-expand icn3d-link" style="width:15px;" title="Expand"></span><span id="'
@@ -11764,7 +11765,7 @@ class Events {
11764
11765
  $("#" + me.pre + id).resizable();
11765
11766
  }
11766
11767
 
11767
- async launchMmdb(ids, bBiounit, hostUrl) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
11768
+ async launchMmdb(ids, bBiounit, hostUrl, bAppend) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
11768
11769
  if(!me.cfg.notebook) dialog.dialog( "close" );
11769
11770
 
11770
11771
  let flag = bBiounit ? 1 : 0;
@@ -11779,40 +11780,41 @@ class Events {
11779
11780
 
11780
11781
  let idArray = ids.split(',');
11781
11782
 
11782
- /*
11783
- if(idArray.length == 1 && (idArray[0].length == 4 || !isNaN(idArray[0])) ) {
11784
- thisClass.setLogCmd("load mmdb" + flag + " " + ids, false);
11785
- let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
11786
- window.open(hostUrl + '?mmdbid=' + ids + '&bu=' + flag, urlTarget);
11787
- }
11788
- else {
11789
- thisClass.setLogCmd("load mmdbaf" + flag + " " + ids, false);
11790
- let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
11791
- window.open(hostUrl + '?mmdbafid=' + ids + '&bu=' + flag, urlTarget);
11792
- }
11793
- */
11794
-
11795
- // single MMDB ID could show memebranes
11796
- if(!ic.structures && idArray.length == 1 && (idArray[0].length == 4 || !isNaN(idArray[0])) ) {
11797
- thisClass.setLogCmd("load mmdb" + flag + " " + ids, false);
11798
- let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
11799
- window.open(hostUrl + '?mmdbid=' + ids + '&bu=' + flag, urlTarget);
11783
+ if(!bAppend) {
11784
+ if(idArray.length == 1 && (idArray[0].length == 4 || !isNaN(idArray[0])) ) {
11785
+ thisClass.setLogCmd("load mmdb" + flag + " " + ids, false);
11786
+ let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
11787
+ window.open(hostUrl + '?mmdbid=' + ids + '&bu=' + flag, urlTarget);
11788
+ }
11789
+ else {
11790
+ thisClass.setLogCmd("load mmdbaf" + flag + " " + ids, false);
11791
+ let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
11792
+ window.open(hostUrl + '?mmdbafid=' + ids + '&bu=' + flag, urlTarget);
11793
+ }
11800
11794
  }
11801
11795
  else {
11802
- me.cfg.mmdbafid = ids;
11803
- me.cfg.bu = flag;
11804
-
11805
- ic.bMmdbafid = true;
11806
- ic.inputid = (ic.inputid) ? ic.inputid + me.cfg.mmdbafid : me.cfg.mmdbafid;
11807
- if(me.cfg.bu == 1) {
11808
- ic.loadCmd = 'load mmdbaf1 ' + me.cfg.mmdbafid;
11796
+ // single MMDB ID could show memebranes
11797
+ if(!ic.structures && idArray.length == 1 && (idArray[0].length == 4 || !isNaN(idArray[0])) ) {
11798
+ thisClass.setLogCmd("load mmdb" + flag + " " + ids, false);
11799
+ let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
11800
+ window.open(hostUrl + '?mmdbid=' + ids + '&bu=' + flag, urlTarget);
11809
11801
  }
11810
11802
  else {
11811
- ic.loadCmd = 'load mmdbaf0 ' + me.cfg.mmdbafid;
11812
- }
11813
- me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
11803
+ me.cfg.mmdbafid = ids;
11804
+ me.cfg.bu = flag;
11805
+
11806
+ ic.bMmdbafid = true;
11807
+ ic.inputid = (ic.inputid) ? ic.inputid + me.cfg.mmdbafid : me.cfg.mmdbafid;
11808
+ if(me.cfg.bu == 1) {
11809
+ ic.loadCmd = 'load mmdbaf1 ' + me.cfg.mmdbafid;
11810
+ }
11811
+ else {
11812
+ ic.loadCmd = 'load mmdbaf0 ' + me.cfg.mmdbafid;
11813
+ }
11814
+ me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
11814
11815
 
11815
- await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
11816
+ await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
11817
+ }
11816
11818
  }
11817
11819
  }
11818
11820
 
@@ -12554,21 +12556,28 @@ class Events {
12554
12556
 
12555
12557
  me.myEventCls.onIds("#" + me.pre + "reload_mmdbaf", "click", function(e) { me.icn3d;
12556
12558
  e.preventDefault();
12557
-
12558
- // remove space
12559
12559
  let ids = $("#" + me.pre + "mmdbafid").val();
12560
-
12561
12560
  thisClass.launchMmdb(ids, 1, hostUrl);
12562
12561
  });
12563
12562
 
12564
12563
  me.myEventCls.onIds("#" + me.pre + "reload_mmdbaf_asym", "click", function(e) { me.icn3d;
12565
12564
  e.preventDefault();
12566
-
12567
- // remove space
12568
12565
  let ids = $("#" + me.pre + "mmdbafid").val();
12569
12566
  thisClass.launchMmdb(ids, 0, hostUrl);
12570
12567
  });
12571
12568
 
12569
+ me.myEventCls.onIds("#" + me.pre + "reload_mmdbaf_append", "click", function(e) { me.icn3d;
12570
+ e.preventDefault();
12571
+ let ids = $("#" + me.pre + "mmdbafid").val();
12572
+ thisClass.launchMmdb(ids, 1, hostUrl, true);
12573
+ });
12574
+
12575
+ me.myEventCls.onIds("#" + me.pre + "reload_mmdbaf_asym_append", "click", function(e) { me.icn3d;
12576
+ e.preventDefault();
12577
+ let ids = $("#" + me.pre + "mmdbafid").val();
12578
+ thisClass.launchMmdb(ids, 0, hostUrl, true);
12579
+ });
12580
+
12572
12581
  me.myEventCls.onIds("#" + me.pre + "mmdbid", "keyup", function(e) { let ic = me.icn3d;
12573
12582
  if (e.keyCode === 13) {
12574
12583
  e.preventDefault();
@@ -14497,11 +14506,11 @@ class SetHtml {
14497
14506
 
14498
14507
  html += me.htmlCls.divStr + "specguide" + indexStr + "' style='display:none; width:500px' class='icn3d-box'>";
14499
14508
 
14500
- html += "<b>Specification:</b> In the selection \"$1HHO,4N7N.A,B,C:5-10,LV,3AlaVal,chemicals@CA,C\":";
14509
+ html += "<b>Specification:</b> In the selection \"$1HHO,4N7N.A,B,C:5-10,LV,3AlaVal,chemicals@CA,C,C*\":";
14501
14510
  html += "<ul><li>\"$1HHO,4N7N\" uses \"$\" to indicate structure selection.<br/>";
14502
14511
  html += "<li>\".A,B,C\" uses \".\" to indicate chain selection.<br/>";
14503
14512
  html += "<li>\":5-10,LV,3LeuVal,chemicals\" uses the colon \":\" to indicate residue selection. Residue selection could be residue number(5-10), one-letter IUPAC residue name abbreviations(LV), three-letter residue names(AlaVal, \"3\" indicates each residue name has three letters), or predefined names: \"proteins\", \"nucleotides\", \"chemicals\", \"ions\", and \"water\". IUPAC abbreviations can be written either as a contiguous string(e.g., \":LV\"), in order to find all instances of that sequence in the structure, or they can be separated by commas(e.g., \":L,V\") to select all residues of a given type in the structure(in the latter case, select all Leucine and Valine in the structure).<br/>";
14504
- html += "<li>\"@CA,C\" uses \"@\" to indicate atom selection.<br/>";
14513
+ html += "<li>\"@CA,C,C*\" uses \"@\" to indicate atom name selection. \"C*\" selects any atom names starting with \"C\". <br/>";
14505
14514
  html += "<li>Partial definition is allowed, e.g., \":1-10\" selects all residue IDs 1-10 in all chains.<br/>";
14506
14515
  html += "<li>Different selections can be unioned(with \"<b>or</b>\", default), intersected(with \"<b>and</b>\"), or negated(with \"<b>not</b>\"). For example, \":1-10 or :K\" selects all residues 1-10 and all Lys residues. \":1-10 and :K\" selects all Lys residues in the range of residue number 1-10. \":1-10 or not :K\" selects all residues 1-10, which are not Lys residues.<br/>";
14507
14516
  html += "<li>The wild card character \"X\" or \"x\" can be used to represent any character.";
@@ -14510,9 +14519,9 @@ class SetHtml {
14510
14519
  html += "<ul><li>Users can select multiple sets in the menu \"Select > Defined Sets\".<br/>";
14511
14520
  html += "<li>Different sets can be unioned(with \"<b>or</b>\", default), intersected(with \"<b>and</b>\"), or negated(with \"<b>not</b>\"). For example, if the \"Defined Sets\" menu has four sets \":1-10\", \":11-20\", \":5-15\", and \":7-8\", the command \"saved atoms :1-10 or :11-20 and :5-15 not :7-8\" unions all residues 1-10 and 11-20 to get the residues 1-20, then intersects with the residues 5-15 to get the residues 5-15, then exclude the residues 7-8 to get the final residues 5-6 and 9-15.</ul>";
14512
14521
  html += "<b>Full commands in url or command window:</b>";
14513
- html += "<ul><li>Select without saving the set: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C<br/>";
14522
+ html += "<ul><li>Select without saving the set: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C,C*<br/>";
14514
14523
  //html += "<li>Select and save: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C | name my_name | description my_description</ul>";
14515
- html += "<li>Select and save: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C | name my_name</ul>";
14524
+ html += "<li>Select and save: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C,C* | name my_name</ul>";
14516
14525
 
14517
14526
  html += "</div>";
14518
14527
 
@@ -20588,7 +20597,9 @@ class ControllerGestures extends THREE.EventDispatcher{
20588
20597
  this.up = new THREE.Vector3(0,1,0);
20589
20598
 
20590
20599
  this.type = 'unknown';
20591
- this.touchCount = 0;
20600
+ //this.touchCount = 0;
20601
+
20602
+ this.prevTap = 'none';
20592
20603
 
20593
20604
  this.clock = clock;
20594
20605
 
@@ -20605,9 +20616,9 @@ class ControllerGestures extends THREE.EventDispatcher{
20605
20616
  self.type = 'unknown';
20606
20617
  this.userData.selectPressed = true;
20607
20618
 
20608
- self.touchCount++;
20619
+ //self.touchCount++;
20609
20620
 
20610
- console.log( `onSelectStart touchCount: ${ self.touchCount }` );
20621
+ //console.log( `onSelectStart touchCount: ${ self.touchCount }` );
20611
20622
  }
20612
20623
 
20613
20624
  function onSelectEnd( ){
@@ -20617,29 +20628,36 @@ class ControllerGestures extends THREE.EventDispatcher{
20617
20628
  const startToEnd = data.endTime - data.startTime;
20618
20629
 
20619
20630
  //console.log(`ControllerGestures.onSelectEnd: startToEnd:${startToEnd.toFixed(2)} taps:${data.taps}`);
20620
-
20621
- // if (self.type === 'swipe'){
20622
- // const direction = ( self.controller1.position.y < data.startPosition.y) ? "DOWN" : "UP";
20623
- // self.dispatchEvent( { type:'swipe', direction } );
20624
- // self.type = 'unknown';
20625
- // }else
20626
-
20631
+ /*
20632
+ if (self.type === 'swipe'){
20633
+ const direction = ( self.controller1.position.y < data.startPosition.y) ? "DOWN" : "UP";
20634
+ self.dispatchEvent( { type:'swipe', direction } );
20635
+ self.type = 'unknown';
20636
+ }else
20637
+
20627
20638
  if (self.type !== "pinch" && self.type !== "rotate" && self.type !== 'pan'){
20628
- if ( startToEnd < self.doubleClickLimit ){
20639
+ // if ( startToEnd < self.doubleClickLimit ){
20629
20640
  self.type = "tap";
20630
- data.taps++;
20631
- }else if ( startToEnd > self.pressMinimum ){
20632
- self.dispatchEvent( { type: 'press', position: self.controller1.position, matrixWorld: self.controller1.matrixWorld } );
20633
- self.type = 'unknown';
20634
- }
20635
- }else {
20641
+ //data.taps++;
20642
+ // }
20643
+ // else if ( startToEnd > self.pressMinimum ){
20644
+ // self.dispatchEvent( { type: 'press', position: self.controller1.position, matrixWorld: self.controller1.matrixWorld } );
20645
+ // self.type = 'unknown';
20646
+ // }
20647
+ }else{
20636
20648
  self.type = 'unknown';
20637
20649
  }
20638
-
20650
+ */
20651
+
20652
+ if ( startToEnd < self.doubleClickLimit ){
20653
+ data.taps++;
20654
+ }
20655
+ self.type = 'tap';
20656
+
20639
20657
  this.userData.selectPressed = false;
20640
20658
  data.startPosition = undefined;
20641
20659
 
20642
- self.touchCount--;
20660
+ //self.touchCount--;
20643
20661
  }
20644
20662
  }
20645
20663
 
@@ -20650,8 +20668,7 @@ class ControllerGestures extends THREE.EventDispatcher{
20650
20668
  }else {
20651
20669
  result = this.controller1.userData.selectPressed && this.controller2.userData.selectPressed;
20652
20670
  }
20653
- const self = this;
20654
- console.log( `ControllerGestures multiTouch: ${result} touchCount:${self.touchCount}`);
20671
+ //console.log( `ControllerGestures multiTouch: ${result} touchCount:${self.touchCount}`);
20655
20672
  return result;
20656
20673
  }
20657
20674
 
@@ -20686,61 +20703,62 @@ class ControllerGestures extends THREE.EventDispatcher{
20686
20703
  elapsedTime = currentTime - data2.startTime;
20687
20704
  if (elapsedTime > 0.05 ) data2.startPosition = this.controller2.position.clone();
20688
20705
  }
20689
-
20706
+
20690
20707
  if (!this.controller1.userData.selectPressed && this.type === 'tap' ){
20691
20708
  //Only dispatch event after double click limit is passed
20692
20709
  elapsedTime = this.clock.getElapsedTime() - data1.endTime;
20693
20710
  if (elapsedTime > this.doubleClickLimit){
20694
- console.log( `ControllerGestures.update dispatchEvent taps:${data1.taps}` );
20711
+ //console.log( `ControllerGestures.update dispatchEvent taps:${data1.taps}` );
20695
20712
  switch( data1.taps ){
20696
20713
  case 1:
20697
- this.dispatchEvent( { type: 'tap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20698
- data1.prevTap = 'tap';
20714
+ //this.dispatchEvent( { type: 'tap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20715
+ self.prevTap = 'tap';
20699
20716
  break;
20700
20717
  case 2:
20701
20718
  this.dispatchEvent( { type: 'doubletap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20702
- data1.prevTap = 'doubletap';
20703
- break;
20704
- case 3:
20705
- this.dispatchEvent( { type: 'tripletap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20706
- break;
20707
- case 4:
20708
- this.dispatchEvent( { type: 'quadtap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20719
+ self.prevTap = 'doubletap';
20709
20720
  break;
20710
20721
  }
20711
20722
  this.type = "unknown";
20712
20723
  data1.taps = 0;
20713
20724
  }
20714
20725
  }
20715
-
20726
+
20716
20727
  if (this.type === 'unknown' && this.touch){
20717
- if (data1.startPosition !== undefined){
20718
- if (this.multiTouch){
20719
- if (data2.startPosition !== undefined){
20728
+ //if (data1.startPosition !== undefined){
20729
+ //if (this.multiTouch){
20730
+
20731
+ if(self.prevTap == 'doubletap') {
20732
+ //if (data2.startPosition !== undefined){
20720
20733
  //startPosition is undefined for 1/20 sec
20721
20734
  //test for pinch or rotate
20722
- data1.startPosition.distanceTo( data2.startPosition );
20723
- this.controller1.position.distanceTo( this.controller2.position );
20724
- //if ( Math.abs(delta) > 0.01 ){
20725
- if(data1.prevTap == 'tap') {
20735
+
20736
+ // const startDistance = data1.startPosition.distanceTo( data2.startPosition );
20737
+ // const currentDistance = this.controller1.position.distanceTo( this.controller2.position );
20738
+ // const delta = currentDistance - startDistance;
20739
+
20740
+ // if ( Math.abs(delta) > 0.01 ){
20726
20741
  this.type = 'pinch';
20727
20742
  this.startDistance = this.controller1.position.distanceTo( this.controller2.position );
20728
- this.dispatchEvent( { type: 'pinch', delta: 0, scale: 1, initialise: true } );
20729
- }else { // data1.prevTap == 'doubletap'
20730
- const v1 = data2.startPosition.clone().sub( data1.startPosition ).normalize();
20731
- const v2 = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20732
- v1.angleTo( v2 );
20733
- //if (Math.abs(theta) > 0.2){
20734
- this.type = 'rotate';
20735
- this.startVector = v2.clone();
20736
- this.dispatchEvent( { type: 'rotate', theta: 0, initialise: true } );
20737
- //}
20738
- }
20739
- }
20740
- }else {
20743
+ //this.dispatchEvent( { type: 'pinch', delta: 0, scale: 1, initialise: true } );
20744
+ this.dispatchEvent( { type: 'pinch', delta: new THREE.Vector3(0,0,0), scale: 1, initialise: true } );
20745
+ // }else{
20746
+ // const v1 = data2.startPosition.clone().sub( data1.startPosition ).normalize();
20747
+ // const v2 = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20748
+ // const theta = v1.angleTo( v2 );
20749
+ // if (Math.abs(theta) > 0.2){
20750
+ // this.type = 'rotate';
20751
+ // this.startVector = v2.clone();
20752
+ // this.dispatchEvent( { type: 'rotate', theta: 0, initialise: true } );
20753
+ // }
20754
+ // }
20755
+ //}
20756
+ }else { //if(self.prevTap == 'tap') {
20741
20757
  //test for swipe or pan
20742
- data1.startPosition.distanceTo( this.controller1.position );
20743
- elapsedTime = this.clock.getElapsedTime() - data1.startTime;
20758
+ // let dist = data1.startPosition.distanceTo( this.controller1.position );
20759
+ // elapsedTime = this.clock.getElapsedTime() - data1.startTime;
20760
+ // const velocity = dist/elapsedTime;
20761
+
20744
20762
  //console.log(`dist:${dist.toFixed(3)} velocity:${velocity.toFixed(3)}`);
20745
20763
  // if ( dist > 0.01 && velocity > 0.1 ){
20746
20764
  // const v = this.controller1.position.clone().sub( data1.startPosition );
@@ -20749,24 +20767,40 @@ class ControllerGestures extends THREE.EventDispatcher{
20749
20767
  // }else if (dist > 0.006 && velocity < 0.03){
20750
20768
  this.type = "pan";
20751
20769
  this.startPosition = this.controller1.position.clone();
20752
- this.dispatchEvent( { type: 'pan', delta: new THREE.Vector3(), initialise: true } );
20770
+ this.dispatchEvent( { type: 'pan', delta: new THREE.Vector3(0,0,0), initialise: true } );
20753
20771
  // }
20754
20772
  }
20773
+ //}
20774
+ }else if (this.type === 'pinch' || this.type === 'pan'){
20775
+ //if (this.type === 'pinch'){
20776
+ //if (this.multiTouch){
20777
+
20778
+ if(self.prevTap == 'doubletap') {
20779
+ if (this.controller2.position) {
20780
+ const currentDistance = this.controller1.position.distanceTo( this.controller2.position );
20781
+ // const delta = currentDistance - this.startDistance;
20782
+ const scale = currentDistance/this.startDistance;
20783
+
20784
+ const delta = this.controller1.position.clone().sub( this.startPosition );
20785
+ this.dispatchEvent( { type: 'pinch', delta, scale });
20786
+ }
20787
+
20788
+ // }else if (this.type === 'rotate'){
20789
+ // const v = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20790
+ // let theta = this.startVector.angleTo( v );
20791
+ // const cross = this.startVector.clone().cross( v );
20792
+ // if (this.up.dot(cross) > 0) theta = -theta;
20793
+ // this.dispatchEvent( { type: 'rotate', theta } );
20794
+ /*
20795
+ //}else if (this.type === 'pan'){
20796
+ } else { //if(self.prevTap == 'tap') {
20797
+ // const delta = this.controller1.position.clone().sub( this.startPosition );
20798
+ // this.dispatchEvent( { type: 'pan', delta } );
20799
+
20800
+ const position = this.controller1.position.clone();
20801
+ this.dispatchEvent( { type: 'pan', position } );
20802
+ */
20755
20803
  }
20756
- }else if (this.type === 'pinch'){
20757
- const currentDistance = this.controller1.position.distanceTo( this.controller2.position );
20758
- const delta = currentDistance - this.startDistance;
20759
- const scale = currentDistance/this.startDistance;
20760
- this.dispatchEvent( { type: 'pinch', delta, scale });
20761
- }else if (this.type === 'rotate'){
20762
- const v = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20763
- let theta = this.startVector.angleTo( v );
20764
- const cross = this.startVector.clone().cross( v );
20765
- if (this.up.dot(cross) > 0) theta = -theta;
20766
- this.dispatchEvent( { type: 'rotate', theta } );
20767
- }else if (this.type === 'pan'){
20768
- const delta = this.controller1.position.clone().sub( this.startPosition );
20769
- this.dispatchEvent( { type: 'pan', delta } );
20770
20804
  }
20771
20805
  }
20772
20806
  }
@@ -22000,45 +22034,51 @@ class Scene {
22000
22034
  ic.scene.add(ic.gestures.controller1);
22001
22035
  ic.scene.add(ic.gestures.controller2);
22002
22036
 
22003
- // firts "tap", then "pinch" event
22004
- ic.gestures.addEventListener('tap', (ev) => {
22005
- // const controller = ic.gestures.controller1;
22006
- // ic.mdl.position.set( -0.03, 0, - 0.3 ).applyMatrix4( controller.matrixWorld );
22007
- // ic.mdl.scale.copy(new THREE.Vector3( 0.001, 0.001, 0.001 ));
22008
-
22009
- const controller = ic.gestures.controller1;
22010
- ic.mdl.position.set( -0.06, 0, - 0.6 ).applyMatrix4( controller.matrixWorld );
22011
- ic.mdl.scale.copy(new THREE.Vector3( 0.005, 0.005, 0.005 ));
22012
- });
22037
+ // ic.gestures.addEventListener('tap', (ev) => {
22038
+ // // const controller = ic.gestures.controller1;
22039
+ // // ic.mdl.position.set( -0.03, 0, - 0.3 ).applyMatrix4( controller.matrixWorld );
22040
+ // // ic.mdl.scale.copy(new THREE.Vector3( 0.001, 0.001, 0.001 ));
22041
+ // });
22013
22042
 
22014
- // first "doubletap", then "rotate" event
22015
22043
  ic.gestures.addEventListener('doubletap', (ev) => {
22016
- const controller = ic.gestures.controller1;
22017
- ic.mdl.position.set( -0.06, 0, - 0.6 ).applyMatrix4( controller.matrixWorld );
22018
- ic.mdl.scale.copy(new THREE.Vector3( 0.005, 0.005, 0.005 ));
22044
+ thisClass.positionCenter();
22019
22045
  });
22020
-
22046
+ /*
22021
22047
  ic.gestures.addEventListener('pan', (ev) => { // touch across screen, move
22022
22048
  if(ev.initialise !== undefined) {
22023
22049
  thisClass.startPosition = ic.mdl.position.clone();
22050
+ thisClass.startQuaternion = ic.mdl.quaternion.clone();
22024
22051
  }
22025
22052
  else {
22026
- const adjustMove = 2; // adjust to follow the finger
22027
- const pos = thisClass.startPosition.clone().add(adjustMove * ev.delta.multiplyScalar(3));
22028
- ic.mdl.position.copy(pos);
22053
+ const endPosition = ev.position;
22054
+ let angle = Math.acos( thisClass.startPosition.dot( endPosition ) / thisClass.startPosition.length() / endPosition.length() );
22055
+
22056
+ let axis = new THREE.Vector3();
22057
+ axis.crossVectors( thisClass.startPosition, endPosition ).normalize();
22058
+
22059
+ let rotateSpeed = 6.0;
22060
+ angle *= rotateSpeed;
22061
+
22062
+ let quaternion = new THREE.Quaternion();
22063
+ quaternion.setFromAxisAngle( axis, -angle );
22064
+
22065
+ ic.mdl.quaternion.copy(thisClass.startQuaternion);
22066
+ ic.mdl.quaternion.multiplyQuaternions(quaternion, ic.mdl.quaternion);
22029
22067
  }
22030
22068
  });
22031
-
22069
+ */
22032
22070
  ic.gestures.addEventListener('pinch', (ev) => { // two fingers opening or closing
22033
22071
  if(ev.initialise !== undefined) {
22072
+ thisClass.startPosition = ic.mdl.position.clone();
22034
22073
  thisClass.startScale = ic.mdl.scale.clone();
22035
22074
  }
22036
22075
  else {
22037
- const scale = thisClass.startScale.clone().multiplyScalar(ev.scale);
22076
+ let zoomSpeed = 1.0;
22077
+ const scale = thisClass.startScale.clone().multiplyScalar(ev.scale * zoomSpeed);
22038
22078
  ic.mdl.scale.copy(scale);
22039
22079
  }
22040
22080
  });
22041
-
22081
+ /*
22042
22082
  ic.gestures.addEventListener('rotate', (ev) => { // two fingers rotating around
22043
22083
  if(ev.initialise !== undefined) {
22044
22084
  thisClass.startQuaternion = ic.mdl.quaternion.clone();
@@ -22047,10 +22087,17 @@ class Scene {
22047
22087
  ic.mdl.quaternion.copy(thisClass.startQuaternion);
22048
22088
  ic.mdl.rotateY(ev.theta);
22049
22089
  }
22050
- });
22090
+ });
22091
+ */
22051
22092
  }
22052
22093
  }
22053
22094
 
22095
+ positionCenter() { let ic = this.icn3d; ic.icn3dui;
22096
+ const controller = ic.gestures.controller1;
22097
+ ic.mdl.position.set( -0.06, 0, - 0.6 ).applyMatrix4( controller.matrixWorld );
22098
+ ic.mdl.scale.copy(new THREE.Vector3( 0.005, 0.005, 0.005 ));
22099
+ }
22100
+
22054
22101
  setVrArButtons() { let ic = this.icn3d, me = ic.icn3dui;
22055
22102
  // call just once
22056
22103
  ic.bSetVrArButtons = true;
@@ -32119,13 +32166,13 @@ class Alternate {
32119
32166
 
32120
32167
  if ( ic.renderer.xr.isPresenting){
32121
32168
  if(ic.canvasUI) ic.canvasUI.update();
32122
- if(ic.canvasUILog) ic.canvasUILog.update();
32169
+ //if(ic.canvasUILog) ic.canvasUILog.update();
32123
32170
  }
32124
32171
  }
32125
32172
  else if(ic.bAr) {
32126
32173
  if ( ic.renderer.xr.isPresenting ){
32127
32174
  ic.gestures.update();
32128
- if(ic.canvasUILog) ic.canvasUILog.update();
32175
+ //if(ic.canvasUILog) ic.canvasUILog.update();
32129
32176
  }
32130
32177
  }
32131
32178
 
@@ -40601,11 +40648,12 @@ class ShowAnno {
40601
40648
  }
40602
40649
  else if(me.cfg.blast_rep_id == chnid && ic.seqStructAlignData === undefined && ic.seqStructAlignDataSmithwm === undefined) {
40603
40650
  let title;
40604
- if(me.cfg.query_id.length > 14) {
40605
- title = 'Query: ' + me.cfg.query_id.substr(0, 6) + '...';
40651
+ let query_id = (me.cfg.oriQuery_id) ? me.cfg.oriQuery_id : me.cfg.query_id;
40652
+ if(query_id.length > 14) {
40653
+ title = 'Query: ' + query_id.substr(0, 6) + '...';
40606
40654
  }
40607
40655
  else {
40608
- title =(isNaN(me.cfg.query_id)) ? 'Query: ' + me.cfg.query_id : 'Query: gi ' + me.cfg.query_id;
40656
+ title =(isNaN(me.cfg.query_id)) ? 'Query: ' + query_id : 'Query: gi ' + query_id;
40609
40657
  }
40610
40658
  let compTitle = undefined;
40611
40659
  let compText = undefined;
@@ -40618,11 +40666,12 @@ class ShowAnno {
40618
40666
  }
40619
40667
  else if(me.cfg.blast_rep_id == chnid && (ic.seqStructAlignData !== undefined || ic.seqStructAlignDataSmithwm !== undefined) ) { // align sequence to structure
40620
40668
  let title;
40621
- if(me.cfg.query_id.length > 14) {
40622
- title = 'Query: ' + me.cfg.query_id.substr(0, 6) + '...';
40669
+ let query_id = (me.cfg.oriQuery_id) ? me.cfg.oriQuery_id : me.cfg.query_id;
40670
+ if(query_id.length > 14) {
40671
+ title = 'Query: ' + query_id.substr(0, 6) + '...';
40623
40672
  }
40624
40673
  else {
40625
- title =(isNaN(me.cfg.query_id)) ? 'Query: ' + me.cfg.query_id : 'Query: gi ' + me.cfg.query_id;
40674
+ title =(isNaN(me.cfg.query_id)) ? 'Query: ' + query_id : 'Query: gi ' + query_id;
40626
40675
  }
40627
40676
 
40628
40677
  let evalue, targetSeq, querySeq, segArray;
@@ -41110,7 +41159,7 @@ class ShowSeq {
41110
41159
  }
41111
41160
  if(me.cfg.blast_rep_id == chnid) {
41112
41161
  // change color in 3D
41113
- ic.opts['color'] = 'conservation';
41162
+ ic.opts['color'] = (ic.blastAcxn) ? 'confidence' : 'conservation';
41114
41163
  ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
41115
41164
  // remove highlight
41116
41165
  //ic.hlUpdateCls.removeHlSeq();
@@ -41400,14 +41449,14 @@ class ShowSeq {
41400
41449
 
41401
41450
  // set hash for the loops
41402
41451
  let strand2len_start_stop = {};
41403
- let prevRefnumStr, prevPostfix;
41452
+ let prevRefnumStr, prevPostfix, prevRefnum;
41404
41453
 
41405
41454
  // sometimes one chain may have several Ig domains,set a index for each IgDomain
41406
- let index = 1;
41455
+ let index = 1, prevStrandPostfix = '', bStart = false;
41407
41456
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41408
41457
  let currResi = ic.ParserUtilsCls.getResi(chnid, i);
41409
41458
  let residueid = chnid + '_' + currResi;
41410
- if(ic.residues.hasOwnProperty(residueid)) {
41459
+ //if(ic.residues.hasOwnProperty(residueid)) {
41411
41460
  refnumLabel = ic.resid2refnum[residueid];
41412
41461
  if(refnumLabel) {
41413
41462
  refnumStr_ori = refnumLabel.replace(/'/g, '').replace(/\*/g, '').replace(/\^/g, '').substr(1); // C', C''
@@ -41425,27 +41474,37 @@ class ShowSeq {
41425
41474
  strand2len_start_stop[prevStrand + prevPostfix].len = currCnt - 1;
41426
41475
  strand2len_start_stop[prevStrand + prevPostfix].end = refnumStr;
41427
41476
  strand2len_start_stop[prevStrand + prevPostfix].nextStrand = currStrand;
41428
-
41429
- console.log("end: " + residueid);
41430
41477
  }
41431
41478
 
41479
+ bStart = false;
41480
+
41432
41481
  currCnt = 1;
41433
41482
  }
41434
41483
 
41484
+ // sometimes insertions may happen inside a strand. Reset currCnt
41485
+ if(currStrand == prevStrand && refnum > 1000 && refnumStr.substr(1,1) != '9') { // strand region
41486
+ currCnt = 1;
41487
+
41488
+ if(bStart && prevStrandPostfix) {
41489
+ delete strand2len_start_stop[prevStrandPostfix];
41490
+ prevStrandPostfix = '';
41491
+ }
41492
+ }
41493
+
41435
41494
  // #9##
41436
- if(prevStrand && refnum > 1000 && refnumStr.substr(1,1) == '9') { // loop region
41495
+ if(prevStrand && currStrand != ' ' && refnum > 1000 && refnumStr.substr(1,1) == '9') { // loop region
41437
41496
  if(currCnt == 1) { // start of a loop
41438
41497
  if(strand2len_start_stop.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41439
41498
  ++index;
41440
41499
  }
41441
-
41442
- console.log("start: " + residueid + " refnumStr: " + refnumStr);
41443
41500
 
41444
41501
  postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41445
41502
  strand2len_start_stop[currStrand + postfix] = {};
41446
41503
 
41447
41504
  strand2len_start_stop[currStrand + postfix].start = prevRefnumStr;
41448
41505
  strand2len_start_stop[currStrand + postfix].chainid = chnid;
41506
+
41507
+ //prevStrandPostfix = currStrand + postfix;
41449
41508
  }
41450
41509
  refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
41451
41510
  refnumLabel = currStrand + refnumStr;
@@ -41455,7 +41514,7 @@ class ShowSeq {
41455
41514
  }
41456
41515
  }
41457
41516
  else {
41458
- if(prevStrand && !bCustom && !kabat_or_imgt) {
41517
+ if(prevStrand && currStrand != ' ' && !bCustom && !kabat_or_imgt) {
41459
41518
  if(currCnt == 1) { // start of a loop
41460
41519
  if(strand2len_start_stop.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41461
41520
  ++index;
@@ -41468,8 +41527,11 @@ class ShowSeq {
41468
41527
 
41469
41528
  strand2len_start_stop[currStrand + postfix].start = prevRefnumStr;
41470
41529
  strand2len_start_stop[currStrand + postfix].chainid = chnid;
41471
- }
41472
41530
 
41531
+ prevStrandPostfix = currStrand + postfix;
41532
+ bStart = true;
41533
+ }
41534
+
41473
41535
  // no ref num
41474
41536
  refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
41475
41537
  refnumLabel = currStrand + refnumStr;
@@ -41478,8 +41540,9 @@ class ShowSeq {
41478
41540
  }
41479
41541
 
41480
41542
  prevRefnumStr = refnumStr;
41543
+ prevRefnum = refnum;
41481
41544
  prevPostfix = postfix;
41482
- }
41545
+ //}
41483
41546
 
41484
41547
  prevStrand = currStrand;
41485
41548
  }
@@ -41488,11 +41551,13 @@ class ShowSeq {
41488
41551
  strand2len_start_stop[prevStrand + prevPostfix].end = prevRefnumStr;
41489
41552
  //strand2len_start_stop[prevStrand].nextStrand = undefined;
41490
41553
  }
41491
-
41554
+
41492
41555
  let refnumLabelNoPostfix;
41493
41556
  // sometimes one chain may have several Ig domains,set a index for each IgDomain
41494
41557
  index = 1;
41495
- let appearedStrands = {}, currStrand_ori;
41558
+ prevStrandPostfix = '';
41559
+ bStart = false;
41560
+ let appearedStrands = {}, currStrand_ori, bShowRefnum = true;
41496
41561
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41497
41562
  bLoop = false;
41498
41563
 
@@ -41501,12 +41566,12 @@ class ShowSeq {
41501
41566
  let currResi = ic.ParserUtilsCls.getResi(chnid, i);
41502
41567
  let residueid = chnid + '_' + currResi;
41503
41568
  let domainid = (bCustom) ? 0 : ic.resid2domainid[residueid];
41504
- if(!ic.residues.hasOwnProperty(residueid)) {
41505
- html += '<span></span>';
41506
- }
41507
- else {
41569
+ //if(!ic.residues.hasOwnProperty(residueid)) {
41570
+ // html += '<span></span>';
41571
+ //}
41572
+ //else {
41508
41573
  refnumLabel = ic.resid2refnum[residueid];
41509
- let bNotShow = false;
41574
+ let bHidelabel = false;
41510
41575
 
41511
41576
  if(refnumLabel) {
41512
41577
  refnumStr_ori = refnumLabel.replace(/'/g, '').replace(/\*/g, '').replace(/\^/g, '').substr(1); // C', C''
@@ -41517,7 +41582,8 @@ class ShowSeq {
41517
41582
 
41518
41583
  refnumLabelNoPostfix = currStrand + parseInt(refnumStr_ori);
41519
41584
 
41520
- if(currStrand != prevStrand) { // reset currCnt
41585
+ if(currStrand_ori != prevStrand) { // reset currCnt
41586
+ bStart = false;
41521
41587
  currCnt = 1;
41522
41588
  }
41523
41589
 
@@ -41535,30 +41601,44 @@ class ShowSeq {
41535
41601
  refnum = parseInt(refnumStr);
41536
41602
  postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41537
41603
 
41604
+ // sometimes insertions may happen inside a strand. Reset currCnt
41605
+ if(currStrand_ori == prevStrand && refnum > 1000 && refnumStr.substr(1,1) != '9') { // strand region
41606
+ currCnt = 1;
41607
+
41608
+ if(bStart && prevStrandPostfix) {
41609
+ --index;
41610
+ prevStrandPostfix = '';
41611
+ }
41612
+ }
41613
+
41538
41614
  // #9##
41539
41615
  if(prevStrand && refnum > 1000 && refnumStr.substr(1,1) == '9') { // loop region
41540
41616
  bLoop = true;
41541
41617
 
41542
41618
  if(currCnt == 1) { // start of a loop
41543
- if(appearedStrands.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41619
+ if(appearedStrands.hasOwnProperty(currStrand_ori + postfix)) { // the strand appeared in 2nd Id domain
41544
41620
  ++index;
41545
41621
  postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41546
41622
  }
41547
41623
 
41548
- appearedStrands[currStrand + postfix] = 1;
41624
+ appearedStrands[currStrand_ori + postfix] = 1;
41549
41625
  }
41550
41626
 
41551
- let result = this.getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix);
41552
-
41627
+ let result = this.getAdjustedRefnum(strand2len_start_stop, currStrand_ori, currCnt, currFirstDigit, postfix, prevRefnum);
41628
+
41629
+ refnum = result.refnum;
41630
+ bShowRefnum = result.bShowRefnum;
41553
41631
  refnumStr = result.refnumStr;
41554
41632
  refnumLabel = result.refnumLabel;
41555
41633
  refnumLabelNoPostfix = result.refnumLabelNoPostfix;
41556
41634
 
41557
- bNotShow = result.bNotShow;
41635
+ bHidelabel = result.bHidelabel;
41558
41636
  currStrand = refnumLabel.replace(new RegExp(refnumStr,'g'), '');
41559
41637
 
41560
41638
  ++currCnt;
41561
41639
  }
41640
+
41641
+ prevRefnum = refnum;
41562
41642
  }
41563
41643
 
41564
41644
  if(bCustom) {
@@ -41596,40 +41676,59 @@ class ShowSeq {
41596
41676
  }
41597
41677
  }
41598
41678
  else {
41599
- html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow);
41679
+ if(bShowRefnum && currStrand != ' ') {
41680
+ html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bHidelabel);
41681
+ }
41682
+ else {
41683
+ html += '<span></span>';
41684
+ }
41600
41685
  }
41601
41686
  }
41602
41687
  else {
41603
41688
  let atom = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[residueid]);
41604
41689
 
41605
41690
  // skip non-protein residues
41606
- if(ic.proteins.hasOwnProperty(atom.serial) && prevStrand && !bCustom && !kabat_or_imgt) {
41691
+ // after G strand and before A strand, just use the mapped reference number
41692
+ if((!atom || ic.proteins.hasOwnProperty(atom.serial)) && prevStrand && !bCustom && !kabat_or_imgt
41693
+ && currStrand_ori.substr(0,1) != 'G') {
41607
41694
  // no ref num
41608
41695
  bLoop = true;
41609
41696
 
41610
41697
  if(currCnt == 1) { // start of a loop
41611
- if(appearedStrands.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41698
+ if(appearedStrands.hasOwnProperty(currStrand_ori + postfix)) { // the strand appeared in 2nd Id domain
41612
41699
  ++index;
41613
41700
  }
41614
41701
 
41615
41702
  postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41616
41703
 
41617
- appearedStrands[currStrand + postfix] = 1;
41704
+ appearedStrands[currStrand_ori + postfix] = 1;
41705
+
41706
+ bStart = true;
41707
+ prevStrandPostfix = currStrand_ori + postfix;
41618
41708
  }
41619
41709
 
41620
41710
  // use previous postfix
41621
- let result = this.getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix);
41622
-
41711
+ let result = this.getAdjustedRefnum(strand2len_start_stop, currStrand_ori, currCnt, currFirstDigit, postfix, prevRefnum);
41712
+
41713
+ refnum = result.refnum;
41714
+ bShowRefnum = result.bShowRefnum;
41623
41715
  refnumStr = result.refnumStr;
41624
41716
  refnumLabel = result.refnumLabel;
41625
41717
  refnumLabelNoPostfix = result.refnumLabelNoPostfix;
41626
41718
 
41627
- bNotShow = result.bNotShow;
41719
+ prevRefnum = refnum;
41720
+
41721
+ bHidelabel = result.bHidelabel;
41628
41722
  currStrand = refnumLabel.replace(new RegExp(refnumStr,'g'), '');
41629
41723
 
41630
41724
  ++currCnt;
41631
41725
 
41632
- html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow);
41726
+ if(bShowRefnum && currStrand != ' ') {
41727
+ html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bHidelabel);
41728
+ }
41729
+ else {
41730
+ html += '<span></span>';
41731
+ }
41633
41732
  }
41634
41733
  else {
41635
41734
  html += '<span></span>';
@@ -41653,7 +41752,7 @@ class ShowSeq {
41653
41752
  // remove the postfix when comparing interactions
41654
41753
  //ic.chainsMapping[chnid][residueid] = refnumLabel;
41655
41754
  ic.chainsMapping[chnid][residueid] = refnumLabelNoPostfix;
41656
- }
41755
+ //}
41657
41756
 
41658
41757
  prevStrand = currStrand_ori; //currStrand;
41659
41758
  }
@@ -41668,10 +41767,11 @@ class ShowSeq {
41668
41767
  return {html: html, html3: html3}
41669
41768
  }
41670
41769
 
41671
- getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix) { let ic = this.icn3d; ic.icn3dui;
41672
- let refnumStr, refnumLabel, refnumLabelNoPostfix;
41770
+ getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix, prevRefnum) { let ic = this.icn3d; ic.icn3dui;
41771
+ let refnum, refnumStr, refnumLabel, refnumLabelNoPostfix;
41673
41772
 
41674
- let bNotShow = false; // do not show the label
41773
+ let bHidelabel = false; // do not show the label
41774
+ let bShowRefnum = true;
41675
41775
 
41676
41776
  if(strand2len_start_stop[currStrand + postfix]) {
41677
41777
  let start = parseInt(strand2len_start_stop[currStrand + postfix].start);
@@ -41683,7 +41783,6 @@ class ShowSeq {
41683
41783
  let len = strand2len_start_stop[currStrand + postfix].len;
41684
41784
  let halfLen = (strand2len_start_stop[currStrand + postfix].nextStrand) ? parseInt(len / 2.0 + 0.5) : len;
41685
41785
 
41686
- let refnum;
41687
41786
  if(currCnt <= halfLen) {
41688
41787
  refnum = start + currCnt;
41689
41788
  refnumStr = refnum + postfixStart;
@@ -41698,25 +41797,36 @@ class ShowSeq {
41698
41797
 
41699
41798
  refnumLabelNoPostfix = currStrand + refnum;
41700
41799
 
41701
- if(currCnt == 0 || currCnt == halfLen || currCnt == halfLen + 1 || currCnt == end - 1) {
41702
- bNotShow = true;
41800
+ //if(currCnt == 0 || currCnt == halfLen || currCnt == halfLen + 1 || currCnt == end - 1) {
41801
+ if(currCnt == 1 || currCnt == halfLen || currCnt == halfLen + 1 || currCnt == end - 1) {
41802
+ bHidelabel = true;
41803
+ }
41804
+
41805
+ if(currCnt == 1 && start != prevRefnum) { // skip insertions
41806
+ bShowRefnum = false;
41807
+
41808
+ refnum = 0;
41809
+ refnumStr = '';
41810
+ refnumLabel = '';
41811
+ refnumLabelNoPostfix = '';
41703
41812
  }
41704
41813
  }
41705
41814
  else {
41706
41815
  // refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
41707
41816
  // refnumLabel = currStrand + refnumStr;
41708
41817
 
41818
+ refnum = 0;
41709
41819
  refnumStr = '';
41710
41820
  refnumLabel = '';
41711
41821
  refnumLabelNoPostfix = '';
41712
41822
 
41713
- bNotShow = true;
41823
+ bHidelabel = true;
41714
41824
  }
41715
41825
 
41716
- return {refnumStr: refnumStr, refnumLabel: refnumLabel, refnumLabelNoPostfix: refnumLabelNoPostfix, bNotShow: bNotShow};
41826
+ return {refnum: refnum, refnumStr: refnumStr, refnumLabel: refnumLabel, refnumLabelNoPostfix: refnumLabelNoPostfix, bHidelabel: bHidelabel, bShowRefnum: bShowRefnum};
41717
41827
  }
41718
41828
 
41719
- getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow) { let ic = this.icn3d, me = ic.icn3dui;
41829
+ getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bHidelabel) { let ic = this.icn3d, me = ic.icn3dui;
41720
41830
  let refnum = parseInt(refnumStr).toString();
41721
41831
  let color = this.getRefnumColor(currStrand);
41722
41832
  let colorStr = 'style="color:' + color + '"';
@@ -41732,7 +41842,7 @@ class ShowSeq {
41732
41842
 
41733
41843
  html += '<span ' + colorStr + ' title="' + refnumLabel + '"><b>' + refnumLabel.substr(0, 1) + '</b>' + refnumLabel.substr(1) + '</span>';
41734
41844
  }
41735
- else if(lastTwo % 2 == 0 && lastTwo != 52 && !bNotShow) { // don't show label for the first, middle, and last loop residues
41845
+ else if(lastTwo % 2 == 0 && lastTwo != 52 && !bHidelabel) { // don't show label for the first, middle, and last loop residues
41736
41846
  // e.g., 2152a
41737
41847
  let lastTwoStr = isNaN(refnumStr) ? lastTwo + refnumStr.substr(refnumStr.length - 1, 1) : lastTwo;
41738
41848
  html += '<span ' + colorStr + ' title="' + refnumLabel + '">' + lastTwoStr + '</span>';
@@ -43147,6 +43257,8 @@ class LineGraph {
43147
43257
  drawGraphPerType(bCommonDiff, structureArray, bScatterplot, nodeArray1, nodeArray2, linkArray, name2node, heightFinal, height, textHeight, len1Split, r, gap, marginY) { let ic = this.icn3d; ic.icn3dui;
43148
43258
  let html = "";
43149
43259
 
43260
+ let bMutation = structureArray.length == 2 && structureArray[1].replace(structureArray[0], '') == '2';
43261
+
43150
43262
  // draw common interaction
43151
43263
  let label, postfix;
43152
43264
  if(bCommonDiff == 0) {
@@ -43163,11 +43275,21 @@ class LineGraph {
43163
43275
  }
43164
43276
 
43165
43277
  for(let i = 0, il = structureArray.length; i < il; ++i) {
43278
+ let labelFinal = label;
43279
+ if(bMutation) {
43280
+ if(i == 0) {
43281
+ labelFinal += "Wild Type ";
43282
+ }
43283
+ else if(i == 1) {
43284
+ labelFinal += "Mutant ";
43285
+ }
43286
+ }
43287
+
43166
43288
  if(bScatterplot) {
43167
- html += this.drawScatterplot_base(nodeArray1[i], nodeArray2[i], linkArray[i], name2node, heightFinal, undefined, label + structureArray[i], textHeight);
43289
+ html += this.drawScatterplot_base(nodeArray1[i], nodeArray2[i], linkArray[i], name2node, heightFinal, undefined, labelFinal + structureArray[i], textHeight);
43168
43290
  height =(len1Split[i] + 1) *(r + gap) + 2 * marginY + textHeight;
43169
43291
  } else {
43170
- html += this.drawLineGraph_base(nodeArray1[i], nodeArray2[i], linkArray[i], name2node, heightFinal, label + structureArray[i], textHeight);
43292
+ html += this.drawLineGraph_base(nodeArray1[i], nodeArray2[i], linkArray[i], name2node, heightFinal, labelFinal + structureArray[i], textHeight);
43171
43293
  }
43172
43294
  heightFinal += height;
43173
43295
 
@@ -54015,6 +54137,16 @@ class LoadPDB {
54015
54137
  this.icn3d = icn3d;
54016
54138
  }
54017
54139
 
54140
+ getStructureId(id, moleculeNum, bMutation) { let ic = this.icn3d; ic.icn3dui;
54141
+ let structure = id;
54142
+
54143
+ if(id == ic.defaultPdbId || bMutation) { // bMutation: side chain prediction
54144
+ structure = (moleculeNum === 1) ? id : id + moleculeNum.toString();
54145
+ }
54146
+
54147
+ return structure;
54148
+ }
54149
+
54018
54150
  // modified from iview (http://istar.cse.cuhk.edu.hk/iview/)
54019
54151
  //This PDB parser feeds the viewer with the content of a PDB file, pdbData.
54020
54152
  loadPDB(src, pdbid, bOpm, bVector, bMutation, bAppend, type, bLastQuery) { let ic = this.icn3d, me = ic.icn3dui;
@@ -54097,12 +54229,7 @@ class LoadPDB {
54097
54229
  }
54098
54230
  }
54099
54231
 
54100
- structure = id;
54101
-
54102
- if(id == ic.defaultPdbId || bMutation) { // bMutation: side chain prediction
54103
- //if(id == ic.defaultPdbId) {
54104
- structure = (moleculeNum === 1) ? id : id + moleculeNum.toString();
54105
- }
54232
+ structure = this.getStructureId(id, moleculeNum, bMutation);
54106
54233
 
54107
54234
  ic.molTitle = '';
54108
54235
 
@@ -54217,12 +54344,7 @@ class LoadPDB {
54217
54344
  ++moleculeNum;
54218
54345
  id = ic.defaultPdbId;
54219
54346
 
54220
- structure = id;
54221
-
54222
- if(id == ic.defaultPdbId || bMutation) { // bMutation: side chain prediction
54223
- //if(id == ic.defaultPdbId) {
54224
- structure = (moleculeNum === 1) ? id : id + moleculeNum.toString();
54225
- }
54347
+ structure = this.getStructureId(id, moleculeNum, bMutation);
54226
54348
 
54227
54349
  //helices = [];
54228
54350
  //sheets = [];
@@ -54241,12 +54363,7 @@ class LoadPDB {
54241
54363
  ic.pmid = line.substr(19).trim();
54242
54364
  }
54243
54365
  } else if (record === 'ATOM ' || record === 'HETATM') {
54244
- structure = id;
54245
-
54246
- if(id == ic.defaultPdbId || bMutation) { // bMutation: side chain prediction
54247
- //if(id == ic.defaultPdbId) {
54248
- structure = (moleculeNum === 1) ? id : id + moleculeNum.toString();
54249
- }
54366
+ structure = this.getStructureId(id, moleculeNum, bMutation);
54250
54367
 
54251
54368
  let alt = line.substr(16, 1);
54252
54369
  //if (alt !== " " && alt !== "A") continue;
@@ -58995,7 +59112,7 @@ class SelectByCommand {
58995
59112
  // $1,2,3: Structure
58996
59113
  // .A,B,C: chain
58997
59114
  // :5-10,K,chemicals: residues, could be 'proteins', 'nucleotides', 'chemicals', 'ions', and 'water'
58998
- // @CA,C: atoms
59115
+ // @CA,C,C*: atoms
58999
59116
  // wild card * can be used to select all
59000
59117
  //var currHighlightAtoms = {}
59001
59118
 
@@ -59045,7 +59162,7 @@ class SelectByCommand {
59045
59162
  testStr = testStr.substr(0, dollarPos);
59046
59163
  }
59047
59164
 
59048
- if(atomStrArray.length == 1 && atomStrArray[0] !== '*') {
59165
+ if(atomStrArray.length > 1 || (atomStrArray.length == 1 && atomStrArray[0] !== '*')) {
59049
59166
  bSelectResidues = false; // selected atoms
59050
59167
  }
59051
59168
 
@@ -59140,7 +59257,7 @@ class SelectByCommand {
59140
59257
  let residArray = [];
59141
59258
 
59142
59259
  if(bRefnum) {
59143
- let residArrayTmp = ic.refnum2residArray[k];
59260
+ let residArrayTmp = (ic.refnum2residArray[k]) ? ic.refnum2residArray[k] : [];
59144
59261
  for(let m = 0, ml = residArrayTmp.length; m < ml; ++m) {
59145
59262
  let residueId = residArrayTmp[m];
59146
59263
  if(residueId.substr(0, residueId.lastIndexOf('_')) == molecule_chain) {
@@ -59168,17 +59285,16 @@ class SelectByCommand {
59168
59285
  for(let m in ic.residues[residueId]) {
59169
59286
  for(let n = 0, nl = atomStrArray.length; n < nl; ++n) {
59170
59287
  let atomStr = atomStrArray[n];
59171
- if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59172
- if(i === 0) {
59173
- //currHighlightAtoms[m] = 1;
59174
- atomHash[m] = 1;
59175
- }
59176
- else {
59177
- //if(!currHighlightAtoms.hasOwnProperty(m)) currHighlightAtoms[m] = undefined;
59178
- //if(!atomHash.hasOwnProperty(m)) atomHash[m] = undefined;
59179
- if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59180
- }
59181
- }
59288
+ atomHash = this.processAtomStr(atomStr, atomHash, i, m);
59289
+
59290
+ // if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59291
+ // if(i === 0) {
59292
+ // atomHash[m] = 1;
59293
+ // }
59294
+ // else {
59295
+ // if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59296
+ // }
59297
+ // }
59182
59298
  }
59183
59299
  }
59184
59300
  } // end for(let l = 0,
@@ -59211,17 +59327,16 @@ class SelectByCommand {
59211
59327
  for(let n = 0, nl = atomStrArray.length; n < nl; ++n) {
59212
59328
  let atomStr = atomStrArray[n];
59213
59329
 
59214
- if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59215
- if(i === 0) {
59216
- //currHighlightAtoms[m] = 1;
59217
- atomHash[m] = 1;
59218
- }
59219
- else {
59220
- //if(!currHighlightAtoms.hasOwnProperty(m)) currHighlightAtoms[m] = undefined;
59221
- //if(!atomHash.hasOwnProperty(m)) atomHash[m] = undefined;
59222
- if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59223
- }
59224
- }
59330
+ atomHash = this.processAtomStr(atomStr, atomHash, i, m);
59331
+
59332
+ // if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59333
+ // if(i === 0) {
59334
+ // atomHash[m] = 1;
59335
+ // }
59336
+ // else {
59337
+ // if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59338
+ // }
59339
+ // }
59225
59340
  }
59226
59341
 
59227
59342
  }
@@ -59276,18 +59391,9 @@ class SelectByCommand {
59276
59391
 
59277
59392
  for(let m in ic.residues[residueId]) {
59278
59393
  for(let n = 0, nl = atomStrArray.length; n < nl; ++n) {
59279
- let atomStr = atomStrArray[n];
59280
- if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59281
- if(i === 0) {
59282
- //currHighlightAtoms[m] = 1;
59283
- atomHash[m] = 1;
59284
- }
59285
- else {
59286
- //if(!currHighlightAtoms.hasOwnProperty(m)) currHighlightAtoms[m] = undefined;
59287
- //if(!atomHash.hasOwnProperty(m)) atomHash[m] = undefined;
59288
- if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59289
- }
59290
- }
59394
+ let atomStr = atomStrArray[n];
59395
+
59396
+ atomHash = this.processAtomStr(atomStr, atomHash, i, m);
59291
59397
  }
59292
59398
  }
59293
59399
  } // for
@@ -59323,6 +59429,34 @@ class SelectByCommand {
59323
59429
  if(!bNoUpdateAll) ic.definedSetsCls.changeCustomAtoms(nameArray);
59324
59430
  }
59325
59431
  }
59432
+
59433
+ processAtomStr(atomStr, atomHash, i, m) { let ic = this.icn3d; ic.icn3dui;
59434
+ let atomStrLen = atomStr.length;
59435
+ let lastChar = atomStr.substr(atomStrLen - 1, 1);
59436
+
59437
+ if(lastChar == '*' && atomStrLen > 1) { // wildcard to replace anything with *
59438
+ if(atomStr.substr(0, atomStrLen - 1) === ic.atoms[m].name.substr(0, atomStrLen - 1)) {
59439
+ if(i === 0) {
59440
+ atomHash[m] = 1;
59441
+ }
59442
+ else {
59443
+ if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59444
+ }
59445
+ }
59446
+ }
59447
+ else {
59448
+ if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59449
+ if(i === 0) {
59450
+ atomHash[m] = 1;
59451
+ }
59452
+ else {
59453
+ if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59454
+ }
59455
+ }
59456
+ }
59457
+
59458
+ return atomHash;
59459
+ }
59326
59460
  }
59327
59461
 
59328
59462
  /**
@@ -61563,12 +61697,12 @@ if(!me.bNode) {
61563
61697
  }
61564
61698
 
61565
61699
  let prevStrand;
61700
+ let bCd19 = ic.chainid2index[chainid].length == 1 && ic.refpdbArray[ic.chainid2index[chainid][0]] == '6al5_cd19';
61566
61701
  for(let i = 0, il = segArray.length; i < il; ++i) {
61567
61702
  let seg = segArray[i];
61568
61703
  let qStart = seg.q_start;
61569
61704
  parseInt(seg.q_start);
61570
- let postfix = '';
61571
- if(isNaN(seg.q_start)) postfix = seg.q_start.substr(seg.q_start.length - 1, 1);
61705
+ if(isNaN(seg.q_start)) seg.q_start.substr(seg.q_start.length - 1, 1);
61572
61706
 
61573
61707
  // one item in "seq"
61574
61708
  // q_start and q_end are numbers, but saved in string
@@ -61579,9 +61713,10 @@ if(!me.bNode) {
61579
61713
 
61580
61714
  let resid = chainid + '_' + seg.t_start;
61581
61715
  //let refnum = qStartInt.toString() + postfix;
61582
- let refnum = qStart + postfix;
61716
+ //let refnum = qStart + postfix;
61717
+ let refnum = qStart;
61583
61718
 
61584
- let refnumLabel = thisClass.getLabelFromRefnum(refnum, prevStrand);
61719
+ let refnumLabel = thisClass.getLabelFromRefnum(refnum, prevStrand, bCd19);
61585
61720
  prevStrand = refnumLabel.replace(new RegExp(refnum,'g'), '');
61586
61721
 
61587
61722
  ic.resid2refnum[resid] = refnumLabel;
@@ -61616,7 +61751,7 @@ if(!me.bNode) {
61616
61751
  }
61617
61752
  }
61618
61753
 
61619
- getLabelFromRefnum(oriRefnum, prevStrand) { let ic = this.icn3d; ic.icn3dui;
61754
+ getLabelFromRefnum(oriRefnum, prevStrand, bCd19) { let ic = this.icn3d; ic.icn3dui;
61620
61755
  let refnum = parseInt(oriRefnum);
61621
61756
 
61622
61757
  // A^: 1xx or 2xx
@@ -61634,7 +61769,10 @@ if(!me.bNode) {
61634
61769
  // G*: 94xx
61635
61770
 
61636
61771
  if(refnum < 100) return " " + oriRefnum;
61637
- else if(refnum >= 100 && refnum < 1000) return "A^" + oriRefnum;
61772
+ else if(refnum >= 100 && refnum < 1000) {
61773
+ if(bCd19) return " " + oriRefnum;
61774
+ else return "A^" + oriRefnum;
61775
+ }
61638
61776
  else if(refnum >= 1000 && refnum < 1200) return "A" + oriRefnum;
61639
61777
  else if(refnum >= 1200 && refnum < 1300) return "A'" + oriRefnum;
61640
61778
  else if(refnum >= 1300 && refnum < 1400) return "A*" + oriRefnum;
@@ -61816,7 +61954,7 @@ class Scap {
61816
61954
 
61817
61955
  let data;
61818
61956
 
61819
- try {
61957
+ // try {
61820
61958
  data = await me.getAjaxPostPromise(url, dataObj, true, undefined, undefined, undefined, 'text');
61821
61959
 
61822
61960
  let pos = data.indexOf('\n');
@@ -61906,8 +62044,10 @@ console.log("free energy: " + energy + " kcal/mol");
61906
62044
 
61907
62045
  let atomWT = ic.firstAtomObjCls.getFirstAtomObj(ic.residues[resid]);
61908
62046
 
61909
- ic.atoms[serial].color = atomWT.color;
61910
- ic.atomPrevColors[serial] = atomWT.color;
62047
+ if(atomWT) {
62048
+ ic.atoms[serial].color = atomWT.color;
62049
+ ic.atomPrevColors[serial] = atomWT.color;
62050
+ }
61911
62051
  }
61912
62052
 
61913
62053
  let chainid = atom.structure + '_' + atom.chain;
@@ -61973,6 +62113,7 @@ console.log("free energy: " + energy + " kcal/mol");
61973
62113
  // expand the toolbar
61974
62114
  let id = ic.pre + 'selection';
61975
62115
  $("#" + id).show();
62116
+ /*
61976
62117
  }
61977
62118
  catch(err) {
61978
62119
  var aaa = 1; //alert("There are some problems in predicting the side chain of the mutant...");
@@ -61982,6 +62123,7 @@ console.log("free energy: " + energy + " kcal/mol");
61982
62123
  /// if(ic.deferredScap !== undefined) ic.deferredScap.resolve();
61983
62124
  return;
61984
62125
  }
62126
+ */
61985
62127
  }
61986
62128
 
61987
62129
  async exportPdbProfix(bHydrogen, pdb, snpStr) { let ic = this.icn3d, me = ic.icn3dui;
@@ -66321,7 +66463,11 @@ class SaveFile {
66321
66463
  $("#" + ic.pre + "title").html(title);
66322
66464
  }
66323
66465
  else if(me.cfg.blast_rep_id) {
66324
- text = 'Query: ' + me.cfg.query_id + '; target: ' + me.cfg.blast_rep_id;
66466
+ let query_id = (me.cfg.oriQuery_id) ? me.cfg.oriQuery_id : me.cfg.query_id;
66467
+ let blast_rep_id = (me.cfg.oriBlast_rep_id) ? me.cfg.oriBlast_rep_id : me.cfg.blast_rep_id;
66468
+ if(query_id.length > 20) query_id = query_id.substr(0, 17) + '...';
66469
+
66470
+ text = 'Query: ' + query_id + '; target: ' + blast_rep_id;
66325
66471
  $("#" + ic.pre + "title").html(text + ", " + title);
66326
66472
  }
66327
66473
  else {
@@ -68972,7 +69118,7 @@ class iCn3D {
68972
69118
  // }
68973
69119
  // else { // WebGL2 supports EXT_frag_depth and ANGLE_instanced_arrays
68974
69120
  this.bExtFragDepth = true;
68975
- this.bImpo = false; //true;
69121
+ this.bImpo = true;
68976
69122
 
68977
69123
  //console.log('WebGL2 is supported. Thus EXT_frag_depth and ANGLE_instanced_arrays are supported. All spheres and cylinders are drawn using shaders. Assembly is drawn with one copy of the asymmetric unit using hardware instancing.');
68978
69124
  // }
@@ -69547,7 +69693,7 @@ class iCn3DUI {
69547
69693
  //even when multiple iCn3D viewers are shown together.
69548
69694
  this.pre = this.cfg.divid + "_";
69549
69695
 
69550
- this.REVISION = '3.23.0';
69696
+ this.REVISION = '3.23.1';
69551
69697
 
69552
69698
  // In nodejs, iCn3D defines "window = {navigator: {}}"
69553
69699
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -69841,6 +69987,9 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
69841
69987
  else if(me.cfg.blast_rep_id !== undefined) {
69842
69988
  // ic.bNCBI = true;
69843
69989
  ic.inputid = me.cfg.query_id + ',' + me.cfg.blast_rep_id;
69990
+
69991
+ me.cfg.oriQuery_id = me.cfg.query_id;
69992
+ me.cfg.oriBlast_rep_id = me.cfg.blast_rep_id;
69844
69993
 
69845
69994
  // custom seqeunce has query_id such as "Query_78989" in BLAST
69846
69995
  if(me.cfg.query_id.substr(0,5) !== 'Query' && me.cfg.rid === undefined) {