First Experiment with HTML5: A Wireframe Cube

HTML5 introduces many new powerful features, one of which is the canvas element. The canvas allows us to draw graphics using JavaScript. Here I present my first experiment with the HTML5 canvas element. If your browser supports the HTML5 canvas element, you should see a rotating wireframe cube below. If this experiment does not work with your browser, make sure you download its latest version.

The Code

I will give you just a brief explanation of the code. First of all, I defined the canvas element in the HTML structure. Then, in the Javascript code I have the Point3D class that represents 3D points. This class has methods to rotate points across the 3 axes (X, Y, and Z), and to map them to 2D space using perspective projection. Using this class I defined 8 vertices of the cube. The startDemo() function is called after the document is fully loaded. It creates a 2d context from the canvas, and starts the main loop. The loop() function transforms and draws the wireframe cube.

<html>
<head>
    <title>First Experiment with HTML5</title>
    <script type="text/javascript">
        window.onload = startDemo;

        function Point3D(x,y,z) {
            this.x = x;
            this.y = y;
            this.z = z;

            this.rotateX = function(angle) {
                var rad, cosa, sina, y, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                y = this.y * cosa - this.z * sina
                z = this.y * sina + this.z * cosa
                return new Point3D(this.x, y, z)
            }

            this.rotateY = function(angle) {
                var rad, cosa, sina, x, z
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                z = this.z * cosa - this.x * sina
                x = this.z * sina + this.x * cosa
                return new Point3D(x,this.y, z)
            }

            this.rotateZ = function(angle) {
                var rad, cosa, sina, x, y
                rad = angle * Math.PI / 180
                cosa = Math.cos(rad)
                sina = Math.sin(rad)
                x = this.x * cosa - this.y * sina
                y = this.x * sina + this.y * cosa
                return new Point3D(x, y, this.z)
            }

            this.project = function(viewWidth, viewHeight, fov, viewDistance) {
                var factor, x, y
                factor = fov / (viewDistance + this.z)
                x = this.x * factor + viewWidth / 2
                y = this.y * factor + viewHeight / 2
                return new Point3D(x, y, this.z)
            }
        }

        var vertices = [
            new Point3D(-1,1,-1),
            new Point3D(1,1,-1),
            new Point3D(1,-1,-1),
            new Point3D(-1,-1,-1),
            new Point3D(-1,1,1),
            new Point3D(1,1,1),
            new Point3D(1,-1,1),
            new Point3D(-1,-1,1)
        ];

        // Define the vertices that compose each of the 6 faces. These numbers are
        // indices to the vertex list defined above.
        var faces = [[0,1,2,3],[1,5,6,2],[5,4,7,6],[4,0,3,7],[0,4,5,1],[3,2,6,7]]

        var angle = 0;

        function startDemo() {
            canvas = document.getElementById("thecanvas");
            if( canvas && canvas.getContext ) {
                ctx = canvas.getContext("2d");
                setInterval(loop,33);
            }
        }

        function loop() {
            var t = new Array();

            ctx.fillStyle = "rgb(0,0,0)";
            ctx.fillRect(0,0,400,200);

            for( var i = 0; i < vertices.length; i++ ) {
                var v = vertices[i];
                var r = v.rotateX(angle).rotateY(angle).rotateZ(angle);
                var p = r.project(400,200,128,3.5);
                t.push(p)
            }

            ctx.strokeStyle = "rgb(255,55,255)"

            for( var i = 0; i < faces.length; i++ ) {
                var f = faces[i]
                ctx.beginPath()
                ctx.moveTo(t[f[0]].x,t[f[0]].y)
                ctx.lineTo(t[f[1]].x,t[f[1]].y)
                ctx.lineTo(t[f[2]].x,t[f[2]].y)
                ctx.lineTo(t[f[3]].x,t[f[3]].y)
                ctx.closePath()
                ctx.stroke()
            }
            angle += 2
        }
    </script>
</head>
<body>
    <h2>First Experiment with HTML5</h2>
    <canvas id="thecanvas" width="400" height="200">
        Your browser does not support the HTML5 canvas element.
    </canvas>
</body>
</html>

I have previously published a tutorial explaining how to make a wireframe cube using python.

What do you think about this? Please comment, share or subscribe.

  1. That is very awesome!

    • Hello Teak. Thank you very much.
      Have you tried to do something with HTML5 and JavaScript?

      • Not HTML5, but I’ve used and am loving the new stuff in CSS3. You can do some pretty neat stuff using JS and CSS3. I going to fiddle with HTML5 when I get some more time…

  2. Thank you very much this code help me for my website ;)

  3. hi,
    i am new in html5 can u plz describe the code… specially this.rotateX = function(angle) {
    var rad, cosa, sina, y, z
    rad = angle * Math.PI / 180
    cosa = Math.cos(rad)
    sina = Math.sin(rad)
    y = this.y * cosa – this.z * sina
    z = this.y * sina + this.z * cosa
    return new Point3D(this.x, y, z)
    }

  4. Where does [x * sina + y * cosa] come from. I cant find any reference to this equation.

    • Radu: That formula is used to calculate new coordinate after rotation operation. You can find more information by googling “Rotation Matrix” or “Transformation Matrix”

  5. Thank you for the code !
    What is the difference fov and ViewDistance ? Looks the same result to me,
    and,
    what if the ViewDistance goes negative ? (camera in the cube) It goes crazy !

Leave a Comment

Notify me of followup comments via e-mail. You can also subscribe without commenting.