icn3d 3.23.0 → 3.23.1

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.
@@ -20611,11 +20618,13 @@ class ControllerGestures extends THREE.EventDispatcher{
20611
20618
 
20612
20619
  //console.log(`ControllerGestures.onSelectEnd: startToEnd:${startToEnd.toFixed(2)} taps:${data.taps}`);
20613
20620
 
20614
- if (self.type === 'swipe'){
20615
- const direction = ( self.controller1.position.y < data.startPosition.y) ? "DOWN" : "UP";
20616
- self.dispatchEvent( { type:'swipe', direction } );
20617
- self.type = 'unknown';
20618
- }else if (self.type !== "pinch" && self.type !== "rotate" && self.type !== 'pan'){
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
+
20627
+ if (self.type !== "pinch" && self.type !== "rotate" && self.type !== 'pan'){
20619
20628
  if ( startToEnd < self.doubleClickLimit ){
20620
20629
  self.type = "tap";
20621
20630
  data.taps++;
@@ -20686,9 +20695,11 @@ class ControllerGestures extends THREE.EventDispatcher{
20686
20695
  switch( data1.taps ){
20687
20696
  case 1:
20688
20697
  this.dispatchEvent( { type: 'tap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20698
+ data1.prevTap = 'tap';
20689
20699
  break;
20690
20700
  case 2:
20691
20701
  this.dispatchEvent( { type: 'doubletap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
20702
+ data1.prevTap = 'doubletap';
20692
20703
  break;
20693
20704
  case 3:
20694
20705
  this.dispatchEvent( { type: 'tripletap', position: this.controller1.position, matrixWorld: this.controller1.matrixWorld } );
@@ -20708,39 +20719,38 @@ class ControllerGestures extends THREE.EventDispatcher{
20708
20719
  if (data2.startPosition !== undefined){
20709
20720
  //startPosition is undefined for 1/20 sec
20710
20721
  //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 ){
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') {
20715
20726
  this.type = 'pinch';
20716
20727
  this.startDistance = this.controller1.position.distanceTo( this.controller2.position );
20717
20728
  this.dispatchEvent( { type: 'pinch', delta: 0, scale: 1, initialise: true } );
20718
- }else {
20729
+ }else { // data1.prevTap == 'doubletap'
20719
20730
  const v1 = data2.startPosition.clone().sub( data1.startPosition ).normalize();
20720
20731
  const v2 = this.controller2.position.clone().sub( this.controller1.position ).normalize();
20721
- const theta = v1.angleTo( v2 );
20722
- if (Math.abs(theta) > 0.2){
20732
+ v1.angleTo( v2 );
20733
+ //if (Math.abs(theta) > 0.2){
20723
20734
  this.type = 'rotate';
20724
20735
  this.startVector = v2.clone();
20725
20736
  this.dispatchEvent( { type: 'rotate', theta: 0, initialise: true } );
20726
- }
20737
+ //}
20727
20738
  }
20728
20739
  }
20729
20740
  }else {
20730
20741
  //test for swipe or pan
20731
- let dist = data1.startPosition.distanceTo( this.controller1.position );
20742
+ data1.startPosition.distanceTo( this.controller1.position );
20732
20743
  elapsedTime = this.clock.getElapsedTime() - data1.startTime;
20733
- const velocity = dist/elapsedTime;
20734
20744
  //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){
20745
+ // if ( dist > 0.01 && velocity > 0.1 ){
20746
+ // const v = this.controller1.position.clone().sub( data1.startPosition );
20747
+ // let maxY = (Math.abs(v.y) > Math.abs(v.x)) && (Math.abs(v.y) > Math.abs(v.z));
20748
+ // if ( maxY )this.type = "swipe";
20749
+ // }else if (dist > 0.006 && velocity < 0.03){
20740
20750
  this.type = "pan";
20741
20751
  this.startPosition = this.controller1.position.clone();
20742
20752
  this.dispatchEvent( { type: 'pan', delta: new THREE.Vector3(), initialise: true } );
20743
- }
20753
+ // }
20744
20754
  }
20745
20755
  }
20746
20756
  }else if (this.type === 'pinch'){
@@ -21899,16 +21909,15 @@ class Scene {
21899
21909
  // https://github.com/mrdoob/three.js/blob/master/examples/webxr_ar_cones.html
21900
21910
  // https://github.com/mrdoob/three.js/blob/master/examples/webxr_vr_cubes.html
21901
21911
 
21912
+
21913
+
21902
21914
  //if(ic.bVr && !ic.dolly) {
21903
21915
  if(ic.bVr) {
21904
21916
  ic.canvasUI = this.createUI();
21917
+
21905
21918
  //ic.canvasUILog = this.createUILog();
21906
- // add canvasUI
21907
- //ic.cam.add( ic.canvasUI.mesh );
21908
21919
  //ic.cam.add( ic.canvasUILog.mesh );
21909
21920
 
21910
- //ic.cam.remove( ic.canvasUI.mesh );
21911
-
21912
21921
  ic.raycasterVR = new THREE.Raycaster();
21913
21922
  ic.workingMatrix = new THREE.Matrix4();
21914
21923
  ic.workingVector = new THREE.Vector3();
@@ -21982,67 +21991,63 @@ class Scene {
21982
21991
  });
21983
21992
  }
21984
21993
  else if(ic.bAr) {
21994
+ // the menu didn't work in AR
21995
+ // ic.canvasUILog = this.createUILog();
21996
+ // ic.cam.add( ic.canvasUILog.mesh );
21997
+
21985
21998
  //Add gestures here
21986
21999
  ic.gestures = new ControllerGestures(ic.renderer);
21987
22000
  ic.scene.add(ic.gestures.controller1);
21988
22001
  ic.scene.add(ic.gestures.controller2);
21989
22002
 
22003
+ // firts "tap", then "pinch" event
21990
22004
  ic.gestures.addEventListener('tap', (ev) => {
21991
- //if(!ic.mdl.visible) {
21992
- // ic.mdl.visible = true;
21993
- //}
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 ));
21994
22008
 
21995
22009
  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 ));
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 ));
22000
22012
  });
22001
22013
 
22014
+ // first "doubletap", then "rotate" event
22002
22015
  ic.gestures.addEventListener('doubletap', (ev) => {
22003
22016
  const controller = ic.gestures.controller1;
22004
- //ic.mdl.position.set( 0, 0, - 0.3 ).applyMatrix4( controller.matrixWorld );
22005
22017
  ic.mdl.position.set( -0.06, 0, - 0.6 ).applyMatrix4( controller.matrixWorld );
22006
- //ic.mdl.scale.copy(ic.mdl.scale.multiplyScalar(10));
22007
22018
  ic.mdl.scale.copy(new THREE.Vector3( 0.005, 0.005, 0.005 ));
22008
22019
  });
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
- // }
22020
+
22021
+ ic.gestures.addEventListener('pan', (ev) => { // touch across screen, move
22022
+ if(ev.initialise !== undefined) {
22023
+ thisClass.startPosition = ic.mdl.position.clone();
22024
+ }
22025
+ 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);
22029
+ }
22024
22030
  });
22025
22031
 
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
- // }
22032
+ ic.gestures.addEventListener('pinch', (ev) => { // two fingers opening or closing
22033
+ if(ev.initialise !== undefined) {
22034
+ thisClass.startScale = ic.mdl.scale.clone();
22035
+ }
22036
+ else {
22037
+ const scale = thisClass.startScale.clone().multiplyScalar(ev.scale);
22038
+ ic.mdl.scale.copy(scale);
22039
+ }
22034
22040
  });
22035
22041
 
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
- // }
22044
- });
22045
- */
22042
+ ic.gestures.addEventListener('rotate', (ev) => { // two fingers rotating around
22043
+ if(ev.initialise !== undefined) {
22044
+ thisClass.startQuaternion = ic.mdl.quaternion.clone();
22045
+ }
22046
+ else {
22047
+ ic.mdl.quaternion.copy(thisClass.startQuaternion);
22048
+ ic.mdl.rotateY(ev.theta);
22049
+ }
22050
+ });
22046
22051
  }
22047
22052
  }
22048
22053
 
@@ -22237,7 +22242,7 @@ class Scene {
22237
22242
  ic.cam.remove( ic.canvasUI.mesh );
22238
22243
  }
22239
22244
  catch(err) {
22240
- ic.canvasUILog.updateElement( "info", "ERROR: " + err );
22245
+ //ic.canvasUILog.updateElement( "info", "ERROR: " + err );
22241
22246
  }
22242
22247
  } },
22243
22248
  // 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 +22324,13 @@ class Scene {
22319
22324
  renderer: ic.renderer
22320
22325
  };
22321
22326
  const content = {
22322
- info: ""
22327
+ info: "Debug info"
22323
22328
  };
22324
22329
 
22325
22330
  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 );
22331
+
22332
+ //ui.mesh.position.set( 0, -2, -3 ); // VR
22333
+ ui.mesh.position.set( 0, -1, -2 ); // AR
22330
22334
 
22331
22335
  return ui;
22332
22336
  }
@@ -32115,12 +32119,13 @@ class Alternate {
32115
32119
 
32116
32120
  if ( ic.renderer.xr.isPresenting){
32117
32121
  if(ic.canvasUI) ic.canvasUI.update();
32118
- //if(ic.canvasUILog) ic.canvasUILog.update();
32122
+ if(ic.canvasUILog) ic.canvasUILog.update();
32119
32123
  }
32120
32124
  }
32121
32125
  else if(ic.bAr) {
32122
32126
  if ( ic.renderer.xr.isPresenting ){
32123
32127
  ic.gestures.update();
32128
+ if(ic.canvasUILog) ic.canvasUILog.update();
32124
32129
  }
32125
32130
  }
32126
32131
 
@@ -41397,6 +41402,8 @@ class ShowSeq {
41397
41402
  let strand2len_start_stop = {};
41398
41403
  let prevRefnumStr, prevPostfix;
41399
41404
 
41405
+ // sometimes one chain may have several Ig domains,set a index for each IgDomain
41406
+ let index = 1;
41400
41407
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41401
41408
  let currResi = ic.ParserUtilsCls.getResi(chnid, i);
41402
41409
  let residueid = chnid + '_' + currResi;
@@ -41409,7 +41416,7 @@ class ShowSeq {
41409
41416
 
41410
41417
  refnumStr = refnumStr_ori;
41411
41418
  refnum = parseInt(refnumStr);
41412
- postfix = refnumStr.replace(refnum.toString(), '');
41419
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41413
41420
 
41414
41421
  if(!bCustom && !kabat_or_imgt) {
41415
41422
  if(currStrand != prevStrand) { // reset currCnt
@@ -41418,26 +41425,51 @@ class ShowSeq {
41418
41425
  strand2len_start_stop[prevStrand + prevPostfix].len = currCnt - 1;
41419
41426
  strand2len_start_stop[prevStrand + prevPostfix].end = refnumStr;
41420
41427
  strand2len_start_stop[prevStrand + prevPostfix].nextStrand = currStrand;
41428
+
41429
+ console.log("end: " + residueid);
41421
41430
  }
41422
41431
 
41423
41432
  currCnt = 1;
41424
41433
  }
41425
41434
 
41426
41435
  // #9##
41427
- if(prevStrand && refnumStr.substr(1,1) == '9') { // loop region
41436
+ if(prevStrand && refnum > 1000 && refnumStr.substr(1,1) == '9') { // loop region
41428
41437
  if(currCnt == 1) { // start of a loop
41438
+ if(strand2len_start_stop.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41439
+ ++index;
41440
+ }
41441
+
41442
+ console.log("start: " + residueid + " refnumStr: " + refnumStr);
41443
+
41444
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41429
41445
  strand2len_start_stop[currStrand + postfix] = {};
41446
+
41430
41447
  strand2len_start_stop[currStrand + postfix].start = prevRefnumStr;
41431
41448
  strand2len_start_stop[currStrand + postfix].chainid = chnid;
41432
41449
  }
41433
41450
  refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
41434
41451
  refnumLabel = currStrand + refnumStr;
41452
+
41435
41453
  ++currCnt;
41436
41454
  }
41437
41455
  }
41438
41456
  }
41439
41457
  else {
41440
41458
  if(prevStrand && !bCustom && !kabat_or_imgt) {
41459
+ if(currCnt == 1) { // start of a loop
41460
+ if(strand2len_start_stop.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41461
+ ++index;
41462
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41463
+ strand2len_start_stop[currStrand + postfix] = {};
41464
+ }
41465
+ else {
41466
+ strand2len_start_stop[currStrand + postfix] = {};
41467
+ }
41468
+
41469
+ strand2len_start_stop[currStrand + postfix].start = prevRefnumStr;
41470
+ strand2len_start_stop[currStrand + postfix].chainid = chnid;
41471
+ }
41472
+
41441
41473
  // no ref num
41442
41474
  refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
41443
41475
  refnumLabel = currStrand + refnumStr;
@@ -41458,6 +41490,9 @@ class ShowSeq {
41458
41490
  }
41459
41491
 
41460
41492
  let refnumLabelNoPostfix;
41493
+ // sometimes one chain may have several Ig domains,set a index for each IgDomain
41494
+ index = 1;
41495
+ let appearedStrands = {}, currStrand_ori;
41461
41496
  for(let i = 0, il = giSeq.length; i < il; ++i) {
41462
41497
  bLoop = false;
41463
41498
 
@@ -41471,9 +41506,13 @@ class ShowSeq {
41471
41506
  }
41472
41507
  else {
41473
41508
  refnumLabel = ic.resid2refnum[residueid];
41509
+ let bNotShow = false;
41510
+
41474
41511
  if(refnumLabel) {
41475
41512
  refnumStr_ori = refnumLabel.replace(/'/g, '').replace(/\*/g, '').replace(/\^/g, '').substr(1); // C', C''
41476
41513
  currStrand = refnumLabel.replace(new RegExp(refnumStr_ori,'g'), '');
41514
+ currStrand_ori = currStrand;
41515
+
41477
41516
  currFirstDigit = refnumStr_ori.substr(0, 1);
41478
41517
 
41479
41518
  refnumLabelNoPostfix = currStrand + parseInt(refnumStr_ori);
@@ -41494,18 +41533,30 @@ class ShowSeq {
41494
41533
  else {
41495
41534
  refnumStr = refnumStr_ori;
41496
41535
  refnum = parseInt(refnumStr);
41497
- postfix = refnumStr.replace(refnum.toString(), '');
41536
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41498
41537
 
41499
41538
  // #9##
41500
- if(prevStrand && refnumStr.substr(1,1) == '9') { // loop region
41539
+ if(prevStrand && refnum > 1000 && refnumStr.substr(1,1) == '9') { // loop region
41501
41540
  bLoop = true;
41502
41541
 
41542
+ if(currCnt == 1) { // start of a loop
41543
+ if(appearedStrands.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41544
+ ++index;
41545
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41546
+ }
41547
+
41548
+ appearedStrands[currStrand + postfix] = 1;
41549
+ }
41550
+
41503
41551
  let result = this.getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix);
41504
41552
 
41505
41553
  refnumStr = result.refnumStr;
41506
41554
  refnumLabel = result.refnumLabel;
41507
41555
  refnumLabelNoPostfix = result.refnumLabelNoPostfix;
41508
41556
 
41557
+ bNotShow = result.bNotShow;
41558
+ currStrand = refnumLabel.replace(new RegExp(refnumStr,'g'), '');
41559
+
41509
41560
  ++currCnt;
41510
41561
  }
41511
41562
  }
@@ -41545,7 +41596,7 @@ class ShowSeq {
41545
41596
  }
41546
41597
  }
41547
41598
  else {
41548
- html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop);
41599
+ html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow);
41549
41600
  }
41550
41601
  }
41551
41602
  else {
@@ -41556,16 +41607,29 @@ class ShowSeq {
41556
41607
  // no ref num
41557
41608
  bLoop = true;
41558
41609
 
41610
+ if(currCnt == 1) { // start of a loop
41611
+ if(appearedStrands.hasOwnProperty(currStrand + postfix)) { // the strand appeared in 2nd Id domain
41612
+ ++index;
41613
+ }
41614
+
41615
+ postfix = refnumStr.replace(refnum.toString(), '') + '_' + index;
41616
+
41617
+ appearedStrands[currStrand + postfix] = 1;
41618
+ }
41619
+
41559
41620
  // use previous postfix
41560
41621
  let result = this.getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix);
41561
41622
 
41562
41623
  refnumStr = result.refnumStr;
41563
41624
  refnumLabel = result.refnumLabel;
41564
41625
  refnumLabelNoPostfix = result.refnumLabelNoPostfix;
41626
+
41627
+ bNotShow = result.bNotShow;
41628
+ currStrand = refnumLabel.replace(new RegExp(refnumStr,'g'), '');
41565
41629
 
41566
41630
  ++currCnt;
41567
41631
 
41568
- html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop);
41632
+ html += this.getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow);
41569
41633
  }
41570
41634
  else {
41571
41635
  html += '<span></span>';
@@ -41591,7 +41655,7 @@ class ShowSeq {
41591
41655
  ic.chainsMapping[chnid][residueid] = refnumLabelNoPostfix;
41592
41656
  }
41593
41657
 
41594
- prevStrand = currStrand;
41658
+ prevStrand = currStrand_ori; //currStrand;
41595
41659
  }
41596
41660
 
41597
41661
  html += '<span class="icn3d-residueNum"></span>';
@@ -41607,6 +41671,8 @@ class ShowSeq {
41607
41671
  getAdjustedRefnum(strand2len_start_stop, currStrand, currCnt, currFirstDigit, postfix) { let ic = this.icn3d; ic.icn3dui;
41608
41672
  let refnumStr, refnumLabel, refnumLabelNoPostfix;
41609
41673
 
41674
+ let bNotShow = false; // do not show the label
41675
+
41610
41676
  if(strand2len_start_stop[currStrand + postfix]) {
41611
41677
  let start = parseInt(strand2len_start_stop[currStrand + postfix].start);
41612
41678
  let end = parseInt(strand2len_start_stop[currStrand + postfix].end);
@@ -41626,10 +41692,15 @@ class ShowSeq {
41626
41692
  else {
41627
41693
  refnum = end - (len + 1 - currCnt);
41628
41694
  refnumStr = refnum + postfixEnd;
41695
+
41629
41696
  refnumLabel = (strand2len_start_stop[currStrand + postfix].nextStrand !== undefined) ? strand2len_start_stop[currStrand + postfix].nextStrand + refnumStr : ' ' + refnumStr;
41630
41697
  }
41631
41698
 
41632
41699
  refnumLabelNoPostfix = currStrand + refnum;
41700
+
41701
+ if(currCnt == 0 || currCnt == halfLen || currCnt == halfLen + 1 || currCnt == end - 1) {
41702
+ bNotShow = true;
41703
+ }
41633
41704
  }
41634
41705
  else {
41635
41706
  // refnumStr = (parseInt(currFirstDigit) * 1000 + 900 + currCnt).toString();
@@ -41638,18 +41709,20 @@ class ShowSeq {
41638
41709
  refnumStr = '';
41639
41710
  refnumLabel = '';
41640
41711
  refnumLabelNoPostfix = '';
41712
+
41713
+ bNotShow = true;
41641
41714
  }
41642
41715
 
41643
- return {refnumStr: refnumStr, refnumLabel: refnumLabel, refnumLabelNoPostfix: refnumLabelNoPostfix};
41716
+ return {refnumStr: refnumStr, refnumLabel: refnumLabel, refnumLabelNoPostfix: refnumLabelNoPostfix, bNotShow: bNotShow};
41644
41717
  }
41645
41718
 
41646
- getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop) { let ic = this.icn3d, me = ic.icn3dui;
41719
+ getRefnumHtml(residueid, refnumStr, refnumStr_ori, refnumLabel, currStrand, bLoop, bNotShow) { let ic = this.icn3d, me = ic.icn3dui;
41647
41720
  let refnum = parseInt(refnumStr).toString();
41648
41721
  let color = this.getRefnumColor(currStrand);
41649
41722
  let colorStr = 'style="color:' + color + '"';
41650
41723
 
41651
41724
  let lastTwo = parseInt(refnum.substr(refnum.length - 2, 2));
41652
- let lastThree = parseInt(refnum.substr(refnum.length - 3, 3));
41725
+ parseInt(refnum.substr(refnum.length - 3, 3));
41653
41726
 
41654
41727
  let html = '';
41655
41728
 
@@ -41659,7 +41732,7 @@ class ShowSeq {
41659
41732
 
41660
41733
  html += '<span ' + colorStr + ' title="' + refnumLabel + '"><b>' + refnumLabel.substr(0, 1) + '</b>' + refnumLabel.substr(1) + '</span>';
41661
41734
  }
41662
- else if(lastTwo % 2 == 0 && lastTwo != 52 && lastThree != 901) {
41735
+ else if(lastTwo % 2 == 0 && lastTwo != 52 && !bNotShow) { // don't show label for the first, middle, and last loop residues
41663
41736
  // e.g., 2152a
41664
41737
  let lastTwoStr = isNaN(refnumStr) ? lastTwo + refnumStr.substr(refnumStr.length - 1, 1) : lastTwo;
41665
41738
  html += '<span ' + colorStr + ' title="' + refnumLabel + '">' + lastTwoStr + '</span>';
@@ -61244,6 +61317,7 @@ class Dssp {
61244
61317
  else {
61245
61318
  //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
61319
  //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'];
61320
+
61247
61321
  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
61322
 
61249
61323
  if(ic.pdbDataArray) {
@@ -61267,7 +61341,7 @@ class Dssp {
61267
61341
  ic.pdbDataArray = await allPromise;
61268
61342
  await thisClass.parseRefPdbData(ic.pdbDataArray);
61269
61343
  // }
61270
- // else {
61344
+ // else {
61271
61345
  // ic.pdbDataArray = [];
61272
61346
  // for(let i = 0, il = pdbAjaxArray.length; i < il; ++i) {
61273
61347
  // try {
@@ -61450,7 +61524,8 @@ class Dssp {
61450
61524
 
61451
61525
  if(!domainid2score.hasOwnProperty(domainid) || queryData[0].score > domainid2score[domainid]) {
61452
61526
  domainid2score[domainid] = queryData[0].score;
61453
- if(!me.bNode) console.log(domainid + ' TM-score: ' + domainid2score[domainid] + ' matched ' + ic.refpdbArray[domainid_index[1]]);
61527
+ if(!me.bNode) console.log(domainid + ' TM-score: ' + domainid2score[domainid] + ' matched ' + ic.refpdbArray[domainid_index[1]]);
61528
+
61454
61529
  //ic.chainid2index[chainid] = domainid_index[1]; // could be several, just take the recent one for simplicity
61455
61530
  ic.domainid2index[domainid] = domainid_index[1];
61456
61531
  domainid2segs[domainid] = queryData[0].segs;
@@ -61487,9 +61562,11 @@ if(!me.bNode) {
61487
61562
  console.log("The reference PDB(s) for chain " + chainid + " are " + chainList);
61488
61563
  }
61489
61564
 
61565
+ let prevStrand;
61490
61566
  for(let i = 0, il = segArray.length; i < il; ++i) {
61491
61567
  let seg = segArray[i];
61492
- let qStartInt = parseInt(seg.q_start);
61568
+ let qStart = seg.q_start;
61569
+ parseInt(seg.q_start);
61493
61570
  let postfix = '';
61494
61571
  if(isNaN(seg.q_start)) postfix = seg.q_start.substr(seg.q_start.length - 1, 1);
61495
61572
 
@@ -61501,9 +61578,11 @@ if(!me.bNode) {
61501
61578
  // let refnum = (j + qStartInt).toString() + postfix;
61502
61579
 
61503
61580
  let resid = chainid + '_' + seg.t_start;
61504
- let refnum = qStartInt.toString() + postfix;
61581
+ //let refnum = qStartInt.toString() + postfix;
61582
+ let refnum = qStart + postfix;
61505
61583
 
61506
- let refnumLabel = thisClass.getLabelFromRefnum(refnum);
61584
+ let refnumLabel = thisClass.getLabelFromRefnum(refnum, prevStrand);
61585
+ prevStrand = refnumLabel.replace(new RegExp(refnum,'g'), '');
61507
61586
 
61508
61587
  ic.resid2refnum[resid] = refnumLabel;
61509
61588
 
@@ -61537,7 +61616,7 @@ if(!me.bNode) {
61537
61616
  }
61538
61617
  }
61539
61618
 
61540
- getLabelFromRefnum(oriRefnum) { let ic = this.icn3d; ic.icn3dui;
61619
+ getLabelFromRefnum(oriRefnum, prevStrand) { let ic = this.icn3d; ic.icn3dui;
61541
61620
  let refnum = parseInt(oriRefnum);
61542
61621
 
61543
61622
  // A^: 1xx or 2xx
@@ -61559,7 +61638,14 @@ if(!me.bNode) {
61559
61638
  else if(refnum >= 1000 && refnum < 1200) return "A" + oriRefnum;
61560
61639
  else if(refnum >= 1200 && refnum < 1300) return "A'" + oriRefnum;
61561
61640
  else if(refnum >= 1300 && refnum < 1400) return "A*" + oriRefnum;
61562
- else if(refnum >= 1400 && refnum < 2000) return "A" + oriRefnum;
61641
+ else if(refnum >= 1400 && refnum < 2000) {
61642
+ if(prevStrand.substr(0, 1) == 'A') {
61643
+ return prevStrand + oriRefnum;
61644
+ }
61645
+ else {
61646
+ return "A" + oriRefnum;
61647
+ }
61648
+ }
61563
61649
  else if(refnum >= 2000 && refnum < 3000) return "B" + oriRefnum;
61564
61650
  else if(refnum >= 3000 && refnum < 4000) return "C" + oriRefnum;
61565
61651
  else if(refnum >= 4000 && refnum < 5000) return "C'" + oriRefnum;
@@ -66197,7 +66283,7 @@ class SaveFile {
66197
66283
  $("#" + ic.pre + "title").html(title);
66198
66284
  }
66199
66285
  else if(me.cfg.mmdbafid !== undefined) {
66200
- let structureArray = me.cfg.mmdbafid.split(',');
66286
+ let structureArray = Object.keys(ic.structures); //me.cfg.mmdbafid.split(',');
66201
66287
  if(structureArray.length > 1) {
66202
66288
  title = 'Multiple structures: ' + structureArray;
66203
66289
  $("#" + ic.pre + "title").html(title);
@@ -68476,6 +68562,7 @@ class VRButton {
68476
68562
  }
68477
68563
 
68478
68564
  //https://github.com/mrdoob/three.js/blob/master/examples/webxr_ar_cones.html
68565
+ //https://github.com/NikLever/Learn-WebXR/blob/master/libs/ARButton.js
68479
68566
 
68480
68567
  class ARButton {
68481
68568
  constructor(icn3d) {
@@ -68486,11 +68573,11 @@ class ARButton {
68486
68573
  }
68487
68574
 
68488
68575
  //static createButton( renderer, sessionInit = {} ) {
68489
- createButton( renderer, sessionInit = {} ) { let ic = this.icn3d, me = ic.icn3dui;
68576
+ createButton( renderer, sessionInit = {} ) { let ic = this.icn3d, me = ic.icn3dui;
68490
68577
 
68491
68578
  const button = document.createElement( 'button' );
68492
68579
 
68493
- function showStartAR( /*device*/ ) {
68580
+ function showStartAR( ) {
68494
68581
 
68495
68582
  if ( sessionInit.domOverlay === undefined ) {
68496
68583
 
@@ -68547,8 +68634,8 @@ class ARButton {
68547
68634
 
68548
68635
  }
68549
68636
 
68550
- function onSessionEnded( /*event*/ ) {
68551
- // reset orientation after VR
68637
+ function onSessionEnded( ) {
68638
+ // reset orientation after AR
68552
68639
  ic.transformCls.resetOrientation();
68553
68640
 
68554
68641
  ic.bAr = false;
@@ -68701,29 +68788,29 @@ class ARButton {
68701
68788
  return button;
68702
68789
 
68703
68790
  } else {
68704
- /*
68705
- const message = document.createElement( 'a' );
68791
+
68792
+ // const message = document.createElement( 'a' );
68706
68793
 
68707
- if ( window.isSecureContext === false ) {
68794
+ // if ( window.isSecureContext === false ) {
68708
68795
 
68709
- message.href = document.location.href.replace( /^http:/, 'https:' );
68710
- message.innerHTML = 'WEBXR NEEDS HTTPS'; // TODO Improve message
68796
+ // message.href = document.location.href.replace( /^http:/, 'https:' );
68797
+ // message.innerHTML = 'WEBXR NEEDS HTTPS'; // TODO Improve message
68711
68798
 
68712
- } else {
68799
+ // } else {
68713
68800
 
68714
- message.href = 'https://immersiveweb.dev/';
68715
- message.innerHTML = 'WEBXR NOT AVAILABLE';
68801
+ // message.href = 'https://immersiveweb.dev/';
68802
+ // message.innerHTML = 'WEBXR NOT AVAILABLE';
68716
68803
 
68717
- }
68804
+ // }
68718
68805
 
68719
- message.style.left = 'calc(66% - 90px)'; //'calc(50% - 90px)';
68720
- message.style.width = '180px';
68721
- message.style.textDecoration = 'none';
68806
+ // message.style.left = 'calc(66% - 90px)'; //'calc(50% - 90px)';
68807
+ // message.style.width = '180px';
68808
+ // message.style.textDecoration = 'none';
68722
68809
 
68723
- stylizeElement( message );
68810
+ // stylizeElement( message );
68811
+
68812
+ // return message;
68724
68813
 
68725
- return message;
68726
- */
68727
68814
  const message = document.createElement( 'span' );
68728
68815
  return message;
68729
68816
  }
@@ -68801,6 +68888,8 @@ class iCn3D {
68801
68888
  });
68802
68889
  // Enable VR
68803
68890
  this.renderer.xr.enabled = true;
68891
+ //https://www.udemy.com/course/learn-webxr/learn/lecture/20512848#questions/18941376
68892
+ //this.renderer.getContext().makeXRCompatible();
68804
68893
  }
68805
68894
  else {
68806
68895
  this.renderer = new THREE.WebGL1Renderer({