December 26, 2011

Chemdoodle web components tricks #2: showing atom numbers

Due to the release of ChemDoodle web components version 4.5 showing atom numbers have been much simplified, and this post has been superseded by a new script in a new post Chemdoodle web components tricks #4: showing atom numbers with the altLabel property

My second try on using the chemdoodle web compontents. Very nice GPL licensed javascript library for chemical 2D (and 3D if you have a webGL supporting browser).

One thing missing from the API is atom numbers (i.e. numbering from 1,2...10 for all atoms). Here I'll show how to display atom numbers using a viewercanvas.

Standard canvas with a caffeine molecule and colored atom labels (from my last post on scaling):

And here, the same canvas with atom numbers shown:

The javascript code for the standard scaled canvas:

 
  var tutorial2_testmol = new ChemDoodle.ViewerCanvas('tutorial2_testmol', 300, 300);
  tutorial2_testmol.specs.atoms_useJMOLColors = true;
  var caffeineMolFile = 'Molecule Name\n  CHEMDOOD08070920033D 0   0.00000     0.00000     0\n[Insert Comment Here]\n 14 15  0  0  0  0  0  0  0  0  1 V2000\n   -0.3318    2.0000    0.0000   O 0  0  0  1  0  0  0  0  0  0  0  0\n   -0.3318    1.0000    0.0000   C 0  0  0  1  0  0  0  0  0  0  0  0\n   -1.1980    0.5000    0.0000   N 0  0  0  1  0  0  0  0  0  0  0  0\n    0.5342    0.5000    0.0000   C 0  0  0  1  0  0  0  0  0  0  0  0\n   -1.1980   -0.5000    0.0000   C 0  0  0  1  0  0  0  0  0  0  0  0\n   -2.0640    1.0000    0.0000   C 0  0  0  4  0  0  0  0  0  0  0  0\n    1.4804    0.8047    0.0000   N 0  0  0  1  0  0  0  0  0  0  0  0\n    0.5342   -0.5000    0.0000   C 0  0  0  1  0  0  0  0  0  0  0  0\n   -2.0640   -1.0000    0.0000   O 0  0  0  1  0  0  0  0  0  0  0  0\n   -0.3318   -1.0000    0.0000   N 0  0  0  1  0  0  0  0  0  0  0  0\n    2.0640   -0.0000    0.0000   C 0  0  0  2  0  0  0  0  0  0  0  0\n    1.7910    1.7553    0.0000   C 0  0  0  4  0  0  0  0  0  0  0  0\n    1.4804   -0.8047    0.0000   N 0  0  0  1  0  0  0  0  0  0  0  0\n   -0.3318   -2.0000    0.0000   C 0  0  0  4  0  0  0  0  0  0  0  0\n  1  2  2  0  0  0  0\n  3  2  1  0  0  0  0\n  4  2  1  0  0  0  0\n  3  5  1  0  0  0  0\n  3  6  1  0  0  0  0\n  7  4  1  0  0  0  0\n  4  8  2  0  0  0  0\n  9  5  2  0  0  0  0\n 10  5  1  0  0  0  0\n 10  8  1  0  0  0  0\n  7 11  1  0  0  0  0\n  7 12  1  0  0  0  0\n 13  8  1  0  0  0  0\n 13 11  2  0  0  0  0\n 10 14  1  0  0  0  0\nM  END\n> \n07-08-2009\n';
  var caffeine = ChemDoodle.readMOL(caffeineMolFile);
  // get the dimension of the molecule
  var size = caffeine.getDimension();
  // find the scale by taking the minimum of the canvas/size ratios
  var scale = Math.min(tutorial2_testmol.width/size.x, tutorial2_testmol.height/size.y);
  // load the molecule first (this function automatically sets scale, so we need to change specs after)
  tutorial2_testmol.loadMolecule(caffeine);
  // change the specs.scale value to the scale calculated, shrinking it slightly so that text is not cut off
  tutorial2_testmol.specs.scale = scale*.9;
  // repaint the canvas
  tutorial2_testmol.repaint(); 

and the javascript code for the canvas with the atom numbers:

 
  var tutorial2_testmol2 = new ChemDoodle.ViewerCanvas('tutorial2_testmol2', 300, 300);
  tutorial2_testmol2.specs.atoms_useJMOLColors = true;
  var caffeineMolFile = 'Molecule Name\n  CHEMDOOD08070920033D 0   0.00000     0.00000     0\n[Insert Comment Here]\n 14 15  0  0  0  0  0  0  0  0  1 V2000\n   -0.3318    2.0000    0.0000   O 0  0  0  1  0  0  0  0  0  0  0  0\n   -0.3318    1.0000    0.0000   C 0  0  0  1  0  0  0  0  0  0  0  0\n   -1.1980    0.5000    0.0000   N 0  0  0  1  0  0  0  0  0  0  0  0\n    0.5342    0.5000    0.0000   C 0  0  0  1  0  0  0  0  0  0  0  0\n   -1.1980   -0.5000    0.0000   C 0  0  0  1  0  0  0  0  0  0  0  0\n   -2.0640    1.0000    0.0000   C 0  0  0  4  0  0  0  0  0  0  0  0\n    1.4804    0.8047    0.0000   N 0  0  0  1  0  0  0  0  0  0  0  0\n    0.5342   -0.5000    0.0000   C 0  0  0  1  0  0  0  0  0  0  0  0\n   -2.0640   -1.0000    0.0000   O 0  0  0  1  0  0  0  0  0  0  0  0\n   -0.3318   -1.0000    0.0000   N 0  0  0  1  0  0  0  0  0  0  0  0\n    2.0640   -0.0000    0.0000   C 0  0  0  2  0  0  0  0  0  0  0  0\n    1.7910    1.7553    0.0000   C 0  0  0  4  0  0  0  0  0  0  0  0\n    1.4804   -0.8047    0.0000   N 0  0  0  1  0  0  0  0  0  0  0  0\n   -0.3318   -2.0000    0.0000   C 0  0  0  4  0  0  0  0  0  0  0  0\n  1  2  2  0  0  0  0\n  3  2  1  0  0  0  0\n  4  2  1  0  0  0  0\n  3  5  1  0  0  0  0\n  3  6  1  0  0  0  0\n  7  4  1  0  0  0  0\n  4  8  2  0  0  0  0\n  9  5  2  0  0  0  0\n 10  5  1  0  0  0  0\n 10  8  1  0  0  0  0\n  7 11  1  0  0  0  0\n  7 12  1  0  0  0  0\n 13  8  1  0  0  0  0\n 13 11  2  0  0  0  0\n 10 14  1  0  0  0  0\nM  END\n> \n07-08-2009\n';
  var caffeine = ChemDoodle.readMOL(caffeineMolFile);
  // get the dimension of the molecule
  var size = caffeine.getDimension();
  // find the scale by taking the minimum of the canvas/size ratios
  var scale = Math.min(tutorial2_testmol2.width/size.x, tutorial2_testmol2.height/size.y);
  // load the molecule first (this function automatically sets scale, so we need to change specs after)
  tutorial2_testmol2.loadMolecule(caffeine);
  // change the specs.scale value to the scale calculated, shrinking it slightly so that text is not cut off
  tutorial2_testmol2.specs.scale = scale*.9;
  tutorial2_testmol2.repaint();
  var molcenter = caffeine.getCenter();
  
  tutorial2_testmol2.drawChildExtras = function(ctx){
    ctx.translate(this.width/2, this.height/2);
    ctx.rotate(this.specs.rotateAngle);
    ctx.scale(this.specs.scale, this.specs.scale);
    ctx.translate(-this.width/2, -this.height/2);
    //draw atom numbers
    ctx.font = 'bold ' + 2.5*scale + 'px sans-serif';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
 //iterate through all atoms
    for (var i = 0, ii=caffeine.atoms.length; i<ii; i++) {
      var atom = caffeine.atoms[i];
      //draw a white circle behind the atom number
      ctx.fillStyle = "white";
      ctx.strokeStyle = "white";
      ctx.beginPath();
      ctx.arc(atom['x'],atom['y'],scale*1.8,0,Math.PI*2,true);
      ctx.fill();
      ctx.stroke();
      //draw the atom number
   thisatomcolor = ChemDoodle.ELEMENT[atom['label']].jmolColor;
      ctx.fillStyle = thisatomcolor;
      ctx.fillText(i + 1, atom['x'], atom['y']);
    }
  }

  tutorial2_testmol2.repaint();

The trickiest part about this is that while the first four lines in the drawChildExtras function (as suggested by Kevin in the comments and the fourth line is needed to simplify the atom locations), do scale the drawing on the canvas correctly, they do not scale or translate the molecule. That's why I had to subtract the x and y coordinates of the center of the molecule to get the positions right.