biojs-vis-pdbviewer
Version:
A BioJS 2.0 component to view protein structures
756 lines (686 loc) • 21.5 kB
JavaScript
// JSmolTM.js -- JSmol TwirlyMol implementation
//
// TM for "TwirlyMol" -- which this is derived from.
// Can't say there is much of TwirlyMol left in here, as
// we are not using dojo, there are no shadows, and I use a simpler
// rendering idea. Nonetheless, TwirlyMol is the inspiration.
//
// author: Bob Hanson, hansonr@stolaf.edu 3/23/2012
// This library requires
//
// JSmoljQuery.js
// JSmolCore.js
//
// and is combined with those in JSmol.lite.jq.js
// or packaged without jQuery -- because you are using it already -- in JSmol.lite.js
//
Jmol._grabberOptions = [
["$", "NCI(small molecules)"],
[":", "PubChem(small molecules)"]
];
Jmol.say = function(msg) {
alert(msg);
}
Jmol._TMApplet = function(id, Info, checkOnly){
this._uniqueId = ("" + Math.random()).substring(3);
this._id = id;
this._is2D = true;
this._isJava = false;
this._ready = true;
this._mouseDown = false;
this._jmolType = "Jmol._Canvas2D (TwirlyMol)";
if (checkOnly)
return this;
this._createCanvas(id, Info);
return this;
}
Jmol._TMApplet._getApplet = function(id, Info, checkOnly) {
if (!Jmol.featureDetection.allowHTML5)
return null;
checkOnly || (checkOnly = false);
Info || (Info = {});
var DefaultInfo = {
color: "#FFFFFF",
width: 300,
height: 300,
addSelectionOptions: false,
serverURL: "http://your.server.here/jsmol.php",
defaultModel: "",
readyFunction: null,
use: "HTML5",
bondWidth: 5,
shadeAtoms: false,
zoomScaling: 1.5,
pinchScaling: 2.0,
mouseDragFactor: 0.5,
touchDragFactor: 0.15,
multipleBondSpacing: 4,
spinRateX: 0.0,
spinRateY: 0.5,
spinFPS: 20,
spin: false,
noscript: true,
debug: false
};
Jmol._addDefaultInfo(Info, DefaultInfo);
var applet = new Jmol._TMApplet(id, Info, checkOnly);
if (checkOnly)
return applet;
return Jmol._registerApplet(id, applet);
}
Jmol.getTMApplet = Jmol._TMApplet._getApplet;
;(function(tm){
tm._CPK = ["#FF1493", "#FFFFFF", "#D9FFFF",
"#CC80FF", "#C2FF00", "#FFB5B5", "#909090", "#3050F8", "#FF0D0D", "#90E050", "#B3E3F5",
"#AB5CF2", "#8AFF00", "#BFA6A6", "#F0C8A0", "#FF8000", "#FFFF30", "#1FF01F", "#80D1E3",
"#8F40D4", "#3DFF00", "#E6E6E6", "#BFC2C7", "#A6A6AB", "#8A99C7", "#9C7AC7", "#E06633",
"#F090A0", "#50D050", "#C88033", "#7D80B0", "#C28F8F", "#668F8F", "#BD80E3", "#FFA100", "#A62929", "#5CB8D1",
"#702EB0", "#00FF00", "#94FFFF", "#94E0E0", "#73C2C9", "#54B5B5", "#3B9E9E", "#248F8F",
"#0A7D8C", "#006985", "#C0C0C0", "#FFD98F", "#A67573", "#668080", "#9E63B5", "#D47A00", "#940094", "#429EB0",
"#57178F", "#00C900"] // through barium
// "#70D4FF", "#FFFFC7", "#D9FFC7", "#C7FFC7", "#A3FFC7", "#8FFFC7", "#61FFC7", "#45FFC7", "#30FFC7", "#1FFFC7", "#00FF9C", "#00E675", "#00D452", "#00BF38", "#00AB24", "#4DC2FF", "#4DA6FF", "#2194D6", "#267DAB", "#266696", "#175487", "#D0D0E0", "#FFD123", "#B8B8D0", "#A6544D", "#575961", "#9E4FB5", "#AB5C00", "#754F45", "#428296", "#420066", "#007D00", "#70ABFA", "#00BAFF", "#00A1FF", "#008FFF", "#0080FF", "#006BFF", "#545CF2", "#785CE3", "#8A4FE3", "#A136D4", "#B31FD4", "#B31FBA", "#B30DA6", "#BD0D87", "#C70066", "#CC0059", "#D1004F", "#D90045", "#E00038", "#E6002E", "#EB0026"];
tm._elem = ['X', 'H', 'He',
'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne',
'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar',
'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr',
'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe',
'Cs', 'Ba',
'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb',
'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb','Bi', 'Po', 'At', 'Rn',
'Fr', 'Ra',
'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es'];
tm._elemNo = {};
;(function(proto) {
// A user-available function
proto.spin = function(TF) {
this.__Info.spin = TF;
this._spin(TF);
}
proto._spin = function(TF) {
if (this._spinThread)clearTimeout(this._spinThread);
if (this.spinFPS == 0 || this.spinRateX == 0 && this.spinRateY == 0)
TF = false;
if (!TF) return;
var me = this;
var delay = 1000 / this.spinFPS;
if (!this._mouseDown) {
this._rotate(this.spinRateY, this.spinRateX);
this._draw();
}
this._spinThread = setTimeout(function(){me._spin(true)}, delay);
}
proto._initParams = function() {
this.zoom = this.__Info.defaultZoom || 100;
this.doSpin = this.__Info.spin || false;
this.center2D = [this._canvas.width/2, this._canvas.height/2, 0];
this._getCenterAndRadius();
this.rotation = new tm.M3();
this.shadeAtoms = false;
this._setParams();
}
proto._setParams = function() {
this.bondWidth = this.__Info.bondWidth || 5;
this.zoomScaling = this.__Info.zoomScaling || 1.5;
this.pinchScaling = this.__Info.pinchScaling || 1;
this.mouseDragFactor = this.__Info.mouseDragFactor || 0.5;
this.touchDragFactor = this.__Info.touchDragFactor || 0.15;
this.multipleBondSpacing = this.__Info.multipleBondSpacing || 4;
this.spinRateX = this.__Info.spinRateX || 0;
this.spinRateY = this.__Info.spinRateY || 0;
this.spinFPS = this.__Info.spinFPS || 0;
var p = this.shadeAtoms;
this.shadeAtoms = this.__Info.shadeAtoms || false;
if (this.shadeAtoms && !p)
this._setAtomShades();
}
proto._setAtomShades = function() {
if (!this.atoms)
return;
for (var i = this.atoms.length; --i >= 0;)
this.atoms[i].color50 = this._getColor(this.atoms[i].color, 0.5);
}
proto._createCanvas = function(id, Info) {
Jmol._setObject(this, id, Info);
this._color = this._color.replace(/0x/,"#");
var t = Jmol._getWrapper(this, true);
if (Jmol._document) {
Jmol._documentWrite(t);
this._createCanvas2d(false);
t = "";
} else {
t += '<script type="text/javascript">' + id + '._createCanvas2d(false)</script>';
}
t += Jmol._getWrapper(this, false);
if (Info.addSelectionOptions)
t += Jmol._getGrabberOptions(this, "");
if (Jmol._debugAlert && !Jmol._document)
alert(t);
this._code = Jmol._documentWrite(t);
};
proto._readyCallback = function(id, fullid, isReady, applet) {
if (!isReady)
return; // ignore -- page is closing
var me = this;
Jmol._setDestroy(me);
me._ready = true;
var script = me._readyScript;
me._applet = applet;
if (me._defaultModel)
me._search(me._defaultModel, (script ? ";" + script : ""));
else if (me._src)
me._loadFile(me._src);
me._showInfo(true);
me._showInfo(false);
me._readyFunction && me._readyFunction(me);
Jmol._setReady(this);
};
proto._createCanvas2d = function(doReplace) {
var canvas = document.createElement( 'canvas' );
var container = Jmol.$(this, "appletdiv");
if (doReplace) {
container[0].removeChild(this._canvas);
Jmol._jsUnsetMouse(this._canvas);
}
var w = Math.round(container.width());
var h = Math.round(container.height());
canvas.applet = this;
this._canvas = canvas;
canvas.style.width = "100%";
canvas.style.height = "100%";
canvas.width = w;
canvas.height = h; // w and h used in setScreenDimension
canvas.id = this._id + "_canvas2d";
container.append(canvas);
setTimeout(this._id+"._start()",10);
}
proto._start = function() {
Jmol._jsSetMouse(this._canvas);
if (this._defaultModel)
Jmol._search(this, this._defaultModel);
else if (this._src)
this._loadFile(this._src);
this._showInfo(true);
this._showInfo(false);
}
proto._search = function(query, script){
Jmol._search(this, query, script);
}
proto._searchDatabase = function(query, database, script){
this._showInfo(false);
if (query.indexOf("?") >= 0) {
Jmol._getInfoFromDatabase(this, database, query.split("?")[0]);
return;
}
var dm = database + query;
this._loadFile(dm, script);
}
proto.__loadModel = function(mol) {
this._spin(false);
if (mol == "''")mol = this._mol;
if (!mol) {
alert("No model data.");
return;
}
this._parse(mol);
this._initParams();
this._draw();
this._showInfo(false);
if (this.doSpin)
this._spin(true);
};
proto._showInfo = function(tf) {
Jmol.$html(Jmol.$(this, "infoheaderspan"), this._infoHeader);
if (this._info)
Jmol.$html(Jmol.$(this, "infodiv"), this._info);
if ((!this._isInfoVisible) == (!tf))
return;
this._isInfoVisible = tf;
Jmol.$setVisible(Jmol.$(this, "infotablediv"), tf);
Jmol.$setVisible(Jmol.$(this, "infoheaderdiv"), tf);
this._show(!tf);
}
proto._show = function(tf) {
Jmol.$setVisible(Jmol.$(this, "appletdiv"), tf);
if (tf)
this._draw();
}
proto._resize = function() {
var s = "__resizeTimeout_" + this._id;
// only at end
if (Jmol[s])
clearTimeout(Jmol[s]);
var me = this;
Jmol[s] = setTimeout(function() {me._draw();Jmol[s]=null}, 100);
}
proto._canScript = function(script) {return false};
proto._loadFile = function(fileName){
this._showInfo(false);
this._thisJmolModel = fileName;
var app = this;
Jmol._loadFileData(this, fileName, function(data){app.__loadModel(data)});
}
proto._processEvent = function(type, xym) {
switch(type) {
case 502: // mouse_up
case 503: // mouse_move
this._mouseDown = false;
default:
return;
case 501: // mouse_down
this._mouseX = xym[0];
this._mouseY = xym[1];
this._mouseDown = true;
return;
case 506: // mouse_drag
var dx = xym[0] - this._mouseX;
var dy = xym[1] - this._mouseY;
dx = (dx < 0 ? -1 : dx > 0 ? 1 : 0)
dy = (dy < 0 ? -1 : dy > 0 ? 1 : 0)
switch (xym[2]) {
case 17: // left-shift
this._zoomBy(dy);
break;
case 24: // left-alt
this.center2D[0] += dx;
this.center2D[1] += dy;
break;
default:
this._rotate(dx, dy);
break;
}
this._mouseX = xym[0];
this._mouseY = xym[1];
break;
case -1: // mouse_scroll
this._zoomBy(xym[1])
break;
}
this._draw();
}
proto._processGesture = function (touches) {
if (touches[0].length < 2) return;
var t1 = touches[0];
var t2 = touches[1];
var t10 = t1[0];
var t11 = t1[t2.length - 1];
var x10 = t10[0];
var x11 = t11[0];
var dx1 = x11 - x10;
var y10 = t10[1];
var y11 = t11[1];
var dy1 = y11 - y10;
var v1 = [dx1, dy1, 0];
var d1 = tm._length(v1);
var t20 = t2[0];
var t21 = t2[t2.length - 1];
var x20 = t20[0];
var x21 = t21[0];
var dx2 = x21 - x20;
var y20 = t20[1];
var y21 = t21[1];
var dy2 = y21 - y20;
var v2 = [dx2, dy2, 0];
var d2 = tm._length(v2);
if (d1 < 3 || d2 < 3) return;
tm._scale(v1, 1/d1);
tm._scale(v2, 1/d2);
var cos12 = tm._dot(v1,v2);
if (cos12 > 0.8) {
var deltaX = Math.round(x11 - t1[t1.length - 2][0]);
var deltaY = Math.round(y11 - t1[t1.length - 2][1]);
this.center2D[0] += deltaX;
this.center2D[1] += deltaY;
} else if (cos12 < -0.8) {
v1 = [x20 - x10, y20 - y10, 0]
v2 = [x21 - x11, y21 - y11, 0];
var dx = tm._length(v2) - tm._length(v1);
this.zoom += (dx < 0 ? -1 : 1) * this.pinchScaling;
}
this._draw();
}
proto._zoomBy = function(dz) {
this.zoom += dz * this.zoomScaling;
if (this.zoom < 5) this.zoom = 5;
if (this.zoom > 500) this.zoom = 500;
}
proto._getRotationScaling = function() {
return [1 / Math.max(this._canvas.width, 500) * this.mouseDragFactor * tm.deg_per_radian,
1 / Math.max(this._canvas.height, 500) * this.mouseDragFactor * tm.deg_per_radian];
}
proto._rotate = function(dx, dy) {
var f = this._getRotationScaling();
if (dy) {
tm._m3.rotX(dy * f[1]);
this.rotation.mul(tm._m3);
}
if (dx) {
tm._m3.rotY(dx * f[0]);
this.rotation.mul(tm._m3);
}
}
proto._getCenterAndRadius = function() {
var p = this;
var size = Math.min(p._canvas.width, p._canvas.height);
var min = [999999, 999999, 999999];
var max = [-999999, -999999, -999999];
for (var i= p.atoms.length; --i >= 0;)
for (var j = 3; --j >= 0;) {
var v = p.atoms[i].xyz[j];
if (v < min[j]) min[j]=v;
if (v > max[j]) max[j]=v;
}
var c = [0, 0, 0];
for (var j = 3; --j >= 0;)
c[j] = (max[j] + min[j])/2;
var r = 0;
for (var i= p.atoms.length; --i >= 0;) {
var a = p.atoms[i];
var d = tm._distance(a.xyz, c) + (a.elemNo == 1 ? 1 : 1.5);//a.radius;
if (d > r)
r = d;
}
this.center = c;
this.modelRadius = (r == 0 ? 10 : r);
}
proto._setScreenCoords = function() {
var c = this.center;
var mat = this.rotation;
var sc = this.center2D;
var f = Math.min(this._canvas.width, this._canvas.height) / 2 / this.modelRadius * this.zoom / 100;
for (var i=this.atoms.length; --i >= 0;) {
var a = this.atoms[i];
this._transform(a.xyz, a.sxyz, c, mat, f, sc);
a.srad = f * a.radius;
}
for (var i=this.bonds.length; --i >= 0;) {
var b = this.bonds[i];
this._transform(b.xyz, b.sxyz, c, mat, f, sc);
this._transform(b.pts[0], b.spts[0], c, mat, f, sc);
this._transform(b.pts[1], b.spts[1], c, mat, f, sc);
}
}
proto._transform = function(pt, spt, c, mat, f, sc) {
var a = tm._temp1;
var b = tm._temp2;
for (var i = 3; --i >= 0;)
a[i] = (pt[i] - c[i]) * f;
mat.transform(a, b);
b[1] = -b[1];
b[2] = -b[2];
for (var i = 3; --i >= 0;)
spt[i] = b[i] + sc[i];
}
// adaptable ---
proto._parse = function(data) {
// just MOL data for now
this._parseSDF(data);
}
proto._parseSDF = function(sdf) {
this._mol = sdf;
if (!tm._elemNo["H"])
for (var i = tm._elem.length; --i >= 0;)
tm._elemNo[tm._elem[i]] = i;
var lines = sdf.split("\n");
var pt = 3;
var line = lines[pt++];
this.nAtoms = parseFloat(line.substring(0, 3));
this.nBonds = parseFloat(line.substring(3, 6));
this.atoms = Array(this.nAtoms);
this.bonds = Array(this.nBonds);
this.elements = Array(this.nAtoms + this.nBonds)
var ept = 0;
var x, y, z;
for (var i = 0; i < this.nAtoms; i++) {
line = lines[pt++];
x = parseFloat(line.substring(0, 10));
y = parseFloat(line.substring(10, 20));
z = parseFloat(line.substring(20, 30));
var e = line.substring(31, 34).replace(/\s+/g, '');
var elemNo = tm._elemNo[e] || 0;
var radius = (elemNo == 1 ? 0.23 : 0.35);
var color = tm._CPK[elemNo] || tm._CPK[0];
this.elements[ept++] = this.atoms[i] = {type:0, elemNo: elemNo, xyz:[x, y, z], sxyz:[0, 0, 0], radius: radius, color: color, color50: color};
}
for (var i = 0; i < this.nBonds; i++) {
line = lines[pt++]
var a1 = this.atoms[parseFloat(line.substring(0, 3)) - 1];
var a2 = this.atoms[parseFloat(line.substring(3, 6)) - 1];
var order = Math.abs(parseFloat(line.substring(6, 9)));
switch (order) {
case 4: // JmolAdapter.ORDER_AROMATIC;
case 5: // JmolAdapter.ORDER_PARTIAL12;
case 6: // JmolAdapter.ORDER_AROMATIC_SINGLE;
case 8: // JmolAdapter.ORDER_PARTIAL01;
order = 1;
break;
case 7: // JmolAdapter.ORDER_AROMATIC_DOUBLE;
order = 2;
break;
}
var xyz = tm._getPointAlong(a1.xyz, a2.xyz, 0.5);
var d = tm._distance(a1.xyz, xyz);
var p1 = (a1.radius < d ? tm._getPointAlong(a1.xyz, xyz, a1.radius/d) : [0, 0, 99999]);
var p2 = (a2.radius < d ? tm._getPointAlong(a2.xyz, xyz, a2.radius/d) : [0, 0, 99999]);
this.elements[ept++] = this.bonds[i] = {type:1, atoms: [a1, a2], xyz:xyz, pts:[p1,p2], sxyz:[0, 0, 0], spts:[[0,0,0],[0,0,0]], order: order, color: 0};
}
//alert(this.atoms.length + " atoms " + this.bonds.length + " bonds")
}
proto._getColor = function(c, f) {
if (c == "#FFFFFF") c = "#D0D0D0";
var n = parseInt("0x" + c.substring(1), 16);
var r=(n >> 16) & 0xFF;
var g=(n >> 8) & 0xFF;
var b=(n) & 0xFF;
if (r != 255)
r += Math.floor((255 - r) * f);
if (g != 255)
g += Math.floor((255 - g) * f);
if (b != 255)
b += Math.floor((255 - b) * f);
var s = "000000" + ((r << 16) | (g << 8) | b).toString(16);
return "#"+s.substring(s.length - 6, s.length);
}
proto._draw = function() {
if (!this.atoms)return;
this._setParams();
this._setScreenCoords();
var es = this.elements;
es.sort(tm._zorder);
var ctx=this._canvas.getContext("2d");
ctx.fillStyle=this._color;
ctx.fillRect(0,0,this._canvas.width, this._canvas.height);
for (var i = es.length; --i >= 0;) {
var e = es[i];
if (e.type == 0)
this._drawAtom(ctx, e);
else
this._drawBond(ctx, e);
}
}
///////////////// drawing ///////////////////
proto._drawAtom = function(ctx, a) {
ctx.beginPath();
// context.fillStyle = "rgba(0, 0, 0, 1)";
if (this.shadeAtoms) {
var offset = a.srad / 4;
var grad = ctx.createRadialGradient(a.sxyz[0]-offset,a.sxyz[1]-offset, offset, a.sxyz[0],a.sxyz[1], a.srad);
grad.addColorStop(0.0, a.color50);
grad.addColorStop(1.0, (a.color == "#FFFFFF" ? "#D0D0D0" : a.color));
ctx.fillStyle = grad;
ctx.arc(a.sxyz[0],a.sxyz[1],a.srad,0,tm._pi2);
ctx.fill();
} else {
ctx.fillStyle = a.color;
ctx.arc(a.sxyz[0],a.sxyz[1],a.srad,0,tm._pi2);
ctx.fill();
ctx.strokeStyle = "#000000";
ctx.lineWidth = 1;
ctx.stroke();
}
}
proto._drawBond = function(ctx, b) {
if (b.pts[0][2] != 99999)
this._drawBondLines(ctx, b, b.spts[0], b.atoms[0].color);
if (b.pts[1][2] != 99999)
this._drawBondLines(ctx, b, b.spts[1], b.atoms[1].color);
}
proto._drawBondLines = function(ctx, b, pt, ac) {
var t = tm._temp;
t.width = this.bondWidth;
t.color = (b.color ? b.color : ac);
if (b.order == 1) {
t.pt1 = pt;
t.pt2 = b.sxyz;
this._drawLine(ctx, t);
return;
}
t.pt1 = tm._temp1;
t.pt2 = tm._temp2;
t.pta = pt;
t.ptb = b.sxyz;
t.dx = t.ptb[0] - t.pta[0];
t.dy = t.ptb[1] - t.pta[1];
t.mag2d = Math.round(Math.sqrt(t.dx * t.dx + t.dy * t.dy));
t.bondOrder = b.order;
this._resetAxisCoordinates(t);
while (t.bondOrder > 0) {
this._drawLine(ctx, t);
t.bondOrder--;
this._stepAxisCoordinates(t);
}
}
proto._drawLine = function(ctx, t) {
ctx.beginPath();
ctx.strokeStyle = t.color;
ctx.moveTo(t.pt1[0], t.pt1[1]);
ctx.lineTo(t.pt2[0], t.pt2[1]);
ctx.lineWidth = t.width;
ctx.stroke();
}
proto._resetAxisCoordinates = function(t) {
var space = t.mag2d >> 3;
if (this.multipleBondSpacing != 1) space *= this.multipleBondSpacing;
var step = t.width + space;
t.dxStep = Math.round(step * t.dy / t.mag2d);
t.dyStep = Math.round(step * -t.dx / t.mag2d);
t.pt1[0] = t.pta[0];
t.pt1[1] = t.pta[1];
t.pt2[0] = t.ptb[0];
t.pt2[1] = t.ptb[1];
var f = (t.bondOrder - 1);
t.pt1[0] -= Math.round(t.dxStep * f / 2);
t.pt1[1] -= Math.round(t.dyStep * f / 2);
t.pt2[0] -= Math.round(t.dxStep * f / 2);
t.pt2[1] -= Math.round(t.dyStep * f / 2);
}
proto._stepAxisCoordinates = function(t) {
t.pt1[0] += t.dxStep;
t.pt1[1] += t.dyStep;
t.pt2[0] += t.dxStep;
t.pt2[1] += t.dyStep;
}
})(tm.prototype)
tm._distance = function(a,b){
var d = 0;
for (var i = 3; --i >= 0;) {
var dx = a[i] - b[i];
d += dx * dx;
}
return Math.sqrt(d);
}
tm._dot = function(a,b){
var d = 0;
for (var i = 3; --i >= 0;)
d += a[i] * b[i];
return d;
}
tm._setPt = function(a,b){
for (var i = 3; --i >= 0;)
b[i] = a[i];
return b;
}
tm._scale = function(a, f){
for (var i = 3; --i >= 0;)
a[i] *= f;
}
tm._length = function(a){
var d = 0;
for (var i = 3; --i >= 0;)
d += a[i] * a[i];
return Math.sqrt(d);
}
tm._getPointAlong = function(a, b, f) {
return [(b[0] - a[0]) * f + a[0],
(b[1] - a[1]) * f + a[1],
(b[2] - a[2]) * f + a[2]];
}
tm._zorder = function(a, b) {
var x = a.sxyz[2];
var y = b.sxyz[2];
return (x < y ? -1 : x > y ? 1 : 0);
}
tm.M3 = function() {
this.m00 = 1.0;
this.m01 = 0.0;
this.m02 = 0.0;
this.m10 = 0.0;
this.m11 = 1.0;
this.m12 = 0.0;
this.m20 = 0.0;
this.m21 = 0.0;
this.m22 = 1.0;
}
tm.M3.prototype.set = function (m00, m01, m02, m10, m11, m12, m20, m21, m22) {
this.m00 = m00;
this.m01 = m01;
this.m02 = m02;
this.m10 = m10;
this.m11 = m11;
this.m12 = m12;
this.m20 = m20;
this.m21 = m21;
this.m22 = m22;
}
tm.M3.prototype.transform = function(a, b) {
b[0] = this.m00 * a[0] + this.m01 * a[1] + this.m02 * a[2];
b[1] = this.m10 * a[0] + this.m11 * a[1] + this.m12 * a[2];
b[2] = this.m20 * a[0] + this.m21 * a[1] + this.m22 * a[2];
}
tm.M3.prototype.rotX = function(angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
this.m00 = 1.0;
this.m01 = 0.0;
this.m02 = 0.0;
this.m10 = 0.0;
this.m11 = c;
this.m12 = -s;
this.m20 = 0.0;
this.m21 = s;
this.m22 = c;
}
tm.M3.prototype.rotY = function(angle) {
var c = Math.cos(angle);
var s = Math.sin(angle);
this.m00 = c;
this.m01 = 0.0;
this.m02 = s;
this.m10 = 0.0;
this.m11 = 1.0;
this.m12 = 0.0;
this.m20 = -s;
this.m21 = 0.0;
this.m22 = c;
}
tm.M3.prototype.mul = function(m) {
var m2 = this;
this.set(m.m00 * m2.m00 + m.m01 * m2.m10 + m.m02 * m2.m20, m.m00 * m2.m01 + m.m01 * m2.m11 + m.m02 * m2.m21, m.m00 * m2.m02 + m.m01 * m2.m12 + m.m02 * m2.m22, m.m10 * m2.m00 + m.m11 * m2.m10 + m.m12 * m2.m20, m.m10 * m2.m01 + m.m11 * m2.m11 + m.m12 * m2.m21, m.m10 * m2.m02 + m.m11 * m2.m12 + m.m12 * m2.m22, m.m20 * m2.m00 + m.m21 * m2.m10 + m.m22 * m2.m20, m.m20 * m2.m01 + m.m21 * m2.m11 + m.m22 * m2.m21, m.m20 * m2.m02 + m.m21 * m2.m12 + m.m22 * m2.m22);
}
tm._pi2 = 2*Math.PI;
tm.deg_per_radian = 180 / Math.PI;
tm._z3 = [0,0,0];
tm._temp1 = [0,0,0];
tm._temp2 = [0,0,0];
tm._temp = {};
tm._m3 = new tm.M3();
})(Jmol._TMApplet);