Introduction

When I was going through a phase of experimenting with 3D graphics, I got bored of building shapes from planes and cubes, and wonder what interesting shapes I could draw without having to be good a drawing. I struck on the idea of molecules, which can be drawn with circles and lines (rather than dealing with paths). During my biochemistry degree I spent some time looking at 3D models of proteins and had built physical models of molecules to better understand their chemistry.

Adenosine triphosphate (ATP). Click and drag the image to rotate.

Atomic data

I knew I could find the 3D coordinates for atoms at www.rcsb.org, so I wouldn't need to figure out any coordinates myself. The format is relatively easy to understand and I wrote a program (which I have since lost) to parse the data into a format I could use. For each molecule I have a list of atom type and coordinate, then a list of bonds, which are pair of atom indices.

The first version I created was on Khan Academy (12 years ago now!). I added more and more molecules before finally making a program where you could select from a whole library of molecules.

Implementation details

Although I said in the previous articles that SVG is not ideal for making 3D rotatable images, I think computers are fast enough, that it works well with a reasonable number of points. That said, it's still worth making the code efficient.

The code has an array of points of 3D points, and an array of shape objects. The points are objects with a x, y, and z attributes, which are what undergo 3D rotation transformations. The shape objects have an element attribute that point to an SVG element, an getZ attribute that points to a function that returns the z-coordinate of the shape, and an update attribute that points to a function that updates the SVG element.

Atoms

Each atom in the molecule, adds a point to the point array, and a shape to the shape array. Its shape element is an SVG group consisting of three circles. One is the atom, whose size and colour depends on the atom type. The other two are not strictly necessary - they are transparent white circles that add some shading to give the atoms a more 3D look. We could improve this by changing the position and intensity of the highlight as the atom moves.

The getZ function of atom shapes just returns the z-coordinate of its corresponding point. The update function updates the translation transformation on the group to the x- and y- coordinates if the point.

Bonds

Each bond in the molecule, adds two points to the point array corresponding to the start and end of the bond. These points are the points for the atoms at each end offset by the radius of the atom.

Each bond also has a shape object. Its element attribute points to an SVG line element. Its getZ function returns the average of the z-coordinates of it's two points. Its update function updates the x1, y1, x2, and y2 attributes of the SVG line element based on the x and y coordinates of its points.

Interactivity

The SVG has handlers to capture drag events and trigger the rotateX and rotateY functions. These functions apply a 3D rotation transformation to each point in the point array. Then it sorts each element in the shape array using its getZ function, and reorders the elements in the DOM into this new order. Finally it calls, the update function on each shape to update it's position.

Conclusion

I'm pretty pleased with how this turned out. It's a lot more efficient that I imagined. The small highlight on each atom gives a really nice effect, and the fact that it's SVG means I can now generate very high resolution images of molecules with a transparent background.