Create a rectangle on a canvas using coordinates that have been translated relative to the original image

Displayed on the screen is an image element that undergoes a css transform: rotate(degree), with degree ranging from 0 to 360. This transformation makes the image appear rotated, even though its original orientation remains unchanged.

Given this scenario, users can choose an area on the ROTATED image, and the resulting output will detail the selected crop region in relation to the transformed image, not the initial one.

The output will include:

  • nativeImageWidth
  • nativeImageHeight
  • positionX
  • positionY
  • width
  • height
  • angle (defaulted to 0 if no previous rotation existed before cropping)

To proceed, a rectangle highlight must be drawn over the user-selected region and then update the displayed image with the modified src data showcasing the highlighted area.

A translation formula is required to convert the cropped area's coordinates into dimensions compatible with the original un-rotated image. These translated values can subsequently be utilized for fillRect operations followed by resetting the img using context.toDataURL

An illustrative example can be viewed at this link: Picture explanation

I have conducted research but couldn't find a solution that matches my specific requirements. The approaches I came across commonly involved using context.rotate() and context.translate(), which weren't effective in my case either.

In essence, I am seeking a solution akin to the following:

function getTranslatedRect(x, y, w, h, angle, nativeImageWidth, nativeImageHeight) {
  let newX = x;
  let newY = y;
  let newWidth = w;
  let newHeight = h;
  let newCanvasWidth = nativeImageWidth;
  let newCanvasHeight = nativeImageHeight;
  
  // perform necessary math calculations beyond my expertise...
  
  newX = 35;
  newY = 320;
  newWidth = 65;
  newHeight = 120;
  
  return {
    newX, newY, newWidth, newHeight, newCanvasWidth, newCanvasHeight
  };
}

let img = document.getElementById('translatedImage');

let translatedRect = getTranslatedRect(60, 35, 120, 65, 90, 350, 500);

let canvas = document.createElement('canvas');
canvas.width = translatedRect.newCanvasWidth;
canvas.height = translatedRect.newCanvasHeight;

let ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'rgba(255, 165, 0, 1)';
ctx.fillRect(translatedRect.newX, translatedRect.newY, translatedRect.newWidth, translatedRect.newHeight);

img.src = canvas.toDataURL('image/jpg', 1.0);
.canvas {
  width: 500px;
  height: 500px;
  text-align: center;
}

.rotated {
  transform: rotate(90deg);
}
translated image with "user highlighted area"
<div class="canvas">
  <img id="translatedImage" class="rotated" src="https://i.ibb.co/fNDs6qQ/Untitled.png" crossorigin="anonymous">

</div>
original image
<div class="canvas">
  
  <img id="originalImage" src="https://i.ibb.co/fNDs6qQ/Untitled.png" crossorigin="anonymous">  
</div>

Answer №1

Utilizing the built-in CSS matrix operations for your calculations is highly recommended. To illustrate this, here is a brief code snippet demonstrating the use of CSS transformations through Javascript.

(Please note that the stackoverflow code snippet feature may not display the following code correctly, so it's advised to copy and paste it into an HTML file and view it in a browser for accurate representation.)

Below are some key points about the code:

  • The element "box1" serves as the main box and is simply rotated.
  • The element "box2" is considered a box "attached" to box1. When rotated, it will rotate around its own center. Therefore, prior to rotating "box2", it needs to be repositioned relative to the center of "box1", then rotated around the center of "box1", and finally moved back.

Regarding your specific inquiry, if you possess the coordinates of the smaller box linked to the larger box and are aware of the transformation applied to the larger box (such as xy movement, rotation, etc.), you can internally create a DOM object representing the smaller box, reverse the known rotations of the larger box, and determine the relationship between the smaller box and the larger box in terms of coordinates...

<html><head>

</head><body>

<div id="box1" style="position:absolute; left:50; width:65; top:100; height:120; background: black"></div>
<div id="box2" style="position:absolute; left:55; width:30; top:110; height:60; background: red"></div>

<input id="rotateInput" value="45"></input>
<button onclick="rotate( parseFloat( document.getElementById('rotateInput').value ) )">Rotate</button>

<script>

var currentAngle = 0;

function rotate( rotDeg ) {

  currentAngle += rotDeg;
  
  // Rotating the large box is straightforward...
  let dom1 = document.getElementById( 'box1' );
  dom1.style.transform = `rotateZ( ${currentAngle}deg )`;

  // Rotating the smaller box requires more steps...
  let dom2 = document.getElementById( 'box2' );
  
  console.log( `box2 before rotate: ( L:${box2.offsetLeft}, T:${box2.offsetTop}, W:${box2.offsetWidth}, H:${box2.offsetHeight} )` );
  console.log( box2.getBoundingClientRect() );
  
  dx = ( box2.offsetLeft + box2.offsetWidth / 2 ) - ( box1.offsetLeft + box1.offsetWidth / 2);
  dy = ( box2.offsetTop + box2.offsetHeight / 2 ) - ( box1.offsetTop + box1.offsetHeight / 2);
  
  dom2.style.transform = `
    translateX( ${-dx}px )
    translateY( ${-dy}px )
    rotateZ( ${currentAngle}deg )
    translateY( ${+dy}px )       
    translateX( ${+dx}px )
  `;
  
  console.log( `box2 after rotate: ( L:${box2.offsetLeft}, T:${box2.offsetTop}, W:${box2.offsetWidth}, H:${box2.offsetHeight} )` );
  console.log( box2.getBoundingClientRect() );
  
}

</script>

</body></html>

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

An investigation into the texturing and highlighting problem in Three.js

I am currently working on a project involving a cube with multiple textures, one for each face. Initially, I was able to change the color of the cube when hovering over it using a single texture. However, I now want to implement this functionality with a t ...

Utilizing JSON for Google Charts

Although I have no prior experience with Google Charts, I am currently attempting to graph temperature data collected from sensors placed around my house. Unfortunately, I keep encountering an Exception error. I suspect the issue lies in the JSON format no ...

error: local server did not return any data

I am currently using PHP on a Linux machine. In my HTML code, I have set up an AJAX request to the local Apache server (check http://localhost), with the intention of displaying the data from the server on the screen. However, for some reason, nothing is b ...

Is there a way for me to display the comment count as text directly on the comment bubble image?

In this example on jsfiddle, I am attempting to display the number of comments (12 in this case) as text over the comment bubble image: http://jsfiddle.net/c337Z/ HTML: <ul id="top"> <li><a href="/comments"><div id="commentlink" ...

There seems to be an error with JVectorMap: the <g> attribute transform is expecting a number but is instead receiving "scale(NaN) translate(N..."

Hey there! I'm currently working on creating a form with a map to select the country of birth using JVectorMap. However, when checking the Google Chrome developer console, I encountered the following error message: jquery-jvectormap-2.0.5.min.js:1 Err ...

Conceal certain components when a user is authenticated

Below is the content of my app.component.html: <nav class="navbar navbar-expand-lg navbar-light bg-light"> <div class='container'> <ul class="nav navbar-nav"> <li class='nav-item'> <a clas ...

Customize your smartphone wallpaper with React Native

As a newcomer to React, I've successfully uploaded an image from my local phone gallery and stored its URI in a global variable. However, I'm struggling to figure out how to set this image as my phone's background image (not within React its ...

Successfully passing props to the image source using React/Next.js

Currently, in my implementation with React and Next.js, I am utilizing next-images for importing images. I am looking for a solution to pass data directly to the img src attribute, like so: <img src={require(`../src/image/${data}`)} /> It appears t ...

Browsing through a jQuery JSON object in Chrome reveals a dynamic reshuffling of its order

Jquery + rails 4 Within the json_data instance, there is data with key-value pairs. The key is an integer ID and the value is an object containing data. However, when attempting to iterate over this data using the jQuery $.each function, the results are s ...

The size of Bootstrap 3 columns adjusts dynamically based on the width of the window as the page is being

I am facing an issue with the layout of my bootstrap site when resizing the 3 horizontal columns based on the window size upon page load. Currently, I have a script that adjusts the height of each column to match the tallest one so they appear uniform whe ...

Add a static line of names to a JavaScript file

Looking for a way to generate data with the following javascript snippet: for (var l = 0; l < table.length; l +=1) { fs.appendFile('results/Test'+ username +'.csv', var1+i, var2 , function(err) { if(err) { return c ...

I'm having issues with my Express.js API not being able to access the specified

My Express js server is not reading the res.body.signatureRequestId property. How can I submit this property to prevent the type error? I have shared my error log, JSON response, and Express js code below. Error log: { account: { account_id: ' ...

PHP script is not successfully receiving the Ajax post request that is

As a newcomer to the world of php and ajax, I am facing a challenge in passing a variable from jquery to a php page loaded within a modal window. My php script fetches table information for multiple users. Next to each user's name, there is an edit b ...

What is the process for uploading files using AngularFire on Firebase Storage?

Despite watching multiple videos and tutorials, I am encountering a 403 error while working with Angular 1. To solve the issue of ng-model not supporting files, I created an Angular directive named file-model: app.directive('fileModel',['$ ...

Utilizing JQuery to recycle data post-load

I've got this function: // AJAX MESSAGES DISPLAYING show_msg.on('click', function(e){ var $this = $(this), url = $this.attr('href'), url_info = url + ' .basic_info > *', url_msg = url + ' .cont ...

Certain components cannot be concealed from particular routes

Having an issue with my app where I want to have a different layout for the Login and Register routes compared to the rest of the routes. I've tried implementing conditional logic in the App component to hide certain components based on the route usin ...

How can we determine in JavaScript whether a certain parameter constitutes a square number?

I've developed a function that can determine whether a given parameter is a square number or not. For more information on square numbers, check out this link: https://en.wikipedia.org/?title=Square_number If the input is a square number, it will ret ...

Is there a CSS3 Selector With Similar Functionality to jQuery's .click()?

For a few years now, I have been utilizing a pure CSS navigation system. However, with the recent increase in mobile site projects at my workplace, I am encountering issues with drop-down menus not functioning properly on mobile devices. Despite this chall ...

"Using a WMD Editor to show the content of the wmd-preview division and questions on how to save this content in a

I am currently in the process of integrating the WMD editor into my website. Everything seems to be functioning correctly so far, but I have hit a roadblock: How can I store the entered information in my database? I have developed a JS/Ajax function that a ...

Struggling to interpret the array of objects retrieved from a call to UrlFetchApp.fetch in Google App Script

When UrlFetchApp.fetch is called, it provides an array of objects that are stored in the variable 'results': var results = [{"Category 1": "Benefits/Compensatio", "Category 2": "Compensation", "Category 3": "Recognizing You", "Processing Team": ...