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

Issue with Dynamic Image Path in Require Function: Unable to locate the relative module

I've been struggling with an error in VueJs require function for the past two days. I'm attempting to pass a prop to the Home component and then display the image. Home.vue <template> <BlogPost :post="welcomeScreen"/> <B ...

Creating key elements in JavaScript with the push() function

I'm working on a basic shopping cart system using JavaScript (Ionic 2 / Angular). In my PHP code, I have the following: <?php $cart = array( 48131 => array( 'size' => 'STANDARD', 'qty' => ...

I am looking to retrieve the values entered in a textbox from an HTML document and then post them using a JSON file in Node.js when the submit button is

Here is the JavaScript code I have written: $(document).ready(function(){ $('form').on('submit', function(){ var email = $("form input[type=text][name=emails]").val(); var todo = {email: email.val(), ...

When using addClass("test"), it throws an error message: TypeError: undefined is not a function

Upon examination in the console, I discovered the following: $(".myCssClass")[0].parentNode <li><span class="myCssClass">some text</span></li> I am attempting to add a CSS class to the parent span tag within the <li> element ...

Improved method for categorizing items within an Array

Currently working on developing a CRUD API for a post-processing tool that deals with data structured like: { _date: '3/19/2021', monitor: 'metric1', project: 'bluejays', id1: 'test-pmon-2', voltageConditio ...

What is the best way to insert a new row into a table upon clicking a button with Javascript?

Hi everyone, I'm facing an issue with my code. Whenever I click on "Add Product", I want a new row with the same fields to be added. However, it's not working as expected when I run the code. Below is the HTML: <table class="table" id="conci ...

Displaying dates in Material UI datepicker is not working

My current setup involves using Material UI v14.4 with React, and I have encountered an issue with the DatePicker component not displaying the dates correctly as shown in the attached screenshot. Strangely, there are no visible error messages either. Any s ...

Tips on obtaining checkbox value in an AJAX request

I need to retrieve the value of a checkbox using Ajax in order to store it as a user preference in the database. This task is new to me, and I'm feeling a bit overwhelmed. Here is my JavaScript file: $(document).ready(function() { E.accounts.chang ...

The arrow function in Jest is missing a name property

Currently, my setup includes: node.js: 9.8.0 Jest: 23.4.2 ts-jest: 23.1.3 typescript: 2.9.2 While attempting the following in my *.test.ts files: const foo = () => 'bar'; console.log(foo.name); // '' foo contains the name pro ...

What is the best way to switch the visibility of a div on click from another div?

My goal is to make a div toggle visible or hidden when another div is clicked. The only connection between the two divs is that they are both nested within the same parent div. There's a DIV element with the class of "comment" which contains a DIV ele ...

Encountering an abundance of concurrent requests using NodeJS and request-promise

I am currently working on a NodeJS project that involves a large array of about 9000 elements containing URLs. These URLs need to be requested using the "request-promise" package. However, making 9000 concurrent GET requests to the same website from the sa ...

Update the dropdown field selection to the color #333 with the help of javascript

I am facing an issue with a dropdown field that has placeholder text and options to select. Initially, both the placeholder text and the options were in color #333. However, I managed to change the color of the placeholder text to light grey using the foll ...

Modifying property values using the onError event when encountering an error with the MUI DateTimePicker and

My goal is to set the 'myError' variable to true when MUI DateTimePicker throws an onError event, but for some reason it's not working. The code itself seems correct because if I replace () => {setValue({ ...value, ...

'Without the need to refresh the page, assign a JavaScript variable from JSP on the server side.'

I'm looking for a way to assign a JavaScript variable from JSP without triggering a full page reload. While my current code successfully sets the variable, it also causes the entire page to refresh as a side effect. Here's an example in the exam ...

Error code received from OpenStack Identity API GET response

I am an intern student and I have a query. Currently, I am working on bug fixing for an Openstack cloud, JavaScript, and Node.js web application. My task involves resolving toastr.error messages and translating them into different languages. How do I ret ...

Wrap it in a ReactJS container tag

Today I encountered a frustrating issue while diving into ReactJS. I'm excited to learn by getting my hands dirty, but unfortunately, I keep running into this error: Adjacent JSX elements must be wrapped in an enclosing tag (47:14) And here's t ...

The unexpected token was found in line 1 of the manifest icons code, but not in column 1

This query appears to have been long-standing on Stackflow, but none of the solutions posted seem to resolve it. Even though the JSON validates correctly in validators, I continue to encounter the following error. Any idea what might be causing this issue ...

Using Jquery to display text when the condition is not met

Here is the code snippet I am currently working with: http://jsfiddle.net/spadez/mn77f/6/ I am trying to make it display a message when there are no fields (questions) present. I attempted to achieve this by adding the following lines of code: } else ...

Using AJAX to dynamically populate PHP form inputs from HTML

I'm trying to create a simple HTML form where users can input their information and have it sent to a PHP file using JavaScript with AJAX. However, I'm encountering an issue where the values from the form are not being included in the email that ...

Can an HTML DOM object be converted to a JSON string using JSON.stringify in JavaScript?

Trying to fetch an external HTML file and convert its body content into a string has been giving me unexpected results. Is there a way to achieve this successfully? var xhr = new XMLHttpRequest(); function loadFile(){ xhr.open("GET", 'index.html ...