Tips and tricks for spinning a collection of canvas rectangles

For my final project in a class, I am developing a Pentomino puzzle game. All twelve puzzle pieces have been created, and they can be moved around using this interactive demo. However, when attempting to rotate the array without using canvas.rotate(), the code provided below swaps the X and Y coordinates while drawing:

var newPiece = targetPiece;
pieces.splice(pieces.indexOf(targetPiece), 1);
targetPiece = null;
console.log(newPiece);
var geometry = [];
for (var i = 0; i < newPiece.geometry.length; i++) {
    geometry.push([newPiece.geometry[i][3], newPiece.geometry[i][0]]);
}
var offset = [newPiece.offset[1], newPiece.offset[0]];
console.log(geometry);
console.log(offset);
newPiece.geometry = geometry;
newPiece.position = geometry;
newPiece.offset = offset;
pieces.push(newPiece);
console.log(pieces);
for (var j = 0; j < pieces.length; j++) {
    draw(pieces[j]);
}

This method shows potential but is not functioning correctly.

In this isolated example in the following fiddle link, the issue has been narrowed down to rotating a single piece using canvas.rotate(). However, it seems that each block of the array rotates individually, resulting in no visible change due to all blocks being squares:

function doubleClickListener(e) {
var br = canvas.getBoundingClientRect();
mouse_x = (e.clientX - br.left) * (canvas.width / br.width);
mouse_y = (e.clientY - br.top) * (canvas.height / br.height);
var pieceToggle = false;
for (var i = 0; i < pieces.length; i++) {
    if (onTarget(pieces[i], mouse_x, mouse_y)) {
        targetPiece = pieces[i];
        rotate(targetPiece);
    }
}
}

function rotate() {
targetPiece.rotationIndex = targetPiece.rotationIndex === 0 ?
1 : targetPiece.rotationIndex === 1 ?
2 : targetPiece.rotationIndex === 2 ?
3 : 0;
for (var j = 0; j < pieces.length; j++) {
    draw(pieces[j]);
}
}

Despite initial attempts to create individual polygons for puzzle pieces, difficulty was faced in capturing them with mousedown events for movement. Canvas rectangle arrays were then used as they were simpler to manipulate.

To achieve a working puzzle before the deadline, two solutions are considered: implementing separate geometries for all piece rotations and mirrors, or utilizing fabric.js for a complete rewrite after the class ends.

The desired functionality is to rotate the array of five blocks by double-clicking, allowing sequential 90° rotations.


Towards a Functional Puzzle:

With assistance from @absolom, progress has been made on the puzzle game. Pieces can be dragged with a click and drag, rotated with a double-click, and mirrored with a right-click (although rotation only applies after moving the piece again). Z-order manipulation ensures the active piece remains on top:

Pentominoes II


Final Iteration:

The completed game has been submitted for grading. While there are still tweaks to be made, overall, I am satisfied with the outcome. For future improvements, such as fixing delayed rotation, an updated version using feedback received will be considered:

Pentominoes Final

Answer №1

Simple & Quick:

A simple and quick solution involves combining 2 or more pieces to create a single image, which can then be manipulated as one entity using an in-memory canvas.

More Complex Approach:

If the assembly of 2 or more pieces needs to be reversible, a more complex approach is required. Each piece must have its own transformation matrix to maintain individual properties.

Ken Fyrstenberg (K3N), a contributor on Stackoverflow, has developed a useful script for tracking polygons like rectangles using transformation matrices: https://github.com/epistemex/transformation-matrix-js

Answer №2

Are you satisfied with the performance of this code snippet? The current rotate method is structured as follows:

   function rotate(piece) {
       for (i = 0; i < piece.geometry.length; i++) {
           var x = piece.geometry[i][0];
           var y = piece.geometry[i][2];
           piece.geometry[i][0] = -y;
           piece.geometry[i][3] = x;
       }
       drawAll();
   }

I have also streamlined how geometry and positioning are managed. While not flawless, it can provide some guidance on resolving any issues.

It's important to recognize that this solution works due to blocks having the same color within each piece, and rotations being at 90 degrees. Essentially, I am rearranging the blocks to imitate rotation without actually rotating them individually. If your pieces have different compositions or require rotations at other angles, an alternative approach such as transformation matrices may be necessary.

UPDATE

For a more effective solution, consider this improved version: fiddle link

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

A guide to converting hexadecimal to the 2^16 system using C++

Currently, I have a coding task that involves converting hexadecimal numbers N1 (str1) and N2 (str2) to a 2^16 system. The goal is to find the sum of these converted numbers in the 2^16 system and then translate the result back into a hexadecimal format. ...

Unable to trigger the show_popup function by clicking the button

Why won't this piece of code function as expected? <script src="web_push.js"></script> <body> <button onclick="show_popup()"> Button </button> </body> The content of web_push.js file is shown below ...

I need to use JavaScript to create HTML to PDF and then upload the PDF file to a SharePoint Document Library

Our current project requires us to convert HTML to PDF and save it in a SharePoint Document Library. While we have successfully converted the HTML to PDF using Kendo plugin, we are facing challenges with storing it in SharePoint. It's worth noting th ...

How to identify the node with the appropriate date range attribute using JavaScript or jQuery

I am seeking assistance in using Javascript, preferably jQuery, to identify the specific "node" within an XML structure where a given date falls between its "begin" and "end" dates. XML EXAMPLE: <nodes> <node begin="2014-01-01" end="2014-01- ...

What is the process for selecting the default option in a drop-down menu?

Is there a way to set the default value in a drop-down list using material-ui? I attempted to use displayEmpty="true", but it did not work. I want the first option, A, to be pre-selected so that it is visible to the user in the UI without them having to m ...

The issue with Framer motion's whileInView is that it does not animate the element when it is within the viewport in Next.js

In my current Next.js 14 project with the App Router, I decided to play around with animations using Framer Motion. One specific feature I wanted to implement was animating text elements into view as they enter the viewport. The idea is for the text to gra ...

Ensure that the content remains at the center of the screen, but is dynamic and changes

I have a unique concept I want to experiment with, but I'm unsure of the best approach to take. My idea involves centering content on the screen and instead of having it scroll off and new content scroll in, I would like it to stay centered and smoot ...

What is the best way to handle an OR scenario in Playwright?

The Playwright documentation explains that a comma-separated list of CSS selectors will match all elements that can be selected by one of the selectors in that list. However, when I try to implement this, it doesn't seem to work as expected. For exam ...

Struggling to add each line into an array

Having an unusual problem with my Ruby script. I'm trying to read data from a file and store it in an array. Interestingly, the same code works fine in another script. quoteArray = [] quoteFile = File.new("quotes.txt", "r") or die "Unable to open fil ...

Error: Attempting to access the 'state' property of an undefined variable within the bootstrap framework

While attempting to update the state value, I encountered an error stating TypeError: Cannot read property 'state' of undefined. This error occurs when I enter something in a field and then click submit. As a newcomer to React, I realize this may ...

Is there a way to trigger a function after a tooltip or popover is generated using Twitter Bootstrap?

Is there a way to manipulate a tooltip or popover with twitter bootstrap after it has been created? It seems like there isn't a built-in method for this. $('#selector').popover({ placement: 'bottom' }); For instance, what if I ...

Creating PropTypes from TypeScript

Currently in my React project, I am utilizing TypeScript along with PropTypes to ensure type checking and validation of props. It feels redundant to write types for both TypeScript and PropTypes, especially when defining components like ListingsList: inte ...

Usage of Firebase data

Looking for assistance on how to retrieve data from Firebase Cloud Store. My code includes the Firebase configuration and app.js but I'm facing an issue where the page appears blank on localhost:3000 without any errors. Below is the firebase.js confi ...

In PHP, populate an array on every nth row

I'm attempting to generate an array with markers on specific rows, such as every 10th row, 50th row, and 100th row. However, the code I have provided is currently only marking each row after "count" = 10 as 10. Can someone help me identify what mistak ...

ReactForms Deprication for NgModel

According to Angular, certain directives and features are considered deprecated and could potentially be removed in upcoming versions. In a hypothetical scenario, let's say I am using NgModel with reactive forms, which Angular has marked as deprecate ...

Unable to automate the selection of a dropdown menu using Selenium WebDriver

I am currently utilizing http://www.makemytrip.com/ This is the HTML code. <div class="mrgnBot30 clearFix"> <span class="watch_icn flL"></span> <div class="widget_inner clearFix suggest_me padBot15 flL"> <h3 class="clearFix has ...

Customize menu items in Angular ui-grid when right clicking on a cell

Seeking help with Angular UI-grid for a specific feature needed: I want to display a custom menu when a user right-clicks on a specific 'CELL/Column' in the grid, such as 'B' in the example image below. When the user right-clicks, the ...

How can a list be returned from an async callback in NodeJS?

Essentially, I am performing a database query to retrieve all posts with a specific id, then adding them to a list before returning. However, the list is being returned before the callback function has finished executing. How can I ensure that the list is ...

Tips for accessing the individual field values of many documents within a MongoDB collection

Within my collection of documents lies a structured schema: { "_id" : ObjectId("8dcaac2eb104c2133d66f144"), "Shape" : "circle", "Color" : "blue" }, The objective is to dynamically retrieve the value of a specific field for multiple docum ...

Sharing an array between two sibling components

Within my 'Home' component, users have the ability to create QR codes. I have implemented a method that generates an array of these QR items. Now, the challenge lies in passing this array to another component that is a sibling and not located wit ...