如何在固定 canvas 中绘制缩放图像并在其中心旋转?

How can I draw a scaled image in a fixed canvas and rotate it in its center?

我有一个固定宽度和高度的 canvas,我想在 canvas 上绘制一个 scaled/fitted 图像并在其中心旋转图像。当我在 angle 中放置 0 以外的任何值时,图像不居中并且偏离 canvas.

这是我现在拥有的:

const box = document.getElementById("box");
const box2 = document.getElementById("box2");

(function() {
  const image = new Image();
  image.onload = () => {
    const myCanvas = drawImage(0, image);
    const img = document.createElement("img");
    img.src = myCanvas.toDataURL("image/png", 1);
    img.style = "border: 1px solid black;";
    box.append(img)
    
    const myCanvas2 = drawImage(15, image);
    const img2 = document.createElement("img");
    img2.src = myCanvas2.toDataURL("image/png", 1);
    img2.style = "border: 1px solid black;";
    box2.append(img2)
    
  };
  image.src = "https://raw.githubusercontent.com/hamza-ameer/Google-Maps-SmoothCarAnimation/Uodated/car_marker.png";
  image.crossOrigin="anonymous"
})()

function drawImage(angle, image) {
  const canvasWidth = 100;
  const canvasHeight = 100;
  
  const myCanvas = document.createElement("canvas");
  myCanvas.width = canvasWidth;
  myCanvas.height = canvasHeight;


  const context = myCanvas.getContext("2d");

  const imageWidth = image.width;
  const imageHeight = image.height;

  const scaler = scalePreserveAspectRatio(imageWidth, imageHeight, canvasWidth, canvasHeight);

  const scaledWidth = imageWidth * scaler;
  const scaledHeight = imageHeight * scaler;

  context.save();
  context.clearRect(0, 0, canvasWidth, canvasHeight);
  context.rotate((angle * Math.PI) / 180);
  context.translate((canvasWidth - scaledWidth) / 2, (canvasHeight - scaledHeight) / 2);
  context.drawImage(image, 0, 0, imageWidth, imageHeight, 0, 0, scaledWidth, scaledHeight);
  context.strokeRect(0, 0, imageWidth * scaler, imageHeight * scaler);

  context.restore();
  
  return myCanvas;
}

function scalePreserveAspectRatio(imgW, imgH, maxW, maxH) {
  return Math.min(maxW / imgW, maxH / imgH);
}
<div id="box"></div>
<div id="box2"></div>

感谢您的帮助。

你只需要在使用context.rotate之前使用context.translate将原点(旋转点)设置为中心,然后再重新设置。

const box = document.getElementById("box");
const box2 = document.getElementById("box2");

(function() {
  const image = new Image();
  image.onload = () => {
    const myCanvas = drawImage(0, image);
    const img = document.createElement("img");
    img.src = myCanvas.toDataURL("image/png", 1);
    img.style = "border: 1px solid black;";
    box.append(img)
    
    const myCanvas2 = drawImage(15, image);
    const img2 = document.createElement("img");
    img2.src = myCanvas2.toDataURL("image/png", 1);
    img2.style = "border: 1px solid black;";
    box2.append(img2)
    
  };
  image.src = "https://raw.githubusercontent.com/hamza-ameer/Google-Maps-SmoothCarAnimation/Uodated/car_marker.png";
  image.crossOrigin="anonymous"
})()

function drawImage(angle, image) {
  const canvasWidth = 100;
  const canvasHeight = 100;
  
  const myCanvas = document.createElement("canvas");
  myCanvas.width = canvasWidth;
  myCanvas.height = canvasHeight;


  const context = myCanvas.getContext("2d");

  const imageWidth = image.width;
  const imageHeight = image.height;

  const scaler = scalePreserveAspectRatio(imageWidth, imageHeight, canvasWidth, canvasHeight);

  const scaledWidth = imageWidth * scaler;
  const scaledHeight = imageHeight * scaler;

  context.save();
  context.clearRect(0, 0, canvasWidth, canvasHeight);
  //set origin at center
  context.translate((canvasWidth - scaledWidth) / 2, (canvasHeight - scaledHeight) / 2);
  context.rotate((angle * Math.PI) / 180);
  //restore origin to left-top corner
  context.translate(-(canvasWidth - scaledWidth) / 2, -(canvasHeight - scaledHeight) / 2);
  context.drawImage(image, 0, 0, imageWidth, imageHeight, 0, 0, scaledWidth, scaledHeight);
  context.strokeRect(0, 0, imageWidth * scaler, imageHeight * scaler);

  context.restore();
  
  return myCanvas;
}

function scalePreserveAspectRatio(imgW, imgH, maxW, maxH) {
  return Math.min(maxW / imgW, maxH / imgH);
}
<div id="box"></div>
<div id="box2"></div>

要将原点设置在对象的中心,您可以在 -objectsWidth/2-objectsHeight/2 处绘制对象。这会将 canvas 的原点 (0,0) 放在对象中心。现在您可以在 canvas 上任意位置翻译对象。请记住,当您翻译时,您正在将 canvas 的 (0,0) 坐标移动到特定位置。

请记住,我故意没有改变笔划的原点,因为我想让你看到不同之处。然而,你会做同样的事情并用 -objectsWidth/2-objectsHeight/2.

绘制它
 context.strokeRect(-scaledWidth/2, -scaledHeight/2, imageWidth * scaler, imageHeight * scaler);

这是放置项目并将原点设置为中心的最简单方法。顺便说一句,您之后不需要翻译回来。这就是使用 save()restore()

的意义所在

const box = document.getElementById("box");
const box2 = document.getElementById("box2");

(function() {
  const image = new Image();
  image.onload = () => {
    const myCanvas = drawImage(0, image);
    const img = document.createElement("img");
    img.src = myCanvas.toDataURL("image/png", 1);
    img.style = "border: 1px solid black;";
    box.append(img)
    
    const myCanvas2 = drawImage(15, image);
    const img2 = document.createElement("img");
    img2.src = myCanvas2.toDataURL("image/png", 1);
    img2.style = "border: 1px solid black;";
    box2.append(img2)
    
  };
  image.src = "https://raw.githubusercontent.com/hamza-ameer/Google-Maps-SmoothCarAnimation/Uodated/car_marker.png";
  image.crossOrigin="anonymous"
})()

function drawImage(angle, image) {
  const canvasWidth = 100;
  const canvasHeight = 100;
  
  const myCanvas = document.createElement("canvas");
  myCanvas.width = canvasWidth;
  myCanvas.height = canvasHeight;


  const context = myCanvas.getContext("2d");

  const imageWidth = image.width;
  const imageHeight = image.height;

  const scaler = scalePreserveAspectRatio(imageWidth, imageHeight, canvasWidth, canvasHeight);

  const scaledWidth = imageWidth * scaler;
  const scaledHeight = imageHeight * scaler;

  context.save();
  context.clearRect(0, 0, canvasWidth, canvasHeight);
  context.translate(canvasWidth/2, canvasHeight/2);
  context.rotate((angle * Math.PI) / 180);
  context.drawImage(image, 0, 0, imageWidth, imageHeight, -scaledWidth/2, -scaledHeight/2, scaledWidth, scaledHeight);
  context.strokeRect(0, 0, imageWidth * scaler, imageHeight * scaler);
  context.restore();
  
  return myCanvas;
}

function scalePreserveAspectRatio(imgW, imgH, maxW, maxH) {
  return Math.min(maxW / imgW, maxH / imgH);
}
<div id="box"></div>
<div id="box2"></div>