This JavaScript Reference section displays the code for an example program that shows how to draw a 3d surface plot with lighting using scalable vector graphics (SVG).
<!DOCTYPE html>
<html>
<head>
<title>XoaX.net's Javascript</title>
</head>
<body>
<script type="text/javascript" src="Svg3dGraph.js"></script>
</body>
</html>var qBody = document.getElementsByTagName("body")[0];
function CProjectedPoint(dX,dY,dZ) {
var dScale = 250.0;
var dDuDx = .612;
var dDuDy = -dDuDx;
var dDuDz = 0.0;
var dDvDx = .25;
var dDvDy = .25;
var dDvDz = -.866;
this.mdU = (dDuDx*dX + dDuDy*dY + dDuDz*dZ)*dScale;
this.mdV = (dDvDx*dX + dDvDy*dY + dDvDz*dZ)*dScale;
}
var qMainDiv = document.createElementNS("http://www.w3.org/2000/svg", "svg")
qMainDiv.style.backgroundColor = "#eeeecc";
qMainDiv.style.width="800px";
qMainDiv.style.height="800px";
qMainDiv.style.position="absolute";
// Bottom x = [-1, 1], y = [-1, 1], z = -1
// scale
var qBottom = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
var cx = 400;
var cy = 400;
var qP1 = new CProjectedPoint(-1.0, -1.0, -1.0);
var qP2 = new CProjectedPoint(-1.0, 1.0, -1.0);
var qP3 = new CProjectedPoint(1.0, 1.0, -1.0);
var qP4 = new CProjectedPoint(1.0, -1.0, -1.0);
var dCoords = (qP1.mdU + cx) + " " + (qP1.mdV + cy) + " " +
(qP2.mdU + cx) + " " + (qP2.mdV + cy) + " " +
(qP3.mdU + cx) + " " + (qP3.mdV + cy) + " " +
(qP4.mdU + cx) + " " + (qP4.mdV + cy);
qBottom.setAttribute('points', dCoords);
qBottom.setAttribute('fill', '#ffbbbb');
qBottom.setAttribute('fill-rule', 'nonzero');
qMainDiv.appendChild(qBottom);
// Left x = -1, y = [-1, 1], z = [-1, 1]
// scale
var qLeftSide = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
qP1 = new CProjectedPoint(-1.0, 1.0, 1.0);
qP2 = new CProjectedPoint(-1.0, 1.0, -1.0);
qP3 = new CProjectedPoint(-1.0, -1.0, -1.0);
qP4 = new CProjectedPoint(-1.0, -1.0, 1.0);
dCoords = (qP1.mdU + cx) + " " + (qP1.mdV + cy) + " " +
(qP2.mdU + cx) + " " + (qP2.mdV + cy) + " " +
(qP3.mdU + cx) + " " + (qP3.mdV + cy) + " " +
(qP4.mdU + cx) + " " + (qP4.mdV + cy);
qLeftSide.setAttribute('points', dCoords);
qLeftSide.setAttribute('fill', '#ffeeee');
qLeftSide.setAttribute('fill-rule', 'nonzero');
qMainDiv.appendChild(qLeftSide);
// Right x = [-1, 1], y = -1, z = [-1, 1]
// scale
var qRightSide = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
qP1 = new CProjectedPoint(1.0, -1.0, 1.0);
qP2 = new CProjectedPoint(1.0, -1.0, -1.0);
qP3 = new CProjectedPoint(-1.0, -1.0, -1.0);
qP4 = new CProjectedPoint(-1.0, -1.0, 1.0);
dCoords = (qP1.mdU + cx) + " " + (qP1.mdV + cy) + " " +
(qP2.mdU + cx) + " " + (qP2.mdV + cy) + " " +
(qP3.mdU + cx) + " " + (qP3.mdV + cy) + " " +
(qP4.mdU + cx) + " " + (qP4.mdV + cy);
qRightSide.setAttribute('points', dCoords);
qRightSide.setAttribute('fill', '#ffd8d8');
qRightSide.setAttribute('fill-rule', 'nonzero');
qMainDiv.appendChild(qRightSide);
// Border - hexagon around the graph
// scale
var qBorder = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
qP1 = new CProjectedPoint(-1.0, -1.0, 1.0);
qP2 = new CProjectedPoint(1.0, -1.0, 1.0);
qP3 = new CProjectedPoint(1.0, -1.0, -1.0);
qP4 = new CProjectedPoint(1.0, 1.0, -1.0);
var qP5 = new CProjectedPoint(-1.0, 1.0, -1.0);
var qP6 = new CProjectedPoint(-1.0, 1.0, 1.0);
dCoords = (qP1.mdU + cx) + " " + (qP1.mdV + cy) + " " +
(qP2.mdU + cx) + " " + (qP2.mdV + cy) + " " +
(qP3.mdU + cx) + " " + (qP3.mdV + cy) + " " +
(qP4.mdU + cx) + " " + (qP4.mdV + cy) + " " +
(qP5.mdU + cx) + " " + (qP5.mdV + cy) + " " +
(qP6.mdU + cx) + " " + (qP6.mdV + cy);
qBorder.setAttribute('points', dCoords);
qBorder.setAttribute('fill', '#ffeedd');
qBorder.setAttribute('fill-rule', 'nonzero');
qBorder.setAttribute('stroke-width', '4');
qBorder.setAttribute('stroke', 'rgb(255, 128, 128)');
qMainDiv.appendChild(qBorder);
// Inner (background) Lines
var qLineZ = document.createElementNS("http://www.w3.org/2000/svg", "line");
qP1 = new CProjectedPoint(-1.0, -1.0, 1.0);
qP2 = new CProjectedPoint(-1.0, -1.0, -1.0);
qLineZ.setAttribute('x1', qP1.mdU + cx);
qLineZ.setAttribute('y1', qP1.mdV + cy);
qLineZ.setAttribute('x2', qP2.mdU + cx);
qLineZ.setAttribute('y2', qP2.mdV + cy);
qLineZ.setAttribute('stroke-width', '2');
qLineZ.setAttribute('stroke', 'rgb(255, 128, 128)');
qMainDiv.appendChild(qLineZ);
var qLineY = document.createElementNS("http://www.w3.org/2000/svg", "line");
qP1 = new CProjectedPoint(-1.0, 1.0, -1.0);
qP2 = new CProjectedPoint(-1.0, -1.0, -1.0);
qLineY.setAttribute('x1', qP1.mdU + cx);
qLineY.setAttribute('y1', qP1.mdV + cy);
qLineY.setAttribute('x2', qP2.mdU + cx);
qLineY.setAttribute('y2', qP2.mdV + cy);
qLineY.setAttribute('stroke-width', '2');
qLineY.setAttribute('stroke', 'rgb(255, 128, 128)');
qMainDiv.appendChild(qLineY);
var qLineX = document.createElementNS("http://www.w3.org/2000/svg", "line");
qP1 = new CProjectedPoint(1.0, -1.0, -1.0);
qP2 = new CProjectedPoint(-1.0, -1.0, -1.0);
qLineX.setAttribute('x1', qP1.mdU + cx);
qLineX.setAttribute('y1', qP1.mdV + cy);
qLineX.setAttribute('x2', qP2.mdU + cx);
qLineX.setAttribute('y2', qP2.mdV + cy);
qLineX.setAttribute('stroke-width', '2');
qLineX.setAttribute('stroke', 'rgb(255, 128, 128)');
qMainDiv.appendChild(qLineX);
var dDeltaX = 2.0/100.0;
var dDeltaY = 2.0/100.0;
var daaZ = new Array(101);
// Calculate the z values
for (var x = 0; x < 101; ++x) {
daaZ[x] = new Array(101);
for (var y = 0; y < 101; ++y) {
var dX = -1 + x*dDeltaX;
var dY = -1 + y*dDeltaY;
var dZ = (dX*dX + dY*dY)*10;
if (dZ < 1.0e-5) {
daaZ[x][y] = 1.0;
} else {
daaZ[x][y] = (Math.sin(3*dZ)/(3*dZ));
}
}
}
function Normalize(daV) {
var dLength = Math.sqrt(daV[0]*daV[0] + daV[1]*daV[1] + daV[2]*daV[2]);
daV[0] /= dLength;
daV[1] /= dLength;
daV[2] /= dLength;
}
function Cross(daV1, daV2) {
var daN = new Array(3);
daN[0] = daV1[1]*daV2[2] - daV1[2]*daV2[1];
daN[1] = daV1[2]*daV2[0] - daV1[0]*daV2[2];
daN[2] = daV1[0]*daV2[1] - daV1[1]*daV2[0];
return daN;
}
// Compute the light reflectance on the triangle from above - take the z value
function Light(daaT) {
var daaV = new Array(2);
daaV[0] = new Array(3);
daaV[1] = new Array(3);
for (var k = 0; k < 3; ++k) {
daaV[0][k] = daaT[1][k] - daaT[0][k];
daaV[1][k] = daaT[2][k] - daaT[0][k];
}
// Normalize those vectors, which are the sides of the triangle
Normalize(daaV[0]);
Normalize(daaV[1]);
// Take a Cross Product to get the normal vector
var daN = Cross(daaV[0], daaV[1]);
Normalize(daN);
return Math.abs(daN[2]);
}
var qGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
var daaTriangle = new Array(3);
daaTriangle[0] = new Array(3);
daaTriangle[1] = new Array(3);
daaTriangle[2] = new Array(3);
var daaProjTri = new Array(3);
for (var i = 0; i < 100; ++i) {
for (var j = 0; j < 100; ++j) {
// Triangle 1
daaTriangle[0][0] = -1 + i*dDeltaX;
daaTriangle[0][1] = -1 + j*dDeltaY;
daaTriangle[0][2] = daaZ[i][j];
daaTriangle[1][0] = -1 + (i+1)*dDeltaX;
daaTriangle[1][1] = -1 + j*dDeltaY;
daaTriangle[1][2] = daaZ[i+1][j];
daaTriangle[2][0] = -1 + i*dDeltaX;
daaTriangle[2][1] = -1 + (j+1)*dDeltaY;
daaTriangle[2][2] = daaZ[i][j+1];
var qTriangle = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
daaProjTri[0] = new CProjectedPoint(daaTriangle[0][0], daaTriangle[0][1], daaZ[i][j]);
daaProjTri[1] = new CProjectedPoint(daaTriangle[1][0], daaTriangle[1][1], daaZ[i+1][j]);
daaProjTri[2] = new CProjectedPoint(daaTriangle[2][0], daaTriangle[2][1], daaZ[i][j+1]);
dCoords = (daaProjTri[0].mdU + cx) + " " + (daaProjTri[0].mdV + cy) + " " +
(daaProjTri[1].mdU + cx) + " " + (daaProjTri[1].mdV + cy) + " " +
(daaProjTri[2].mdU + cx) + " " + (daaProjTri[2].mdV + cy);
qTriangle.setAttribute('points', dCoords);
var dLight = Light(daaTriangle);
var qColor = 'rgb(' + Math.floor(dLight*128 + 100) + ', ' +
Math.floor(dLight*128 + 127.9) + ', ' +
Math.floor(dLight*128 + 100) + ')';
qTriangle.setAttribute('fill', qColor);
qTriangle.setAttribute('fill-rule', 'nonzero');
qTriangle.setAttribute('stroke-width', '1');
qTriangle.setAttribute('stroke', qColor);
qGroup.appendChild(qTriangle);
// Triangle 2
daaTriangle[0][0] = -1 + (i+1)*dDeltaX;
daaTriangle[0][1] = -1 + (j+1)*dDeltaY;
daaTriangle[0][2] = daaZ[i+1][j+1];
qTriangle = document.createElementNS("http://www.w3.org/2000/svg", "polygon");
daaProjTri[0] = new CProjectedPoint(daaTriangle[0][0], daaTriangle[0][1], daaZ[i+1][j+1]);
dCoords = (daaProjTri[0].mdU + cx) + " " + (daaProjTri[0].mdV + cy) + " " +
(daaProjTri[1].mdU + cx) + " " + (daaProjTri[1].mdV + cy) + " " +
(daaProjTri[2].mdU + cx) + " " + (daaProjTri[2].mdV + cy);
qTriangle.setAttribute('points', dCoords);
dLight = Light(daaTriangle);
qColor = 'rgb(' + Math.floor(dLight*128 + 100) + ', ' +
Math.floor(dLight*128 + 127.9) + ', ' +
Math.floor(dLight*128 + 100) + ')';
qTriangle.setAttribute('fill', qColor);
qTriangle.setAttribute('fill-rule', 'nonzero');
qTriangle.setAttribute('stroke-width', '1');
qTriangle.setAttribute('stroke', qColor);
qGroup.appendChild(qTriangle);
}
}
qMainDiv.appendChild(qGroup);
// Outer Lines
qLineZ = document.createElementNS("http://www.w3.org/2000/svg", "line");
qP1 = new CProjectedPoint(1.0, 1.0, 1.0);
qP2 = new CProjectedPoint(1.0, 1.0, -1.0);
qLineZ.setAttribute('x1', qP1.mdU + cx);
qLineZ.setAttribute('y1', qP1.mdV + cy);
qLineZ.setAttribute('x2', qP2.mdU + cx);
qLineZ.setAttribute('y2', qP2.mdV + cy);
qLineZ.setAttribute('stroke-width', '1');
qLineZ.setAttribute('stroke', 'rgb(255, 128, 128)');
qMainDiv.appendChild(qLineZ);
qLineY = document.createElementNS("http://www.w3.org/2000/svg", "line");
qP1 = new CProjectedPoint(1.0, 1.0, 1.0);
qP2 = new CProjectedPoint(1.0, -1.0, 1.0);
qLineY.setAttribute('x1', qP1.mdU + cx);
qLineY.setAttribute('y1', qP1.mdV + cy);
qLineY.setAttribute('x2', qP2.mdU + cx);
qLineY.setAttribute('y2', qP2.mdV + cy);
qLineY.setAttribute('stroke-width', '1');
qLineY.setAttribute('stroke', 'rgb(255, 128, 128)');
qMainDiv.appendChild(qLineY);
qLineX = document.createElementNS("http://www.w3.org/2000/svg", "line");
qP1 = new CProjectedPoint(1.0, 1.0, 1.0);
qP2 = new CProjectedPoint(-1.0, 1.0, 1.0);
qLineX.setAttribute('x1', qP1.mdU + cx);
qLineX.setAttribute('y1', qP1.mdV + cy);
qLineX.setAttribute('x2', qP2.mdU + cx);
qLineX.setAttribute('y2', qP2.mdV + cy);
qLineX.setAttribute('stroke-width', '1');
qLineX.setAttribute('stroke', 'rgb(255, 128, 128)');
qMainDiv.appendChild(qLineX);
qBody.appendChild(qMainDiv);
© 20072025 XoaX.net LLC. All rights reserved.