Advertisement
Guest User

Untitled

a guest
Nov 24th, 2014
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 13.84 KB | None | 0 0
  1. <!DOCTYPE html>
  2.  
  3. <html>
  4. <head>
  5.     <title>Canvas Surface Rotation</title>
  6.     <style>
  7.         body {
  8.             text-align: center;
  9.         }
  10.  
  11.         canvas {
  12.             border: 1px solid black;
  13.         }
  14.  
  15.     </style>
  16.     <script>
  17.         var constants = {
  18.             canvasWidth: 600, // In pixels.
  19.             canvasHeight: 600, // In pixels.
  20.             leftArrow: 37,
  21.             upArrow: 38,
  22.             rightArrow: 39,
  23.             downArrow: 40,
  24.             xMin: -15, // These four max/min values define a square on the xy-plane that the surface will be plotted over.
  25.             xMax: 15,
  26.             yMin: -15,
  27.             yMax: 15,
  28.             xDelta: 0.03, // Make smaller for more surface points.
  29.             yDelta: 0.03, // Make smaller for more surface points.
  30.             colorMap: ["#060", "#090", "#0C0", "#0F0", "#9F0", "#9C0", "#990", "#960", "#930", "#900", "#C00"], // There are eleven possible "vertical" color values for the surface, based on the last row of http://www.cs.siena.edu/~lederman/truck/AdvanceDesignTrucks/html_color_chart.gif
  31.             pointWidth: 2, // The size of a rendered surface point (i.e., rectangle width and height) in pixels.
  32.             dTheta: 0.05, // The angle delta, in radians, by which to rotate the surface per key press.
  33.             surfaceScale: 5, // An empirically derived constant that makes the surface a good size for the given canvas size.
  34.             eps: 0.0001
  35.         };
  36.  
  37.         var X = 0;
  38.         var Y = 1;
  39.         var Z = 2;
  40.  
  41.  
  42.         var controlKeyPressed = false;
  43.         var surface = new Surface();
  44.  
  45.  
  46.         function point(x, y, z) {
  47.             return [x, y, z];
  48.         }
  49.  
  50.  
  51.         function Surface() {
  52.             this.points = [];
  53.         }
  54.  
  55.  
  56.         Surface.prototype.equation = function (x, y) {
  57.             var d = Math.sqrt(x * x + y * y);
  58.  
  59.             return 4 * (Math.sin(d) / d);
  60.         }
  61.  
  62.  
  63.         Surface.prototype.generate = function () {
  64.             var i = 0;
  65.  
  66.             for (var x = constants.xMin; x <= constants.xMax; x += constants.xDelta) {
  67.                for (var y = constants.yMin; y <= constants.yMax; y += constants.yDelta) {
  68.                    for (var z = constants.yMin; z <= constants.yMax; z += constants.yDelta) {
  69.                        var a = Math.pow((x * x + y * y + z * z), 2);
  70.                        var b = constants.a * z * Math.pow((x * x + y * y), 2);
  71.                        if (Math.abs(a - b) < constants.eps) {
  72.                            this.points[i] = point(x, y, z);
  73.                            ++i;
  74.                        }
  75.                    }
  76.                }
  77.            }
  78.        }
  79.  
  80.        Surface.prototype.color = function () {
  81.            var z;
  82.  
  83.            this.zMin = this.zMax = this.points[0][Z];
  84.            for (var i = 0; i < this.points.length; i++) {
  85.                z = this.points[i][Z];
  86.                if (z < this.zMin) { this.zMin = z; }
  87.                if (z > this.zMax) { this.zMax = z; }
  88.             }
  89.  
  90.             var zDelta = Math.abs(this.zMax - this.zMin) / constants.colorMap.length;
  91.  
  92.             for (var i = 0; i < this.points.length; i++) {
  93.                this.points[i].color = constants.colorMap[Math.floor((this.points[i][Z] - this.zMin) / zDelta)];
  94.            }
  95.        }
  96.  
  97.  
  98.        function appendCanvasElement() {
  99.            var canvasElement = document.createElement('canvas');
  100.  
  101.            canvasElement.width = constants.canvasWidth;
  102.            canvasElement.height = constants.canvasHeight;
  103.            canvasElement.id = "myCanvas";
  104.  
  105.            canvasElement.getContext('2d').translate(constants.canvasWidth / 2, constants.canvasHeight / 2);
  106.  
  107.            document.body.appendChild(canvasElement);
  108.        }
  109.  
  110.  
  111.        Surface.prototype.sortByZIndex = function (A, B) {
  112.            return A[Z] - B[Z];
  113.        }
  114.  
  115.  
  116.        Surface.prototype.draw = function () {
  117.            var myCanvas = document.getElementById("myCanvas"); // Required for Firefox.
  118.            var ctx = myCanvas.getContext("2d");
  119.  
  120.            this.points = surface.points.sort(surface.sortByZIndex); // Sort the set of points based on relative z-axis position. If the points are visibly small, you can sort of get away with removing this step.
  121.  
  122.            for (var i = 0; i < this.points.length; i++) {
  123.                ctx.fillStyle = this.points[i].color;
  124.                ctx.fillRect(this.points[i][X] * constants.surfaceScale, this.points[i][Y] * constants.surfaceScale, constants.pointWidth, constants.pointWidth);
  125.            }
  126.        }
  127.  
  128.        // -----------------------------------------------------------------------------------------------------
  129.  
  130.        Surface.prototype.multi = function (R)
  131.            /*
  132.              Assumes that R is a 3 x 3 matrix and that this.points (i.e., P) is a 3 x n matrix. This method performs P = R * P.
  133.            */ {
  134.            var Px = 0, Py = 0, Pz = 0; // Variables to hold temporary results.
  135.            var P = this.points; // P is a pointer to the set of surface points (i.e., the set of 3 x 1 vectors).
  136.            var sum; // The sum for each row/column matrix product.
  137.  
  138.            for (var V = 0; V < P.length; V++) // For all 3 x 1 vectors in the point list.
  139.            {
  140.                Px = P[V][X], Py = P[V][Y], Pz = P[V][Z];
  141.                for (var Rrow = 0; Rrow < 3; Rrow++) // For each row in the R matrix.
  142.                {
  143.                    sum = (R[Rrow][X] * Px) + (R[Rrow][Y] * Py) + (R[Rrow][Z] * Pz);
  144.                    P[V][Rrow] = sum;
  145.                }
  146.            }
  147.        }
  148.  
  149.        // -----------------------------------------------------------------------------------------------------
  150.  
  151.        Surface.prototype.erase = function () {
  152.            var myCanvas = document.getElementById("myCanvas"); // Required for Firefox.
  153.            var ctx = myCanvas.getContext("2d");
  154.  
  155.            ctx.clearRect(-constants.canvasWidth / 2, -constants.canvasHeight / 2, myCanvas.width, myCanvas.height);
  156.        }
  157.  
  158.        // -----------------------------------------------------------------------------------------------------
  159.  
  160.        Surface.prototype.xRotate = function (sign)
  161.            /*
  162.              Assumes "sign" is either 1 or -1, which is used to rotate the surface "clockwise" or "counterclockwise".
  163.            */ {
  164.            var Rx = [[0, 0, 0],
  165.                       [0, 0, 0],
  166.                       [0, 0, 0]]; // Create an initialized 3 x 3 rotation matrix.
  167.  
  168.            Rx[0][0] = 1;
  169.            Rx[0][1] = 0; // Redundant but helps with clarity.
  170.            Rx[0][2] = 0;
  171.            Rx[1][0] = 0;
  172.            Rx[1][1] = Math.cos(sign * constants.dTheta);
  173.            Rx[1][2] = -Math.sin(sign * constants.dTheta);
  174.            Rx[2][0] = 0;
  175.            Rx[2][1] = Math.sin(sign * constants.dTheta);
  176.            Rx[2][2] = Math.cos(sign * constants.dTheta);
  177.  
  178.            this.multi(Rx); // If P is the set of surface points, then this method performs the matrix multiplcation: Rx * P
  179.            this.erase(); // Note that one could use two canvases to speed things up, which also eliminates the need to erase.
  180.            this.draw();
  181.        }
  182.  
  183.        // -----------------------------------------------------------------------------------------------------
  184.  
  185.        Surface.prototype.yRotate = function (sign)
  186.            /*
  187.              Assumes "sign" is either 1 or -1, which is used to rotate the surface "clockwise" or "counterclockwise".
  188.            */ {
  189.            var Ry = [[0, 0, 0],
  190.                       [0, 0, 0],
  191.                       [0, 0, 0]]; // Create an initialized 3 x 3 rotation matrix.
  192.  
  193.            Ry[0][0] = Math.cos(sign * constants.dTheta);
  194.            Ry[0][1] = 0; // Redundant but helps with clarity.
  195.            Ry[0][2] = Math.sin(sign * constants.dTheta);
  196.            Ry[1][0] = 0;
  197.            Ry[1][1] = 1;
  198.            Ry[1][2] = 0;
  199.            Ry[2][0] = -Math.sin(sign * constants.dTheta);
  200.            Ry[2][1] = 0;
  201.            Ry[2][2] = Math.cos(sign * constants.dTheta);
  202.  
  203.            this.multi(Ry); // If P is the set of surface points, then this method performs the matrix multiplcation: Rx * P
  204.            this.erase(); // Note that one could use two canvases to speed things up, which also eliminates the need to erase.
  205.            this.draw();
  206.        }
  207.  
  208.        // -----------------------------------------------------------------------------------------------------
  209.  
  210.        Surface.prototype.zRotate = function (sign)
  211.            /*
  212.              Assumes "sign" is either 1 or -1, which is used to rotate the surface "clockwise" or "counterclockwise".
  213.            */ {
  214.            var Rz = [[0, 0, 0],
  215.                       [0, 0, 0],
  216.                       [0, 0, 0]]; // Create an initialized 3 x 3 rotation matrix.
  217.  
  218.            Rz[0][0] = Math.cos(sign * constants.dTheta);
  219.            Rz[0][1] = -Math.sin(sign * constants.dTheta);
  220.            Rz[0][2] = 0; // Redundant but helps with clarity.
  221.            Rz[1][0] = Math.sin(sign * constants.dTheta);
  222.            Rz[1][1] = Math.cos(sign * constants.dTheta);
  223.            Rz[1][2] = 0;
  224.            Rz[2][0] = 0
  225.            Rz[2][1] = 0;
  226.            Rz[2][2] = 1;
  227.  
  228.            this.multi(Rz); // If P is the set of surface points, then this method performs the matrix multiplcation: Rx * P
  229.            this.erase(); // Note that one could use two canvases to speed things up, which also eliminates the need to erase.
  230.            this.draw();
  231.        }
  232.  
  233.        // -----------------------------------------------------------------------------------------------------
  234.  
  235.        function processKeyDown(evt) {
  236.            if (evt.ctrlKey) {
  237.                switch (evt.keyCode) {
  238.                    case constants.upArrow:
  239.                        // No operation other than preventing the default behavior of the arrow key.
  240.                        evt.preventDefault(); // This prevents the default behavior of the arrow keys, which is to scroll the browser window when scroll bars are present. The user can still scroll the window with the mouse.
  241.                        break;
  242.                    case constants.downArrow:
  243.                        // No operation other than preventing the default behavior of the arrow key.
  244.                        evt.preventDefault();
  245.                        break;
  246.                    case constants.leftArrow:
  247.                        // console.log("ctrl+leftArrow");
  248.                        surface.zRotate(-1); // The sign determines if the surface rotates "clockwise" or "counterclockwise".
  249.                        evt.preventDefault();
  250.                        break;
  251.                    case constants.rightArrow:
  252.                        // console.log("ctrl+rightArrow");
  253.                        surface.zRotate(1);
  254.                        evt.preventDefault();
  255.                        break;
  256.                }
  257.                return; // When the control key is pressed, only the left and right arrows have meaning, no need to process any other key strokes (i.e., bail now).
  258.            }
  259.  
  260.            // Assert: The control key is not pressed.
  261.  
  262.            switch (evt.keyCode) {
  263.                case constants.upArrow:
  264.                    // console.log("upArrow");
  265.                    surface.xRotate(1);
  266.                    evt.preventDefault();
  267.                    break;
  268.                case constants.downArrow:
  269.                    // console.log("downArrow");
  270.                    surface.xRotate(-1);
  271.                    evt.preventDefault();
  272.                    break;
  273.                case constants.leftArrow:
  274.                    // console.log("leftArrow");
  275.                    surface.yRotate(-1);
  276.                    evt.preventDefault();
  277.                    break;
  278.                case constants.rightArrow:
  279.                    // console.log("rightArrow");
  280.                    surface.yRotate(1);
  281.                    evt.preventDefault();
  282.                    break;
  283.            }
  284.        }
  285.  
  286.        // -----------------------------------------------------------------------------------------------------
  287.  
  288.        function onloadInit() {
  289.            appendCanvasElement(); // Create and append the canvas element to the DOM.
  290.            surface.draw(); // Draw the surface on the canvas.
  291.            document.addEventListener('keydown', processKeyDown, false); // Used to detect if the control key has been pressed.
  292.            document.getElementById("myCanvas").addEventListener('mousewheel', function (event) {
  293.                if (event.wheelDelta / 120 > 0) {
  294.                     constants.surfaceScale++; surface.erase(); surface.draw();
  295.                 }
  296.                 else {
  297.                     constants.surfaceScale--; surface.erase(); surface.draw();
  298.                 }
  299.                 return false;
  300.             }, false);
  301.         }
  302.  
  303.         // -----------------------------------------------------------------------------------------------------
  304.  
  305.         constants.a = 1;
  306.         surface.generate(); // Creates the set of points reprsenting the surface. Must be called before color().
  307.         surface.color(); // Based on the min and max z-coordinate values, chooses colors for each point based on the point's z-ccordinate value (i.e., height).
  308.         window.addEventListener('load', onloadInit, false); // Perform processing that must occur after the page has fully loaded.
  309.     </script>
  310. </head>
  311. <body>
  312.     <h1>Canvas Surface Rotation</h1>
  313.     <div id="buttons">
  314.         <button onclick="constants.a++; surface.erase(); surface.generate(); surface.color(); surface.draw(); document.getElementById('a').innerText = constants.a">a++</button>
  315.         <button onclick="if (a == 1) return; constants.a--; surface.erase(); surface.generate(); surface.color();  surface.draw(); document.getElementById('a').innerText = constants.a;">a--</button>
  316.         a=<span id="a">1</span>
  317.     </div>
  318. </body>
  319. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement