From 7f45a18cf2165071e98f145b29e47331ab19efb6 Mon Sep 17 00:00:00 2001 From: "Wang, Jiyao" Date: Fri, 15 Jul 2016 20:12:03 -0400 Subject: [PATCH 1/4] add MMTF support, enable data input by url, add disulfide bond display --- README.md | 11 +- full.html | 78 ++- gulpfile.js | 1 + icn3d.html | 24 +- index.html | 25 +- package.json | 2 +- src/full_ui.js | 1132 ++++++++++++++++++++++++++++++++++++----- src/icn3d.js | 334 +++++++++--- src/icn3d_full_ui.css | 3 + src/mmtf.js | 1 + src/simple_ui.js | 495 +++++++++++++++++- 11 files changed, 1848 insertions(+), 258 deletions(-) create mode 100644 src/mmtf.js diff --git a/README.md b/README.md index 36a94b92..1a2276ef 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,13 @@ We provided two versions of iCn3D widgets: [basic interface](https://www.ncbi.nl Either of these widgets could be easily added to your own web pages. Please see the [help page](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d.html) for more details. -Complete package of iCn3D including Three.js and jQuery can be downloaded from [https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d-1.0.1.zip](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d-1.0.1.zip). The "Download ZIP" link in this page does not include these third-party libraries. +Complete package of iCn3D including Three.js and jQuery can be downloaded from [https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d-1.1.0.zip](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d-1.1.0.zip). The "Download ZIP" link in this page does not include these third-party libraries. ## Usage -iCn3D page accepts the following IDs: +iCn3D accepts the following IDs: +* mmtfid: MMTF ID, e.g., [https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?mmtfid=2por](https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?mmtfid=2por) * pdbid: PDB ID, e.g., [https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?pdbid=2por](https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?pdbid=2por) * mmcifid: mmCIF ID, e.g., [https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?mmcifid=2por](https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?mmcifid=2por) * mmdbid: NCBI MMDB ID, e.g., [https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?mmdbid=2por](https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?mmdbid=2por) @@ -24,7 +25,9 @@ iCn3D page accepts the following IDs: * cid: PubChem Compound ID, e.g., [https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?cid=2244](https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?cid=2244) * align: Two PDB IDs or MMDB IDs for structure alignment, e.g., [https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?align=1hho,4n7n](https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?align=1hho,4n7n) -See the [help page](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d.html) for more details on these parameters. +iCn3D also accepts the following file types: PDB, mmCIF, Mol2, SDF, and XYZ. The files can be passed through a url, e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?type=pdb&url=https%3A%2F%2Ffiles.rcsb.org%2Fview%2F1gpk.pdb: + +See the [help page](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d.html) for more details. ## Third-party libraries used @@ -86,7 +89,7 @@ gulp gh-pages ## Change log -The production version [icn3d-1.0.1](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d-1.0.1.zip) was release on May 16, 2016. All previous releases can be found at the [help page](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d.html#log). +The production version [icn3d-1.1.0](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d-1.1.0.zip) was release on July 14, 2016. The new binary MMTF file format was supported. A new "Analysis" menu was added with an option to show disulfide bonds. Users can also input data from a url, either through the UI or through a encoded url parameter "?type=pdb&url=...", e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?type=pdb&url=https%3A%2F%2Ffiles.rcsb.org%2Fview%2F1gpk.pdb. ## Contact diff --git a/full.html b/full.html index b141bac2..d5298dd9 100644 --- a/full.html +++ b/full.html @@ -4,9 +4,9 @@ - + -iCn3D Structure Viewer +iCn3D: Web-based 3D Structure Viewer
@@ -25,33 +25,41 @@ + + @@ -287,6 +288,7 @@

What is iCn3D Structure Viewer?downloadGi
downloadMmcif
downloadMmdb
+downloadMmcif
downloadPdb
@@ -523,12 +525,14 @@

How to use iCn3D Structure Viewer in your html page:

URL parameters for the advanced interfaceback to top

+ + @@ -549,6 +553,7 @@

Commands for the advanced interfacea) Retrieve by ID +

@@ -560,7 +565,9 @@

Commands for the advanced interfaceMol2 File:

+ + @@ -638,6 +645,11 @@

Commands for the advanced interface
  • Different selections can be unioned (with "or", default), intersected (with "and"), or negated (with "not"). For example, ":1-10 or :Lys" selects all residues 1-10 and all Lys residues. ":1-10 and :Lys" selects all Lys residues in the range of residue number 1-10. ":1-10 or not :Lys" selects all residues 1-10, which are not Lys residues. +Full commands in url or command window: +
      +
    • Select without saving the set: select #1,2,3.A,B,C:5-10,Lys,ligands@CA,C
      +
    • Select and save: select #1,2,3.A,B,C:5-10,Lys,ligands@CA,C | name my_name | description my_description +

    @@ -1276,6 +1288,9 @@

    API Documents of the advanced UI library iCn3DUIparameters for the 3D viewer by calling the function loadAtomDataIn. The deferred parameter was resolved after the parsing so that other javascript code can be executed. +

    downloadMmtf(mmtfid)    
    +MMTF is a new binary data format besides the previous PDB and mmCIF formats for 3D structures. The JavaScript APIs at http://mmtf.rcsb.org/ was used to load and parse the data. +

    downloadPdb(pdbid)    
    Ajax call was used to get the atom data from the "pdbid". This function was deferred so that it can be chained together with other deferred functions for sequential execution. A wrapper was added to support both http and https. @@ -1482,7 +1497,10 @@

    API Documents of the advanced UI library iCn3DUI

    Change Log:back to top

    -The production version icn3d-1.0.1 was release on May 16, 2016. +The production version icn3d-1.1.0 was release on July 14, 2016. The new binary MMTF file format was supported. A new "Analysis" menu was added with an option to show disulfide bonds. Users can also input data from a url, either through the UI or through a encoded url parameter "?type=pdb&url=...", e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?type=pdb&url=https%3A%2F%2Ffiles.rcsb.org%2Fview%2F1gpk.pdb. +

    + +The production version icn3d-1.0.1 was release on May 16, 2016.

    The production version icn3d-1.0.0 was release on April 28, 2016. diff --git a/index.html b/index.html index ba6ba07e..268ae991 100644 --- a/index.html +++ b/index.html @@ -4,9 +4,9 @@ - + -iCn3D Structure Viewer +iCn3D: Web-based 3D Structure Viewer
    @@ -25,6 +25,7 @@ + @@ -32,8 +33,7 @@ // separating the GET parameters from the current URL if(document.URL.indexOf("?") === -1) { - window.location = "icn3d.html"; - //alert("Please include '?pdbid=1GPK,2POR,...' in your url"); + alert("Please include '?pdbid=1GPK,2POR,...' in your url"); } var getParams = document.URL.split("?"); @@ -50,11 +50,15 @@ var gi = params.gi; var mmdbid = params.mmdbid; + var mmtfid = params.mmtfid; var pdbid = params.pdbid; var cid = params.cid; var mmcifid = params.mmcifid; + var urlname = params.url; + var urltype = (params.type === undefined) ? 'pdb' : params.type; var align = params.align; + var term = params.term; var width = params.width; var height = params.height; @@ -77,7 +81,7 @@ $( document ).ready(function() { function setupViewer(idName, idValue) { - var maxStructure = 1; // show max 1 structures + var maxStructure = 5; // show max 5 structures var idArray = idValue.replace(/\s/g, '').split(','); @@ -107,11 +111,17 @@ } } + if(mmtfid !== undefined) setupViewer('mmtfid', mmtfid); if(pdbid !== undefined) setupViewer('pdbid', pdbid); if(cid !== undefined) setupViewer('cid', cid); if(mmcifid !== undefined) setupViewer('mmcifid', mmcifid); if(mmdbid !== undefined) setupViewer('mmdbid', mmdbid); if(gi !== undefined) setupViewer('gi', gi); + if(term !== undefined) setupViewer('term', term); + if(urlname !== undefined) { + urlname = decodeURIComponent(urlname); + setupViewer('url', urltype + '|' + urlname); + } // e.g., align=103701,1,4,68563,1,167 [mmdbid1,biounit,molecule,mmdbid2,biounit,molecule] if(align !== undefined) { @@ -134,6 +144,5 @@ - - - \ No newline at end of file + + diff --git a/package.json b/package.json index 04d0c7ba..ec4660d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "icn3d", - "version": "1.0.1", + "version": "1.1.0", "description": "iCn3D Structure Viewer", "main": "index.html", "scripts": { diff --git a/src/full_ui.js b/src/full_ui.js index a02576b9..fe8a429e 100644 --- a/src/full_ui.js +++ b/src/full_ui.js @@ -37,7 +37,7 @@ var iCn3DUI = function(cfg) { //me.MENU_WIDTH = 690; me.MENU_WIDTH = 750; - me.LESSWIDTH = 0; //20; + me.LESSWIDTH = 20; me.LESSWIDTH_RESIZE = 20; me.LESSHEIGHT = 20; @@ -65,7 +65,7 @@ var iCn3DUI = function(cfg) { me.options = {}; me.options['camera'] = 'perspective'; //perspective, orthographic me.options['background'] = 'black'; //black, grey, white - me.options['color'] = 'spectrum'; //spectrum, secondary structure, charge, hydrophobic, chain, residue, atom, red, green, blue, magenta, yellow, cyan, white, grey, custom + me.options['color'] = 'spectrum'; //spectrum, secondary structure, charge, hydrophobic, conserved, chain, residue, atom, red, green, blue, magenta, yellow, cyan, white, grey, custom me.options['sidechains'] = 'nothing'; //lines, stick, ball and stick, sphere, nothing me.options['proteins'] = 'ribbon'; //ribbon, strand, cylinder and plate, schematic, c alpha trace, b factor tube, lines, stick, ball and stick, sphere, nothing me.options['surface'] = 'nothing'; //Van der Waals surface, molecular surface, solvent accessible surface, nothing @@ -75,6 +75,8 @@ var iCn3DUI = function(cfg) { me.options['water'] = 'nothing'; //sphere, dot, nothing me.options['ions'] = 'sphere'; //sphere, dot, nothing me.options['hbonds'] = 'no'; //yes, no + me.options['ncbonds'] = 'no'; //yes, no + me.options['ssbonds'] = 'no'; //yes, no //me.options['labels'] = 'no'; //yes, no //me.options['lines'] = 'no'; //yes, no me.options['rotationcenter'] = 'molecule center'; //molecule center, pick center, display center @@ -84,6 +86,8 @@ var iCn3DUI = function(cfg) { me.options['picking'] = 'residue'; //no, atom, residue, strand me.options['nucleotides'] = 'nucleotide cartoon'; //nucleotide cartoon, schematic, phosphorus trace, lines, stick, ball and stick, sphere, nothing + if(me.cfg.align !== undefined) me.options['color'] = 'conserved'; + me.modifyIcn3d(); me.bAddCommands = true; @@ -109,54 +113,33 @@ iCn3DUI.prototype = { iCn3D.prototype.showPicking = function(atom) { this.showPickingBase(atom); - //if(this.picking === 1) { - // if(!me.icn3d.bShiftKey) { - // me.removeSeqChainBkgd(); - // me.removeSeqResidueBkgd(); - // } - // } - // else - if(this.picking === 1 || this.picking === 2) { - // highlight the sequence background - var idArray = this.id.split('_'); // id: div0_canvas - me.pre = idArray[0] + "_"; - - var pickedResidue = atom.structure + '_' + atom.chain + '_' + atom.resi; - - me.clearSelection(); - - if(!me.icn3d.bShiftKey) { - me.removeSeqChainBkgd(); - me.removeSeqResidueBkgd(); - } + // highlight the sequence background + var idArray = this.id.split('_'); // id: div0_canvas + me.pre = idArray[0] + "_"; - if($("#" + me.pre + pickedResidue).length !== 0) { - $("#" + me.pre + pickedResidue).addClass('icn3d-highlightSeq'); - } + me.clearSelection(); - // add "align" in front of id so that full sequence and aligned sequence will not conflict - if($("#align" + me.pre + pickedResidue).length !== 0) { - $("#align" + me.pre + pickedResidue).addClass('icn3d-highlightSeq'); - } + if(!me.icn3d.bShiftKey && !me.icn3d.bCtrlKey) { + me.removeSeqChainBkgd(); + me.removeSeqResidueBkgd(); } - else if(this.picking === 3) { - // highlight the sequence background - var idArray = this.id.split('_'); // id: div0_canvas - me.pre = idArray[0] + "_"; - - var firstAtom = this.getFirstAtomObj(this.highlightAtoms); - var lastAtom = this.getLastAtomObj(this.highlightAtoms); - me.clearSelection(); + var firstAtom, lastAtom; - if(!me.icn3d.bShiftKey) { - me.removeSeqChainBkgd(); - me.removeSeqResidueBkgd(); - } + if(me.icn3d.bShiftKey) { + firstAtom = this.getFirstAtomObj(this.highlightAtoms); + lastAtom = this.getLastAtomObj(this.highlightAtoms); + } + else { + firstAtom = this.getFirstAtomObj(this.pickedAtomList); + lastAtom = this.getLastAtomObj(this.pickedAtomList); + } - for(var i = firstAtom.resi; i <= lastAtom.resi; ++i) { - var pickedResidue = atom.structure + '_' + atom.chain + '_' + i; + var pickedResidue, prevResidue = ''; + for(var i = firstAtom.serial; i <= lastAtom.serial; ++i) { + pickedResidue = this.atoms[i].structure + '_' + this.atoms[i].chain + '_' + this.atoms[i].resi; + if(prevResidue !== pickedResidue) { if($("#" + me.pre + pickedResidue).length !== 0) { $("#" + me.pre + pickedResidue).addClass('icn3d-highlightSeq'); } @@ -166,6 +149,8 @@ iCn3DUI.prototype = { $("#align" + me.pre + pickedResidue).addClass('icn3d-highlightSeq'); } } + + prevResidue = pickedResidue; } var transformation = {}; @@ -216,8 +201,6 @@ iCn3DUI.prototype = { me.deferred = $.Deferred(function() { if(me.isSessionStorageSupported()) me.getCommandsBeforeCrash(); - me.setTopMenusHtml(me.divid); - me.setViewerWidthHeight(); var width, height; @@ -236,6 +219,11 @@ iCn3DUI.prototype = { height = me.cfg.height; } + me.realWidth = width; + me.realHeight = height; + + me.setTopMenusHtml(me.divid); + me.allEventFunctions(); me.allCustomEvents(); @@ -273,7 +261,7 @@ iCn3DUI.prototype = { var id = loadCommand.substr(loadCommand.lastIndexOf(' ') + 1); // reload only if viewing the same structure - if(id === me.cfg.pdbid || id === me.cfg.mmdbid || id === me.cfg.gi || id === me.cfg.cid || id === me.cfg.mmcifid || id === me.cfg.align) { + if(id === me.cfg.mmtfid || id === me.cfg.pdbid || id === me.cfg.mmdbid || id === me.cfg.gi || id === me.cfg.cid || id === me.cfg.mmcifid || id === me.cfg.align) { me.loadScript(me.commandsBeforeCrash, true); return; @@ -282,7 +270,26 @@ iCn3DUI.prototype = { me.icn3d.moleculeTitle = ''; - if(me.cfg.pdbid !== undefined) { + if(me.cfg.url !== undefined) { + var type_url = me.cfg.url.split('|'); + var type = type_url[0]; + var url = type_url[1]; + + me.icn3d.moleculeTitle = ""; + me.inputid = undefined; + + me.setLogCommand('load a ' + type + ' file from the url ' + url, false); + + me.downloadUrl(url, type); + } + else if(me.cfg.mmtfid !== undefined) { + me.inputid = me.cfg.mmtfid; + + me.setLogCommand('load mmtf ' + me.cfg.mmtfid, true); + + me.downloadMmtf(me.cfg.mmtfid); + } + else if(me.cfg.pdbid !== undefined) { me.inputid = me.cfg.pdbid; me.setLogCommand('load pdb ' + me.cfg.pdbid, true); @@ -348,7 +355,8 @@ iCn3DUI.prototype = { me.downloadAlignment(me.cfg.align); } else { - alert("Please input a gi, MMDB ID, PDB ID, CID, or mmCIF ID..."); + //alert("Please input a gi, MMDB ID, PDB ID, CID, or mmCIF ID..."); + alert("Please use the \"File\" menu to retrieve a structure of interest or to display a local file."); } }); @@ -434,7 +442,7 @@ iCn3DUI.prototype = { if(id === 'color') { me.icn3d.setColorByOptions(me.icn3d.options, me.icn3d.highlightAtoms); - //me.icn3d.draw(options2); + me.icn3d.draw(); setTimeout(function(){ @@ -449,7 +457,6 @@ iCn3DUI.prototype = { me.icn3d.render(); } else { - //me.icn3d.draw(options2); me.icn3d.draw(); } }, @@ -537,7 +544,7 @@ iCn3DUI.prototype = { } } - if(me.bAddLogs) { + if(me.bAddLogs && me.cfg.showcommand) { me.icn3d.logs.push(str); // move cursor to the end, and scroll to the end @@ -551,7 +558,11 @@ iCn3DUI.prototype = { if(me.bInitial) { if(me.cfg.command !== undefined && me.cfg.command !== '') { me.icn3d.bRender = false; - me.icn3d.draw(me.options); + + //me.icn3d.draw(me.options); + jQuery.extend(me.icn3d.options, me.options); + me.icn3d.draw(); + me.icn3d.bRender = true; //var bAddPrevCommand = false; @@ -559,7 +570,9 @@ iCn3DUI.prototype = { me.loadScript(me.cfg.command); } else { - me.icn3d.draw(me.options); + //me.icn3d.draw(me.options); + jQuery.extend(me.icn3d.options, me.options); + me.icn3d.draw(); } if(Object.keys(me.icn3d.structures).length > 1) { @@ -1659,28 +1672,18 @@ iCn3DUI.prototype = { me.icn3d.maxD = centerAtomsResults.maxD; if (me.icn3d.maxD < 25) me.icn3d.maxD = 25; -// var options2 = {}; - //show selected rotationcenter -// options2['rotationcenter'] = 'display center'; - -// me.icn3d.setAtomStyleByOptions(me.options); - -// me.icn3d.draw(options2); - //show selected rotationcenter me.icn3d.options['rotationcenter'] = 'display center'; - // show side chains in case residues are all stand-alone residues - //me.icn3d.options['sidechains'] = 'lines'; - -// me.icn3d.setAtomStyleByOptions(me.icn3d.options); me.saveSelectionIfSelected(); me.icn3d.draw(); }, selectByCommand: function (select, commandname, commanddesc) { var me = this; - var commandStr = (select.trim().substr(0, 6) === 'select') ? select.trim().substr(7) : select.trim(); + var selectTmp = select.replace(/ AND /g, ' and ').replace(/ OR /g, ' or '); + + var commandStr = (selectTmp.trim().substr(0, 6) === 'select') ? selectTmp.trim().substr(7) : selectTmp.trim(); // each select command may have several commands separated by ' or ' var commandArray = commandStr.split(' or '); @@ -2039,13 +2042,110 @@ iCn3DUI.prototype = { me.changeCustomResidues(nameArray); - me.saveSelectionIfSelected(); + me.saveSelectionIfSelected(); - //me.icn3d.draw(options2); - me.icn3d.draw(); + // show side chains for the selected atoms + me.setStyle('sidechains', 'ball and stick'); + me.setStyle('water', 'dot'); + //me.setLogCommand('style sidechains ball and stick', true); + + //me.icn3d.draw(); } }, + // between the highlighted and the rest atoms + showNcbonds: function () { var me = this; + me.icn3d.options["ncbonds"] = "yes"; + + var select = 'noncovalent bonds'; + + var complement = {}; + + for(var i in me.icn3d.atoms) { + if(!me.icn3d.highlightAtoms.hasOwnProperty(i) && me.icn3d.displayAtoms.hasOwnProperty(i)) { + complement[i] = me.icn3d.atoms[i]; + } + } + + var firstAtom = me.icn3d.getFirstAtomObj(me.icn3d.highlightAtoms); + + if(Object.keys(complement).length > 0 && Object.keys(me.icn3d.highlightAtoms).length > 0) { + me.icn3d.calculateNonCovalentBonds(complement, me.icn3d.intersectHash2Atoms(me.icn3d.displayAtoms, me.icn3d.highlightAtoms)); + + me.clearSelection(); + + var residues = {}, atomArray = []; + + for (var i in me.icn3d.highlightAtoms) { + var residueid = me.icn3d.atoms[i].structure + '_' + me.icn3d.atoms[i].chain + '_' + me.icn3d.atoms[i].resi; + residues[residueid] = 1; + + atomArray.push(i); + } + + var commandname = 'ncbonds_' + firstAtom.serial; + var commanddesc = 'all atoms that have noncovalent bonds with the selected atoms'; + me.addCustomSelection(Object.keys(residues), atomArray, commandname, commanddesc, select, true); + + var nameArray = [commandname]; + + me.changeCustomResidues(nameArray); + + me.saveSelectionIfSelected(); + + // show side chains for the selected atoms + me.setStyle('sidechains', 'ball and stick'); + //me.setLogCommand('style sidechains ball and stick', true); + + //me.icn3d.draw(); + } + }, + + // show all disulfide bonds + showSsbonds: function () { var me = this; + me.icn3d.options["ssbonds"] = "yes"; + + var select = 'disulfide bonds'; + + me.clearSelection(); + + var residues = {}, atomArray = []; + + for (var i = 0, lim = Math.floor(me.icn3d.ssbondpoints.length / 2); i < lim; i++) { + var res1 = me.icn3d.ssbondpoints[2 * i], res2 = me.icn3d.ssbondpoints[2 * i + 1]; + + residues[res1] = 1; + residues[res2] = 1; + + me.icn3d.highlightAtoms = me.icn3d.unionHash(me.icn3d.highlightAtoms, me.icn3d.residues[res1]); + me.icn3d.highlightAtoms = me.icn3d.unionHash(me.icn3d.highlightAtoms, me.icn3d.residues[res2]); + + for(var j in me.icn3d.residues[res1]) { + atomArray.push(j); + } + + for(var j in me.icn3d.residues[res2]) { + atomArray.push(j); + } + } + + var commandname = 'ssbonds'; + var commanddesc = 'all atoms that have disulfide bonds'; + me.addCustomSelection(Object.keys(residues), atomArray, commandname, commanddesc, select, true); + + var nameArray = [commandname]; + + me.changeCustomResidues(nameArray); + + me.saveSelectionIfSelected(); + + // show side chains for the selected atoms + me.setStyle('sidechains', 'ball and stick'); + //me.setLogCommand('style sidechains ball and stick', true); + + //me.icn3d.draw(); + }, + addLabel: function (text, x, y, z, size, color, background, type) { var me = this; var label = {}; // Each label contains 'position', 'text', 'color', 'background' @@ -2361,10 +2461,14 @@ iCn3DUI.prototype = { var preCommands = []; if(me.icn3d.commands.length > 0) preCommands[0] = me.icn3d.commands[0]; - me.icn3d.commands = dataStr.split('\n'); - + me.icn3d.commands = preCommands.concat(dataStr.split('\n')); me.STATENUMBER = me.icn3d.commands.length; + me.execCommands(me.STATENUMBER); + +/* + me.icn3d.commands = dataStr.split('\n'); + if(bStatefile !== undefined && bStatefile) { me.icn3d.commands = preCommands.concat(me.icn3d.commands); me.STATENUMBER = me.icn3d.commands.length; @@ -2377,6 +2481,7 @@ iCn3DUI.prototype = { me.icn3d.commands = preCommands.concat(me.icn3d.commands); me.STATENUMBER = me.icn3d.commands.length; } +*/ }, loadSelection: function (dataStr) { var me = this; @@ -2492,7 +2597,9 @@ iCn3DUI.prototype = { me.updateSeqWinForCurrentAtoms(); - me.icn3d.draw(me.icn3d.optionsHistory[steps - 1]); + //me.icn3d.draw(me.icn3d.optionsHistory[steps - 1]); + jQuery.extend(me.icn3d.options, me.icn3d.optionsHistory[steps - 1]); + me.icn3d.draw(); } else { me.updateSeqWinForCurrentAtoms(); @@ -2555,7 +2662,11 @@ iCn3DUI.prototype = { // load pdb, mmcif, mmdb, cid var id = loadStr.substr(loadStr.lastIndexOf(' ') + 1); - if(command.indexOf('pdb') !== -1) { + if(command.indexOf('mmtf') !== -1) { + me.downloadMmtf(id); + me.cfg.mmtfid = id; + } + else if(command.indexOf('pdb') !== -1) { me.downloadPdb(id); me.cfg.pdbid = id; } @@ -2918,18 +3029,40 @@ iCn3DUI.prototype = { me.showHbonds(threshold); } + else if(command.indexOf('noncovalent bonds') !== -1) { + me.showNcbonds(); + } + else if(command.indexOf('disulfide bonds') !== -1) { + me.showSsbonds(); + } + else if(command.indexOf('cross linkage') !== -1) { + me.icn3d.bShowCrossResidueBond = true; + me.icn3d.draw(); + } else if(command.indexOf('set hbonds off') !== -1) { me.icn3d.options["hbonds"] = "no"; me.icn3d.draw(); - } + } + else if(command.indexOf('set noncovalent bonds off') !== -1) { + me.icn3d.options["ncbonds"] = "no"; + me.icn3d.draw(); + } + else if(command.indexOf('set disulfide bonds off') !== -1) { + me.icn3d.options["ssbonds"] = "no"; + me.icn3d.draw(); + } + else if(command.indexOf('set cross linkage off') !== -1) { + me.icn3d.bShowCrossResidueBond = false; + me.icn3d.draw(); + } else if(command.indexOf('set lines off') !== -1) { //me.icn3d.options["lines"] = "no"; me.icn3d.draw(); - } + } else if(command.indexOf('set labels off') !== -1) { //me.icn3d.options["labels"] = "no"; me.icn3d.draw(); - } + } else if(command.indexOf('back') !== -1) { me.back(); } @@ -2942,6 +3075,11 @@ iCn3DUI.prototype = { else if(command.indexOf('select all') !== -1) { me.selectAll(); + me.icn3d.addHighlightObjects(); + } + else if(command.indexOf('clear all') !== -1) { + me.selectAll(); + //me.icn3d.addHighlightObjects(); } else if(command.indexOf('select complement') !== -1) { me.selectComplement(); @@ -3018,6 +3156,7 @@ iCn3DUI.prototype = { html += "
  • "; html += " "; html += " "; + html += " "; html += " "; html += "
    ParameterBasic interface
    (index.html)
    Advanced interface
    (full.html)
    Description
    mmtfidYesYesMMTF ID, e.g., ?mmtfid=2por
    pdbidYesYesPDB ID, e.g., ?pdbid=2por
    mmcifidYesYesmmCIF ID, e.g., ?mmcifid=2por
    mmdbidYesYesNCBI MMDB ID or PDB ID, e.g., ?mmdbid=2por
    giYesYesNCBI protein gi number, e.g., ?gi=827343227
    cidYesYesPubChem Compound ID, e.g., ?cid=2244
    alignYesYesTwo PDB IDs or MMDB IDs for structure alignment, e.g., ?align=1hho,4n7n
    urlYesYesUse the url (encoded) to retrieve the 3D structure. The url requires another parameter "type", e.g., ?type=pdb&url=https%3A%2F%2Ffiles.rcsb.org%2Fview%2F1gpk.pdb
    widthYesYesWidth of the structure image. It can be percentage such as '100%', or pixel values such as 400. The default is '100%'.
    heightYesYesHeight of the structure image. It can be percentage such as '100%', or pixel values such as 400. The default is '100%'.
    MMTF ID: load mmtf [1GPK]
    PDB ID: load pdb [1GPK]
    MMDB ID: load mmdb [1GPK]
    gi: load gi [827343227]
    [no command available]
    SDF File: [no command available]
    XYZ File: [no command available]
    URL: [no command available]
    State/Script File: [no command available]
    Selection File: [no command available]
    c) Export File
    State File: [no command available]
    " + me.setMenu3() + "" + me.setMenu4() + "" + me.setMenu5() + "" + me.setMenu5b() + "" + me.setMenu6() + ""; @@ -3041,11 +3180,18 @@ iCn3DUI.prototype = { html += " "; - html += "
    Loading the structure...
    "; + if(me.cfg.mmtfid === undefined) { + if(me.realHeight < 300) { + html += "
    Loading the structure...
    "; + } + else { + html += "
    Loading the structure...
    "; + } + } html += " Your browser does not support WebGL."; // separate for the log box - html += me.setLogWindow(); + if(me.cfg.showcommand === undefined || me.cfg.showcommand) html += me.setLogWindow(); html += " "; @@ -3074,6 +3220,8 @@ iCn3DUI.prototype = { $("#" + me.pre + "accordion5").hover( function(){ $("#" + me.pre + "accordion5 div").css("display", "block"); }, function(){ $("#" + me.pre + "accordion5 div").css("display", "none"); } ); + $("#" + me.pre + "accordion5b").hover( function(){ $("#" + me.pre + "accordion5b div").css("display", "block"); }, function(){ $("#" + me.pre + "accordion5b div").css("display", "none"); } ); + $("#" + me.pre + "accordion6").hover( function(){ $("#" + me.pre + "accordion6 div").css("display", "block"); }, function(){ $("#" + me.pre + "accordion6 div").css("display", "none"); } ); }, @@ -3087,6 +3235,7 @@ iCn3DUI.prototype = { html += "
    "; html += ""; + html += "
    "; + html += "MMTF ID: "; + html += ""; + html += "
    "; + html += "
    "; html += "PDB ID: "; html += ""; @@ -3676,6 +3883,11 @@ iCn3DUI.prototype = { html += ""; html += "
    "; + html += "
    "; + html += "Enter the PDB IDs or MMDB IDs of two structures that have been found to be similar by VAST or VAST+ :

    ID1:       ID2:

    "; + html += "   "; + html += "
    "; + html += "
    "; html += "Mol2 File: "; html += ""; @@ -3688,6 +3900,17 @@ iCn3DUI.prototype = { html += "XYZ File: "; html += ""; html += "
    "; + html += "
    "; + html += "File type: "; + html += ""; + html += "URL: "; + html += ""; + html += "
    "; html += "
    "; html += "mmCIF File: "; @@ -3780,7 +4003,7 @@ iCn3DUI.prototype = { html += "2. Size:
    "; html += "3. Color:
    "; html += "4. Background:
    "; - html += "5. Pick TWO atoms
    "; + html += "5. Pick TWO atoms while holding \"Alt\" key
    "; html += "6. "; html += "
    "; @@ -3793,7 +4016,7 @@ iCn3DUI.prototype = { html += ""; html += "
    "; - html += " 1. Pick TWO atoms
    "; + html += " 1. Pick TWO atoms while holding \"Alt\" key
    "; html += " 2. "; html += "
    "; @@ -3814,7 +4037,7 @@ iCn3DUI.prototype = { var html = ""; html += "
    "; - html += " "; + html += "
    "; if(me.cfg.cid === undefined) { html += " "; //} - html += " "; + html += " "; html += " "; @@ -3934,8 +4157,9 @@ iCn3DUI.prototype = { // highlight condensed view //if(me.icn3d.molid2ss !== undefined) me.icn3d.drawHelixBrick(me.icn3d.molid2ss, me.icn3d.molid2color, me.icn3d.bHighlight); // condensed view + ////me.icn3d.draw(); + //me.icn3d.addHighlightObjects(); - me.icn3d.draw(); }, selectComplement: function() { var me = this; @@ -4141,6 +4365,14 @@ iCn3DUI.prototype = { }, //menu 1 + clickMenu1_mmtfid: function() { var me = this; + $("#" + me.pre + "menu1_mmtfid").click(function(e) { + //e.preventDefault(); + + me.openDialog(me.pre + 'dl_mmtfid', 'Please input MMTF ID'); + }); + }, + clickMenu1_pdbid: function() { var me = this; $("#" + me.pre + "menu1_pdbid").click(function(e) { //e.preventDefault(); @@ -4149,6 +4381,14 @@ iCn3DUI.prototype = { }); }, + clickMenu1_align: function() { var me = this; + $("#" + me.pre + "menu1_align").click(function(e) { + //e.preventDefault(); + + me.openDialog(me.pre + 'dl_align', 'Please input two PDB IDs or MMDB IDs'); + }); + }, + clickMenu1_pdbfile: function() { var me = this; $("#" + me.pre + "menu1_pdbfile").click(function(e) { //e.preventDefault(); @@ -4178,6 +4418,13 @@ iCn3DUI.prototype = { me.openDialog(me.pre + 'dl_xyzfile', 'Please input XYZ File'); }); }, + clickMenu1_urlfile: function() { var me = this; + $("#" + me.pre + "menu1_urlfile").click(function(e) { + //e.preventDefault(); + + me.openDialog(me.pre + 'dl_urlfile', 'Please specify the file type and URL'); + }); + }, clickMenu1_mmciffile: function() { var me = this; $("#" + me.pre + "menu1_mmciffile").click(function(e) { @@ -4311,8 +4558,9 @@ iCn3DUI.prototype = { var url = "./full.html?"; - var pos = inpara.indexOf('&command='); - var inparaWithoutCommand = (pos !== -1 ) ? inpara.substr(0, pos) : inpara; + var pos = -1; + if(me.cfg.inpara !== undefined) pos = me.cfg.inpara.indexOf('&command='); + var inparaWithoutCommand = (pos !== -1 ) ? me.cfg.inpara.substr(0, pos) : me.cfg.inpara; url += inparaWithoutCommand.substr(1) + '&command='; @@ -4458,13 +4706,29 @@ iCn3DUI.prototype = { }, clickMenu2_selectall: function() { var me = this; - $("#" + me.pre + "menu2_selectall").add("#" + me.pre + "selectall").click(function (e) { + $("#" + me.pre + "menu2_selectall").click(function (e) { //e.preventDefault(); + //me.setLogCommand("select all", true); me.setLogCommand("select all", true); me.selectAll(); + + me.icn3d.addHighlightObjects(); + + }); + + $("#" + me.pre + "clearall").click(function (e) { + //e.preventDefault(); + + me.setLogCommand("clear all", true); + + me.selectAll(); + + me.icn3d.draw(); + }); + }, clickMenu2_selectcomplement: function() { var me = this; @@ -4571,7 +4835,6 @@ iCn3DUI.prototype = { clickmenu3_proteinsStrand: function() { var me = this; $("#" + me.pre + "menu3_proteinsStrand").click(function (e) { //e.preventDefault(); - me.setStyle('proteins', 'strand'); me.setLogCommand('style proteins strand', true); @@ -4659,7 +4922,6 @@ iCn3DUI.prototype = { }); }, - clickMenu3_sidechainsLines: function() { var me = this; $("#" + me.pre + "menu3_sidechainsLines").click(function (e) { //e.preventDefault(); @@ -5522,7 +5784,92 @@ iCn3DUI.prototype = { me.icn3d.lines['hbond'] = []; - me.icn3d.draw(); + me.setStyle('sidechains', 'nothing'); + me.setStyle('water', 'nothing'); + + //me.icn3d.draw(); + }); + }, + + clickMenu6_ncbondsYes: function() { var me = this; + $("#" + me.pre + "menu6_ncbondsYes").click(function (e) { + //e.preventDefault(); + + var select = "noncovalent bonds"; + me.setLogCommand(select, true); + + me.showNcbonds(); + }); + }, + + clickMenu6_ncbondsNo: function() { var me = this; + $("#" + me.pre + "menu6_ncbondsNo").click(function (e) { + //e.preventDefault(); + + me.icn3d.options["ncbonds"] = "no"; + + var select = "set noncovalent bonds off"; + me.setLogCommand(select, true); + + me.icn3d.lines['ncbond'] = []; + + me.icn3d.draw(); + }); + }, + + clickMenu6_ssbondsYes: function() { var me = this; + $("#" + me.pre + "menu6_ssbondsYes").click(function (e) { + //e.preventDefault(); + + var select = "disulfide bonds"; + me.setLogCommand(select, true); + + me.showSsbonds(); + }); + }, + + clickMenu6_ssbondsNo: function() { var me = this; + $("#" + me.pre + "menu6_ssbondsNo").click(function (e) { + //e.preventDefault(); + + me.icn3d.options["ssbonds"] = "no"; + + var select = "set disulfide bonds off"; + me.setLogCommand(select, true); + + me.icn3d.lines['ssbond'] = []; + + me.setStyle('sidechains', 'nothing'); + + //me.icn3d.draw(); + }); + }, + + clickMenu6_clbondsYes: function() { var me = this; + $("#" + me.pre + "menu6_clbondsYes").click(function (e) { + //e.preventDefault(); + + var select = "cross linkage"; + me.setLogCommand(select, true); + + me.icn3d.bShowCrossResidueBond = true; + + me.icn3d.draw(); + }); + }, + + clickMenu6_clbondsNo: function() { var me = this; + $("#" + me.pre + "menu6_clbondsNo").click(function (e) { + //e.preventDefault(); + + me.icn3d.options["clbonds"] = "no"; + + var select = "set cross linkage off"; + me.setLogCommand(select, true); + + me.icn3d.bShowCrossResidueBond = false; + + me.icn3d.draw(); }); }, @@ -6137,6 +6484,18 @@ iCn3DUI.prototype = { }); }, + clickReload_mmtf: function() { var me = this; + $("#" + me.pre + "reload_mmtf").click(function(e) { + e.preventDefault(); + + dialog.dialog( "close" ); + + me.setLogCommand("load mmtf " + $("#" + me.pre + "mmtfid").val(), false); + + window.open('http://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?mmtfid=' + $("#" + me.pre + "mmtfid").val(), '_blank'); + }); + }, + clickReload_pdb: function() { var me = this; $("#" + me.pre + "reload_pdb").click(function(e) { e.preventDefault(); @@ -6152,6 +6511,34 @@ iCn3DUI.prototype = { }); }, + clickReload_align_refined: function() { var me = this; + $("#" + me.pre + "reload_align_refined").click(function(e) { + e.preventDefault(); + + dialog.dialog( "close" ); + + var alignment = $("#" + me.pre + "alignid1").val() + "," + $("#" + me.pre + "alignid2").val(); + + me.setLogCommand("load alignment " + alignment + ' | parameters &atype=1', false); + + window.open('http://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?align=' + alignment + '&showalignseq=1&atype=1', '_blank'); + }); + }, + + clickReload_align_ori: function() { var me = this; + $("#" + me.pre + "reload_align_ori").click(function(e) { + e.preventDefault(); + + dialog.dialog( "close" ); + + var alignment = $("#" + me.pre + "alignid1").val() + "," + $("#" + me.pre + "alignid2").val(); + + me.setLogCommand("load alignment " + alignment + ' | parameters &atype=0', false); + + window.open('http://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?align=' + alignment + '&showalignseq=1&atype=0', '_blank'); + }); + }, + clickReload_mmcif: function() { var me = this; $("#" + me.pre + "reload_mmcif").click(function(e) { e.preventDefault(); @@ -6410,6 +6797,19 @@ iCn3DUI.prototype = { }); }, + clickReload_urlfile: function() { var me = this; + $("#" + me.pre + "reload_urlfile").click(function(e) { + e.preventDefault(); + + dialog.dialog( "close" ); + + var type = $("#" + me.pre + "filetype").val(); + var url = $("#" + me.pre + "urlfile").val(); + + me.downloadUrl(url, type); + }); + }, + clickReload_mmciffile: function() { var me = this; $("#" + me.pre + "reload_mmciffile").click(function(e) { e.preventDefault(); @@ -6898,11 +7298,14 @@ iCn3DUI.prototype = { me.clickHlStyleObject(); me.clickAlternate(); + me.clickMenu1_mmtfid(); me.clickMenu1_pdbid(); + me.clickMenu1_align(); me.clickMenu1_pdbfile(); me.clickMenu1_mol2file(); me.clickMenu1_sdffile(); me.clickMenu1_xyzfile(); + me.clickMenu1_urlfile(); me.clickMenu1_mmciffile(); me.clickMenu1_mmcifid(); me.clickMenu1_mmdbid(); @@ -7027,6 +7430,12 @@ iCn3DUI.prototype = { me.clickMenu6_showaxisNo(); me.clickMenu6_hbondsYes(); me.clickMenu6_hbondsNo(); + me.clickMenu6_ncbondsYes(); + me.clickMenu6_ncbondsNo(); + me.clickMenu6_ssbondsYes(); + me.clickMenu6_ssbondsNo(); + me.clickMenu6_clbondsYes(); + me.clickMenu6_clbondsNo(); me.clickStructureid(); me.clickChainid(); me.clickAlignChainid(); @@ -7038,10 +7447,14 @@ iCn3DUI.prototype = { me.clickShow_selected_atom(); me.clickCommand_apply(); me.clickReload_pdb(); + me.clickReload_align_refined(); + me.clickReload_align_ori(); + me.clickReload_mmtf(); me.clickReload_pdbfile(); me.clickReload_mol2file(); me.clickReload_sdffile(); me.clickReload_xyzfile(); + me.clickReload_urlfile(); me.clickReload_mmciffile(); me.clickReload_mmcif(); me.clickReload_mmdb(); @@ -7116,7 +7529,12 @@ iCn3DUI.prototype = { iCn3DUI.prototype.rotateStructure = function (direction, bInitial) { var me = this; if(me.icn3d.bStopRotate) return false; - if(me.icn3d.rotateCount > me.icn3d.rotateCountMax) return false; + if(me.icn3d.rotateCount > me.icn3d.rotateCountMax) { + // back to the original orientation + me.icn3d.resetOrientation(); + + return false; + } ++me.icn3d.rotateCount; if(bInitial !== undefined && bInitial) { @@ -7324,6 +7742,8 @@ iCn3DUI.prototype = { // The PDB service doesn't support https, so use our reverse-proxy // service when using https var uri, dataType; + +/* if(document.location.protocol !== "https:") { //uri = "http://www.rcsb.org/pdb/files/" + pdbid + ".pdb"; uri = "http://files.rcsb.org/view/" + pdbid + ".pdb"; @@ -7338,6 +7758,11 @@ iCn3DUI.prototype = { window.open(url, '_self'); return; } +*/ + + uri = "https://files.rcsb.org/view/" + pdbid + ".pdb"; + + dataType = "text"; me.icn3d.bCid = undefined; @@ -7356,12 +7781,50 @@ iCn3DUI.prototype = { if($("#" + me.pre + "commandlog")) $("#" + me.pre + "commandlog").show(); }, success: function(data) { - if(document.location.protocol !== "https:") { - me.loadPdbData(data); - } - else { - me.loadPdbData(data.data); // from mmcifparser.cgi - } + //if(document.location.protocol !== "https:") { + // me.loadPdbData(data); + //} + //else { + // me.loadPdbData(data.data); // from mmcifparser.cgi + //} + + me.loadPdbData(data); + } + }); + }; + + iCn3DUI.prototype.downloadUrl = function (url, type) { var me = this; + var dataType = "text"; + + me.icn3d.bCid = undefined; + + $.ajax({ + url: url, + dataType: dataType, + cache: true, + beforeSend: function() { + if($("#" + me.pre + "wait")) $("#" + me.pre + "wait").show(); + if($("#" + me.pre + "canvas")) $("#" + me.pre + "canvas").hide(); + if($("#" + me.pre + "commandlog")) $("#" + me.pre + "commandlog").hide(); + }, + complete: function() { + if($("#" + me.pre + "wait")) $("#" + me.pre + "wait").hide(); + if($("#" + me.pre + "canvas")) $("#" + me.pre + "canvas").show(); + if($("#" + me.pre + "commandlog")) $("#" + me.pre + "commandlog").show(); + }, + success: function(data) { + if(type === 'pdb') { + me.loadPdbData(data); + } + else if(type === 'mol2') { + me.loadMol2Data(data); + } + else if(type === 'sdf') { + me.loadSdfData(data); + } + else if(type === 'xyz') { + me.loadXyzData(data); + } } }); }; @@ -7392,6 +7855,375 @@ iCn3DUI.prototype = { if(me.deferred !== undefined) me.deferred.resolve(); if(me.deferred2 !== undefined) me.deferred2.resolve(); }; + // from the 2016 NCBI hackathon in Orlando: https://github.com/NCBI-Hackathons/iCN3D-MMTF + iCn3DUI.prototype.downloadMmtf = function (mmtfid) { var me = this; + // The MMTF service doesn't support https, use http instead + var uri, dataType; + if(document.location.protocol === "https:") { + var url = document.location.href; + url = url.replace('https', 'http'); + window.open(url, '_self'); + return; + } + + MMTF.fetch( + mmtfid, + // onLoad callback + function( mmtfData ){ + + me.icn3d.init(); + + var pmin = new THREE.Vector3( 9999, 9999, 9999); + var pmax = new THREE.Vector3(-9999,-9999,-9999); + var psum = new THREE.Vector3(); + + //console.log(mmtfData); + + var id = mmtfData.structureId; + + me.icn3d.moleculeTitle = mmtfData.title; + + // bioAsembly + if(mmtfData.bioAssemblyList[0].transformList.length > 1) { + me.icn3d.biomtMatrices = []; + for(var i = 0, il = mmtfData.bioAssemblyList[0].transformList.length; i < il; ++i) { + var biomt = new THREE.Matrix4().identity(); + + for(var j = 0, jl = mmtfData.bioAssemblyList[0].transformList[i].matrix.length; j < jl; ++j) { + biomt.elements[j] = mmtfData.bioAssemblyList[0].transformList[i].matrix[j]; + } + + me.icn3d.biomtMatrices.push(biomt); + } + } + + var oriindex2serial = {}; + + // save SG atoms in CYS residues + var SGAtomSerialArray = []; + + var prevSS = 'coil'; + var prevChain = ''; + + var serial = 0; + + var structure, chain, resn, resi, ss, ssbegin, ssend; + var het, bProtein, bNucleotide; + var elem, atomName, coord, b, alt; + + var callbackDict = { + onModel: function( modelData ){ + structure = (modelData.modelIndex === 0) ? id : id + (modelData.modelIndex + 1).toString(); + }, + onChain: function( chainData ){ + chain = chainData.chainName; // or chainData.chainId + var chainid = structure + '_' + chain; + + if(me.icn3d.structures[structure] === undefined) me.icn3d.structures[structure] = []; + me.icn3d.structures[structure].push(chainid); + + if(me.icn3d.chainsAnnoTitle[chainid] === undefined ) me.icn3d.chainsAnnoTitle[chainid] = []; + if(me.icn3d.chainsAnnoTitle[chainid][0] === undefined ) me.icn3d.chainsAnnoTitle[chainid][0] = []; + if(me.icn3d.chainsAnnoTitle[chainid][1] === undefined ) me.icn3d.chainsAnnoTitle[chainid][1] = []; + me.icn3d.chainsAnnoTitle[chainid][0].push(''); + me.icn3d.chainsAnnoTitle[chainid][1].push('SS'); + }, + onGroup: function( groupData ){ + resn = groupData.groupName; + resi = groupData.groupId; + var resid = structure + '_' + chain + '_' + resi; + + if(groupData.secStruct === 0 || groupData.secStruct === 2 || groupData.secStruct === 4) { + ss = 'helix'; + } + else if(groupData.secStruct === 3) { + ss = 'sheet'; + } + else { + ss = 'coil'; + } + + // no residue can be both ssbegin and ssend in DSSP calculated secondary structures + var bSetPrevResidue = 0; // 0: no need to reset, 1: reset previous residue to "ssbegin = true", 2: reset previous residue to "ssend = true" + + if(chain !== prevChain) { + // new chain + if(ss !== 'coil') { + ssbegin = true; + ssend = false; + } + else { + ssbegin = false; + ssend = false; + } + } + else if(ss !== prevSS) { + if(prevSS === 'coil') { + ssbegin = true; + ssend = false; + } + else if(ss === 'coil') { + bSetPrevResidue = 2; + ssbegin = false; + ssend = false; + } + else if( (prevSS === 'sheet' && ss === 'helix') || (prevSS === 'helix' && ss === 'sheet')) { + bSetPrevResidue = 1; + ssbegin = true; + ssend = false; + } + } + else { + ssbegin = false; + ssend = false; + } + + if(bSetPrevResidue == 1) { //1: reset previous residue to "ssbegin = true" + var prevResid = structure + '_' + chain + '_' + (resi - 1).toString(); + for(var i in me.icn3d.residues[prevResid]) { + me.icn3d.atoms[i].ssbegin = true; + me.icn3d.atoms[i].ssend = false; + } + } + else if(bSetPrevResidue == 2) { //2: reset previous residue to "ssend = true" + var prevResid = structure + '_' + chain + '_' + (resi - 1).toString(); + for(var i in me.icn3d.residues[prevResid]) { + me.icn3d.atoms[i].ssbegin = false; + me.icn3d.atoms[i].ssend = true; + } + } + + prevSS = ss; + prevChain = chain; + + het = false; + bProtein = false; + bNucleotide = false; + if(groupData.chemCompType.toLowerCase() === 'non-polymer' || groupData.chemCompType.toLowerCase() === 'other' || groupData.chemCompType.toLowerCase().indexOf('saccharide') !== -1) { + het = true; + } + else if(groupData.chemCompType.toLowerCase().indexOf('peptide') !== -1) { + bProtein = true; + } + else if(groupData.chemCompType.toLowerCase().indexOf('dna') !== -1 || groupData.chemCompType.toLowerCase().indexOf('rna') !== -1) { + bNucleotide = true; + } + else { + bProtein = true; + } + + // add sequence information + var chainid = structure + '_' + chain; + + var resObject = {}; + resObject.resi = resi; + resObject.name = me.icn3d.residueName2Abbr(resn); + + me.icn3d.residueId2Name[resid] = resObject.name; + + if(me.icn3d.chainsSeq[chainid] === undefined) me.icn3d.chainsSeq[chainid] = []; + + if(me.icn3d.chainsAnno[chainid] === undefined ) me.icn3d.chainsAnno[chainid] = []; + if(me.icn3d.chainsAnno[chainid][0] === undefined ) me.icn3d.chainsAnno[chainid][0] = []; + if(me.icn3d.chainsAnno[chainid][1] === undefined ) me.icn3d.chainsAnno[chainid][1] = []; + + var numberStr = ''; + if(resObject.resi % 10 === 0) numberStr = resObject.resi.toString(); + + var secondaries = 'c'; + if(ss === 'helix') { + secondaries = 'H'; + } + else if(ss === 'sheet') { + secondaries = 'E'; + } + + if(me.icn3d.chainsSeq[chainid] === undefined) me.icn3d.chainsSeq[chainid] = []; + me.icn3d.chainsSeq[chainid].push(resObject); + + + if(me.icn3d.chainsAnno[chainid] === undefined) me.icn3d.chainsAnno[chainid] = []; + if(me.icn3d.chainsAnno[chainid][0] === undefined) me.icn3d.chainsAnno[chainid][0] = []; + if(me.icn3d.chainsAnno[chainid][1] === undefined) me.icn3d.chainsAnno[chainid][1] = []; + me.icn3d.chainsAnno[chainid][0].push(numberStr); + me.icn3d.chainsAnno[chainid][1].push(secondaries); + + me.icn3d.secondaries[resid] = secondaries; + + }, + onAtom: function( atomData ){ + elem = atomData.element; + atomName = atomData.atomName; + coord = new THREE.Vector3(atomData.xCoord, atomData.yCoord, atomData.zCoord); + b = atomData.bFactor; + + alt = atomData.altLoc; + if(atomData.altLoc === '\u0000') { // a temp value, should be '' + alt = ''; + } + + // skip the atoms where alt is not '' or 'A' + if(alt === '' || alt === 'A') { + ++serial; + + if(atomName === 'SG') SGAtomSerialArray.push(serial); + + oriindex2serial[atomData.atomIndex] = serial; + + var atomDetails = { + het: het, // optional, used to determine ligands, water, ions, etc + serial: serial, // required, unique atom id + name: atomName, // required, atom name + alt: alt, // optional, some alternative coordinates + resn: resn, // optional, used to determine protein or nucleotide + structure: structure, // optional, used to identify structure + chain: chain, // optional, used to identify chain + resi: resi, // optional, used to identify residue ID + //insc: line.substr(26, 1), + coord: coord, // required, used to draw 3D shape + b: b, // optional, used to draw B-factor tube + elem: elem, // optional, used to determine hydrogen bond + bonds: [], // required, used to connect atoms + bondOrder: [], + ss: ss, // optional, used to show secondary structures + ssbegin: ssbegin, // optional, used to show the beginning of secondary structures + ssend: ssend // optional, used to show the end of secondary structures + }; + + //if(het) atomDetails.bondOrder = []; + + me.icn3d.atoms[serial] = atomDetails; + + pmin.min(coord); + pmax.max(coord); + psum.add(coord); + + var chainid = structure + '_' + chain; + var resid = chainid + '_' + resi; + + if(me.icn3d.chains[chainid] === undefined) me.icn3d.chains[chainid] = {}; + me.icn3d.chains[chainid][serial] = 1; + + if(me.icn3d.residues[resid] === undefined) me.icn3d.residues[resid] = {}; + me.icn3d.residues[resid][serial] = 1; + + if (bProtein) { + me.icn3d.proteins[serial] = 1; + + if (atomName === 'CA') me.icn3d.calphas[serial] = 1; + if (atomName !== 'N' && atomName !== 'CA' && atomName !== 'C' && atomName !== 'O') me.icn3d.sidechains[serial] = 1; + } + else if (bNucleotide) { + me.icn3d.nucleotides[serial] = 1; + + if (atomName == 'P') me.icn3d.nucleotidesP[serial] = 1; + } + else { + if (elem.toLowerCase() === resn.toLowerCase()) { + me.icn3d.ions[serial] = 1; + } + else if(resn === 'HOH' || resn === 'WAT' || resn === 'SQL' || resn === 'H2O' || resn === 'W' || resn === 'DOD' || resn === 'D3O') { + me.icn3d.water[serial] = 1; + } + else { + me.icn3d.ligands[serial] = 1; + } + } + + me.icn3d.displayAtoms[serial] = 1; + me.icn3d.highlightAtoms[serial] = 1; + } + }, + onBond: function( bondData ){ + var from = oriindex2serial[bondData.atomIndex1]; + var to = oriindex2serial[bondData.atomIndex2]; + + //var from = bondData.atomIndex1 + 1; + //var to = bondData.atomIndex2 + 1; + + if(from !== undefined && to !== undefined) { // some alt atoms were skipped + me.icn3d.atoms[from].bonds.push(to); + me.icn3d.atoms[to].bonds.push(from); + + if(het) { + var order = bondData.bondOrder; + + me.icn3d.atoms[from].bondOrder.push(order); + me.icn3d.atoms[to].bondOrder.push(order); + if(order == '2') { + me.icn3d.doublebonds[from + '_' + to] = 1; + me.icn3d.doublebonds[to + '_' + from] = 1; + } + else if(order == '3') { + me.icn3d.triplebonds[from + '_' + to] = 1; + me.icn3d.triplebonds[to + '_' + from] = 1; + } + } + } + } + }; + + // traverse + MMTF.traverse( mmtfData, callbackDict ); + + // set up disulfide bonds + var sgLength = SGAtomSerialArray.length; + for(var i = 0, il = sgLength; i < il; ++i) { + for(var j = i+1, jl = sgLength; j < il; ++j) { + + var serial1 = SGAtomSerialArray[i]; + var serial2 = SGAtomSerialArray[j]; + + var atom1 = me.icn3d.atoms[serial1]; + var atom2 = me.icn3d.atoms[serial2]; + + if($.inArray(serial2, atom1.bonds) !== -1) { + var resid1 = atom1.structure + '_' + atom1.chain + '_' + atom1.resi; + var resid2 = atom2.structure + '_' + atom2.chain + '_' + atom2.resi; + + me.icn3d.ssbondpoints.push(resid1); + me.icn3d.ssbondpoints.push(resid2); + } + } + } + + me.icn3d.cnt = serial; + + me.icn3d.pmin = pmin; + me.icn3d.pmax = pmax; + me.icn3d.maxD = pmax.distanceTo(pmin); + me.icn3d.center = psum.multiplyScalar(1.0 / me.icn3d.cnt); + + if (me.icn3d.maxD < 25) me.icn3d.maxD = 25; + me.icn3d.oriMaxD = me.icn3d.maxD; + me.icn3d.oriCenter = me.icn3d.center.clone(); + + if(me.cfg.align === undefined && Object.keys(me.icn3d.structures).length == 1) { + $("#" + me.pre + "alternateWrapper").hide(); + } + + me.icn3d.setAtomStyleByOptions(me.options); + me.icn3d.setColorByOptions(me.options, me.icn3d.atoms); + + me.renderStructure(); + + me.showTitle(); + + if(me.cfg.rotate !== undefined) me.rotateStructure(me.cfg.rotate, true); + + if(me.cfg.showseq !== undefined && me.cfg.showseq) me.openDialog(me.pre + 'dl_selectresidues', 'Select residues in sequences'); + + if(me.deferred !== undefined) me.deferred.resolve(); if(me.deferred2 !== undefined) me.deferred2.resolve(); + + }, + // onError callback + function( error ){ + console.error( error ) + } + ); + }; + + iCn3DUI.prototype.downloadMmcif = function (mmcifid) { var me = this; // The PDB service doesn't support https, so use our reverse-proxy // service when using https @@ -7425,7 +8257,7 @@ iCn3DUI.prototype = { if($("#" + me.pre + "commandlog")) $("#" + me.pre + "commandlog").show(); }, success: function(data) { - url = "//www.ncbi.nlm.nih.gov/Structure/mmcifparser/mmcifparser.cgi"; + url = "//www.ncbi.nlm.nih.gov/Structure/mmcifparser/mmcifparser.cgi"; $.ajax({ url: url, @@ -7594,7 +8426,9 @@ iCn3DUI.prototype = { me.icn3d.setAtomStyleByOptions(me.options); // use the original color from cgi output - me.icn3d.setColorByOptions(me.options, me.icn3d.atoms, true); + //me.icn3d.setColorByOptions(me.options, me.icn3d.atoms, true); + // change the default color to "Identity" + me.icn3d.setColorByOptions(me.options, me.icn3d.atoms); me.renderStructure(); @@ -9166,6 +10000,36 @@ iCn3DUI.prototype = { me.icn3d.oriMaxD = me.icn3d.maxD; me.icn3d.oriCenter = me.icn3d.center.clone(); + // set up disulfide bonds + if(type === 'mmdbid') { + var disulfideArray = data.disulfides; + + for(var i = 0, il = disulfideArray.length; i < il; ++i) { + var serial1 = disulfideArray[i][0].ca; + var serial2 = disulfideArray[i][1].ca; + + var atom1 = me.icn3d.atoms[serial1]; + var atom2 = me.icn3d.atoms[serial2]; + + var resid1 = atom1.structure + '_' + atom1.chain + '_' + atom1.resi; + var resid2 = atom2.structure + '_' + atom2.chain + '_' + atom2.resi; + + me.icn3d.ssbondpoints.push(resid1); + me.icn3d.ssbondpoints.push(resid2); + } + } + else if(type === 'mmcifid') { + var disulfideArray = data.disulfides; + + for(var i = 0, il = disulfideArray.length; i < il; ++i) { + var resid1 = disulfideArray[i][0]; + var resid2 = disulfideArray[i][1]; + + me.icn3d.ssbondpoints.push(resid1); + me.icn3d.ssbondpoints.push(resid2); + } + } + // set up sequence alignment if(type === 'align' && seqalign !== undefined) { //loadSeqAlignment diff --git a/src/icn3d.js b/src/icn3d.js index 3a30c960..b33a5390 100644 --- a/src/icn3d.js +++ b/src/icn3d.js @@ -40,6 +40,8 @@ var iCn3D = function (id) { this.overdraw = 0; + this.bDrawn = false; + this.bHighlight = 1; // undefined: no highlight, 1: highlight by outline, 2: highlight by 3D object if(Detector.webgl){ @@ -99,6 +101,8 @@ var iCn3D = function (id) { this.bConsiderNeighbors = false; // a flag to show surface considering the neighboring atoms or not + this.bShowCrossResidueBond = false; + this.effects = { //'anaglyph': new THREE.AnaglyphEffect(this.renderer), //'parallax barrier': new THREE.ParallaxBarrierEffect(this.renderer), @@ -111,8 +115,8 @@ var iCn3D = function (id) { this.oriMaxD = this.maxD; // size of the molecule //this.camera_z = -150; - //this.camera_z = this.maxD * 2; // when zooming in, it gets dark if the camera is in front - this.camera_z = -this.maxD * 2; + this.camera_z = this.maxD * 2; // when zooming in, it gets dark if the camera is in front + //this.camera_z = -this.maxD * 2; // these variables will not be cleared for each structure this.commands = []; // a list of commands, ordered by the operation steps. Each operation will be converted into a command. this command list can be used to go backward and forward. @@ -159,6 +163,8 @@ var iCn3D = function (id) { //labels: 'no', //effect: 'none', hbonds: 'no', + ssbonds: 'no', + ncbonds: 'no', labels: 'no', lines: 'no', rotationcenter: 'molecule center', @@ -394,7 +400,7 @@ var iCn3D = function (id) { me.isDragging = true; // see ref http://soledadpenades.com/articles/three-js-tutorials/object-picking/ - if(me.picking && (e.altKey || e.ctrlKey || e.shiftKey || e.keyCode === 16 || e.keyCode === 17 || e.keyCode === 224 || e.keyCode === 91) ) { + if(me.picking && (e.altKey || e.ctrlKey || e.shiftKey || e.keyCode === 18 || e.keyCode === 16 || e.keyCode === 17 || e.keyCode === 224 || e.keyCode === 91) ) { me.highlightlevel = me.picking; me.mouse.x = ( (x - me.container.offset().left) / me.container.width() ) * 2 - 1; @@ -591,7 +597,7 @@ iCn3D.prototype = { // added nucleotides and ions nucleotidesArray: [' G', ' A', ' T', ' C', ' U', ' DG', ' DA', ' DT', ' DC', ' DU'], - ionsArray: [' NA', ' MG', ' AL', ' CA', ' TI', ' MN', ' FE', ' NI', ' CU', ' ZN', ' AG', ' BA', ' F', ' CL', ' BR', ' I'], + ionsArray: [' K', ' NA', ' MG', ' AL', ' CA', ' TI', ' MN', ' FE', ' NI', ' CU', ' ZN', ' AG', ' BA', ' F', ' CL', ' BR', ' I'], vdwRadii: { // Hu, S.Z.; Zhou, Z.H.; Tsai, K.R. Acta Phys.-Chim. Sin., 2003, 19:1073. H: 1.08, @@ -1013,7 +1019,8 @@ iCn3D.prototype = { coil: new THREE.Color(0x6080FF), }, - defaultBondColor: new THREE.Color(0x2194D6), + //defaultBondColor: new THREE.Color(0x2194D6), + defaultBondColor: new THREE.Color(0xBBBBBB), // cross residue bonds surfaces: { 1: undefined, @@ -1030,7 +1037,7 @@ iCn3D.prototype = { init: function () { this.structures = {}; // structure name -> array of chains - this.chains = {}; // structure_chain name -> array of residues + this.chains = {}; // structure_chain name -> atom hash this.residues = {}; // structure_chain_resi name -> atom hash this.secondaries = {}; // structure_chain_resi name -> secondary structure: 'C', 'H', or 'E' this.alignChains = {}; // structure_chain name -> atom hash @@ -1077,6 +1084,8 @@ iCn3D.prototype = { //this.hbonds = {}; this.hbondpoints = []; + this.ssbondpoints = []; // disulfide bonds + this.ncbondpoints = []; // non-covalent bonds this.doublebonds = {}; this.triplebonds = {}; @@ -1088,7 +1097,7 @@ iCn3D.prototype = { this.labels = {}; // hash of name -> a list of labels. Each label contains 'position', 'text', 'size', 'color', 'background' // label name could be custom, residue, schmatic, distance this.lines = {}; // hash of name -> a list of solid or dashed lines. Each line contains 'position1', 'position2', 'color', and a boolean of 'dashed' - // line name could be custom, hbond, distance + // line name could be custom, hbond, ssbond, ncbond, distance this.inputid = {"idtype": undefined, "id":undefined}; // support pdbid, mmdbid @@ -1108,11 +1117,13 @@ iCn3D.prototype = { //this.hbonds = {}; this.hbondpoints = []; + this.ssbondpoints = []; + this.ncbondpoints = []; this.labels = {}; // hash of name -> a list of labels. Each label contains 'position', 'text', 'size', 'color', 'background' // label name could be custom, residue, schmatic, distance this.lines = {}; // hash of name -> a list of solid or dashed lines. Each line contains 'position1', 'position2', 'color', and a boolean of 'dashed' - // line name could be custom, hbond, distance + // line name could be custom, hbond, ssbond, ncbond, distance this.biomtMatrices = []; this.bAssembly = false; @@ -1227,6 +1238,18 @@ iCn3D.prototype = { this.hbondpoints.push(new THREE.Vector3(ligand_x, ligand_y, ligand_z)); this.hbondpoints.push(new THREE.Vector3(protein_x, protein_y, protein_z)); + } else if (record === 'SSBOND') { + //SSBOND 1 CYS E 48 CYS E 51 2555 + var chain1 = line.substr(15, 1); + var resi1 = line.substr(17, 4).replace(/ /g, ""); + var resid1 = id + '_' + chain1 + '_' + resi1; + + var chain2 = line.substr(29, 1); + var resi2 = line.substr(31, 4).replace(/ /g, ""); + var resid2 = id + '_' + chain2 + '_' + resi2; + + this.ssbondpoints.push(resid1); + this.ssbondpoints.push(resid2); } else if (record === 'REMARK') { var type = parseInt(line.substr(7, 3)); // from GLMol @@ -1523,6 +1546,7 @@ iCn3D.prototype = { this.chains[chainNum] = this.unionHash2Atoms(this.chains[chainNum], chainsTmp); var curChain, curResi, curInsc, curResAtoms = [], me = this; + // refresh for atoms in each residue var refreshBonds = function (f) { var n = curResAtoms.length; for (var j = 0; j < n; ++j) { @@ -1566,7 +1590,7 @@ iCn3D.prototype = { if(atom.resn === 'HOH' || atom.resn === 'WAT') { this.water[atom.serial] = 1; } - else if($.inArray(atom.resn, this.ionsArray) !== -1) { + else if($.inArray(atom.resn, this.ionsArray) !== -1 || atom.elem.trim() === atom.resn.trim()) { this.ions[atom.serial] = 1; } else { @@ -1576,6 +1600,7 @@ iCn3D.prototype = { //if (!(curChain === atom.chain && curResi === atom.resi && curInsc === atom.insc)) { if (!(curChain === atom.chain && curResi === atom.resi)) { + // a new residue, add the residue-residue bond beides the regular bonds refreshBonds(function (atom0) { if (((atom0.name === 'C' && atom.name === 'N') || (atom0.name === 'O3\'' && atom.name === 'P')) && me.hasCovalentBond(atom0, atom)) { atom0.bonds.push(atom.serial); @@ -1590,6 +1615,7 @@ iCn3D.prototype = { curResAtoms.push(atom); } // end of for + // last residue refreshBonds(); this.pmin = pmin; @@ -1781,20 +1807,21 @@ iCn3D.prototype = { // output hydrogen bonds //var other_chain_resi_atom = j.split('_'); // some chain may have underline - var firstPos = j.indexOf('_'); - var lastPos = j.lastIndexOf('_'); - var structure = j.substr(0, firstPos); - var chain_resi = j.substr(firstPos + 1, lastPos - firstPos - 1); - lastPos = chain_resi.lastIndexOf('_'); - var chain = chain_resi.substr(0, lastPos); - var resi = chain_resi.substr(lastPos + 1); +// var firstPos = j.indexOf('_'); +// var lastPos = j.lastIndexOf('_'); +// var structure = j.substr(0, firstPos); +// var chain_resi = j.substr(firstPos + 1, lastPos - firstPos - 1); +// lastPos = chain_resi.lastIndexOf('_'); +// var chain = chain_resi.substr(0, lastPos); +// var resi = chain_resi.substr(lastPos + 1); // remove those hydrogen bonds in the same residue //if(parseInt(atom.resi) !== parseInt(other_chain_resi_atom[2])) { this.hbondpoints.push(atom.coord); this.hbondpoints.push(atomHbond[j].coord); - this.highlightAtoms = this.unionHash(this.highlightAtoms, this.residues[structure + "_" + chain + "_" + resi]); + this.highlightAtoms = this.unionHash(this.highlightAtoms, this.residues[atom.structure + "_" + atom.chain + "_" + atom.resi]); + this.highlightAtoms = this.unionHash(this.highlightAtoms, this.residues[atomHbond[j].structure + "_" + atomHbond[j].chain + "_" + atomHbond[j].resi]); //} } // end of for (var j in atomHbond) { @@ -1803,6 +1830,43 @@ iCn3D.prototype = { } // end of for (var i in ligands) { }, + // get non-covalent bonds (ncbonds) between selection and the rest atoms + calculateNonCovalentBonds: function (rest, selection) { + if(Object.keys(selection).length === 0 || Object.keys(rest).length === 0) return; + + // http://proteopedia.org/wiki/index.php/Salt_bridges + // http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3069487/ + var saltbridgelength = 4; + + var allatoms1 = this.unionHash(selection, rest); + var minRest = this.getNeighboringAtoms(allatoms1, selection, saltbridgelength); + + var allatoms2 = this.unionHash(selection, minRest); + var minSelection = this.getNeighboringAtoms(allatoms2, minRest, saltbridgelength); + + this.highlightAtoms = {}; + + var maxDistSq = saltbridgelength * saltbridgelength; + + for(var i in minSelection) { + var oriAtom = minSelection[i]; + + for (var j in minRest) { + var atom = minRest[j]; + + var atomDistSq = (atom.coord.x - oriAtom.coord.x) * (atom.coord.x - oriAtom.coord.x) + (atom.coord.y - oriAtom.coord.y) * (atom.coord.y - oriAtom.coord.y) + (atom.coord.z - oriAtom.coord.z) * (atom.coord.z - oriAtom.coord.z); + + // non hydrogen bonds + if(atomDistSq < maxDistSq && atom.elem !== "N" && atom.elem !== "O" && atom.elem !== "F" && oriAtom.elem !== "N" && oriAtom.elem !== "O" && oriAtom.elem !== "F") { + this.ncbondpoints.push(atom.coord); + this.ncbondpoints.push(oriAtom.coord); + + this.highlightAtoms = this.unionHash(this.highlightAtoms, this.residues[atom.structure + "_" + atom.chain + "_" + atom.resi]); + } + } + } + }, + // modified from iview (http://istar.cse.cuhk.edu.hk/iview/) createSphere: function (atom, defaultRadius, forceDefault, scale, bHighlight) { var mesh; @@ -1935,7 +1999,7 @@ iCn3D.prototype = { } }, - // from iview (http://istar.cse.cuhk.edu.hk/iview/) +/* createRepresentationSub: function (atoms, f0, f01) { var ged = new THREE.Geometry(); for (var i in atoms) { @@ -1949,6 +2013,31 @@ iCn3D.prototype = { } } }, +*/ + + // from iview (http://istar.cse.cuhk.edu.hk/iview/) + createRepresentationSub: function (atoms, f0, f01) { + var ged = new THREE.Geometry(); + for (var i in atoms) { + var atom0 = atoms[i]; + f0 && f0(atom0); + for (var j in atom0.bonds) { + var atom1 = this.atoms[atom0.bonds[j]]; + if (atom1 === undefined || atom1.serial < atom0.serial) continue; + if (atom1.chain === atom0.chain && ((atom1.resi === atom0.resi) || (atom0.name === 'C' && atom1.name === 'N') || (atom0.name === 'O3\'' && atom1.name === 'P'))) { + f01 && f01(atom0, atom1); + } else { + ged.vertices.push(atom0.coord); + ged.vertices.push(atom1.coord); + } + } + } + if (ged.vertices.length && this.bShowCrossResidueBond) { + ged.computeLineDistances(); + //this.mdl.add(new THREE.Line(ged, new THREE.LineDashedMaterial({ linewidth: this.linewidth, color: this.defaultBondColor, dashSize: 0.25, gapSize: 0.125 }), THREE.LinePieces)); + this.mdl.add(new THREE.Line(ged, new THREE.LineDashedMaterial({ linewidth: this.linewidth, color: this.defaultBondColor, dashSize: 0.3, gapSize: 0.15 }), THREE.LinePieces)); + } + }, // modified from iview (http://istar.cse.cuhk.edu.hk/iview/) createSphereRepresentation: function (atoms, defaultRadius, forceDefault, scale, bHighlight) { @@ -3582,6 +3671,32 @@ iCn3D.prototype = { new THREE.Vector3(end.coord.x, end.coord.y, end.coord.z), 0.3, start.color, bHighlight); }, + isPhosphorusOnly: function(atomlist) { + var bPhosphorusOnly = false; + + var index = 0, testLength = 30; + var bOtherAtoms = false; + for(var i in atomlist) { + if(index < testLength) { + if(atomlist[i].name !== 'P') { + bOtherAtoms = true; + break; + } + } + else { + break; + } + + ++index; + } + + if(!bOtherAtoms) { + bPhosphorusOnly = true; + } + + return bPhosphorusOnly; + }, + // modified from GLmol (http://webglmol.osdn.jp/index-en.html) drawCartoonNucleicAcid: function(atomlist, div, thickness, bHighlight) { this.drawStrandNucleicAcid(atomlist, 2, div, true, undefined, thickness, bHighlight); @@ -3935,8 +4050,7 @@ iCn3D.prototype = { } }, - // modified from iview (http://istar.cse.cuhk.edu.hk/iview/) - getAtomsWithinAtom: function(atomlist, atomlistTarget, distance) { + getNeighboringAtoms: function(atomlist, atomlistTarget, distance) { var extent = this.getExtent(atomlistTarget); var targetRadiusSq1 = (extent[2][0] - extent[0][0]) * (extent[2][0] - extent[0][0]) + (extent[2][1] - extent[0][1]) * (extent[2][1] - extent[0][1]) + (extent[2][2] - extent[0][2]) * (extent[2][2] - extent[0][2]); @@ -3967,6 +4081,13 @@ iCn3D.prototype = { //} } + return neighbors; + }, + + // modified from iview (http://istar.cse.cuhk.edu.hk/iview/) + getAtomsWithinAtom: function(atomlist, atomlistTarget, distance) { + var neighbors = this.getNeighboringAtoms(atomlist, atomlistTarget, distance); + var ret = {}; for(var i in atomlistTarget) { var oriAtom = atomlistTarget[i]; @@ -3977,7 +4098,7 @@ iCn3D.prototype = { var atomDistSq = (atom.coord.x - oriAtom.coord.x) * (atom.coord.x - oriAtom.coord.x) + (atom.coord.y - oriAtom.coord.y) * (atom.coord.y - oriAtom.coord.y) + (atom.coord.z - oriAtom.coord.z) * (atom.coord.z - oriAtom.coord.z); - maxDistSq = (radius + distance) * (radius + distance); + var maxDistSq = (radius + distance) * (radius + distance); if(atomDistSq < maxDistSq) { ret[atom.serial] = atom; @@ -4056,7 +4177,7 @@ iCn3D.prototype = { var mat; if(dashed) { - mat = new THREE.LineDashedMaterial({ linewidth: 1, color: colorHex, dashSize: dashSize, gapSize: dashSize }); + mat = new THREE.LineDashedMaterial({ linewidth: 1, color: colorHex, dashSize: dashSize, gapSize: 0.5*dashSize }); } else { mat = new THREE.LineBasicMaterial({ linewidth: 1, color: colorHex }); } @@ -4473,27 +4594,100 @@ iCn3D.prototype = { this.createLabelRepresentation(this.labels); // lines - if (options.hbonds.toLowerCase() === 'yes') { - var color = '#FFFFFF'; - if(options.background.toLowerCase() !== "black") { - color = '#000000'; + if (options.hbonds.toLowerCase() === 'yes' || options.ncbonds.toLowerCase() === 'yes') { + var color; + var points; + + if(options.hbonds.toLowerCase() === 'yes') { + //color = '#FFFFFF'; + //if(options.background.toLowerCase() !== "black") { + // color = '#000000'; + //} + color = '#00FF00'; + points = this.hbondpoints; + } + else if(options.ncbonds.toLowerCase() === 'yes') { + color = '#0000FF'; + points = this.ncbondpoints; } - for (var i = 0, lim = Math.floor(this.hbondpoints.length / 2); i < lim; i++) { - var p1 = this.hbondpoints[2 * i], p2 = this.hbondpoints[2 * i + 1]; - + for (var i = 0, lim = Math.floor(points.length / 2); i < lim; i++) { var line = {}; - line.position1 = this.hbondpoints[2 * i]; - line.position2 = this.hbondpoints[2 * i + 1]; + line.position1 = points[2 * i]; + line.position2 = points[2 * i + 1]; line.color = color; line.dashed = true; - if(this.lines['hbond'] === undefined) this.lines['hbond'] = []; - this.lines['hbond'].push(line); + if(options.hbonds.toLowerCase() === 'yes') { + if(this.lines['hbond'] === undefined) this.lines['hbond'] = []; + this.lines['hbond'].push(line); + } + else if(options.ncbonds.toLowerCase() === 'yes') { + if(this.lines['ncbond'] === undefined) this.lines['ncbond'] = []; + this.lines['ncbond'].push(line); + } } this.createLines(this.lines); } + else if (options.ssbonds.toLowerCase() === 'yes') { + var color = '#FFFF00'; + var colorObj = new THREE.Color(0xFFFF00); + + for (var i = 0, lim = Math.floor(this.ssbondpoints.length / 2); i < lim; i++) { + var res1 = this.ssbondpoints[2 * i], res2 = this.ssbondpoints[2 * i + 1]; + + var line = {}; + line.color = color; + line.dashed = true; + + var bFound = false; + for(var j in this.residues[res1]) { + if(this.atoms[j].name === 'SG') { + line.position1 = this.atoms[j].coord; + bFound = true; + break; + } + } + + if(!bFound) { + for(var j in this.residues[res1]) { + if(this.atoms[j].name === 'CA') { + line.position1 = this.atoms[j].coord; + bFound = true; + break; + } + } + } + + bFound = false; + for(var j in this.residues[res2]) { + if(this.atoms[j].name === 'SG') { + line.position2 = this.atoms[j].coord; + bFound = true; + break; + } + } + + if(!bFound) { + for(var j in this.residues[res2]) { + if(this.atoms[j].name === 'CA') { + line.position2 = this.atoms[j].coord; + bFound = true; + break; + } + } + } + + if(this.lines['ssbond'] === undefined) this.lines['ssbond'] = []; + this.lines['ssbond'].push(line); + + // create bonds for disulfide bonds + this.createCylinder(line.position1, line.position2, this.cylinderRadius * 0.5, colorObj); + } + + //this.createLines(this.lines); + } else { this.createLines(this.lines); } @@ -4705,7 +4899,8 @@ iCn3D.prototype = { var currentCalphas = {}; if(this.options['sidechains'] !== 'nothing') { - currentCalphas = this.intersectHash(atoms, this.calphas); + //currentCalphas = this.intersectHash(atoms, this.calphas); + currentCalphas = this.intersectHash(this.highlightAtoms, this.calphas); } // remove schematic labels @@ -4727,9 +4922,16 @@ iCn3D.prototype = { this.createCylinderHelix(this.hash2Atoms(atomHash), 1.6, bHighlight); } else if(style === 'nucleotide cartoon') { - this.drawCartoonNucleicAcid(this.hash2Atoms(atomHash), null, this.thickness, bHighlight); + var bPhosphorusOnly = this.isPhosphorusOnly(this.hash2Atoms(atomHash)); + + if(bPhosphorusOnly) { + this.createCylinderCurve(this.hash2Atoms(atomHash), 'P', 0.2, false, bHighlight); + } + else { + this.drawCartoonNucleicAcid(this.hash2Atoms(atomHash), null, this.thickness, bHighlight); - if(bHighlight !== 2) this.drawNucleicAcidStick(this.hash2Atoms(atomHash), bHighlight); + if(bHighlight !== 2) this.drawNucleicAcidStick(this.hash2Atoms(atomHash), bHighlight); + } } else if(style === 'phosphorus trace') { this.createCylinderCurve(this.hash2Atoms(atomHash), 'P', 0.2, false, bHighlight); @@ -4894,7 +5096,8 @@ iCn3D.prototype = { rebuildScene: function (options) { var me = this; jQuery.extend(me.options, options); - this.camera_z = -this.maxD * 2; + this.camera_z = this.maxD * 2; + //this.camera_z = -this.maxD * 2; if(this.scene !== undefined) { @@ -5075,10 +5278,13 @@ iCn3D.prototype = { this.mdl.position.sub(coord); }, - draw: function (options, bPrevColor) { - this.rebuildScene(options); + //draw: function (options, bPrevColor) { + draw: function () { + //this.rebuildScene(options); + this.rebuildScene(); - if(bPrevColor === undefined || bPrevColor) this.applyPrevColor(); + //if(bPrevColor === undefined || bPrevColor) this.applyPrevColor(); + this.applyPrevColor(); if(this.bSSOnly) this.drawHelixBrick(this.molid2ss, this.molid2color); // highlight the helices and bricks @@ -5087,7 +5293,6 @@ iCn3D.prototype = { if(this.bAssembly) this.drawSymmetryMates2(); // show the highlightAtoms - //if(this.highlightAtoms !== undefined && Object.keys(this.highlightAtoms).length > 0 && Object.keys(this.highlightAtoms).length < Object.keys(this.displayAtoms).length) { if(this.highlightAtoms !== undefined && Object.keys(this.highlightAtoms).length > 0 && Object.keys(this.highlightAtoms).length < Object.keys(this.atoms).length) { this.removeHighlightObjects(); //if(this.bShowHighlight === undefined || this.bShowHighlight) this.addHighlightObjects(undefined, false); @@ -5098,6 +5303,9 @@ iCn3D.prototype = { this.applyTransformation(this._zoomFactor, this.mouseChange, this.quaternion); this.render(); } + + // reset to hide the side chain + this.options['sidechains'] = 'nothing'; }, // zoom @@ -5319,43 +5527,17 @@ iCn3D.prototype = { if(!this.bShiftKey && !this.bCtrlKey) { this.highlightAtoms = this.cloneHash(this.pickedAtomList); } - else { - if(this.bShiftKey) { // select a range - var prevStart = this.getFirstAtomObj(this.highlightAtoms).serial; - var prevEnd = this.getLastAtomObj(this.highlightAtoms).serial; - var currStart = this.getFirstAtomObj(this.pickedAtomList).serial; - var currEnd = this.getLastAtomObj(this.pickedAtomList).serial; - - var startSerial = (prevEnd < currStart) ? prevEnd : currEnd; - var endSerial = (prevEnd < currStart) ? currEnd + 1 : prevStart; + else if(this.bShiftKey) { // select a range + this.highlightAtoms = this.unionHash(this.highlightAtoms, this.pickedAtomList); + var firstAtom = this.getFirstAtomObj(this.highlightAtoms); + var lastAtom = this.getLastAtomObj(this.highlightAtoms); - // select the range in the same chain - var prevChainid = ''; - if(prevEnd < currStart) { - for(var i = startSerial + 1; i < endSerial; ++i) { - var chainid = this.atoms[i].structure + '_' + this.atoms[i].chain; - - if(i !== startSerial + 1 && chainid !== prevChainid) break; - - this.highlightAtoms[i] = 1; - - prevChainid = chainid; - } + for(var i = firstAtom.serial; i <= lastAtom.serial; ++i) { + this.highlightAtoms[i] = 1; } - else { - for(var i = endSerial - 1; i > startSerial; --i) { - var chainid = this.atoms[i].structure + '_' + this.atoms[i].chain; - - if(i !== endSerial - 1 && chainid !== prevChainid) break; - - this.highlightAtoms[i] = 1; - - prevChainid = chainid; - } - } - } - - if(this.bCtrlKey) this.highlightAtoms = this.unionHash(this.highlightAtoms, this.pickedAtomList); + } + else if(this.bCtrlKey) { + this.highlightAtoms = this.unionHash(this.highlightAtoms, this.pickedAtomList); } this.addHighlightObjects(); diff --git a/src/icn3d_full_ui.css b/src/icn3d_full_ui.css index 787f3ec6..746d8f40 100644 --- a/src/icn3d_full_ui.css +++ b/src/icn3d_full_ui.css @@ -3,8 +3,11 @@ .ui-dialog .ui-button { width: 12px; height:12px; margin: -5px 0px 0px 0px;} .ui-dialog .ui-dialog-titlebar { padding: 0px 1em 2px 1em; } +.ui-accordion .ui-accordion-icons { padding-left: 0; text-align: center; } + accordion {font-size: 14px!important; z-index:1999; } accordion h3 {width: 60px; font-size: 14px!important;} +accordion h3 > .ui-icon { display: none !important; } accordion > ul {width: 60px;} accordion ul ul {width: 160px;} accordion ul li {cursor:default!important; white-space:nowrap;} diff --git a/src/mmtf.js b/src/mmtf.js new file mode 100644 index 00000000..6bca5a85 --- /dev/null +++ b/src/mmtf.js @@ -0,0 +1 @@ +!function(r,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(r.MMTF=r.MMTF||{})}(this,function(r){"use strict";function t(r,t,n){for(var e=(r.byteLength,0),i=n.length;i>e;e++){var o=n.charCodeAt(e);if(128>o)r.setUint8(t++,o>>>0&127|0);else if(2048>o)r.setUint8(t++,o>>>6&31|192),r.setUint8(t++,o>>>0&63|128);else if(65536>o)r.setUint8(t++,o>>>12&15|224),r.setUint8(t++,o>>>6&63|128),r.setUint8(t++,o>>>0&63|128);else{if(!(1114112>o))throw new Error("bad codepoint "+o);r.setUint8(t++,o>>>18&7|240),r.setUint8(t++,o>>>12&63|128),r.setUint8(t++,o>>>6&63|128),r.setUint8(t++,o>>>0&63|128)}}}function n(r){for(var t=0,n=0,e=r.length;e>n;n++){var i=r.charCodeAt(n);if(128>i)t+=1;else if(2048>i)t+=2;else if(65536>i)t+=3;else{if(!(1114112>i))throw new Error("bad codepoint "+i);t+=4}}return t}function e(r,i,o){var a=typeof r;if("string"===a){var u=n(r);if(32>u)return i.setUint8(o,160|u),t(i,o+1,r),1+u;if(256>u)return i.setUint8(o,217),i.setUint8(o+1,u),t(i,o+2,r),2+u;if(65536>u)return i.setUint8(o,218),i.setUint16(o+1,u),t(i,o+3,r),3+u;if(4294967296>u)return i.setUint8(o,219),i.setUint32(o+1,u),t(i,o+5,r),5+u}if(r instanceof Uint8Array){var u=r.byteLength,s=new Uint8Array(i.buffer);if(256>u)return i.setUint8(o,196),i.setUint8(o+1,u),s.set(r,o+2),2+u;if(65536>u)return i.setUint8(o,197),i.setUint16(o+1,u),s.set(r,o+3),3+u;if(4294967296>u)return i.setUint8(o,198),i.setUint32(o+1,u),s.set(r,o+5),5+u}if("number"===a){if(!isFinite(r))throw new Error("Number not finite: "+r);if(Math.floor(r)!==r)return i.setUint8(o,203),i.setFloat64(o+1,r),9;if(r>=0){if(128>r)return i.setUint8(o,r),1;if(256>r)return i.setUint8(o,204),i.setUint8(o+1,r),2;if(65536>r)return i.setUint8(o,205),i.setUint16(o+1,r),3;if(4294967296>r)return i.setUint8(o,206),i.setUint32(o+1,r),5;throw new Error("Number too big 0x"+r.toString(16))}if(r>=-32)return i.setInt8(o,r),1;if(r>=-128)return i.setUint8(o,208),i.setInt8(o+1,r),2;if(r>=-32768)return i.setUint8(o,209),i.setInt16(o+1,r),3;if(r>=-2147483648)return i.setUint8(o,210),i.setInt32(o+1,r),5;throw new Error("Number too small -0x"+(-r).toString(16).substr(1))}if(null===r)return i.setUint8(o,192),1;if("boolean"===a)return i.setUint8(o,r?195:194),1;if("object"===a){var u,f=0,c=Array.isArray(r);if(c)u=r.length;else{var d=Object.keys(r);u=d.length}var f;if(16>u?(i.setUint8(o,u|(c?144:128)),f=1):65536>u?(i.setUint8(o,c?220:222),i.setUint16(o+1,u),f=3):4294967296>u&&(i.setUint8(o,c?221:223),i.setUint32(o+1,u),f=5),c)for(var l=0;u>l;l++)f+=e(r[l],i,o+f);else for(var l=0;u>l;l++){var g=d[l];f+=e(g,i,o+f),f+=e(r[g],i,o+f)}return f}throw new Error("Unknown type "+a)}function i(r){var t=typeof r;if("string"===t){var e=n(r);if(32>e)return 1+e;if(256>e)return 2+e;if(65536>e)return 3+e;if(4294967296>e)return 5+e}if(r instanceof Uint8Array){var e=r.byteLength;if(256>e)return 2+e;if(65536>e)return 3+e;if(4294967296>e)return 5+e}if("number"===t){if(Math.floor(r)!==r)return 9;if(r>=0){if(128>r)return 1;if(256>r)return 2;if(65536>r)return 3;if(4294967296>r)return 5;throw new Error("Number too big 0x"+r.toString(16))}if(r>=-32)return 1;if(r>=-128)return 2;if(r>=-32768)return 3;if(r>=-2147483648)return 5;throw new Error("Number too small -0x"+r.toString(16).substr(1))}if("boolean"===t||null===r)return 1;if("object"===t){var e,o=0;if(Array.isArray(r)){e=r.length;for(var a=0;e>a;a++)o+=i(r[a])}else{var u=Object.keys(r);e=u.length;for(var a=0;e>a;a++){var s=u[a];o+=i(s)+i(r[s])}}if(16>e)return 1+o;if(65536>e)return 3+o;if(4294967296>e)return 5+o;throw new Error("Array or object too long 0x"+e.toString(16))}throw new Error("Unknown type "+t)}function o(r){var t=new ArrayBuffer(i(r)),n=new DataView(t);return e(r,n,0),new Uint8Array(t)}function a(r,t,n){return t?new r(t.buffer,t.byteOffset,t.byteLength/(n||1)):void 0}function u(r){return a(DataView,r)}function s(r){return a(Uint8Array,r)}function f(r){return a(Int8Array,r)}function c(r){return a(Int32Array,r,4)}function d(r){return a(Float32Array,r,4)}function l(r,t){var n=r.length/2;t||(t=new Int16Array(n));for(var e=0,i=0;n>e;++e,i+=2)t[e]=r[i]<<8^r[i+1]<<0;return t}function g(r,t){var n=r.length;t||(t=new Uint8Array(2*n));for(var e=u(t),i=0;n>i;++i)e.setInt16(2*i,r[i]);return s(t)}function v(r,t){var n=r.length/4;t||(t=new Int32Array(n));for(var e=0,i=0;n>e;++e,i+=4)t[e]=r[i]<<24^r[i+1]<<16^r[i+2]<<8^r[i+3]<<0;return t}function L(r,t){var n=r.length;t||(t=new Uint8Array(4*n));for(var e=u(t),i=0;n>i;++i)e.setInt32(4*i,r[i]);return s(t)}function h(r,t){var n=r.length;t||(t=new Float32Array(n/4));for(var e=u(t),i=u(r),o=0,a=0,s=n/4;s>o;++o,a+=4)e.setFloat32(a,i.getFloat32(a),!0);return t}function y(r,t,n){var e=r.length,i=1/t;n||(n=new Float32Array(e));for(var o=0;e>o;++o)n[o]=r[o]*i;return n}function m(r,t,n){var e=r.length;n||(n=new Int32Array(e));for(var i=0;e>i;++i)n[i]=Math.round(r[i]*t);return n}function p(r,t){var n,e;if(!t){var i=0;for(n=0,e=r.length;e>n;n+=2)i+=r[n+1];t=new r.constructor(i)}var o=0;for(n=0,e=r.length;e>n;n+=2)for(var a=r[n],u=r[n+1],s=0;u>s;++s)t[o]=a,++o;return t}function U(r){if(0===r.length)return new Int32Array;var t,n,e=2;for(t=1,n=r.length;n>t;++t)r[t-1]!==r[t]&&(e+=2);var i=new Int32Array(e),o=0,a=1;for(t=1,n=r.length;n>t;++t)r[t-1]!==r[t]?(i[o]=r[t-1],i[o+1]=a,a=1,o+=2):++a;return i[o]=r[r.length-1],i[o+1]=a,i}function b(r,t){var n=r.length;t||(t=new r.constructor(n)),n&&(t[0]=r[0]);for(var e=1;n>e;++e)t[e]=r[e]+t[e-1];return t}function I(r,t){var n=r.length;t||(t=new r.constructor(n)),t[0]=r[0];for(var e=1;n>e;++e)t[e]=r[e]-r[e-1];return t}function w(r,t){var n,e,i=r instanceof Int8Array?127:32767,o=-i-1,a=r.length;if(!t){var u=0;for(n=0;a>n;++n)r[n]o&&++u;t=new Int32Array(u)}for(n=0,e=0;a>n;){for(var s=0;(r[n]===i||r[n]===o)&&(s+=r[n],++n,0!==r[n]););s+=r[n],++n,t[e]=s,++e}return t}function C(r,t){var n,e=t?127:32767,i=-e-1,o=r.length,a=0;for(n=0;o>n;++n){var u=r[n];0===u?++a:a+=u===e||u===i?2:u>0?Math.ceil(u/e):Math.ceil(u/i)}var s=t?new Int8Array(a):new Int16Array(a),f=0;for(n=0;o>n;++n){var u=r[n];if(u>=0)for(;u>=e;)s[f]=e,++f,u-=e;else for(;i>=u;)s[f]=i,++f,u-=i;s[f]=u,++f}return s}function A(r,t){return b(p(r),t)}function x(r){return U(I(r))}function M(r,t,n){return y(p(r,c(n)),t,n)}function F(r,t){return U(m(r,t))}function S(r,t,n){return y(b(r,c(n)),t,n)}function E(r,t,n){return I(m(r,t),n)}function N(r,t,n){return y(w(r,c(n)),t,n)}function O(r,t,n){var e=w(r,c(n));return S(e,t,d(e))}function T(r,t,n){return C(E(r,t),n)}function k(r){var t=u(r),n=t.getInt32(0),e=t.getInt32(4),i=r.subarray(8,12),r=r.subarray(12);return[n,r,e,i]}function j(r,t,n,e){var i=new ArrayBuffer(12+e.byteLength),o=new Uint8Array(i),a=new DataView(i);return a.setInt32(0,r),a.setInt32(4,t),n&&o.set(n,8),o.set(e,12),o}function q(r){var t=r.length,n=s(r);return j(2,t,void 0,n)}function D(r){var t=r.length,n=L(r);return j(4,t,void 0,n)}function P(r,t){var n=r.length/t,e=L([t]),i=s(r);return j(5,n,e,i)}function z(r){var t=r.length,n=L(U(r));return j(6,t,void 0,n)}function B(r){var t=r.length,n=L(x(r));return j(8,t,void 0,n)}function V(r,t){var n=r.length,e=L([t]),i=L(F(r,t));return j(9,n,e,i)}function G(r,t){var n=r.length,e=L([t]),i=g(T(r,t));return j(10,n,e,i)}function R(r){var t={};return rr.forEach(function(n){void 0!==r[n]&&(t[n]=r[n])}),r.bondAtomList&&(t.bondAtomList=D(r.bondAtomList)),r.bondOrderList&&(t.bondOrderList=q(r.bondOrderList)),t.xCoordList=G(r.xCoordList,1e3),t.yCoordList=G(r.yCoordList,1e3),t.zCoordList=G(r.zCoordList,1e3),r.bFactorList&&(t.bFactorList=G(r.bFactorList,100)),r.atomIdList&&(t.atomIdList=B(r.atomIdList)),r.altLocList&&(t.altLocList=z(r.altLocList)),r.occupancyList&&(t.occupancyList=V(r.occupancyList,100)),t.groupIdList=B(r.groupIdList),t.groupTypeList=D(r.groupTypeList),r.secStructList&&(t.secStructList=q(r.secStructList,1)),r.insCodeList&&(t.insCodeList=z(r.insCodeList)),r.sequenceIndexList&&(t.sequenceIndexList=B(r.sequenceIndexList)),t.chainIdList=P(r.chainIdList,4),r.chainNameList&&(t.chainNameList=P(r.chainNameList,4)),t}function H(r){function t(r){for(var t={},n=0;r>n;n++){var e=o();t[e]=o()}return t}function n(t){var n=r.subarray(a,a+t);return a+=t,n}function e(t){var n=r.subarray(a,a+t);a+=t;var e=65535;if(t>e){for(var i=[],o=0;on;n++)t[n]=o();return t}function o(){var o,s,f=r[a];if(0===(128&f))return a++,f;if(128===(240&f))return s=15&f,a++,t(s);if(144===(240&f))return s=15&f,a++,i(s);if(160===(224&f))return s=31&f,a++,e(s);if(224===(224&f))return o=u.getInt8(a),a++,o;switch(f){case 192:return a++,null;case 194:return a++,!1;case 195:return a++,!0;case 196:return s=u.getUint8(a+1),a+=2,n(s);case 197:return s=u.getUint16(a+1),a+=3,n(s);case 198:return s=u.getUint32(a+1),a+=5,n(s);case 202:return o=u.getFloat32(a+1),a+=5,o;case 203:return o=u.getFloat64(a+1),a+=9,o;case 204:return o=r[a+1],a+=2,o;case 205:return o=u.getUint16(a+1),a+=3,o;case 206:return o=u.getUint32(a+1),a+=5,o;case 208:return o=u.getInt8(a+1),a+=2,o;case 209:return o=u.getInt16(a+1),a+=3,o;case 210:return o=u.getInt32(a+1),a+=5,o;case 217:return s=u.getUint8(a+1),a+=2,e(s);case 218:return s=u.getUint16(a+1),a+=3,e(s);case 219:return s=u.getUint32(a+1),a+=5,e(s);case 220:return s=u.getUint16(a+1),a+=3,i(s);case 221:return s=u.getUint32(a+1),a+=5,i(s);case 222:return s=u.getUint16(a+1),a+=3,t(s);case 223:return s=u.getUint32(a+1),a+=5,t(s)}throw new Error("Unknown type 0x"+f.toString(16))}var a=0,u=new DataView(r.buffer);return o()}function W(r,t,n,e){switch(r){case 1:return h(t);case 2:return f(t);case 3:return l(t);case 4:return v(t);case 5:return s(t);case 6:return p(v(t),new Uint8Array(n));case 7:return p(v(t));case 8:return A(v(t));case 9:return M(v(t),v(e)[0]);case 10:return O(l(t),v(e)[0]);case 11:return y(l(t),v(e)[0]);case 12:return N(l(t),v(e)[0]);case 13:return N(f(t),v(e)[0]);case 14:return w(l(t));case 15:return w(f(t))}}function X(r,t){t=t||{};var n=t.ignoreFields,e={};return nr.forEach(function(t){var i=n?-1!==n.indexOf(t):!1,o=r[t];i||void 0===o||(o instanceof Uint8Array?e[t]=W.apply(null,k(o)):e[t]=o)}),e}function J(r){return String.fromCharCode.apply(null,r).replace(/\0/g,"")}function K(r,t,n){n=n||{};var e,i,o,a,u,s,f=n.firstModelOnly,c=t.onModel,d=t.onChain,l=t.onGroup,g=t.onAtom,v=t.onBond,L=0,h=0,y=0,m=0,p=0,U=-1,b=r.chainNameList,I=r.secStructList,w=r.insCodeList,C=r.sequenceIndexList,A=r.atomIdList,x=r.bFactorList,M=r.altLocList,F=r.occupancyList,S=r.bondAtomList,E=r.bondOrderList;for(e=0,i=r.chainsPerModel.length;i>e&&!(f&&L>0);++e){var N=r.chainsPerModel[L];for(c&&c({chainCount:N,modelIndex:L}),o=0;N>o;++o){var O=r.groupsPerChain[h];if(d){var T=J(r.chainIdList.subarray(4*h,4*h+4)),k=null;b&&(k=J(b.subarray(4*h,4*h+4))),d({groupCount:O,chainIndex:h,modelIndex:L,chainId:T,chainName:k})}for(a=0;O>a;++a){var j=r.groupList[r.groupTypeList[y]],q=j.atomNameList.length;if(l){var D=null;I&&(D=I[y]);var P=null;r.insCodeList&&(P=String.fromCharCode(w[y]));var z=null;C&&(z=C[y]),l({atomCount:q,groupIndex:y,chainIndex:h,modelIndex:L,groupId:r.groupIdList[y],groupType:r.groupTypeList[y],groupName:j.groupName,singleLetterCode:j.singleLetterCode,chemCompType:j.chemCompType,secStruct:D,insCode:P,sequenceIndex:z})}for(u=0;q>u;++u){if(g){var B=null;A&&(B=A[m]);var V=null;x&&(V=x[m]);var G=null;M&&(G=String.fromCharCode(M[m]));var R=null;F&&(R=F[m]),g({atomIndex:m,groupIndex:y,chainIndex:h,modelIndex:L,atomId:B,element:j.elementList[u],atomName:j.atomNameList[u],formalCharge:j.formalChargeList[u],xCoord:r.xCoordList[m],yCoord:r.yCoordList[m],zCoord:r.zCoordList[m],bFactor:V,altLoc:G,occupancy:R})}m+=1}if(v){var H=j.bondAtomList;for(u=0,s=j.bondOrderList.length;s>u;++u)v({atomIndex1:m-q+H[2*u],atomIndex2:m-q+H[2*u+1],bondOrder:j.bondOrderList[u]})}y+=1}h+=1}if(p=U+1,U=m-1,v&&S)for(u=0,s=S.length;s>u;u+=2){var W=S[u],X=S[u+1];(W>=p&&U>=W||X>=p&&U>=X)&&v({atomIndex1:W,atomIndex2:X,bondOrder:E?E[u/2]:null})}L+=1}}function Q(r){return o(R(r))}function Y(r,t){r instanceof ArrayBuffer&&(r=new Uint8Array(r));var n;return n=r instanceof Uint8Array?H(r):r,X(n,t)}function Z(r,t,n,e){function i(){try{var r=Y(o.response);n(r)}catch(t){e(t)}}var o=new XMLHttpRequest;o.addEventListener("load",i,!0),o.addEventListener("error",e,!0),o.responseType="arraybuffer",o.open("GET",t+r.toUpperCase()),o.send()}function $(r,t,n){Z(r,or,t,n)}function _(r,t,n){Z(r,ar,t,n)}var rr=["mmtfVersion","mmtfProducer","unitCell","spaceGroup","structureId","title","depositionDate","releaseDate","experimentalMethods","resolution","rFree","rWork","bioAssemblyList","ncsOperatorList","entityList","groupList","numBonds","numAtoms","numGroups","numChains","numModels","groupsPerChain","chainsPerModel"],tr=["xCoordList","yCoordList","zCoordList","groupIdList","groupTypeList","chainIdList","bFactorList","atomIdList","altLocList","occupancyList","secStructList","insCodeList","sequenceIndexList","chainNameList","bondAtomList","bondOrderList"],nr=rr.concat(tr),er="v0.3.0",ir="http://mmtf.rcsb.org/v0.2/",or=ir+"full/",ar=ir+"reduced/";r.encode=Q,r.decode=Y,r.traverse=K,r.fetch=$,r.fetchReduced=_,r.version=er,r.fetchUrl=or,r.fetchReducedUrl=ar,r.encodeMsgpack=o,r.encodeMmtf=R,r.decodeMsgpack=H,r.decodeMmtf=X}); \ No newline at end of file diff --git a/src/simple_ui.js b/src/simple_ui.js index 619485ca..5ac0300d 100644 --- a/src/simple_ui.js +++ b/src/simple_ui.js @@ -186,7 +186,7 @@ iCn3DUI.prototype = { html += "
    "; - html += "
    Loading the structure...
    "; + if(me.cfg.mmtfid === undefined) html += "
    Loading the structure...
    "; html += "Your browser does not support WebGL."; @@ -330,7 +330,12 @@ iCn3DUI.prototype = { loadStructure: function() { var me = this; me.icn3d.moleculeTitle = ''; - if(me.cfg.pdbid !== undefined) { + if(me.cfg.mmtfid !== undefined) { + me.inputid = me.cfg.mmtfid; + + me.downloadMmtf(me.cfg.mmtfid); + } + else if(me.cfg.pdbid !== undefined) { me.inputid = me.cfg.pdbid; var pdbid = me.cfg.pdbid.toLowerCase(); // http://www.rcsb.org/pdb/files/1gpk.pdb only allow lower case @@ -388,6 +393,15 @@ iCn3DUI.prototype = { me.inputid = me.cfg.align; me.downloadAlignment(me.cfg.align); } + else if(me.cfg.url !== undefined) { + var type_url = me.cfg.url.split('|'); + var type = type_url[0]; + var url = type_url[1]; + + me.inputid = undefined; + + me.downloadUrl(url, type); + } else { alert("Please input a gi, MMDB ID, PDB ID, CID, or mmCIF ID..."); } @@ -395,7 +409,10 @@ iCn3DUI.prototype = { renderStructure: function(bInitial) { var me = this; if(bInitial) { - me.icn3d.draw(me.options); + //me.icn3d.draw(me.options); + + jQuery.extend(me.icn3d.options, me.options); + me.icn3d.draw(); } else { me.icn3d.draw(); @@ -495,7 +512,8 @@ iCn3DUI.prototype = { me.icn3d.picking = 0; me.icn3d.options['picking'] = 'no'; - me.icn3d.draw(undefined, false); + //me.icn3d.draw(undefined, false); + me.icn3d.draw(); me.icn3d.removeHighlightObjects(); }); @@ -655,7 +673,12 @@ iCn3DUI.prototype = { iCn3DUI.prototype.rotateStructure = function (direction, bInitial) { var me = this; if(me.icn3d.bStopRotate) return false; - if(me.icn3d.rotateCount > me.icn3d.rotateCountMax) return false; + if(me.icn3d.rotateCount > me.icn3d.rotateCountMax) { + // back to the original orientation + me.icn3d.resetOrientation(); + + return false; + } ++me.icn3d.rotateCount; if(bInitial !== undefined && bInitial) { @@ -863,6 +886,8 @@ iCn3DUI.prototype = { // The PDB service doesn't support https, so use our reverse-proxy // service when using https var uri, dataType; + +/* if(document.location.protocol !== "https:") { //uri = "http://www.rcsb.org/pdb/files/" + pdbid + ".pdb"; uri = "http://files.rcsb.org/view/" + pdbid + ".pdb"; @@ -877,6 +902,11 @@ iCn3DUI.prototype = { window.open(url, '_self'); return; } +*/ + + uri = "https://files.rcsb.org/view/" + pdbid + ".pdb"; + + dataType = "text"; me.icn3d.bCid = undefined; @@ -895,12 +925,50 @@ iCn3DUI.prototype = { if($("#" + me.pre + "commandlog")) $("#" + me.pre + "commandlog").show(); }, success: function(data) { - if(document.location.protocol !== "https:") { - me.loadPdbData(data); - } - else { - me.loadPdbData(data.data); // from mmcifparser.cgi - } + //if(document.location.protocol !== "https:") { + // me.loadPdbData(data); + //} + //else { + // me.loadPdbData(data.data); // from mmcifparser.cgi + //} + + me.loadPdbData(data); + } + }); + }; + + iCn3DUI.prototype.downloadUrl = function (url, type) { var me = this; + var dataType = "text"; + + me.icn3d.bCid = undefined; + + $.ajax({ + url: url, + dataType: dataType, + cache: true, + beforeSend: function() { + if($("#" + me.pre + "wait")) $("#" + me.pre + "wait").show(); + if($("#" + me.pre + "canvas")) $("#" + me.pre + "canvas").hide(); + if($("#" + me.pre + "commandlog")) $("#" + me.pre + "commandlog").hide(); + }, + complete: function() { + if($("#" + me.pre + "wait")) $("#" + me.pre + "wait").hide(); + if($("#" + me.pre + "canvas")) $("#" + me.pre + "canvas").show(); + if($("#" + me.pre + "commandlog")) $("#" + me.pre + "commandlog").show(); + }, + success: function(data) { + if(type === 'pdb') { + me.loadPdbData(data); + } + else if(type === 'mol2') { + me.loadMol2Data(data); + } + else if(type === 'sdf') { + me.loadSdfData(data); + } + else if(type === 'xyz') { + me.loadXyzData(data); + } } }); }; @@ -931,6 +999,375 @@ iCn3DUI.prototype = { if(me.deferred !== undefined) me.deferred.resolve(); if(me.deferred2 !== undefined) me.deferred2.resolve(); }; + // from the 2016 NCBI hackathon in Orlando: https://github.com/NCBI-Hackathons/iCN3D-MMTF + iCn3DUI.prototype.downloadMmtf = function (mmtfid) { var me = this; + // The MMTF service doesn't support https, use http instead + var uri, dataType; + if(document.location.protocol === "https:") { + var url = document.location.href; + url = url.replace('https', 'http'); + window.open(url, '_self'); + return; + } + + MMTF.fetch( + mmtfid, + // onLoad callback + function( mmtfData ){ + + me.icn3d.init(); + + var pmin = new THREE.Vector3( 9999, 9999, 9999); + var pmax = new THREE.Vector3(-9999,-9999,-9999); + var psum = new THREE.Vector3(); + + //console.log(mmtfData); + + var id = mmtfData.structureId; + + me.icn3d.moleculeTitle = mmtfData.title; + + // bioAsembly + if(mmtfData.bioAssemblyList[0].transformList.length > 1) { + me.icn3d.biomtMatrices = []; + for(var i = 0, il = mmtfData.bioAssemblyList[0].transformList.length; i < il; ++i) { + var biomt = new THREE.Matrix4().identity(); + + for(var j = 0, jl = mmtfData.bioAssemblyList[0].transformList[i].matrix.length; j < jl; ++j) { + biomt.elements[j] = mmtfData.bioAssemblyList[0].transformList[i].matrix[j]; + } + + me.icn3d.biomtMatrices.push(biomt); + } + } + + var oriindex2serial = {}; + + // save SG atoms in CYS residues + var SGAtomSerialArray = []; + + var prevSS = 'coil'; + var prevChain = ''; + + var serial = 0; + + var structure, chain, resn, resi, ss, ssbegin, ssend; + var het, bProtein, bNucleotide; + var elem, atomName, coord, b, alt; + + var callbackDict = { + onModel: function( modelData ){ + structure = (modelData.modelIndex === 0) ? id : id + (modelData.modelIndex + 1).toString(); + }, + onChain: function( chainData ){ + chain = chainData.chainName; // or chainData.chainId + var chainid = structure + '_' + chain; + + if(me.icn3d.structures[structure] === undefined) me.icn3d.structures[structure] = []; + me.icn3d.structures[structure].push(chainid); + + if(me.icn3d.chainsAnnoTitle[chainid] === undefined ) me.icn3d.chainsAnnoTitle[chainid] = []; + if(me.icn3d.chainsAnnoTitle[chainid][0] === undefined ) me.icn3d.chainsAnnoTitle[chainid][0] = []; + if(me.icn3d.chainsAnnoTitle[chainid][1] === undefined ) me.icn3d.chainsAnnoTitle[chainid][1] = []; + me.icn3d.chainsAnnoTitle[chainid][0].push(''); + me.icn3d.chainsAnnoTitle[chainid][1].push('SS'); + }, + onGroup: function( groupData ){ + resn = groupData.groupName; + resi = groupData.groupId; + var resid = structure + '_' + chain + '_' + resi; + + if(groupData.secStruct === 0 || groupData.secStruct === 2 || groupData.secStruct === 4) { + ss = 'helix'; + } + else if(groupData.secStruct === 3) { + ss = 'sheet'; + } + else { + ss = 'coil'; + } + + // no residue can be both ssbegin and ssend in DSSP calculated secondary structures + var bSetPrevResidue = 0; // 0: no need to reset, 1: reset previous residue to "ssbegin = true", 2: reset previous residue to "ssend = true" + + if(chain !== prevChain) { + // new chain + if(ss !== 'coil') { + ssbegin = true; + ssend = false; + } + else { + ssbegin = false; + ssend = false; + } + } + else if(ss !== prevSS) { + if(prevSS === 'coil') { + ssbegin = true; + ssend = false; + } + else if(ss === 'coil') { + bSetPrevResidue = 2; + ssbegin = false; + ssend = false; + } + else if( (prevSS === 'sheet' && ss === 'helix') || (prevSS === 'helix' && ss === 'sheet')) { + bSetPrevResidue = 1; + ssbegin = true; + ssend = false; + } + } + else { + ssbegin = false; + ssend = false; + } + + if(bSetPrevResidue == 1) { //1: reset previous residue to "ssbegin = true" + var prevResid = structure + '_' + chain + '_' + (resi - 1).toString(); + for(var i in me.icn3d.residues[prevResid]) { + me.icn3d.atoms[i].ssbegin = true; + me.icn3d.atoms[i].ssend = false; + } + } + else if(bSetPrevResidue == 2) { //2: reset previous residue to "ssend = true" + var prevResid = structure + '_' + chain + '_' + (resi - 1).toString(); + for(var i in me.icn3d.residues[prevResid]) { + me.icn3d.atoms[i].ssbegin = false; + me.icn3d.atoms[i].ssend = true; + } + } + + prevSS = ss; + prevChain = chain; + + het = false; + bProtein = false; + bNucleotide = false; + if(groupData.chemCompType.toLowerCase() === 'non-polymer' || groupData.chemCompType.toLowerCase() === 'other' || groupData.chemCompType.toLowerCase().indexOf('saccharide') !== -1) { + het = true; + } + else if(groupData.chemCompType.toLowerCase().indexOf('peptide') !== -1) { + bProtein = true; + } + else if(groupData.chemCompType.toLowerCase().indexOf('dna') !== -1 || groupData.chemCompType.toLowerCase().indexOf('rna') !== -1) { + bNucleotide = true; + } + else { + bProtein = true; + } + + // add sequence information + var chainid = structure + '_' + chain; + + var resObject = {}; + resObject.resi = resi; + resObject.name = me.icn3d.residueName2Abbr(resn); + + me.icn3d.residueId2Name[resid] = resObject.name; + + if(me.icn3d.chainsSeq[chainid] === undefined) me.icn3d.chainsSeq[chainid] = []; + + if(me.icn3d.chainsAnno[chainid] === undefined ) me.icn3d.chainsAnno[chainid] = []; + if(me.icn3d.chainsAnno[chainid][0] === undefined ) me.icn3d.chainsAnno[chainid][0] = []; + if(me.icn3d.chainsAnno[chainid][1] === undefined ) me.icn3d.chainsAnno[chainid][1] = []; + + var numberStr = ''; + if(resObject.resi % 10 === 0) numberStr = resObject.resi.toString(); + + var secondaries = 'c'; + if(ss === 'helix') { + secondaries = 'H'; + } + else if(ss === 'sheet') { + secondaries = 'E'; + } + + if(me.icn3d.chainsSeq[chainid] === undefined) me.icn3d.chainsSeq[chainid] = []; + me.icn3d.chainsSeq[chainid].push(resObject); + + + if(me.icn3d.chainsAnno[chainid] === undefined) me.icn3d.chainsAnno[chainid] = []; + if(me.icn3d.chainsAnno[chainid][0] === undefined) me.icn3d.chainsAnno[chainid][0] = []; + if(me.icn3d.chainsAnno[chainid][1] === undefined) me.icn3d.chainsAnno[chainid][1] = []; + me.icn3d.chainsAnno[chainid][0].push(numberStr); + me.icn3d.chainsAnno[chainid][1].push(secondaries); + + me.icn3d.secondaries[resid] = secondaries; + + }, + onAtom: function( atomData ){ + elem = atomData.element; + atomName = atomData.atomName; + coord = new THREE.Vector3(atomData.xCoord, atomData.yCoord, atomData.zCoord); + b = atomData.bFactor; + + alt = atomData.altLoc; + if(atomData.altLoc === '\u0000') { // a temp value, should be '' + alt = ''; + } + + // skip the atoms where alt is not '' or 'A' + if(alt === '' || alt === 'A') { + ++serial; + + if(atomName === 'SG') SGAtomSerialArray.push(serial); + + oriindex2serial[atomData.atomIndex] = serial; + + var atomDetails = { + het: het, // optional, used to determine ligands, water, ions, etc + serial: serial, // required, unique atom id + name: atomName, // required, atom name + alt: alt, // optional, some alternative coordinates + resn: resn, // optional, used to determine protein or nucleotide + structure: structure, // optional, used to identify structure + chain: chain, // optional, used to identify chain + resi: resi, // optional, used to identify residue ID + //insc: line.substr(26, 1), + coord: coord, // required, used to draw 3D shape + b: b, // optional, used to draw B-factor tube + elem: elem, // optional, used to determine hydrogen bond + bonds: [], // required, used to connect atoms + bondOrder: [], + ss: ss, // optional, used to show secondary structures + ssbegin: ssbegin, // optional, used to show the beginning of secondary structures + ssend: ssend // optional, used to show the end of secondary structures + }; + + //if(het) atomDetails.bondOrder = []; + + me.icn3d.atoms[serial] = atomDetails; + + pmin.min(coord); + pmax.max(coord); + psum.add(coord); + + var chainid = structure + '_' + chain; + var resid = chainid + '_' + resi; + + if(me.icn3d.chains[chainid] === undefined) me.icn3d.chains[chainid] = {}; + me.icn3d.chains[chainid][serial] = 1; + + if(me.icn3d.residues[resid] === undefined) me.icn3d.residues[resid] = {}; + me.icn3d.residues[resid][serial] = 1; + + if (bProtein) { + me.icn3d.proteins[serial] = 1; + + if (atomName === 'CA') me.icn3d.calphas[serial] = 1; + if (atomName !== 'N' && atomName !== 'CA' && atomName !== 'C' && atomName !== 'O') me.icn3d.sidechains[serial] = 1; + } + else if (bNucleotide) { + me.icn3d.nucleotides[serial] = 1; + + if (atomName == 'P') me.icn3d.nucleotidesP[serial] = 1; + } + else { + if (elem.toLowerCase() === resn.toLowerCase()) { + me.icn3d.ions[serial] = 1; + } + else if(resn === 'HOH' || resn === 'WAT' || resn === 'SQL' || resn === 'H2O' || resn === 'W' || resn === 'DOD' || resn === 'D3O') { + me.icn3d.water[serial] = 1; + } + else { + me.icn3d.ligands[serial] = 1; + } + } + + me.icn3d.displayAtoms[serial] = 1; + me.icn3d.highlightAtoms[serial] = 1; + } + }, + onBond: function( bondData ){ + var from = oriindex2serial[bondData.atomIndex1]; + var to = oriindex2serial[bondData.atomIndex2]; + + //var from = bondData.atomIndex1 + 1; + //var to = bondData.atomIndex2 + 1; + + if(from !== undefined && to !== undefined) { // some alt atoms were skipped + me.icn3d.atoms[from].bonds.push(to); + me.icn3d.atoms[to].bonds.push(from); + + if(het) { + var order = bondData.bondOrder; + + me.icn3d.atoms[from].bondOrder.push(order); + me.icn3d.atoms[to].bondOrder.push(order); + if(order == '2') { + me.icn3d.doublebonds[from + '_' + to] = 1; + me.icn3d.doublebonds[to + '_' + from] = 1; + } + else if(order == '3') { + me.icn3d.triplebonds[from + '_' + to] = 1; + me.icn3d.triplebonds[to + '_' + from] = 1; + } + } + } + } + }; + + // traverse + MMTF.traverse( mmtfData, callbackDict ); + + // set up disulfide bonds + var sgLength = SGAtomSerialArray.length; + for(var i = 0, il = sgLength; i < il; ++i) { + for(var j = i+1, jl = sgLength; j < il; ++j) { + + var serial1 = SGAtomSerialArray[i]; + var serial2 = SGAtomSerialArray[j]; + + var atom1 = me.icn3d.atoms[serial1]; + var atom2 = me.icn3d.atoms[serial2]; + + if($.inArray(serial2, atom1.bonds) !== -1) { + var resid1 = atom1.structure + '_' + atom1.chain + '_' + atom1.resi; + var resid2 = atom2.structure + '_' + atom2.chain + '_' + atom2.resi; + + me.icn3d.ssbondpoints.push(resid1); + me.icn3d.ssbondpoints.push(resid2); + } + } + } + + me.icn3d.cnt = serial; + + me.icn3d.pmin = pmin; + me.icn3d.pmax = pmax; + me.icn3d.maxD = pmax.distanceTo(pmin); + me.icn3d.center = psum.multiplyScalar(1.0 / me.icn3d.cnt); + + if (me.icn3d.maxD < 25) me.icn3d.maxD = 25; + me.icn3d.oriMaxD = me.icn3d.maxD; + me.icn3d.oriCenter = me.icn3d.center.clone(); + + if(me.cfg.align === undefined && Object.keys(me.icn3d.structures).length == 1) { + $("#" + me.pre + "alternateWrapper").hide(); + } + + me.icn3d.setAtomStyleByOptions(me.options); + me.icn3d.setColorByOptions(me.options, me.icn3d.atoms); + + me.renderStructure(); + + me.showTitle(); + + if(me.cfg.rotate !== undefined) me.rotateStructure(me.cfg.rotate, true); + + if(me.cfg.showseq !== undefined && me.cfg.showseq) me.openDialog(me.pre + 'dl_selectresidues', 'Select residues in sequences'); + + if(me.deferred !== undefined) me.deferred.resolve(); if(me.deferred2 !== undefined) me.deferred2.resolve(); + + }, + // onError callback + function( error ){ + console.error( error ) + } + ); + }; + + iCn3DUI.prototype.downloadMmcif = function (mmcifid) { var me = this; // The PDB service doesn't support https, so use our reverse-proxy // service when using https @@ -964,7 +1401,7 @@ iCn3DUI.prototype = { if($("#" + me.pre + "commandlog")) $("#" + me.pre + "commandlog").show(); }, success: function(data) { - url = "//www.ncbi.nlm.nih.gov/Structure/mmcifparser/mmcifparser.cgi"; + url = "//www.ncbi.nlm.nih.gov/Structure/mmcifparser/mmcifparser.cgi"; $.ajax({ url: url, @@ -1133,7 +1570,9 @@ iCn3DUI.prototype = { me.icn3d.setAtomStyleByOptions(me.options); // use the original color from cgi output - me.icn3d.setColorByOptions(me.options, me.icn3d.atoms, true); + //me.icn3d.setColorByOptions(me.options, me.icn3d.atoms, true); + // change the default color to "Identity" + me.icn3d.setColorByOptions(me.options, me.icn3d.atoms); me.renderStructure(); @@ -2705,6 +3144,36 @@ iCn3DUI.prototype = { me.icn3d.oriMaxD = me.icn3d.maxD; me.icn3d.oriCenter = me.icn3d.center.clone(); + // set up disulfide bonds + if(type === 'mmdbid') { + var disulfideArray = data.disulfides; + + for(var i = 0, il = disulfideArray.length; i < il; ++i) { + var serial1 = disulfideArray[i][0].ca; + var serial2 = disulfideArray[i][1].ca; + + var atom1 = me.icn3d.atoms[serial1]; + var atom2 = me.icn3d.atoms[serial2]; + + var resid1 = atom1.structure + '_' + atom1.chain + '_' + atom1.resi; + var resid2 = atom2.structure + '_' + atom2.chain + '_' + atom2.resi; + + me.icn3d.ssbondpoints.push(resid1); + me.icn3d.ssbondpoints.push(resid2); + } + } + else if(type === 'mmcifid') { + var disulfideArray = data.disulfides; + + for(var i = 0, il = disulfideArray.length; i < il; ++i) { + var resid1 = disulfideArray[i][0]; + var resid2 = disulfideArray[i][1]; + + me.icn3d.ssbondpoints.push(resid1); + me.icn3d.ssbondpoints.push(resid2); + } + } + // set up sequence alignment if(type === 'align' && seqalign !== undefined) { //loadSeqAlignment From 42061018640b571cf15d3e61781881b2126fde05 Mon Sep 17 00:00:00 2001 From: "Wang, Jiyao" Date: Fri, 15 Jul 2016 20:24:11 -0400 Subject: [PATCH 2/4] change release date --- README.md | 2 +- icn3d.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a2276ef..e0261da6 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ gulp gh-pages ## Change log -The production version [icn3d-1.1.0](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d-1.1.0.zip) was release on July 14, 2016. The new binary MMTF file format was supported. A new "Analysis" menu was added with an option to show disulfide bonds. Users can also input data from a url, either through the UI or through a encoded url parameter "?type=pdb&url=...", e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?type=pdb&url=https%3A%2F%2Ffiles.rcsb.org%2Fview%2F1gpk.pdb. +The production version [icn3d-1.1.0](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d-1.1.0.zip) was release on July 18, 2016. The new binary MMTF file format was supported. A new "Analysis" menu was added with an option to show disulfide bonds. Users can also input data from a url, either through the UI or through a encoded url parameter "?type=pdb&url=...", e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?type=pdb&url=https%3A%2F%2Ffiles.rcsb.org%2Fview%2F1gpk.pdb. ## Contact diff --git a/icn3d.html b/icn3d.html index 26dd87c8..05206c1d 100644 --- a/icn3d.html +++ b/icn3d.html @@ -1497,7 +1497,7 @@

    API Documents of the advanced UI library iCn3DUI

    Change Log:back to top

    -The production version icn3d-1.1.0 was release on July 14, 2016. The new binary MMTF file format was supported. A new "Analysis" menu was added with an option to show disulfide bonds. Users can also input data from a url, either through the UI or through a encoded url parameter "?type=pdb&url=...", e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?type=pdb&url=https%3A%2F%2Ffiles.rcsb.org%2Fview%2F1gpk.pdb. +The production version icn3d-1.1.0 was release on July 18, 2016. The new binary MMTF file format was supported. A new "Analysis" menu was added with an option to show disulfide bonds. Users can also input data from a url, either through the UI or through a encoded url parameter "?type=pdb&url=...", e.g., https://www.ncbi.nlm.nih.gov/Structure/icn3d/full.html?type=pdb&url=https%3A%2F%2Ffiles.rcsb.org%2Fview%2F1gpk.pdb.

    The production version icn3d-1.0.1 was release on May 16, 2016. From 8d0e3dfb57204958ff0e64b0f1b97b3b331c5d2f Mon Sep 17 00:00:00 2001 From: "Wang, Jiyao" Date: Fri, 15 Jul 2016 20:34:18 -0400 Subject: [PATCH 3/4] change some descriptions --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e0261da6..33d7baf6 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ See the [help page](https://www.ncbi.nlm.nih.gov/Structure/icn3d/icn3d.html) for ## Tools based on -* **[iview](http://istar.cse.cuhk.edu.hk/iview/)**: iCn3D is mainly based on iview. -* **[GLmol](https://en.osdn.jp/projects/webglmol/)**: Drawing cartoon of nucleotides is from GLmol. +* **[iview](http://istar.cse.cuhk.edu.hk/iview/)**: The drawing of 3D objects is mainly based on iview. +* **[GLmol](https://en.osdn.jp/projects/webglmol/)**: The drawing of nucleotides cartoon is from GLmol. * **[3Dmol](http://3dmol.csb.pitt.edu/)**: The surface generation and labeling are from 3Dmol. ## Building From 675fd33488132c673bcaf05397f7c3f74c48f384 Mon Sep 17 00:00:00 2001 From: "Wang, Jiyao" Date: Mon, 18 Jul 2016 23:11:45 -0400 Subject: [PATCH 4/4] fix double bond drawing --- src/full_ui.js | 10 +++++----- src/icn3d.js | 33 ++++++++++++++++++++------------- src/simple_ui.js | 10 +++++----- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/full_ui.js b/src/full_ui.js index fe8a429e..9971d91c 100644 --- a/src/full_ui.js +++ b/src/full_ui.js @@ -7877,8 +7877,6 @@ iCn3DUI.prototype = { var pmax = new THREE.Vector3(-9999,-9999,-9999); var psum = new THREE.Vector3(); - //console.log(mmtfData); - var id = mmtfData.structureId; me.icn3d.moleculeTitle = mmtfData.title; @@ -8141,7 +8139,8 @@ iCn3DUI.prototype = { //var from = bondData.atomIndex1 + 1; //var to = bondData.atomIndex2 + 1; - if(from !== undefined && to !== undefined) { // some alt atoms were skipped + //if(from !== undefined && to !== undefined) { // some alt atoms were skipped + if(oriindex2serial.hasOwnProperty(bondData.atomIndex1) && oriindex2serial.hasOwnProperty(bondData.atomIndex2)) { // some alt atoms were skipped me.icn3d.atoms[from].bonds.push(to); me.icn3d.atoms[to].bonds.push(from); @@ -8150,11 +8149,12 @@ iCn3DUI.prototype = { me.icn3d.atoms[from].bondOrder.push(order); me.icn3d.atoms[to].bondOrder.push(order); - if(order == '2') { + + if(order === 2) { me.icn3d.doublebonds[from + '_' + to] = 1; me.icn3d.doublebonds[to + '_' + from] = 1; } - else if(order == '3') { + else if(order === 3) { me.icn3d.triplebonds[from + '_' + to] = 1; me.icn3d.triplebonds[to + '_' + from] = 1; } diff --git a/src/icn3d.js b/src/icn3d.js index b33a5390..ca3daca2 100644 --- a/src/icn3d.js +++ b/src/icn3d.js @@ -2070,16 +2070,20 @@ iCn3D.prototype = { if(me.doublebonds.hasOwnProperty(pair)) { // show double bond var a0, a1, a2; - if(atom0.bonds.length > atom1.bonds.length) { + if(atom0.bonds.length > atom1.bonds.length && atom0.bonds.length > 1) { a0 = atom0.serial; a1 = atom0.bonds[0]; a2 = atom0.bonds[1]; } - else { + //else { + else if(atom1.bonds.length > 1) { a0 = atom1.serial; a1 = atom1.bonds[0]; a2 = atom1.bonds[1]; } + else { + return; + } var v1 = me.atoms[a0].coord.clone(); v1.sub(me.atoms[a1].coord); @@ -2106,16 +2110,19 @@ iCn3D.prototype = { } else if(me.aromaticbonds.hasOwnProperty(pair)) { // show aromatic bond var a0, a1, a2; - if(atom0.bonds.length > atom1.bonds.length) { + if(atom0.bonds.length > atom1.bonds.length && atom0.bonds.length > 1) { a0 = atom0.serial; a1 = atom0.bonds[0]; a2 = atom0.bonds[1]; } - else { + else if(atom1.bonds.length > 1) { a0 = atom1.serial; a1 = atom1.bonds[0]; a2 = atom1.bonds[1]; } + else { + return; + } var v1 = me.atoms[a0].coord.clone(); v1.sub(me.atoms[a1].coord); @@ -3695,7 +3702,7 @@ iCn3D.prototype = { } return bPhosphorusOnly; - }, + }, // modified from GLmol (http://webglmol.osdn.jp/index-en.html) drawCartoonNucleicAcid: function(atomlist, div, thickness, bHighlight) { @@ -4922,16 +4929,16 @@ iCn3D.prototype = { this.createCylinderHelix(this.hash2Atoms(atomHash), 1.6, bHighlight); } else if(style === 'nucleotide cartoon') { - var bPhosphorusOnly = this.isPhosphorusOnly(this.hash2Atoms(atomHash)); + var bPhosphorusOnly = this.isPhosphorusOnly(this.hash2Atoms(atomHash)); - if(bPhosphorusOnly) { - this.createCylinderCurve(this.hash2Atoms(atomHash), 'P', 0.2, false, bHighlight); - } - else { - this.drawCartoonNucleicAcid(this.hash2Atoms(atomHash), null, this.thickness, bHighlight); + if(bPhosphorusOnly) { + this.createCylinderCurve(this.hash2Atoms(atomHash), 'P', 0.2, false, bHighlight); + } + else { + this.drawCartoonNucleicAcid(this.hash2Atoms(atomHash), null, this.thickness, bHighlight); - if(bHighlight !== 2) this.drawNucleicAcidStick(this.hash2Atoms(atomHash), bHighlight); - } + if(bHighlight !== 2) this.drawNucleicAcidStick(this.hash2Atoms(atomHash), bHighlight); + } } else if(style === 'phosphorus trace') { this.createCylinderCurve(this.hash2Atoms(atomHash), 'P', 0.2, false, bHighlight); diff --git a/src/simple_ui.js b/src/simple_ui.js index 5ac0300d..a747a29b 100644 --- a/src/simple_ui.js +++ b/src/simple_ui.js @@ -1021,8 +1021,6 @@ iCn3DUI.prototype = { var pmax = new THREE.Vector3(-9999,-9999,-9999); var psum = new THREE.Vector3(); - //console.log(mmtfData); - var id = mmtfData.structureId; me.icn3d.moleculeTitle = mmtfData.title; @@ -1285,7 +1283,8 @@ iCn3DUI.prototype = { //var from = bondData.atomIndex1 + 1; //var to = bondData.atomIndex2 + 1; - if(from !== undefined && to !== undefined) { // some alt atoms were skipped + //if(from !== undefined && to !== undefined) { // some alt atoms were skipped + if(oriindex2serial.hasOwnProperty(bondData.atomIndex1) && oriindex2serial.hasOwnProperty(bondData.atomIndex2)) { // some alt atoms were skipped me.icn3d.atoms[from].bonds.push(to); me.icn3d.atoms[to].bonds.push(from); @@ -1294,11 +1293,12 @@ iCn3DUI.prototype = { me.icn3d.atoms[from].bondOrder.push(order); me.icn3d.atoms[to].bondOrder.push(order); - if(order == '2') { + + if(order === 2) { me.icn3d.doublebonds[from + '_' + to] = 1; me.icn3d.doublebonds[to + '_' + from] = 1; } - else if(order == '3') { + else if(order === 3) { me.icn3d.triplebonds[from + '_' + to] = 1; me.icn3d.triplebonds[to + '_' + from] = 1; }
    Structure:
    "; @@ -3861,7 +4084,7 @@ iCn3DUI.prototype = { html += "