Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Demo of many NGL instances on one page
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<link rel="stylesheet" href="" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src=""></script>
<script src=""></script>
.structureframe {
height: 220px;
/*border:solid 1px black;*/
text-align: center;
.structureframe .pdbid {
text-transform: uppercase;
font-size: 12px;
.structureframe .pdbdate {
font-size: 10px;
.structureframe .title {
font-size: 10px;
color: grey;
width: 140px;
text-transform: capitalize;
.structureframe .viewport {
.structureframe .light {
width: 8px;
height: 8px;
position: absolute;
right: 1px;
bottom: 1px;
border-radius: 50%;
background: red;
/*display: none; */
<script src=""></script>
<script src=""></script>
'use strict';
NGL.mainScriptFilePath = "";
var spinnerUrl = "";
* Represents one structure on the page.
* Boxes can be active (NGL instance), or inactive (static image).
* You can listen for state change notifications with
* box.$viewport.on('StructureBox:activate',... or 'StructureBox:deactivate'
class StructureBox {
constructor(pdbId,$viewport) {
this.pdbId = pdbId;
this._active = false;
this.$viewport = $viewport;
this.stage = null;
this.orientation = null;
/// Trigger notifications on the viewport
set active(val) {
if(this._active != val) {
if(val) {
this._active = val;
} else {
this._active = val;
get active() {
return this._active;
* Enable NGL for this structure
* @return a Promise to resolve upon completion
activate() {
var pdbId = this.pdbId;
console.log("Activating "+pdbId); = true;
// Replace static image with NGL
// set up NGL
this.stage = new NGL.Stage( "viewport"+pdbId );
this.stage.setParameters({ backgroundColor:"white"} );
// Debugging info about webgl events
this.$viewport.find("canvas").on('webglcontextlost', function(e) {
console.log("Lost context for "+pdbId);
}).on('webglcontextrestored', function(e) {
console.log("Restored context for "+pdbId);
return this.stage.loadFile("rcsb://"+pdbId, { defaultRepresentation: true } )
.then(() => {
if(this.orientation) {
* Disable NGL for this structure, replacing it with an image.
* @return a Promise
deactivate() {
var pdbId = this.pdbId;
console.log("Deactivating "+pdbId); = false;
// toggle click handler
var $viewport = this.$viewport;
// Save canvas reference
var $canvas = $viewport.find("canvas");
// async replace spinner with screenshot of NGL
var stage = this.stage;
if( stage ) {
this.orientation = stage.getOrientation();
return stage.makeImage({
factor: 2,
antialias: true,
trim: false,
transparent: false
}).then( (blob) => { //resolve
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL(blob);
// Replace NGL with static image
// // Destroy NGL stage
// $canvas.each(function(i,canvas) {
// var gl = canvas.getContext("webgl");
// // currently only implemented on Firefox
// var ext = gl.getExtension("WEBGL_lose_context")
// if(ext) {
// // Explicitely free webgl
// // On other browsers, will happen upon garbage collection
// ext.loseContext();
// }
// });
}, () => { //reject
} else {
return Promise.resolve();
setImage(url) {
if( url ){
this.imageUrl = url;
var $img = $("<img/>", {
"src": this.imageUrl,
"css": {
* Queue to manage activating StructureBoxes.
* Because browsers are limited to 16 WebGL instances (across all browser tabs),
* this class automatically disables boxes to keep the total number active reasonable.
* Note that the actual WebGL contexts won't get dropped until the browser runs GC.
* All activations of the boxes managed by this queue should happen through the queue.
class StructureQueue {
constructor(boxes) {
this.boxes = boxes; // map pdbId -> StructureBox
this.activeBoxes = []; //queue of pdbId by activateion time (push latest, shift oldest)
this.maxActive = 2;
this.ongoing = Promise.resolve(); // promise with ongoing activations
* @return a Promise, whose resolve and return methods will be passed the StructureBox
activate(pdbId) {
var box = this.boxes[pdbId];
if( box === undefined) {
return Promise.reject(new Error("Error: unregistered pdbId: "+pdbId));
this.ongoing = this.ongoing.then( () => {
var activeIndex = this.activeBoxes.indexOf(pdbId);
if( activeIndex >= 0 ) {
// Already active; make most recent item
console.log("DEBUG "+pdbId+" already active; ignoring");
return Promise.resolve();
// check for free WebGL contexts
if(this.activeBoxes.length < this.maxActive) {
// activate immediately
console.log("DEBUG activating "+pdbId+" immediately");
return box.activate();
} else {
// deactivate a box first
var oldBoxId = this.activeBoxes[0];
var oldBox = this.boxes[oldBoxId];
console.log("DEBUG first deactivating "+oldBoxId+" to make space for "+pdbId);
return oldBox.deactivate().then( () => {
if( ) {
throw new Error("Error: unsuccessfully deactivated "+pdbId);
// Remove old box from queue
var i = this.activeBoxes.indexOf(oldBoxId);
for( i in this.boxes) {
if( this.boxes[i].active != (this.activeBoxes.indexOf(i)>=0)) {
// Shouldn't happen; debugging
console.log("Error: "+i+" is "+(this.boxes[i].active?"active":"inactive")
+" but is "+((this.activeBoxes.indexOf(i)>=0)?"":"not ")+ "in activeBoxes");
//TODO not thread safe. Race conditions?
if(this.activeBoxes.length >= this.maxActive) {
// shouldn't happen; could indicate threading error
throw new Error("Error: Too many active boxes");
// now activate the new box
return box.activate();
}, (e) => {
// Try to clean up activeBoxes list despite error
if( ! && this.activeBoxes[0].pdbId == pdbId) {
throw e;
return this.ongoing;
* Create basic wrapper div for a single structure (in inactive state)
* @param structure: dict with structure info
* @return
function createStructPanel($parent,structure) {
var pdbId = structure.pdbId;
var $wrapper = $("<div/>", {
id: 'wrapper'+pdbId,
class: 'structureframe col-sm-4 col-md-1',
text: pdbId,
class: "pdbid",
// $("<p/>", {
// text: structure.title,
// class: "pdbtitle",
// }).appendTo($wrapper);
var date = moment("YYYY-MM-DD");
$("<p/>", {
text: date,
class: "pdbdate",
var $viewport = $("<div/>", {
'id': 'viewport'+pdbId,
'class': 'viewport'
// Light to indicate that this box is active; debugging only
var $light = $("<div/>", {
'id': 'light'+pdbId,
'class': 'light',
$viewport.on('StructureBox:deactivate', (box) => {
$viewport.on('StructureBox:activate', (box) => {
var box = new StructureBox(pdbId,$viewport);
return box;
function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
var data = [
{"title":"1-AMINOCYCLOPROPANE-1-CARBOXYLATE SYNTHASE","pdbId":"1B8G","date":"1999-01-31","description":"LYASE"},{"title":"ASPARTATE AMINOTRANSFERASE P195A MUTANT","pdbId":"1BQA","date":"1998-08-13","description":"AMINOTRANSFERASE"},{"title":"ASPARTATE AMINOTRANSFERASE P138A/P195A DOUBLE MUTANT","pdbId":"1BQD","date":"1998-08-14","description":"AMINOTRANSFERASE"},{"title":"CRYSTAL STRUCTURE OF THIOREDOXIN F FROM SPINACH CHLOROPLAST (SHORT FORM)","pdbId":"1F9M","date":"2000-07-11","description":"ELECTRON TRANSPORT"},{"title":"CRYSTAL STRUCTURE OF THIOREDOXIN F FROM SPINACH CHLOROPLAST (LONG FORM)","pdbId":"1FAA","date":"2000-07-13","description":"ELECTRON TRANSPORT"},{"title":"CRYSTAL STRUCTURE OF THIOREDOXIN M FROM SPINACH CHLOROPLAST (REDUCED FORM)","pdbId":"1FB0","date":"2000-07-14","description":"ELECTRON TRANSPORT"},{"title":"CRYSTAL STRUCTURE OF THIOREDOXIN M FROM SPINACH CHLOROPLAST (OXIDIZED FORM)","pdbId":"1FB6","date":"2000-07-14","description":"ELECTRON TRANSPORT"},{"title":"CRYSTAL STRUCTURE OF THE SOLUBLE DOMAIN OF TLPA FROM BRADYRHIZOBIUM JAPONICUM","pdbId":"1JFU","date":"2001-06-22","description":"MEMBRANE PROTEIN"},{"title":"Crystal Structure Of The LCMV Peptidic Epitope Gp276 In Complex With The Murine Class I Mhc Molecule H-2Db","pdbId":"1JPF","date":"2001-08-02","description":"IMMUNE SYSTEM"},{"title":"Crystal Structure Of The LCMV Peptidic Epitope Np396 In Complex With The Murine Class I Mhc Molecule H-2Db","pdbId":"1JPG","date":"2001-08-02","description":"IMMUNE SYSTEM"},{"title":"Crystal Structure of the Anti-His Tag Antibody 3D5 Single-Chain Fragment (scFv) in Complex with a Oligohistidine peptide","pdbId":"1KTR","date":"2002-01-17","description":"IMMUNE SYSTEM"},{"title":"CRYSTAL STRUCTURE OF APPLE ACC SYNTHASE IN COMPLEX WITH [2-(AMINO-OXY)ETHYL](5\u0027-DEOXYADENOSIN-5\u0027-YL)(METHYL)SULFONIUM","pdbId":"1M4N","date":"2002-07-03","description":"LYASE"},{"title":"Crystal structure of apple ACC synthase in complex with L-aminoethoxyvinylglycine","pdbId":"1M7Y","date":"2002-07-23","description":"LYASE"},{"title":"Crystal structure of a mycobacterial hsp60 epitope with the murine class I MHC molecule H-2Db","pdbId":"1N3N","date":"2002-10-29","description":"IMMUNE SYSTEM"},{"title":"Crystal structure of Escherichia coli GadB (low pH)","pdbId":"1PMM","date":"2003-06-11","description":"LYASE"},{"title":"Crystal structure of Escherichia coli GadB (neutral pH)","pdbId":"1PMO","date":"2003-06-11","description":"LYASE"},{"title":"Crystal structure of the disulfide-linked complex between the N-terminal and C-terminal domain of the electron transfer catalyst DsbD","pdbId":"1VRS","date":"2005-06-17","description":"OXIDOREDUCTASE"},{"title":"Crystal structure of apple ACC synthase in complex with L-vinylglycine","pdbId":"1YNU","date":"2005-01-25","description":"Lyase"},{"title":"Crystal Structure Of The Disulfide-Linked Complex Between The N-Terminal Domain Of The Electron Transfer Catalyst DsbD and The Cytochrome c Biogenesis Protein CcmG","pdbId":"1Z5Y","date":"2005-03-21","description":"OXIDOREDUCTASE/BIOSYNTHETIC PROTEIN"},{"title":"Solution Structure of the type 1 pilus assembly platform FimD(25-139)","pdbId":"1ZDV","date":"2005-04-15","description":"MEMBRANE PROTEIN"},{"title":"Solution Structure of the type 1 pilus assembly platform FimD(25-125)","pdbId":"1ZDX","date":"2005-04-15","description":"Membrane Protein"},{"title":"Crystal Structure of the Ternary Complex of FIMD (N-Terminal Domain) with FIMC and the Pilin Domain of FIMH","pdbId":"1ZE3","date":"2005-04-17","description":"CHAPERONE/STRUCTURAL/MEMBRANE PROTEIN"},{"title":"Crystal structure of Aminoglycoside Phosphotransferase APH(3\u0027)-IIIa in complex with the designed ankyrin repeat inhibitor AR_3a","pdbId":"2BKK","date":"2005-02-16","description":"TRANSFERASE/PEPTIDE"},{"title":"Crystal structure of an N-terminal deletion mutant of Escherichia coli GadB in an autoinhibited state (aldamine)","pdbId":"2DGK","date":"2006-03-14","description":"LYASE"},{"title":"Crystal structure of Escherichia coli GadB in complex with bromide","pdbId":"2DGL","date":"2006-03-14","description":"LYASE"},{"title":"Crystal structure of Escherichia coli GadB in complex with iodide","pdbId":"2DGM","date":"2006-03-14","description":"LYASE"},{"title":"Crystal Structure of the PRYSPRY-domain","pdbId":"2FBE","date":"2005-12-09","description":"UNKNOWN FUNCTION"},{"title":"crystal structure of the C-terminal domain of the electron transfer catalyst DsbD (oxidized form)","pdbId":"2FWE","date":"2006-02-02","description":"Oxidoreductase"},{"title":"high resolution crystal structure of the C-terminal domain of the electron transfer catalyst DsbD (reduced form)","pdbId":"2FWF","date":"2006-02-02","description":"Oxidoreductase"},{"title":"high resolution crystal structure of the C-terminal domain of the electron transfer catalyst DsbD (photoreduced form)","pdbId":"2FWG","date":"2006-02-02","description":"Oxidoreductase"},{"title":"atomic resolution crystal structure of the C-terminal domain of the electron transfer catalyst DsbD (reduced form at pH7)","pdbId":"2FWH","date":"2006-02-02","description":"Oxidoreductase"},{"title":"NMR structure of region 2 of E. coli sigmaE","pdbId":"2MAO","date":"2013-07-16","description":"TRANSCRIPTION"},{"title":"Solution structure of the complex formed by the region 2 of E. coli sigmaE and its cognate -10 promoter element non template strand TGTCAAA.","pdbId":"2MAP","date":"2013-07-16","description":"TRANSCRIPTION/DNA"},{"title":"ORNITHINE AMINOTRANSFERASE COMPLEXED WITH 5-FLUOROMETHYLORNITHINE","pdbId":"2OAT","date":"1998-05-07","description":"AMINOTRANSFERASE"},{"title":"Inhibition of caspase-2 by a designed ankyrin repeat protein (DARPin)","pdbId":"2P2C","date":"2007-03-07","description":"HYDROLASE"},{"title":"Crystal structure of truncated FimG (FimGt) in complex with the donor strand peptide of FimF (DSF)","pdbId":"3BFQ","date":"2007-11-23","description":"STRUCTURAL PROTEIN/STRUCTURAL PROTEIN"},{"title":"Crystal structure of truncated FimG (FimGt) in complex with the donor strand peptide of FimF (DSF)","pdbId":"3BFW","date":"2007-11-23","description":"STRUCTURAL PROTEIN/STRUCTURAL PROTEIN"},{"title":"Crystal structure of the ternary complex of FimD (N-Terminal Domain, FimDN) with FimC and the N-terminally truncated pilus subunit FimF (FimFt)","pdbId":"3BWU","date":"2008-01-10","description":"CHAPERONE, STRUCTURAL, MEMBRANE PROTEIN"},{"title":"Crystal structure of reduced DsbL","pdbId":"3C7M","date":"2008-02-07","description":"OXIDOREDUCTASE"},{"title":"Crystal structure of the zink-knuckle 2 domain of human CLIP-170 in complex with CAP-Gly domain of human dynactin-1 (p150-GLUED)","pdbId":"3E2U","date":"2008-08-06","description":"PROTEIN BINDING"},{"title":"Crystal structure of oxidized Ost6L","pdbId":"3G7Y","date":"2009-02-11","description":"TRANSFERASE"},{"title":"Crystal structure of reduced Ost6L","pdbId":"3G9B","date":"2009-02-13","description":"TRANSFERASE"},{"title":"Crystal structure of Ost6L (photoreduced form)","pdbId":"3GA4","date":"2009-02-16","description":"TRANSFERASE"},{"title":"Crystal structure of GAD1 from Arabidopsis thaliana","pdbId":"3HBX","date":"2009-05-05","description":"LYASE"},{"title":"Crystal structure of StSPL (symmetric form)","pdbId":"3MAD","date":"2010-03-23","description":"LYASE"},{"title":"Crystal structure of StSPL (asymmetric form)","pdbId":"3MAF","date":"2010-03-23","description":"LYASE"},{"title":"Crystal structure of StSPL in complex with phosphoethanolamine","pdbId":"3MAU","date":"2010-03-24","description":"LYASE"},{"title":"Crystal structure of StSPL - apo form, after treatment with semicarbazide","pdbId":"3MBB","date":"2010-03-25","description":"LYASE"},{"title":"Crystal structure of ScDPL1","pdbId":"3MC6","date":"2010-03-27","description":"LYASE"},{"title":"High-resolution structure of native Malus domestica ACC synthase","pdbId":"3PIU","date":"2010-11-08","description":"LYASE"},{"title":"Structure of the major type 1 pilus subunit FimA bound to the FimC chaperone","pdbId":"3SQB","date":"2011-07-05","description":"STRUCTURAL PROTEIN/CHAPERONE"},{"title":"EB1c/EB3c heterodimer in complex with the CAP-Gly domain of P150glued","pdbId":"3TQ7","date":"2011-09-09","description":"PROTEIN BINDING"},{"title":"Structure of the major type 1 pilus subunit FIMA bound to the FIMC (2.5 A resolution)","pdbId":"4DWH","date":"2012-02-24","description":"STRUCTURAL PROTEIN/CHAPERONE"},{"title":"E. coli thioredoxin variant with Pro76 as single proline residue","pdbId":"4HU7","date":"2012-11-02","description":"oxidoreductase"},{"title":"E. coli thioredoxin variant with (4S)-FluoroPro76 as single proline residue","pdbId":"4HU9","date":"2012-11-02","description":"oxidoreductase"},{"title":"E. coli thioredoxin variant with (4R)-FluoroPro76 as single proline residue","pdbId":"4HUA","date":"2012-11-02","description":"oxidoreductase"},{"title":"CRYSTAL STRUCTURE OF THE BOTULINUM NEUROTOXIN A RECEPTOR-BINDING DOMAIN IN COMPLEX WITH THE LUMINAL DOMAIN Of SV2C","pdbId":"4JRA","date":"2013-03-21","description":"HYDROLASE"},{"title":"Crystal structure of the complex formed by region of E. coli sigmaE bound to its -10 element non template strand","pdbId":"4LUP","date":"2013-07-25","description":"TRANSCRIPTION/DNA"},{"title":"Crystal structure of serine hydroxymethyltransferase from Psychromonas ingrahamii","pdbId":"4P3M","date":"2014-03-09","description":"TRANSFERASE"},{"title":"Crystal structure of LppA from Legionella pneumophila","pdbId":"4TVV","date":"2014-06-28","description":"HYDROLASE"},{"title":"Crystal structure of the mixed disulfide complex of thioredoxin-like TlpAs(C110S) and copper chaperone ScoIs(C74S)","pdbId":"4TXO","date":"2014-07-04","description":"OXIDODREDUCTASE/COPPER BINDING PROTEIN"},{"title":"Crystal structure of the mixed disulfide intermediate between thioredoxin-like TlpAs(C110S) and subunit II of cytochrome c oxidase CoxBPD (C233S)","pdbId":"4TXV","date":"2014-07-07","description":"PROTEIN BINDING"},{"title":"Apo-structure of the Y79F,W322E-double mutant of Etr1p","pdbId":"4W99","date":"2014-08-27","description":"OXIDOREDUCTASE"},{"title":"STRUCTURE OF THE ETR1P/NADP/CROTONYL-COA COMPLEX","pdbId":"4WAS","date":"2014-08-31","description":"OXIDOREDUCTASE"},{"title":"Crystal structure of the E. coli type 1 pilus subunit FimG (engineered variant with substitution Q134E; N-terminal FimG residues 1-12 truncated) in complex with the donor strand peptide DsF_T4R-T6R-D13N","pdbId":"5IQM","date":"2016-03-11","description":"CELL ADHESION"},{"title":"Crystal structure of the E. coli type 1 pilus subunit FimG (engineered variant with substitution Q134E; N-terminal FimG residues 1-12 truncated) in complex with the donor strand peptide DsF_SRIRIRGYVR","pdbId":"5IQN","date":"2016-03-11","description":"CELL ADHESION"},{"title":"Crystal structure of the E. coli type 1 pilus subunit FimG (engineered variant with substitutions Q134E and S138E; N-terminal FimG residues 1-12 truncated) in complex with the donor strand peptide DsF_T4R-T6R-D13N","pdbId":"5IQO","date":"2016-03-11","description":"CELL ADHESION"},{"title":"Complex structure between p60N/p80C katanin and a peptide derived from ASPM","pdbId":"5LB7","date":"2016-06-15","description":"HYDROLASE"},{"title":"Apo structure of p60N/p80C katanin","pdbId":"5NBT","date":"2017-03-02","description":"HYDROLASE"},{"title":"Crystal structure of VEGF-A in complex with VEGFR-1 domains D1-6","pdbId":"5T89","date":"2016-09-07","description":"TRANSFERASE"}
<title>Guido's Structures</title>
var boxes;
var queue;
$(document).ready( function() {
var $row;
$row = $("<div/>", {
boxes = {};
for(var i=0;i<data.length-66;i++) {
// for(var i=0;i<10;i++) {
// if(i%9 == 0) {
// $row = $("<div/>", {
// class:"row"
// }).appendTo("#structures");
// }
var box = createStructPanel($row,data[i]);
boxes[box.pdbId] = box;
queue = new StructureQueue(boxes);
// Click handlers
for( var pdbId in boxes) {
var box = boxes[pdbId];
(function(box) {
.click( function() {
}).on('mouseenter', (event) => {
var hoverTime = 200; //ms
box.lastEntered = event.timeStamp;
if(! {
// console.log("DEBUG entered");
setTimeout( () => {
if( {
if( box.lastEntered ) {
}, hoverTime);
}).on('mouseleave',(event) => {
// console.log("DEBUG left");
box.lastEntered = undefined;
//.on('mousemove', (event) => {
// activate if the mouse has hovered long enough
// Activate everything sequentially
var q = Promise.resolve();
for( var pdbId in boxes) {
//TODO Improve queue so that sequential activation isn't required
// (function(pdbId){q = q.then(() => queue.activate(pdbId))})(pdbId);
} );
<div class="container">
<div class="jumbotron">
<h1>Structures by Guido Capitani</h1>
<div id="structures"></div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.