Created
January 6, 2009 11:33
-
-
Save anonymous/43774 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<script language=javascript> | |
// | |
// molecular depictions in a canvas element, by Richard Hall, Jan 2009 | |
// | |
// when I've finished reading Crockford's Javascript - The Good Parts, I should tidy this up... | |
// | |
//a really simple atom class | |
function Atom(type, x, y){ | |
this.type = type; | |
this.crd = new Array(x, y); | |
} | |
//an atom representation string | |
Atom.prototype.repr = function(){ | |
return('atom '+this.type+':'+this.crd[0]+' '+this.crd[1]); | |
} | |
//scale 2d atom coordinates to coordinates that will fit in the canvas context, leaving some border | |
Atom.prototype.context = function(border, xscale, yscale, xr, yr){ | |
var x = border + (this.crd[0]-xr[0])/(xr[1]-xr[0]) * xscale; | |
var y = border + (1.0 - (this.crd[1]-yr[0])/(yr[1]-yr[0])) * yscale; | |
return new Array(x, y); | |
} | |
//a really simple bond class | |
function Bond(a, b, type){ | |
this.a = a; | |
this.b = b; | |
this.type = type; | |
} | |
//a bond representation string | |
Bond.prototype.repr = function(){ | |
var atype = new Array('x', '-', '=', '#'); | |
return('bond '+this.a+atype[this.type]+this.b); | |
} | |
//a really simple molecule class, built from a jme string... | |
function Molecule(str){ | |
var i; | |
this.atoms = new Array; | |
this.bonds = new Array; | |
var tok = str.split(" "); | |
this.natoms = parseInt(tok[0]); | |
this.nbonds = parseInt(tok[1]); | |
for(i=2; i<2+3*this.natoms; i+=3){ | |
var type = tok[i]; | |
var xcrd = parseFloat(tok[i+1]); | |
var ycrd = parseFloat(tok[i+2]); | |
this.atoms[this.atoms.length] = new Atom(type, xcrd, ycrd); | |
} | |
var start = 2+3*this.natoms; | |
for(var i=start; i<tok.length; i+=3){ | |
var a = parseInt(tok[i])-1; | |
var b = parseInt(tok[i+1])-1; | |
var type = parseInt(tok[i+2]); | |
this.bonds[this.bonds.length] = new Bond(a, b, type); | |
} | |
} | |
//a molecular representation string | |
Molecule.prototype.repr = function(){ | |
var i; | |
var s = ''; | |
for(i=0; i<this.atoms.length; i++){ | |
s += this.atoms[i].repr()+'\n'; | |
} | |
for(i=0; i<this.bonds.length; i++){ | |
s += this.bonds[i].repr()+'\n'; | |
} | |
return(s); | |
} | |
//return the min max extent in a given dimension (0:x, 1:y) | |
Molecule.prototype.minmax = function(dim){ | |
var minv = 99999.9; | |
var maxv = -99999.9; | |
for(var i=0; i<this.atoms.length;i++){ | |
minv = this.atoms[i].crd[dim] < minv ? this.atoms[i].crd[dim] : minv; | |
maxv = this.atoms[i].crd[dim] > maxv ? this.atoms[i].crd[dim] : maxv; | |
} | |
return Array(minv, maxv); | |
} | |
//draw a molecule to the canvas element named id | |
Molecule.prototype.depict = function(id){ | |
var cnv = document.getElementById(id); | |
var border=20; //the amount of whitespace around the depiction in pixels | |
//scaling to make the molecule fit the element dimensions | |
var xreg = this.minmax(0); | |
var yreg = this.minmax(1); | |
var xyratio = (xreg[1]-xreg[0])/(yreg[1]-yreg[0]); | |
//additional scaling if the canvas is not square... | |
var canvasratio = (cnv.width-2*border)/(cnv.height-2*border); | |
var xyratio = xyratio/canvasratio; | |
var xscale, yscale; | |
if(xyratio > 1){ | |
xscale = (cnv.width-2*border); | |
yscale = (cnv.height-2*border)/xyratio; | |
} | |
else{ | |
xscale = (cnv.width-2*border)*xyratio; | |
yscale = (cnv.height-2*border); | |
} | |
var ctx = cnv.getContext('2d'); | |
//clear the context | |
ctx.clearRect(0, 0, cnv.width, cnv.height) | |
//draw the bonds | |
for(var i=0; i<this.bonds.length;i++){ | |
var a = this.atoms[this.bonds[i].a]; | |
var b = this.atoms[this.bonds[i].b]; | |
var actx = a.context(border, xscale, yscale, xreg, yreg); | |
var bctx = b.context(border, xscale, yscale, xreg, yreg); | |
ctx.moveTo(actx[0], actx[1]); | |
ctx.lineTo(bctx[0], bctx[1]); | |
} | |
ctx.stroke(); | |
} | |
//this function is called when the button is pressed - it copies the jme string from the applet and uses it to build a new molecule | |
function depict(){ | |
var jmestr = document.getElementById('jme').jmeFile(); | |
if(jmestr.length()){ | |
document.getElementById('jmestr').value = jmestr; | |
} | |
var m = new Molecule(document.getElementById('jmestr').value); | |
//draw the molecule onto the element with id 'mycanvas' | |
m.depict('mycanvas') | |
} | |
</script> | |
</head> | |
</head> | |
<body> | |
<p> | |
this is an example of using the canvas widget to depict molecules in 2D - to make life a bit easier, I'm starting with the JME string, so I use their coordinates etc for rendering...wouldn't it would be nice to be able to use a molfile or a smiles string though ;) | |
</p> | |
<p> | |
You'll need a copy of the <a href="http://www.molinspiration.com/jme/index.html">JME Editor</a>, <a href="http://www.mozilla-europe.org/en/firefox/">firefox</a> is the only browser I've tested it in and <a href="http://getfirebug.com/">firebug</a> was used during development. | |
</p> | |
<table> | |
<tr> | |
<td> | |
<applet id='jme' code='JME.class' archive='JME.jar' codebase='./' width=300 height=300> | |
<param name='options' value='nohydrogens,query,multipart'> | |
</applet> | |
</br> | |
<font face="arial,helvetica,sans-serif"><small><a href="http://www.molinspiration.com/jme/index.html">JME Editor</a> courtesy of Peter Ertl, Novartis</small></font> | |
</td> | |
<td> | |
<canvas id=mycanvas width=300 height=300> | |
</canvas> | |
</td> | |
</tr> | |
</table> | |
</br> | |
paste a jme string into the textbox (or draw onto the applet) and click depict - you should see a depiction in the canvas element | |
</br> | |
there is a sample string below if you don't have a JME applet to hand - you may need to hack the depict function to get it to work | |
</br> | |
<input id=jmestr type=text value="12 13 C 7.32 -7.53 C 7.32 -6.13 C 6.10 -5.43 C 4.89 -6.13 C 4.89 -7.53 C 6.10 -8.23 C 8.53 -8.23 C 9.74 -7.53 C 9.74 -6.13 C 8.53 -5.43 C 6.10 -4.03 C 3.68 -8.23 1 2 1 2 3 2 3 4 1 4 5 2 5 6 1 6 1 2 7 8 2 8 9 1 9 10 2 2 10 1 1 7 1 3 11 1 5 12 1" /> | |
<input onClick=depict() type=button value='depict' /> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment