icn3d 3.23.0 → 3.23.2

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
@@ -11764,7 +11764,7 @@ class Events {
11764
11764
  $("#" + me.pre + id).resizable();
11765
11765
  }
11766
11766
 
11767
- async launchMmdb(ids, bBiounit, hostUrl) { let me = this.icn3dui, ic = me.icn3d;
11767
+ async launchMmdb(ids, bBiounit, hostUrl) { let me = this.icn3dui, ic = me.icn3d, thisClass = this;
11768
11768
  if(!me.cfg.notebook) dialog.dialog( "close" );
11769
11769
 
11770
11770
  let flag = bBiounit ? 1 : 0;
@@ -11777,9 +11777,9 @@ class Events {
11777
11777
  return;
11778
11778
  }
11779
11779
 
11780
- /*
11781
11780
  let idArray = ids.split(',');
11782
11781
 
11782
+ /*
11783
11783
  if(idArray.length == 1 && (idArray[0].length == 4 || !isNaN(idArray[0])) ) {
11784
11784
  thisClass.setLogCmd("load mmdb" + flag + " " + ids, false);
11785
11785
  let urlTarget = (ic.structures && Object.keys(ic.structures).length > 0) ? '_blank' : '_self';
@@ -11792,21 +11792,28 @@ class Events {
11792
11792
  }
11793
11793
  */
11794
11794
 
11795
- // remove space
11796
- me.cfg.mmdbafid = ids;
11797
- me.cfg.bu = flag;
11798
-
11799
- ic.bMmdbafid = true;
11800
- ic.inputid = me.cfg.mmdbafid;
11801
- if(me.cfg.bu == 1) {
11802
- ic.loadCmd = 'load mmdbaf1 ' + me.cfg.mmdbafid;
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);
11803
11800
  }
11804
11801
  else {
11805
- ic.loadCmd = 'load mmdbaf0 ' + me.cfg.mmdbafid;
11806
- }
11807
- me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
11802
+ me.cfg.mmdbafid = ids;
11803
+ me.cfg.bu = flag;
11808
11804
 
11809
- await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
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;
11809
+ }
11810
+ else {
11811
+ ic.loadCmd = 'load mmdbaf0 ' + me.cfg.mmdbafid;
11812
+ }
11813
+ me.htmlCls.clickMenuCls.setLogCmd(ic.loadCmd, true);
11814
+
11815
+ await ic.chainalignParserCls.downloadMmdbAf(me.cfg.mmdbafid);
11816
+ }
11810
11817
  }
11811
11818
 
11812
11819
  //Hold all functions related to click events.
@@ -14490,11 +14497,11 @@ class SetHtml {
14490
14497
 
14491
14498
  html += me.htmlCls.divStr + "specguide" + indexStr + "' style='display:none; width:500px' class='icn3d-box'>";
14492
14499
 
14493
- html += "<b>Specification:</b> In the selection \"$1HHO,4N7N.A,B,C:5-10,LV,3AlaVal,chemicals@CA,C\":";
14500
+ html += "<b>Specification:</b> In the selection \"$1HHO,4N7N.A,B,C:5-10,LV,3AlaVal,chemicals@CA,C,C*\":";
14494
14501
  html += "<ul><li>\"$1HHO,4N7N\" uses \"$\" to indicate structure selection.<br/>";
14495
14502
  html += "<li>\".A,B,C\" uses \".\" to indicate chain selection.<br/>";
14496
14503
  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/>";
14497
- html += "<li>\"@CA,C\" uses \"@\" to indicate atom selection.<br/>";
14504
+ html += "<li>\"@CA,C,C*\" uses \"@\" to indicate atom name selection. \"C*\" selects any atom names starting with \"C\". <br/>";
14498
14505
  html += "<li>Partial definition is allowed, e.g., \":1-10\" selects all residue IDs 1-10 in all chains.<br/>";
14499
14506
  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/>";
14500
14507
  html += "<li>The wild card character \"X\" or \"x\" can be used to represent any character.";
@@ -14503,9 +14510,9 @@ class SetHtml {
14503
14510
  html += "<ul><li>Users can select multiple sets in the menu \"Select > Defined Sets\".<br/>";
14504
14511
  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>";
14505
14512
  html += "<b>Full commands in url or command window:</b>";
14506
- html += "<ul><li>Select without saving the set: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C<br/>";
14513
+ html += "<ul><li>Select without saving the set: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C,C*<br/>";
14507
14514
  //html += "<li>Select and save: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C | name my_name | description my_description</ul>";
14508
- html += "<li>Select and save: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C | name my_name</ul>";
14515
+ html += "<li>Select and save: select $1HHO,4N7N.A,B,C:5-10,LV,chemicals@CA,C,C* | name my_name</ul>";
14509
14516
 
14510
14517
  html += "</div>";
14511
14518
 
@@ -20581,7 +20588,9 @@ class ControllerGestures extends THREE.EventDispatcher{
20581
20588
  this.up = new THREE.Vector3(0,1,0);
20582
20589
 
20583
20590
  this.type = 'unknown';
20584
- this.touchCount = 0;
20591
+ //this.touchCount = 0;
20592
+
20593
+ this.prevTap = 'none';
20585
20594
 
20586
20595
  this.clock = clock;
20587
20596
 
@@ -20598,9 +20607,9 @@ class ControllerGestures extends THREE.EventDispatcher{
20598
20607
  self.type = 'unknown';
20599
20608
  this.userData.selectPressed = true;
20600
20609
 
20601
- self.touchCount++;
20610
+ //self.touchCount++;
20602
20611
 
20603
- console.log( `onSelectStart touchCount: ${ self.touchCount }` );
20612
+ //console.log( `onSelectStart touchCount: ${ self.touchCount }` );
20604
20613
  }
20605
20614
 
20606
20615
  function onSelectEnd( ){
@@ -20610,27 +20619,36 @@ class ControllerGestures extends THREE.EventDispatcher{
20610
20619
  const startToEnd = data.endTime - data.startTime;
20611
20620
 
20612
20621
  //console.log(`ControllerGestures.onSelectEnd: startToEnd:${startToEnd.toFixed(2)} taps:${data.taps}`);
20613
-
20622
+ /*
20614
20623
  if (self.type === 'swipe'){
20615
20624
  const direction = ( self.controller1.position.y < data.startPosition.y) ? "DOWN" : "UP";
20616
20625
  self.dispatchEvent( { type:'swipe', direction } );
20617
20626
  self.type = 'unknown';
20618
- }else if (self.type !== "pinch" && self.type !== "rotate" && self.type !== 'pan'){
20619
- if ( startToEnd < self.doubleClickLimit ){
20627
+ }else
20628
+
20629
+ if (self.type !== "pinch" && self.type !== "rotate" && self.type !== 'pan'){
20630
+ // if ( startToEnd < self.doubleClickLimit ){
20620
20631
  self.type = "tap";
20621
- data.taps++;
20622
- }else if ( startToEnd > self.pressMinimum ){
20623
- self.dispatchEvent( { type: 'press', position: self.controller1.position, matrixWorld: self.controller1.matrixWorld } );
20624
- self.type = 'unknown';
20625
- }
20626
- }else {
20632
+ //data.taps++;
20633
+ // }
20634
+ // else if ( startToEnd > self.pressMinimum ){
20635
+ // self.dispatchEvent( { type: 'press', position: self.controller1.position, matrixWorld: self.controller1.matrixWorld } );
20636
+ // self.type = 'unknown';
20637
+ // }
20638
+ }else{
20627
20639
  self.type = 'unknown';
20628
20640
  }
20629
-
20641
+ */
20642
+
20643
+ if ( startToEnd < self.doubleClickLimit ){
20644
+ data.taps++;
20645
+ }
20646
+ self.type = 'tap';
20647
+
20630
20648
  this.userData.selectPressed = false;
20631
20649
  data.startPosition = undefined;
20632
20650
 
20633
- self.touchCount--;
20651
+ //self.touchCount--;
20634
20652
  }
20635
20653
  }
20636
20654
 
@@ -20641,8 +20659,7 @@ class ControllerGestures extends THREE.EventDispatcher{
20641
20659
  }else {
20642
20660
  result = this.controller1.userData.selectPressed && this.controller2.userData.selectPressed;
20643
20661
  }
20644
- const self = this;
20645
- console.log( `ControllerGestures multiTouch: ${result} touchCount:${self.touchCount}`);
20662
+ //console.log( `ControllerGestures multiTouch: ${result} touchCount:${self.touchCount}`);
20646
20663
  return result;
20647
20664
  }
20648
20665
 
@@ -20677,86 +20694,104 @@ class ControllerGestures extends THREE.EventDispatcher{
20677
20694
  elapsedTime = currentTime - data2.startTime;
20678
20695
  if (elapsedTime > 0.05 ) data2.startPosition = this.controller2.position.clone();
20679
20696
  }
20680
-
20697
+
20681
20698
  if (!this.controller1.userData.selectPressed && this.type === 'tap' ){
20682
20699
  //Only dispatch event after double click limit is passed
20683
20700
  elapsedTime = this.clock.getElapsedTime() - data1.endTime;
20684
20701
  if (elapsedTime > this.doubleClickLimit){
20685
- console.log( `ControllerGestures.update dispatchEvent taps:${data1.taps}` );
20702
+ //console.log( `ControllerGestures.update dispatchEvent taps:${data1.taps}` );
20686
20703
  switch( data1.taps ){
20687
20704
  case 1:
20688
- this.dispatchEvent( { type: 'tap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20705
+ //this.dispatchEvent( { type: 'tap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20706
+ self.prevTap = 'tap';
20689
20707
  break;
20690
20708
  case 2:
20691
20709
  this.dispatchEvent( { type: 'doubletap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20692
- break;
20693
- case 3:
20694
- this.dispatchEvent( { type: 'tripletap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20695
- break;
20696
- case 4:
20697
- this.dispatchEvent( { type: 'quadtap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20710
+ self.prevTap = 'doubletap';
20698
20711
  break;
20699
20712
  }
20700
20713
  this.type = "unknown";
20701
20714
  data1.taps = 0;
20702
20715
  }
20703
20716
  }
20704
-
20717
+
20705
20718
  if (this.type === 'unknown' && this.touch){
20706
- if (data1.startPosition !== undefined){
20707
- if (this.multiTouch){
20708
- if (data2.startPosition !== undefined){
20719
+ //if (data1.startPosition !== undefined){
20720
+ //if (this.multiTouch){
20721
+
20722
+ if(self.prevTap == 'doubletap') {
20723
+ //if (data2.startPosition !== undefined){
20709
20724
  //startPosition is undefined for 1/20 sec
20710
20725
  //test for pinch or rotate
20711
- const startDistance = data1.startPosition.distanceTo( data2.startPosition );
20712
- const currentDistance = this.controller1.position.distanceTo( this.controller2.position );
20713
- const delta = currentDistance - startDistance;
20714
- if ( Math.abs(delta) > 0.01 ){
20726
+
20727
+ // const startDistance = data1.startPosition.distanceTo( data2.startPosition );
20728
+ // const currentDistance = this.controller1.position.distanceTo( this.controller2.position );
20729
+ // const delta = currentDistance - startDistance;
20730
+
20731
+ // if ( Math.abs(delta) > 0.01 ){
20715
20732
  this.type = 'pinch';
20716
20733
  this.startDistance = this.controller1.position.distanceTo( this.controller2.position );
20717
- this.dispatchEvent( { type: 'pinch', delta: 0, scale: 1, initialise: true } );
20718
- }else {
20719
- const v1 = data2.startPosition.clone().sub( data1.startPosition ).normalize();
20720
- const v2 = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20721
- const theta = v1.angleTo( v2 );
20722
- if (Math.abs(theta) > 0.2){
20723
- this.type = 'rotate';
20724
- this.startVector = v2.clone();
20725
- this.dispatchEvent( { type: 'rotate', theta: 0, initialise: true } );
20726
- }
20727
- }
20728
- }
20729
- }else {
20734
+ //this.dispatchEvent( { type: 'pinch', delta: 0, scale: 1, initialise: true } );
20735
+ this.dispatchEvent( { type: 'pinch', delta: new THREE.Vector3(0,0,0), scale: 1, initialise: true } );
20736
+ // }else{
20737
+ // const v1 = data2.startPosition.clone().sub( data1.startPosition ).normalize();
20738
+ // const v2 = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20739
+ // const theta = v1.angleTo( v2 );
20740
+ // if (Math.abs(theta) > 0.2){
20741
+ // this.type = 'rotate';
20742
+ // this.startVector = v2.clone();
20743
+ // this.dispatchEvent( { type: 'rotate', theta: 0, initialise: true } );
20744
+ // }
20745
+ // }
20746
+ //}
20747
+ }else { //if(self.prevTap == 'tap') {
20730
20748
  //test for swipe or pan
20731
- let dist = data1.startPosition.distanceTo( this.controller1.position );
20732
- elapsedTime = this.clock.getElapsedTime() - data1.startTime;
20733
- const velocity = dist/elapsedTime;
20749
+ // let dist = data1.startPosition.distanceTo( this.controller1.position );
20750
+ // elapsedTime = this.clock.getElapsedTime() - data1.startTime;
20751
+ // const velocity = dist/elapsedTime;
20752
+
20734
20753
  //console.log(`dist:${dist.toFixed(3)} velocity:${velocity.toFixed(3)}`);
20735
- if ( dist > 0.01 && velocity > 0.1 ){
20736
- const v = this.controller1.position.clone().sub( data1.startPosition );
20737
- let maxY = (Math.abs(v.y) > Math.abs(v.x)) && (Math.abs(v.y) > Math.abs(v.z));
20738
- if ( maxY )this.type = "swipe";
20739
- }else if (dist > 0.006 && velocity < 0.03){
20754
+ // if ( dist > 0.01 && velocity > 0.1 ){
20755
+ // const v = this.controller1.position.clone().sub( data1.startPosition );
20756
+ // let maxY = (Math.abs(v.y) > Math.abs(v.x)) && (Math.abs(v.y) > Math.abs(v.z));
20757
+ // if ( maxY )this.type = "swipe";
20758
+ // }else if (dist > 0.006 && velocity < 0.03){
20740
20759
  this.type = "pan";
20741
20760
  this.startPosition = this.controller1.position.clone();
20742
- this.dispatchEvent( { type: 'pan', delta: new THREE.Vector3(), initialise: true } );
20743
- }
20761
+ this.dispatchEvent( { type: 'pan', delta: new THREE.Vector3(0,0,0), initialise: true } );
20762
+ // }
20744
20763
  }
20764
+ //}
20765
+ }else if (this.type === 'pinch' || this.type === 'pan'){
20766
+ //if (this.type === 'pinch'){
20767
+ //if (this.multiTouch){
20768
+
20769
+ if(self.prevTap == 'doubletap') {
20770
+ if (this.controller2.position) {
20771
+ const currentDistance = this.controller1.position.distanceTo( this.controller2.position );
20772
+ // const delta = currentDistance - this.startDistance;
20773
+ const scale = currentDistance/this.startDistance;
20774
+
20775
+ const delta = this.controller1.position.clone().sub( this.startPosition );
20776
+ this.dispatchEvent( { type: 'pinch', delta, scale });
20777
+ }
20778
+
20779
+ // }else if (this.type === 'rotate'){
20780
+ // const v = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20781
+ // let theta = this.startVector.angleTo( v );
20782
+ // const cross = this.startVector.clone().cross( v );
20783
+ // if (this.up.dot(cross) > 0) theta = -theta;
20784
+ // this.dispatchEvent( { type: 'rotate', theta } );
20785
+ /*
20786
+ //}else if (this.type === 'pan'){
20787
+ } else { //if(self.prevTap == 'tap') {
20788
+ // const delta = this.controller1.position.clone().sub( this.startPosition );
20789
+ // this.dispatchEvent( { type: 'pan', delta } );
20790
+
20791
+ const position = this.controller1.position.clone();
20792
+ this.dispatchEvent( { type: 'pan', position } );
20793
+ */
20745
20794
  }
20746
- }else if (this.type === 'pinch'){
20747
- const currentDistance = this.controller1.position.distanceTo( this.controller2.position );
20748
- const delta = currentDistance - this.startDistance;
20749
- const scale = currentDistance/this.startDistance;
20750
- this.dispatchEvent( { type: 'pinch', delta, scale });
20751
- }else if (this.type === 'rotate'){
20752
- const v = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20753
- let theta = this.startVector.angleTo( v );
20754
- const cross = this.startVector.clone().cross( v );
20755
- if (this.up.dot(cross) > 0) theta = -theta;
20756
- this.dispatchEvent( { type: 'rotate', theta } );
20757
- }else if (this.type === 'pan'){
20758
- const delta = this.controller1.position.clone().sub( this.startPosition );
20759
- this.dispatchEvent( { type: 'pan', delta } );
20760
20795
  }
20761
20796
  }
20762
20797
  }
@@ -21899,16 +21934,15 @@ class Scene {
21899
21934
  // https://github.com/mrdoob/three.js/blob/master/examples/webxr_ar_cones.html
21900
21935
  // https://github.com/mrdoob/three.js/blob/master/examples/webxr_vr_cubes.html
21901
21936
 
21937
+
21938
+
21902
21939
  //if(ic.bVr && !ic.dolly) {
21903
21940
  if(ic.bVr) {
21904
21941
  ic.canvasUI = this.createUI();
21942
+
21905
21943
  //ic.canvasUILog = this.createUILog();
21906
- // add canvasUI
21907
- //ic.cam.add( ic.canvasUI.mesh );
21908
21944
  //ic.cam.add( ic.canvasUILog.mesh );
21909
21945
 
21910
- //ic.cam.remove( ic.canvasUI.mesh );
21911
-
21912
21946
  ic.raycasterVR = new THREE.Raycaster();
21913
21947
  ic.workingMatrix = new THREE.Matrix4();
21914
21948
  ic.workingVector = new THREE.Vector3();
@@ -21982,70 +22016,79 @@ class Scene {
21982
22016
  });
21983
22017
  }
21984
22018
  else if(ic.bAr) {
22019
+ // the menu didn't work in AR
22020
+ // ic.canvasUILog = this.createUILog();
22021
+ // ic.cam.add( ic.canvasUILog.mesh );
22022
+
21985
22023
  //Add gestures here
21986
22024
  ic.gestures = new ControllerGestures(ic.renderer);
21987
22025
  ic.scene.add(ic.gestures.controller1);
21988
22026
  ic.scene.add(ic.gestures.controller2);
21989
22027
 
21990
- ic.gestures.addEventListener('tap', (ev) => {
21991
- //if(!ic.mdl.visible) {
21992
- // ic.mdl.visible = true;
21993
- //}
21994
-
21995
- const controller = ic.gestures.controller1;
21996
- //ic.mdl.position.set( 0, 0, - 0.3 ).applyMatrix4( controller.matrixWorld );
21997
- ic.mdl.position.set( -0.03, 0, - 0.3 ).applyMatrix4( controller.matrixWorld );
21998
- //ic.mdl.scale.copy(ic.mdl.scale.multiplyScalar(0.1));
21999
- ic.mdl.scale.copy(new THREE.Vector3( 0.001, 0.001, 0.001 ));
22000
- });
22028
+ // ic.gestures.addEventListener('tap', (ev) => {
22029
+ // // const controller = ic.gestures.controller1;
22030
+ // // ic.mdl.position.set( -0.03, 0, - 0.3 ).applyMatrix4( controller.matrixWorld );
22031
+ // // ic.mdl.scale.copy(new THREE.Vector3( 0.001, 0.001, 0.001 ));
22032
+ // });
22001
22033
 
22002
22034
  ic.gestures.addEventListener('doubletap', (ev) => {
22003
- const controller = ic.gestures.controller1;
22004
- //ic.mdl.position.set( 0, 0, - 0.3 ).applyMatrix4( controller.matrixWorld );
22005
- ic.mdl.position.set( -0.06, 0, - 0.6 ).applyMatrix4( controller.matrixWorld );
22006
- //ic.mdl.scale.copy(ic.mdl.scale.multiplyScalar(10));
22007
- ic.mdl.scale.copy(new THREE.Vector3( 0.005, 0.005, 0.005 ));
22008
- });
22009
- /*
22010
- ic.gestures.addEventListener('swipe', (ev) => {
22011
- // if(ic.mdl.visible) {
22012
- // ic.mdl.visible = false;
22013
- // }
22014
- });
22015
-
22016
- ic.gestures.addEventListener('pan', (ev) => {
22017
- // if(ev.initialise !== undefined) {
22018
- // thisClass.startPosition = ic.mdl.position.clone();
22019
- // }
22020
- // else {
22021
- // const pos = thisClass.startPosition.clone().add(ev.delta.multiplyScalar(3));
22022
- // ic.mdl.position.copy(pos);
22023
- // }
22035
+ thisClass.positionCenter();
22024
22036
  });
22037
+ /*
22038
+ ic.gestures.addEventListener('pan', (ev) => { // touch across screen, move
22039
+ if(ev.initialise !== undefined) {
22040
+ thisClass.startPosition = ic.mdl.position.clone();
22041
+ thisClass.startQuaternion = ic.mdl.quaternion.clone();
22042
+ }
22043
+ else {
22044
+ const endPosition = ev.position;
22045
+ let angle = Math.acos( thisClass.startPosition.dot( endPosition ) / thisClass.startPosition.length() / endPosition.length() );
22025
22046
 
22026
- ic.gestures.addEventListener('pinch', (ev) => {
22027
- // if(ev.initialise !== undefined) {
22028
- // thisClass.startScale = ic.mdl.scale.clone();
22029
- // }
22030
- // else {
22031
- // const scale = thisClass.startScale.clone().multiplyScalar(ev.scale);
22032
- // ic.mdl.scale.copy(scale);
22033
- // }
22047
+ let axis = new THREE.Vector3();
22048
+ axis.crossVectors( thisClass.startPosition, endPosition ).normalize();
22049
+
22050
+ let rotateSpeed = 6.0;
22051
+ angle *= rotateSpeed;
22052
+
22053
+ let quaternion = new THREE.Quaternion();
22054
+ quaternion.setFromAxisAngle( axis, -angle );
22055
+
22056
+ ic.mdl.quaternion.copy(thisClass.startQuaternion);
22057
+ ic.mdl.quaternion.multiplyQuaternions(quaternion, ic.mdl.quaternion);
22058
+ }
22034
22059
  });
22035
-
22036
- ic.gestures.addEventListener('rotate', (ev) => {
22037
- // if(ev.initialise !== undefined) {
22038
- // thisClass.startQuaternion = ic.mdl.quaternion.clone();
22039
- // }
22040
- // else {
22041
- // ic.mdl.quaternion.copy(thisClass.startQuaternion);
22042
- // ic.mdl.rotateY(ev.theta);
22043
- // }
22060
+ */
22061
+ ic.gestures.addEventListener('pinch', (ev) => { // two fingers opening or closing
22062
+ if(ev.initialise !== undefined) {
22063
+ thisClass.startPosition = ic.mdl.position.clone();
22064
+ thisClass.startScale = ic.mdl.scale.clone();
22065
+ }
22066
+ else {
22067
+ let zoomSpeed = 1.0;
22068
+ const scale = thisClass.startScale.clone().multiplyScalar(ev.scale * zoomSpeed);
22069
+ ic.mdl.scale.copy(scale);
22070
+ }
22071
+ });
22072
+ /*
22073
+ ic.gestures.addEventListener('rotate', (ev) => { // two fingers rotating around
22074
+ if(ev.initialise !== undefined) {
22075
+ thisClass.startQuaternion = ic.mdl.quaternion.clone();
22076
+ }
22077
+ else {
22078
+ ic.mdl.quaternion.copy(thisClass.startQuaternion);
22079
+ ic.mdl.rotateY(ev.theta);
22080
+ }
22044
22081
  });
22045
- */
22082
+ */
22046
22083
  }
22047
22084
  }
22048
22085
 
22086
+ positionCenter() { let ic = this.icn3d; ic.icn3dui;
22087
+ const controller = ic.gestures.controller1;
22088
+ ic.mdl.position.set( -0.06, 0, - 0.6 ).applyMatrix4( controller.matrixWorld );
22089
+ ic.mdl.scale.copy(new THREE.Vector3( 0.005, 0.005, 0.005 ));
22090
+ }
22091
+
22049
22092
  setVrArButtons() { let ic = this.icn3d, me = ic.icn3dui;
22050
22093
  // call just once
22051
22094
  ic.bSetVrArButtons = true;
@@ -22237,7 +22280,7 @@ class Scene {
22237
22280
  ic.cam.remove( ic.canvasUI.mesh );
22238
22281
  }
22239
22282
  catch(err) {
22240
- ic.canvasUILog.updateElement( "info", "ERROR: " + err );
22283
+ //ic.canvasUILog.updateElement( "info", "ERROR: " + err );
22241
22284
  }
22242
22285
  } },
22243
22286
  // delphi: { type: "button", position:{ top: margin + 4*(btnHeight + margin), left: margin + 2*(btnWidth + margin)}, width: btnWidth, height: btnHeight, fontColor: fontColor, fontSize: fontSize, backgroundColor: bkgdColor, hover: hoverColor, onSelect: function() {
@@ -22319,14 +22362,13 @@ class Scene {
22319
22362
  renderer: ic.renderer
22320
22363
  };
22321
22364
  const content = {
22322
- info: ""
22365
+ info: "Debug info"
22323
22366
  };
22324
22367
 
22325
22368
  const ui = new CanvasUI( content, config );
22326
-
22327
- //ui.mesh.position.set( 0, 1.5, -1.2 );
22328
- //ui.mesh.position.set( 0, 0, -1.2 );
22329
- ui.mesh.position.set( 0, -2, -3 );
22369
+
22370
+ //ui.mesh.position.set( 0, -2, -3 ); // VR
22371
+ ui.mesh.position.set( 0, -1, -2 ); // AR
22330
22372
 
22331
22373
  return ui;
22332
22374
  }
@@ -32121,6 +32163,7 @@ class Alternate {
32121
32163
  else if(ic.bAr) {
32122
32164
  if ( ic.renderer.xr.isPresenting ){
32123
32165
  ic.gestures.update();
32166
+ //if(ic.canvasUILog) ic.canvasUILog.update();
32124
32167
  }
32125
32168
  }
32126
32169
 
@@ -40596,11 +40639,12 @@ class ShowAnno {
40596
40639
  }
40597
40640
  else if(me.cfg.blast_rep_id == chnid && ic.seqStructAlignData === undefined && ic.seqStructAlignDataSmithwm === undefined) {
40598
40641
  let title;
40599
- if(me.cfg.query_id.length > 14) {
40600
- title = 'Query: ' + me.cfg.query_id.substr(0, 6) + '...';
40642
+ let query_id = (me.cfg.oriQuery_id) ? me.cfg.oriQuery_id : me.cfg.query_id;
40643
+ if(query_id.length > 14) {
40644
+ title = 'Query: ' + query_id.substr(0, 6) + '...';
40601
40645
  }
40602
40646
  else {
40603
- title =(isNaN(me.cfg.query_id)) ? 'Query: ' + me.cfg.query_id : 'Query: gi ' + me.cfg.query_id;
40647
+ title =(isNaN(me.cfg.query_id)) ? 'Query: ' + query_id : 'Query: gi ' + query_id;
40604
40648
  }
40605
40649
  let compTitle = undefined;
40606
40650
  let compText = undefined;
@@ -40613,11 +40657,12 @@ class ShowAnno {
40613
40657
  }
40614
40658
  else if(me.cfg.blast_rep_id == chnid && (ic.seqStructAlignData !== undefined || ic.seqStructAlignDataSmithwm !== undefined) ) { // align sequence to structure
40615
40659
  let title;
40616
- if(me.cfg.query_id.length > 14) {
40617
- title = 'Query: ' + me.cfg.query_id.substr(0, 6) + '...';
40660
+ let query_id = (me.cfg.oriQuery_id) ? me.cfg.oriQuery_id : me.cfg.query_id;
40661
+ if(query_id.length > 14) {
40662
+ title = 'Query: ' + query_id.substr(0, 6) + '...';
40618
40663
  }
40619
40664
  else {
40620
- title =(isNaN(me.cfg.query_id)) ? 'Query: ' + me.cfg.query_id : 'Query: gi ' + me.cfg.query_id;
40665
+ title =(isNaN(me.cfg.query_id)) ? 'Query: ' + query_id : 'Query: gi ' + query_id;
40621
40666
  }
40622
40667
 
40623
40668
  let evalue, targetSeq, querySeq, segArray;
@@ -41105,7 +41150,7 @@ class ShowSeq {
41105
41150
  }
41106
41151
  if(me.cfg.blast_rep_id == chnid) {
41107
41152
  // change color in 3D
41108
- ic.opts['color'] = 'conservation';
41153
+ ic.opts['color'] = (ic.blastAcxn) ? 'confidence' : 'conservation';
41109
41154
  ic.setColorCls.setColorByOptions(ic.opts, ic.atoms);
41110
41155
  // remove highlight
41111
41156
  //ic.hlUpdateCls.removeHlSeq();
@@ -41397,6 +41442,8 @@ class ShowSeq {
41397
41442
  let strand2len_start_stop = {};
41398
41443
  let prevRefnumStr, prevPostfix;
41399
41444
 
41445
+ // sometimes one chain may have several Ig domains,set a index for each IgDomain
41446
+ let index = 1;
41400
41447
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41401
41448
  let currResi = ic.ParserUtilsCls.getResi(chnid, i);
41402
41449
  let residueid = chnid + '_' + currResi;
@@ -41409,7 +41456,7 @@ class ShowSeq {
41409
41456
 
41410
41457
  refnumStr = refnumStr_ori;
41411
41458
  refnum = parseInt(refnumStr);
41412
- postfix = refnumStr.replace(refnum.toString(), '');
41459
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41413
41460
 
41414
41461
  if(!bCustom && !kabat_or_imgt) {
41415
41462
  if(currStrand != prevStrand) { // reset currCnt
@@ -41418,26 +41465,51 @@ class ShowSeq {
41418
41465
  strand2len_start_stop[prevStrand + prevPostfix].len = currCnt - 1;
41419
41466
  strand2len_start_stop[prevStrand + prevPostfix].end = refnumStr;
41420
41467
  strand2len_start_stop[prevStrand + prevPostfix].nextStrand = currStrand;
41468
+
41469
+ console.log("end: " + residueid);
41421
41470
  }
41422
41471
 
41423
41472
  currCnt = 1;
41424
41473
  }
41425
41474
 
41426
41475
  // #9##
41427
- if(prevStrand && refnumStr.substr(1,1) == '9') { // loop region
41476
+ if(prevStrand && refnum > 1000 && refnumStr.substr(1,1) == '9') { // loop region
41428
41477
  if(currCnt == 1) { // start of a loop
41478
+ if(strand2len_start_stop.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41479
+ ++index;
41480
+ }
41481
+
41482
+ console.log("start: " + residueid + " refnumStr: " + refnumStr);
41483
+
41484
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41429
41485
  strand2len_start_stop[currStrand + postfix] = {};
41486
+
41430
41487
  strand2len_start_stop[currStrand + postfix].start = prevRefnumStr;
41431
41488
  strand2len_start_stop[currStrand + postfix].chainid = chnid;
41432
41489
  }
41433
41490
  refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
41434
41491
  refnumLabel = currStrand + refnumStr;
41492
+
41435
41493
  ++currCnt;
41436
41494
  }
41437
41495
  }
41438
41496
  }
41439
41497
  else {
41440
41498
  if(prevStrand && !bCustom && !kabat_or_imgt) {
41499
+ if(currCnt == 1) { // start of a loop
41500
+ if(strand2len_start_stop.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41501
+ ++index;
41502
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41503
+ strand2len_start_stop[currStrand + postfix] = {};
41504
+ }
41505
+ else {
41506
+ strand2len_start_stop[currStrand + postfix] = {};
41507
+ }
41508
+
41509
+ strand2len_start_stop[currStrand + postfix].start = prevRefnumStr;
41510
+ strand2len_start_stop[currStrand + postfix].chainid = chnid;
41511
+ }
41512
+
41441
41513
  // no ref num
41442
41514
  refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
41443
41515
  refnumLabel = currStrand + refnumStr;
@@ -41458,6 +41530,9 @@ class ShowSeq {
41458
41530
  }
41459
41531
 
41460
41532
  let refnumLabelNoPostfix;
41533
+ // sometimes one chain may have several Ig domains,set a index for each IgDomain
41534
+ index = 1;
41535
+ let appearedStrands = {}, currStrand_ori;
41461
41536
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41462
41537
  bLoop = false;
41463
41538
 
@@ -41471,9 +41546,13 @@ class ShowSeq {
41471
41546
  }
41472
41547
  else {
41473
41548
  refnumLabel = ic.resid2refnum[residueid];
41549
+ let bNotShow = false;
41550
+
41474
41551
  if(refnumLabel) {
41475
41552
  refnumStr_ori = refnumLabel.replace(/'/g, '').replace(/\*/g, '').replace(/\^/g, '').substr(1); // C', C''
41476
41553
  currStrand = refnumLabel.replace(new RegExp(refnumStr_ori,'g'), '');
41554
+ currStrand_ori = currStrand;
41555
+
41477
41556
  currFirstDigit = refnumStr_ori.substr(0, 1);
41478
41557
 
41479
41558
  refnumLabelNoPostfix = currStrand + parseInt(refnumStr_ori);
@@ -41494,18 +41573,30 @@ class ShowSeq {
41494
41573
  else {
41495
41574
  refnumStr = refnumStr_ori;
41496
41575
  refnum = parseInt(refnumStr);
41497
- postfix = refnumStr.replace(refnum.toString(), '');
41576
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41498
41577
 
41499
41578
  // #9##
41500
- if(prevStrand && refnumStr.substr(1,1) == '9') { // loop region
41579
+ if(prevStrand && refnum > 1000 && refnumStr.substr(1,1) == '9') { // loop region
41501
41580
  bLoop = true;
41502
41581
 
41582
+ if(currCnt == 1) { // start of a loop
41583
+ if(appearedStrands.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41584
+ ++index;
41585
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41586
+ }
41587
+
41588
+ appearedStrands[currStrand + postfix] = 1;
41589
+ }
41590
+
41503
41591
  let result = this.getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix);
41504
41592
 
41505
41593
  refnumStr = result.refnumStr;
41506
41594
  refnumLabel = result.refnumLabel;
41507
41595
  refnumLabelNoPostfix = result.refnumLabelNoPostfix;
41508
41596
 
41597
+ bNotShow = result.bNotShow;
41598
+ currStrand = refnumLabel.replace(new RegExp(refnumStr,'g'), '');
41599
+
41509
41600
  ++currCnt;
41510
41601
  }
41511
41602
  }
@@ -41545,7 +41636,7 @@ class ShowSeq {
41545
41636
  }
41546
41637
  }
41547
41638
  else {
41548
- html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop);
41639
+ html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow);
41549
41640
  }
41550
41641
  }
41551
41642
  else {
@@ -41556,16 +41647,29 @@ class ShowSeq {
41556
41647
  // no ref num
41557
41648
  bLoop = true;
41558
41649
 
41650
+ if(currCnt == 1) { // start of a loop
41651
+ if(appearedStrands.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41652
+ ++index;
41653
+ }
41654
+
41655
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41656
+
41657
+ appearedStrands[currStrand + postfix] = 1;
41658
+ }
41659
+
41559
41660
  // use previous postfix
41560
41661
  let result = this.getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix);
41561
41662
 
41562
41663
  refnumStr = result.refnumStr;
41563
41664
  refnumLabel = result.refnumLabel;
41564
41665
  refnumLabelNoPostfix = result.refnumLabelNoPostfix;
41666
+
41667
+ bNotShow = result.bNotShow;
41668
+ currStrand = refnumLabel.replace(new RegExp(refnumStr,'g'), '');
41565
41669
 
41566
41670
  ++currCnt;
41567
41671
 
41568
- html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop);
41672
+ html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow);
41569
41673
  }
41570
41674
  else {
41571
41675
  html += '<span></span>';
@@ -41591,7 +41695,7 @@ class ShowSeq {
41591
41695
  ic.chainsMapping[chnid][residueid] = refnumLabelNoPostfix;
41592
41696
  }
41593
41697
 
41594
- prevStrand = currStrand;
41698
+ prevStrand = currStrand_ori; //currStrand;
41595
41699
  }
41596
41700
 
41597
41701
  html += '<span class="icn3d-residueNum"></span>';
@@ -41607,6 +41711,8 @@ class ShowSeq {
41607
41711
  getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix) { let ic = this.icn3d; ic.icn3dui;
41608
41712
  let refnumStr, refnumLabel, refnumLabelNoPostfix;
41609
41713
 
41714
+ let bNotShow = false; // do not show the label
41715
+
41610
41716
  if(strand2len_start_stop[currStrand + postfix]) {
41611
41717
  let start = parseInt(strand2len_start_stop[currStrand + postfix].start);
41612
41718
  let end = parseInt(strand2len_start_stop[currStrand + postfix].end);
@@ -41626,10 +41732,15 @@ class ShowSeq {
41626
41732
  else {
41627
41733
  refnum = end - (len + 1 - currCnt);
41628
41734
  refnumStr = refnum + postfixEnd;
41735
+
41629
41736
  refnumLabel = (strand2len_start_stop[currStrand + postfix].nextStrand !== undefined) ? strand2len_start_stop[currStrand + postfix].nextStrand + refnumStr : ' ' + refnumStr;
41630
41737
  }
41631
41738
 
41632
41739
  refnumLabelNoPostfix = currStrand + refnum;
41740
+
41741
+ if(currCnt == 0 || currCnt == halfLen || currCnt == halfLen + 1 || currCnt == end - 1) {
41742
+ bNotShow = true;
41743
+ }
41633
41744
  }
41634
41745
  else {
41635
41746
  // refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
@@ -41638,18 +41749,20 @@ class ShowSeq {
41638
41749
  refnumStr = '';
41639
41750
  refnumLabel = '';
41640
41751
  refnumLabelNoPostfix = '';
41752
+
41753
+ bNotShow = true;
41641
41754
  }
41642
41755
 
41643
- return {refnumStr: refnumStr, refnumLabel: refnumLabel, refnumLabelNoPostfix: refnumLabelNoPostfix};
41756
+ return {refnumStr: refnumStr, refnumLabel: refnumLabel, refnumLabelNoPostfix: refnumLabelNoPostfix, bNotShow: bNotShow};
41644
41757
  }
41645
41758
 
41646
- getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop) { let ic = this.icn3d, me = ic.icn3dui;
41759
+ getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow) { let ic = this.icn3d, me = ic.icn3dui;
41647
41760
  let refnum = parseInt(refnumStr).toString();
41648
41761
  let color = this.getRefnumColor(currStrand);
41649
41762
  let colorStr = 'style="color:' + color + '"';
41650
41763
 
41651
41764
  let lastTwo = parseInt(refnum.substr(refnum.length - 2, 2));
41652
- let lastThree = parseInt(refnum.substr(refnum.length - 3, 3));
41765
+ parseInt(refnum.substr(refnum.length - 3, 3));
41653
41766
 
41654
41767
  let html = '';
41655
41768
 
@@ -41659,7 +41772,7 @@ class ShowSeq {
41659
41772
 
41660
41773
  html += '<span ' + colorStr + ' title="' + refnumLabel + '"><b>' + refnumLabel.substr(0, 1) + '</b>' + refnumLabel.substr(1) + '</span>';
41661
41774
  }
41662
- else if(lastTwo % 2 == 0 && lastTwo != 52 && lastThree != 901) {
41775
+ else if(lastTwo % 2 == 0 && lastTwo != 52 && !bNotShow) { // don't show label for the first, middle, and last loop residues
41663
41776
  // e.g., 2152a
41664
41777
  let lastTwoStr = isNaN(refnumStr) ? lastTwo + refnumStr.substr(refnumStr.length - 1, 1) : lastTwo;
41665
41778
  html += '<span ' + colorStr + ' title="' + refnumLabel + '">' + lastTwoStr + '</span>';
@@ -58922,7 +59035,7 @@ class SelectByCommand {
58922
59035
  // $1,2,3: Structure
58923
59036
  // .A,B,C: chain
58924
59037
  // :5-10,K,chemicals: residues, could be 'proteins', 'nucleotides', 'chemicals', 'ions', and 'water'
58925
- // @CA,C: atoms
59038
+ // @CA,C,C*: atoms
58926
59039
  // wild card * can be used to select all
58927
59040
  //var currHighlightAtoms = {}
58928
59041
 
@@ -58972,7 +59085,7 @@ class SelectByCommand {
58972
59085
  testStr = testStr.substr(0, dollarPos);
58973
59086
  }
58974
59087
 
58975
- if(atomStrArray.length == 1 && atomStrArray[0] !== '*') {
59088
+ if(atomStrArray.length > 1 || (atomStrArray.length == 1 && atomStrArray[0] !== '*')) {
58976
59089
  bSelectResidues = false; // selected atoms
58977
59090
  }
58978
59091
 
@@ -59095,17 +59208,16 @@ class SelectByCommand {
59095
59208
  for(let m in ic.residues[residueId]) {
59096
59209
  for(let n = 0, nl = atomStrArray.length; n < nl; ++n) {
59097
59210
  let atomStr = atomStrArray[n];
59098
- if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59099
- if(i === 0) {
59100
- //currHighlightAtoms[m] = 1;
59101
- atomHash[m] = 1;
59102
- }
59103
- else {
59104
- //if(!currHighlightAtoms.hasOwnProperty(m)) currHighlightAtoms[m] = undefined;
59105
- //if(!atomHash.hasOwnProperty(m)) atomHash[m] = undefined;
59106
- if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59107
- }
59108
- }
59211
+ atomHash = this.processAtomStr(atomStr, atomHash, i, m);
59212
+
59213
+ // if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59214
+ // if(i === 0) {
59215
+ // atomHash[m] = 1;
59216
+ // }
59217
+ // else {
59218
+ // if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59219
+ // }
59220
+ // }
59109
59221
  }
59110
59222
  }
59111
59223
  } // end for(let l = 0,
@@ -59138,17 +59250,16 @@ class SelectByCommand {
59138
59250
  for(let n = 0, nl = atomStrArray.length; n < nl; ++n) {
59139
59251
  let atomStr = atomStrArray[n];
59140
59252
 
59141
- if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59142
- if(i === 0) {
59143
- //currHighlightAtoms[m] = 1;
59144
- atomHash[m] = 1;
59145
- }
59146
- else {
59147
- //if(!currHighlightAtoms.hasOwnProperty(m)) currHighlightAtoms[m] = undefined;
59148
- //if(!atomHash.hasOwnProperty(m)) atomHash[m] = undefined;
59149
- if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59150
- }
59151
- }
59253
+ atomHash = this.processAtomStr(atomStr, atomHash, i, m);
59254
+
59255
+ // if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59256
+ // if(i === 0) {
59257
+ // atomHash[m] = 1;
59258
+ // }
59259
+ // else {
59260
+ // if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59261
+ // }
59262
+ // }
59152
59263
  }
59153
59264
 
59154
59265
  }
@@ -59203,18 +59314,9 @@ class SelectByCommand {
59203
59314
 
59204
59315
  for(let m in ic.residues[residueId]) {
59205
59316
  for(let n = 0, nl = atomStrArray.length; n < nl; ++n) {
59206
- let atomStr = atomStrArray[n];
59207
- if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59208
- if(i === 0) {
59209
- //currHighlightAtoms[m] = 1;
59210
- atomHash[m] = 1;
59211
- }
59212
- else {
59213
- //if(!currHighlightAtoms.hasOwnProperty(m)) currHighlightAtoms[m] = undefined;
59214
- //if(!atomHash.hasOwnProperty(m)) atomHash[m] = undefined;
59215
- if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59216
- }
59217
- }
59317
+ let atomStr = atomStrArray[n];
59318
+
59319
+ atomHash = this.processAtomStr(atomStr, atomHash, i, m);
59218
59320
  }
59219
59321
  }
59220
59322
  } // for
@@ -59250,6 +59352,34 @@ class SelectByCommand {
59250
59352
  if(!bNoUpdateAll) ic.definedSetsCls.changeCustomAtoms(nameArray);
59251
59353
  }
59252
59354
  }
59355
+
59356
+ processAtomStr(atomStr, atomHash, i, m) { let ic = this.icn3d; ic.icn3dui;
59357
+ let atomStrLen = atomStr.length;
59358
+ let lastChar = atomStr.substr(atomStrLen - 1, 1);
59359
+
59360
+ if(lastChar == '*' && atomStrLen > 1) { // wildcard to replace anything with *
59361
+ if(atomStr.substr(0, atomStrLen - 1) === ic.atoms[m].name.substr(0, atomStrLen - 1)) {
59362
+ if(i === 0) {
59363
+ atomHash[m] = 1;
59364
+ }
59365
+ else {
59366
+ if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59367
+ }
59368
+ }
59369
+ }
59370
+ else {
59371
+ if(atomStr === '*' || atomStr === ic.atoms[m].name) {
59372
+ if(i === 0) {
59373
+ atomHash[m] = 1;
59374
+ }
59375
+ else {
59376
+ if(!atomHash.hasOwnProperty(m)) delete atomHash[m];
59377
+ }
59378
+ }
59379
+ }
59380
+
59381
+ return atomHash;
59382
+ }
59253
59383
  }
59254
59384
 
59255
59385
  /**
@@ -61244,6 +61374,7 @@ class Dssp {
61244
61374
  else {
61245
61375
  //ic.refpdbArray = ['1bqu_fn3', '1cd8_igv', '1t6v_vnar', '1wio_c2', '1wio_igv', '2atp_a', '2atp_b', '2dm3_iset', '5esv_vh', '5esv_vl', '6al5_cd19', '7bz5_cl1', '7bz5_vh', '7bz5_vl'];
61246
61376
  //ic.refpdbArray = ['1bqu_fn3', '1cd8_igv', '1cdh_cd4', '1dr9_cd80', '1hnf_cd2', '1hxm_d', '1hxm_g', '1ifr_lamin', '1ncn_cd86', '1t6v_vnar', '1yjd_cd28', '2atp_a', '2atp_b', '2dm3_iset', '3kys_tead1', '3pv7_ncr', '4f9l_cd277', '4gos_vtc', '4i0k_cd276', '4jqi_b', '4z18_cd274', '4zqk_pd1', '4zt1_e', '5esv_vh', '5esv_vl', '6al5_cd19', '6jxr_a', '6jxr_b', '6jxr_d', '6jxr_e', '6jxr_g', '6oil_vista', '6rp8_at', '6rp8_t', '6umt_cd273', '6x4g_cd275', '6x4g_icos', '7xq8_a', '7xq8_b', 'q71h61_ild', 'q9um44_hhl', 'p42081_cd86', 'q7z7d3_vtc', '1bqu_x', '1cdh_x', '1hnf_x', '1hxm_dx', '1hxm_gx', '4jqi_x', '4zt1_x', '5esv_vhx', '5esv_vlx', '6jxr_ax', '6jxr_bx', '1dr9_x', '3pv7_x', '4f9l_x', '4iok_x', '4z18_x', '6x4g_cd275x', 'q9um44_x'];
61377
+
61247
61378
  ic.refpdbArray = ['1bqu_fn3', '1cd8_igv', '1cdh_cd4', '1dr9_cd80', '1hnf_cd2', '1hxm_d', '1hxm_g', '1ifr_lamin', '1ncn_cd86', '1t6v_vnar', '1yjd_cd28', '2atp_a', '2atp_b', '2dm3_iset', '3kys_tead1', '3pv7_ncr', '4f9l_cd277', '4gos_vtc', '4i0k_cd276', '4jqi_b', '4z18_cd274', '4zqk_pd1', '4zt1_e', '5esv_vh', '5esv_vl', '6al5_cd19', '6jxr_a', '6jxr_b', '6jxr_d', '6jxr_e', '6jxr_g', '6oil_vista', '6rp8_at', '6rp8_t', '6umt_cd273', '6x4g_cd275', '6x4g_icos', '7xq8_a', '7xq8_b', 'q71h61_ild', 'q9um44_hhl'];
61248
61379
 
61249
61380
  if(ic.pdbDataArray) {
@@ -61267,7 +61398,7 @@ class Dssp {
61267
61398
  ic.pdbDataArray = await allPromise;
61268
61399
  await thisClass.parseRefPdbData(ic.pdbDataArray);
61269
61400
  // }
61270
- // else {
61401
+ // else {
61271
61402
  // ic.pdbDataArray = [];
61272
61403
  // for(let i = 0, il = pdbAjaxArray.length; i < il; ++i) {
61273
61404
  // try {
@@ -61450,7 +61581,8 @@ class Dssp {
61450
61581
 
61451
61582
  if(!domainid2score.hasOwnProperty(domainid) || queryData[0].score > domainid2score[domainid]) {
61452
61583
  domainid2score[domainid] = queryData[0].score;
61453
- if(!me.bNode) console.log(domainid + ' TM-score: ' + domainid2score[domainid] + ' matched ' + ic.refpdbArray[domainid_index[1]]);
61584
+ if(!me.bNode) console.log(domainid + ' TM-score: ' + domainid2score[domainid] + ' matched ' + ic.refpdbArray[domainid_index[1]]);
61585
+
61454
61586
  //ic.chainid2index[chainid] = domainid_index[1]; // could be several, just take the recent one for simplicity
61455
61587
  ic.domainid2index[domainid] = domainid_index[1];
61456
61588
  domainid2segs[domainid] = queryData[0].segs;
@@ -61487,9 +61619,11 @@ if(!me.bNode) {
61487
61619
  console.log("The reference PDB(s) for chain " + chainid + " are " + chainList);
61488
61620
  }
61489
61621
 
61622
+ let prevStrand;
61490
61623
  for(let i = 0, il = segArray.length; i < il; ++i) {
61491
61624
  let seg = segArray[i];
61492
- let qStartInt = parseInt(seg.q_start);
61625
+ let qStart = seg.q_start;
61626
+ parseInt(seg.q_start);
61493
61627
  let postfix = '';
61494
61628
  if(isNaN(seg.q_start)) postfix = seg.q_start.substr(seg.q_start.length - 1, 1);
61495
61629
 
@@ -61501,9 +61635,11 @@ if(!me.bNode) {
61501
61635
  // let refnum = (j + qStartInt).toString() + postfix;
61502
61636
 
61503
61637
  let resid = chainid + '_' + seg.t_start;
61504
- let refnum = qStartInt.toString() + postfix;
61638
+ //let refnum = qStartInt.toString() + postfix;
61639
+ let refnum = qStart + postfix;
61505
61640
 
61506
- let refnumLabel = thisClass.getLabelFromRefnum(refnum);
61641
+ let refnumLabel = thisClass.getLabelFromRefnum(refnum, prevStrand);
61642
+ prevStrand = refnumLabel.replace(new RegExp(refnum,'g'), '');
61507
61643
 
61508
61644
  ic.resid2refnum[resid] = refnumLabel;
61509
61645
 
@@ -61537,7 +61673,7 @@ if(!me.bNode) {
61537
61673
  }
61538
61674
  }
61539
61675
 
61540
- getLabelFromRefnum(oriRefnum) { let ic = this.icn3d; ic.icn3dui;
61676
+ getLabelFromRefnum(oriRefnum, prevStrand) { let ic = this.icn3d; ic.icn3dui;
61541
61677
  let refnum = parseInt(oriRefnum);
61542
61678
 
61543
61679
  // A^: 1xx or 2xx
@@ -61559,7 +61695,14 @@ if(!me.bNode) {
61559
61695
  else if(refnum >= 1000 && refnum < 1200) return "A" + oriRefnum;
61560
61696
  else if(refnum >= 1200 && refnum < 1300) return "A'" + oriRefnum;
61561
61697
  else if(refnum >= 1300 && refnum < 1400) return "A*" + oriRefnum;
61562
- else if(refnum >= 1400 && refnum < 2000) return "A" + oriRefnum;
61698
+ else if(refnum >= 1400 && refnum < 2000) {
61699
+ if(prevStrand.substr(0, 1) == 'A') {
61700
+ return prevStrand + oriRefnum;
61701
+ }
61702
+ else {
61703
+ return "A" + oriRefnum;
61704
+ }
61705
+ }
61563
61706
  else if(refnum >= 2000 && refnum < 3000) return "B" + oriRefnum;
61564
61707
  else if(refnum >= 3000 && refnum < 4000) return "C" + oriRefnum;
61565
61708
  else if(refnum >= 4000 && refnum < 5000) return "C'" + oriRefnum;
@@ -66197,7 +66340,7 @@ class SaveFile {
66197
66340
  $("#" + ic.pre + "title").html(title);
66198
66341
  }
66199
66342
  else if(me.cfg.mmdbafid !== undefined) {
66200
- let structureArray = me.cfg.mmdbafid.split(',');
66343
+ let structureArray = Object.keys(ic.structures); //me.cfg.mmdbafid.split(',');
66201
66344
  if(structureArray.length > 1) {
66202
66345
  title = 'Multiple structures: ' + structureArray;
66203
66346
  $("#" + ic.pre + "title").html(title);
@@ -66235,7 +66378,11 @@ class SaveFile {
66235
66378
  $("#" + ic.pre + "title").html(title);
66236
66379
  }
66237
66380
  else if(me.cfg.blast_rep_id) {
66238
- text = 'Query: ' + me.cfg.query_id + '; target: ' + me.cfg.blast_rep_id;
66381
+ let query_id = (me.cfg.oriQuery_id) ? me.cfg.oriQuery_id : me.cfg.query_id;
66382
+ let blast_rep_id = (me.cfg.oriBlast_rep_id) ? me.cfg.oriBlast_rep_id : me.cfg.blast_rep_id;
66383
+ if(query_id.length > 20) query_id = query_id.substr(0, 17) + '...';
66384
+
66385
+ text = 'Query: ' + query_id + '; target: ' + blast_rep_id;
66239
66386
  $("#" + ic.pre + "title").html(text + ", " + title);
66240
66387
  }
66241
66388
  else {
@@ -68476,6 +68623,7 @@ class VRButton {
68476
68623
  }
68477
68624
 
68478
68625
  //https://github.com/mrdoob/three.js/blob/master/examples/webxr_ar_cones.html
68626
+ //https://github.com/NikLever/Learn-WebXR/blob/master/libs/ARButton.js
68479
68627
 
68480
68628
  class ARButton {
68481
68629
  constructor(icn3d) {
@@ -68486,11 +68634,11 @@ class ARButton {
68486
68634
  }
68487
68635
 
68488
68636
  //static createButton( renderer, sessionInit = {} ) {
68489
- createButton( renderer, sessionInit = {} ) { let ic = this.icn3d, me = ic.icn3dui;
68637
+ createButton( renderer, sessionInit = {} ) { let ic = this.icn3d, me = ic.icn3dui;
68490
68638
 
68491
68639
  const button = document.createElement( 'button' );
68492
68640
 
68493
- function showStartAR( /*device*/ ) {
68641
+ function showStartAR( ) {
68494
68642
 
68495
68643
  if ( sessionInit.domOverlay === undefined ) {
68496
68644
 
@@ -68547,8 +68695,8 @@ class ARButton {
68547
68695
 
68548
68696
  }
68549
68697
 
68550
- function onSessionEnded( /*event*/ ) {
68551
- // reset orientation after VR
68698
+ function onSessionEnded( ) {
68699
+ // reset orientation after AR
68552
68700
  ic.transformCls.resetOrientation();
68553
68701
 
68554
68702
  ic.bAr = false;
@@ -68701,29 +68849,29 @@ class ARButton {
68701
68849
  return button;
68702
68850
 
68703
68851
  } else {
68704
- /*
68705
- const message = document.createElement( 'a' );
68852
+
68853
+ // const message = document.createElement( 'a' );
68706
68854
 
68707
- if ( window.isSecureContext === false ) {
68855
+ // if ( window.isSecureContext === false ) {
68708
68856
 
68709
- message.href = document.location.href.replace( /^http:/, 'https:' );
68710
- message.innerHTML = 'WEBXR NEEDS HTTPS'; // TODO Improve message
68857
+ // message.href = document.location.href.replace( /^http:/, 'https:' );
68858
+ // message.innerHTML = 'WEBXR NEEDS HTTPS'; // TODO Improve message
68711
68859
 
68712
- } else {
68860
+ // } else {
68713
68861
 
68714
- message.href = 'https://immersiveweb.dev/';
68715
- message.innerHTML = 'WEBXR NOT AVAILABLE';
68862
+ // message.href = 'https://immersiveweb.dev/';
68863
+ // message.innerHTML = 'WEBXR NOT AVAILABLE';
68716
68864
 
68717
- }
68865
+ // }
68718
68866
 
68719
- message.style.left = 'calc(66% - 90px)'; //'calc(50% - 90px)';
68720
- message.style.width = '180px';
68721
- message.style.textDecoration = 'none';
68867
+ // message.style.left = 'calc(66% - 90px)'; //'calc(50% - 90px)';
68868
+ // message.style.width = '180px';
68869
+ // message.style.textDecoration = 'none';
68722
68870
 
68723
- stylizeElement( message );
68871
+ // stylizeElement( message );
68872
+
68873
+ // return message;
68724
68874
 
68725
- return message;
68726
- */
68727
68875
  const message = document.createElement( 'span' );
68728
68876
  return message;
68729
68877
  }
@@ -68801,6 +68949,8 @@ class iCn3D {
68801
68949
  });
68802
68950
  // Enable VR
68803
68951
  this.renderer.xr.enabled = true;
68952
+ //https://www.udemy.com/course/learn-webxr/learn/lecture/20512848#questions/18941376
68953
+ //this.renderer.getContext().makeXRCompatible();
68804
68954
  }
68805
68955
  else {
68806
68956
  this.renderer = new THREE.WebGL1Renderer({
@@ -68883,7 +69033,7 @@ class iCn3D {
68883
69033
  // }
68884
69034
  // else { // WebGL2 supports EXT_frag_depth and ANGLE_instanced_arrays
68885
69035
  this.bExtFragDepth = true;
68886
- this.bImpo = false; //true;
69036
+ this.bImpo = true;
68887
69037
 
68888
69038
  //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.');
68889
69039
  // }
@@ -69458,7 +69608,7 @@ class iCn3DUI {
69458
69608
  //even when multiple iCn3D viewers are shown together.
69459
69609
  this.pre = this.cfg.divid + "_";
69460
69610
 
69461
- this.REVISION = '3.23.0';
69611
+ this.REVISION = '3.23.1';
69462
69612
 
69463
69613
  // In nodejs, iCn3D defines "window = {navigator: {}}"
69464
69614
  this.bNode = (Object.keys(window).length < 2) ? true : false;
@@ -69752,6 +69902,9 @@ iCn3DUI.prototype.show3DStructure = async function(pdbStr) { let me = this;
69752
69902
  else if(me.cfg.blast_rep_id !== undefined) {
69753
69903
  // ic.bNCBI = true;
69754
69904
  ic.inputid = me.cfg.query_id + ',' + me.cfg.blast_rep_id;
69905
+
69906
+ me.cfg.oriQuery_id = me.cfg.query_id;
69907
+ me.cfg.oriBlast_rep_id = me.cfg.blast_rep_id;
69755
69908
 
69756
69909
  // custom seqeunce has query_id such as "Query_78989" in BLAST
69757
69910
  if(me.cfg.query_id.substr(0,5) !== 'Query' && me.cfg.rid === undefined) {