【问题标题】:typescript/javascript draw rect on canvas given translated coordinates relative to original image给定相对于原始图像的翻译坐标,打字稿/javascript在画布上绘制矩形
【发布时间】:2022-10-23 02:33:59
【问题描述】:

在屏幕上,我有一个具有 css 变换的 img 元素:rotate(degree),其中度数可以是 0、90、180、270,但实际上它可以是任何度数。

意思是,原始图像实际上并没有旋转,只是转换为看起来旋转。

考虑到这一点,用户可以在 TRANSFORMED 图像上选择一个区域,接收到的输出将是相对于 TRANSFORMED 图像的裁剪区域的细节,而不是原始图像。

裁剪区域的输出将包含以下信息:

  • nativeImageWidth
  • nativeImageHeight
  • 位置X
  • 位置Y
  • 宽度
  • 高度
  • 角度(如果在选择裁剪区域之前没有进行旋转,则为 0)

我需要做的是基本上在用户选择的区域绘制一个矩形突出显示,然后使用具有突出显示的选定区域的新 src 数据重新设置原始显示的 img 元素。

我相信最好的方法是将给定的裁剪区域位置/宽度/高度转换为原始未旋转图像所需的值,然后使用这些转换后的尺寸简单地填充该区域,然后重新- 设置使用 context.toDataURL 显示的 img

我只是不确定坐标的翻译公式是什么样的。

一张图来解释我上面所说的: Picture explanation

我确实环顾四周,但似乎找不到与我要求的解决方案完全一样的解决方案。我在其他帖子上发现的大部分内容都涉及使用 context.rotate() 和 context.translate() 但我也无法让它像那样工作

基本上我正在寻找的是这样的:

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;
  
  // do cool math stuff that i am far to un-educated to do (sin? cos? :D)....
  
  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>

【问题讨论】:

    标签: javascript html css image html5-canvas


    【解决方案1】:

    建议您利用内置的 CSS 矩阵运算来执行计算。为此,以下代码 sn-p 是通过 Javascript 使用 CSS 转换的小示例。

    (stackoverflow 代码 sn-p 功能无法正确呈现以下代码,因此您需要将其复制并粘贴为 HTML 文件,然后在浏览器中打开以查看它的运行情况。)

    关于代码的几点说明:

    • “box1”被认为是主框,所以只是简单地旋转。
    • “box2”被认为是一个“附加”到 box1 的盒子,如果只是简单地旋转,它将在它自己的中心旋转。因此,在旋转“box2”之前,必须先相对于“box1”的中心移动,然后围绕“box1”中心旋转,然后再往回移动。

    因此,要回答您的具体问题,如果您将较小框的坐标“附加”到较大框,并且知道较大框的转换(即 xy 移动、旋转等),那么您可以在内部创建一个 DOM表示较小框的对象,应用较大框的已知旋转的反向,然后知道较小框与较大框在坐标方面的关系......

    <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 easy...
      let dom1 = document.getElementById( 'box1' );
      dom1.style.transform = `rotateZ( ${currentAngle}deg )`;
    
      // Rotating the smaller box is a bit more involved...
      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>
    

    【讨论】:

      猜你喜欢
      • 2017-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-11
      • 2021-08-18
      • 1970-01-01
      相关资源
      最近更新 更多