The canvas doesn't seem to be rotating even after executing the setTransform

Within my HTML5 canvas, I have been experimenting with drawing lines and rotating them around the center point. My goal is to reset the canvas's transformation each time I draw, followed by re-translating/rotating the canvas. However, I have encountered an issue where the rotation does not seem to take effect as intended. In one version of my code, I managed to achieve the desired outcome by storing the previous rotation and only rotating based on the difference in angles.

To illustrate this problem, I have created two fiddles - the first version where the transform reset doesn't work properly and the second version where adjusting the angle difference works correctly. Both snippets are provided below. How can I modify the second version to replicate the functionality of the first?

First version (functional but undesired approach)

(function () {    
    // dynamic canvas
    var dynamic = document.getElementById("dynamic");
    var dynamicCtx = dynamic.getContext("2d");
    
    // animation status
    var FPS = 10;
    var INTERVAL = 1000 / FPS;
    
    dynamicCtx.translate(dynamic.width/2, dynamic.width/2);
    var previousRotation_rad = 0;
    var rotationCounter_deg = 0;

    var myDynamicObject = {
    center: dynamic.width / 2,
        length: dynamic.width * 0.4,
        draw: function () {   // example of dynamic animation code
        dynamicCtx.clearRect(-this.center, -this.center, 2*this.center, 2*this.center);
            
            // draw the current rotation angle
            dynamicCtx.textBaseline = 'middle';
            dynamicCtx.textAlign = 'center';
            dynamicCtx.fillText(rotationCounter_deg + '°', 0, -this.length);
            
            // draw a line from the center up
            dynamicCtx.beginPath();
            dynamicCtx.moveTo(0, 0);
            dynamicCtx.lineTo(0, -this.length + 20);
            dynamicCtx.stroke();
            
            // rotate the canvas
            var currentRotation_rad = rotationCounter_deg * Math.PI / 180;
            var rotationDifference_rad = currentRotation_rad - previousRotation_rad;
            previousRotation_rad = currentRotation_rad;
            console.log('rotating', rotationDifference_rad, 'radians');
            dynamicCtx.rotate(rotationDifference_rad);
          ++rotationCounter_deg;
        }
    };

    function drawDynamic() {        
        myDynamicObject.draw();
        // you can add more dynamic objects and draw here
    }

    function animate() {
        setInterval(function () {
            // only need to redraw dynamic objects
            drawDynamic();
        }, INTERVAL);
    }

    animate(); // entry point for animated (dynamic) objects
})();
#canvasesdiv {
    position:relative;
    width:400px;
    height:400px;
}
#dynamic {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 1;
}
<div id="canvasesdiv">
    <canvas id="dynamic" width=400 height=400>This text is displayed if your browser does not support HTML5 Canvas</canvas>
</div>

Second version (non-functional yet desired implementation)

(function () {    
    // dynamic canvas
    var dynamic = document.getElementById("dynamic");
    var dynamicCtx = dynamic.getContext("2d");
    
    // animation status
    var FPS = 10;
    var INTERVAL = 1000 / FPS;
    
    var rotationCounter_deg = 0;

    var myDynamicObject = {
    center: dynamic.width / 2,
        length: dynamic.width * 0.4,
        draw: function () {   // example of dynamic animation code
        dynamicCtx.setTransform(1, 0, 0, 1, 0, 0);
        dynamicCtx.translate(dynamic.width/2, dynamic.width/2);
        dynamicCtx.clearRect(-this.center, -this.center, 2*this.center, 2*this.center);
            
            // draw the current rotation angle
            dynamicCtx.textBaseline = 'middle';
            dynamicCtx.textAlign = 'center';
            dynamicCtx.fillText(rotationCounter_deg + '°', 0, -this.length);
            
            // draw a line from the center up
            dynamicCtx.beginPath();
            dynamicCtx.moveTo(0, 0);
            dynamicCtx.lineTo(0, -this.length + 20);
            dynamicCtx.stroke();
            
            // rotate the canvas
            var currentRotation_rad = rotationCounter_deg * Math.PI / 180;
            console.log('rotating', currentRotation_rad, 'radians');
            dynamicCtx.rotate(currentRotation_rad);
          ++rotationCounter_deg;
        }
    };

    function drawDynamic() {        
        myDynamicObject.draw();
        // you can add more dynamic objects and draw here
    }

    function animate() {
        setInterval(function () {
            // only need to redraw dynamic objects
            drawDynamic();
        }, INTERVAL);
    }

    animate(); // entry point for animated (dynamic) objects
})();
#canvasesdiv {
    position:relative;
    width:400px;
    height:400px;
}
#dynamic {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 1;
}
<div id="canvasesdiv">
    <canvas id="dynamic" width=400 height=400>This text is displayed if your browser does not support HTML5 Canvas</canvas>
</div>

Answer №1

One key difference from CSS is that in the canvas context, all transforms must be applied before any drawing takes place.

Remember to move the rotation transform up before you start drawing on the canvas:

(function() {
  // create a dynamic canvas
  var dynamic = document.getElementById("dynamic");
  var dynamicCtx = dynamic.getContext("2d");

  // define animation variables
  var FPS = 10;
  var INTERVAL = 1000 / FPS;

  var rotationCounter_deg = 0;

  var myDynamicObject = {
    center: dynamic.width / 2,
    length: dynamic.width * 0.4,
    draw: function() { // example of dynamic animation code
      var currentRotation_rad = rotationCounter_deg * Math.PI / 180;

      dynamicCtx.setTransform(1, 0, 0, 1, 0, 0);
      dynamicCtx.translate(dynamic.width / 2, dynamic.width / 2);
      dynamicCtx.clearRect(-this.center, -this.center, 2 * this.center, 2 * this.center);
      dynamicCtx.rotate(currentRotation_rad);

      // display the current rotation angle
      dynamicCtx.textBaseline = 'middle';
      dynamicCtx.textAlign = 'center';
      dynamicCtx.fillText(rotationCounter_deg + '°', 0, -this.length);

      // draw a line from the center up
      dynamicCtx.beginPath();
      dynamicCtx.moveTo(0, 0);
      dynamicCtx.lineTo(0, -this.length + 20);
      dynamicCtx.stroke();

      console.log('rotating', currentRotation_rad, 'radians');
      ++rotationCounter_deg;
    }
  };

  function drawDynamic() {
    myDynamicObject.draw();
  }

  function animate() {
    setInterval(function() {
      drawDynamic();
    }, INTERVAL);
  }

  animate(); // starts the animation for dynamic objects
})();
#canvasesdiv {
  position: relative;
  width: 400px;
  height: 400px;
}
#dynamic {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
}
<div id="canvasesdiv">
  <canvas id="dynamic" width=400 height=400>This text is displayed if your browser does not support HTML5 Canvas</canvas>
</div>

Additionally, you can combine setTransform() and the initial translate():

dynamicCtx.setTransform(1, 0, 0, 1, 0, 0);
dynamicCtx.translate(dynamic.width / 2, dynamic.width / 2);

into:

dynamicCtx.setTransform(1, 0, 0, 1, dynamic.width * 0.5, dynamic.width * 0.5);

Answer №2

Make sure to rotate the canvas before adding any content to avoid issues with the display.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The method for transferring text box values to the next page using a hyperlink in JSP is as follows:

Is there a way to pass the values of a text box in a JSP through a hyperlink on the same page? I want to achieve this but am not sure how. ...

What is the best way to utilize jspdf for formatting data, specifically when wanting the first column to be in bold?

How can I customize data formatting using jspdf? Specifically, I would like the first column to be in bold and the second column in normal text. Additionally, I want to align them in the middle of the pdf output with different colors for each column. Belo ...

What is the best way to compare the previous and next values in React?

When working with the code snippet below to send a list of values to another component - React.createElement("ul", null, this.state.stock.map(function (value){ return (React.createElement(Price, { price: value })) }) ) the values are then sent t ...

Having trouble with querySelector or getElementById not functioning properly?

Currently, I am in the midst of developing an experimental web application that features a quiz component. For this project, I have implemented a Python file to handle the questions and quiz functionalities. However, I have encountered an issue with the Ja ...

The shader on the background plane takes precedence over all other elements in three.js

I'm struggling to achieve a simple setup in my scene where a plane serves as the background with a shader, and a box is placed on top with a lambert material. Despite my efforts, I can't seem to make both the plane and the box appear together. An ...

Attempting to interpret HTML in Javascript

I have a text string that contains HTML tags. Initially, I attempted to insert this using innerHTML, but the tags were displayed as plain text. After some troubleshooting, I realized that I needed to properly parse the HTML content. Although jQuery prov ...

Store the checkbox's data in the database for safekeeping

Hey there, I'm working on saving the value of a checkbox using PHP. The twist is that the value is generated through JavaScript. How can I handle this scenario and save the value using PHP? Checkbox: <input type='checkbox' name='ca ...

Nextjs introduces an innovative "OnThisDay" functionality, leveraging getServerSideProps and Date.now() to provide real-time information

I am currently working on adding an "OnThisDay" feature in my Nextjs project, inspired by Wikipedia's style of displaying events that happened on a specific date. To achieve this, I have implemented a function structured like the following code snippe ...

Refreshing the page using location.reload triggers a reload of various elements

I am currently working on a website that supports multiple languages and utilizes a cookie named nav_lang to determine the user's preferred language for navigation. Whenever a user selects a new language, the cookie is updated accordingly and the page ...

Utilizing data attributes and JavaScript to dynamically assign a class to carousel navigation items

Hello there! I recently created a carousel and carousel navigation system using Bootstrap. I am now trying to figure out how to detect the value of 'data-slide-to' and then apply a specific style to the corresponding navigation item based on that ...

What is the process for transforming a String into an HTML element within a Next JS Application?

I stored the product description as HTML elements in a Database, but when I try to render this data into a div, it displays as a String. I am looking to showcase all the data as HTML elements in my Next JS application. I attempted using JSON.parse, but unf ...

Enhancing JSON Objects in AngularJS with Custom Properties and Calculations

Hello, I'm still getting the hang of angularjs and could use some guidance. I have a Rest service that provides data on saleItems when a get request is made, as shown below: saleItems = [ { "id": 236, "variant": "Oval Holder", "mrp": "6 ...

What is the best way to pass a prop into the <router-link>?

If I replace this {{ name }}, the result is "campaigns" Now, I want to use that in my link <router-link :to="'/' + '123' + '/' + item.id"> {{ item.name }}</router-link> I attempted to substitute '1 ...

Step-by-step guide on transferring an HTML5 sqlite result set to a server using AJAX

Imagine I have a scenario where I receive a result set as shown below: db.transaction( function(transaction) { transaction.executeSql( 'SELECT col1, col2, col3 FROM table;', [],function(transaction, result){ //need to find a ...

Overlap of sub menus

Seeking assistance from a CSS expert for a challenge I am facing. I am currently working on a toggle menu for mobile view, and encountering issues with the submenu. Any list item placed below another one with children is not visible. Removing the parent l ...

Having trouble retrieving input field values with Angular.js

I am struggling to access the input field values in my Angular.js application. Below is the code snippet I am using: <div class="input-group bmargindiv1 col-md-12"> <span class="input-group-addon ndrftextwidth text-right" style="width:180px"& ...

The declaration file for the module 'tailwind-scrollbar' could not be located

Currently, I am in the process of utilizing Tailwind packages for a Next.js application, however, I have encountered an issue that has proved to be quite challenging to resolve. Every time I attempt to add a "require" statement to my tailwind.config.js fil ...

What steps should be taken to develop a Hybrid Mobile App concept?

We are currently developing our first hybrid mobile application with a monetizable idea in mind. After conducting some research, it seems that to reach our end goal we will need: A Front End UI Framework: options include Ionic or AngularGap (although d ...

Is it possible to assign numerical values to attributes in HTML code?

I'm unsure about something - is it possible to set an attribute value as a number? For example: <div data-check="1"></div> Is this the correct way to do it or not? I've heard conflicting opinions, with some people saying you shouldn ...

My React component is experiencing issues with the Console.log functionality

Utilizing React for a component, I have incorporated a button that triggers a function 'myFunction' upon clicking, which essentially executes a console.log command. Despite compiling the code without any errors in both Visual Studio and the brow ...