【问题标题】:How to get pixel range in scaled canvas?如何在缩放的画布中获取像素范围?
【发布时间】:2020-01-19 16:03:32
【问题描述】:

在下面的代码中,我在中心画了一个圆,但是因为它是缩放的,所以圆在右下角!

var canvas = document.getElementById('mycanvas');
context = canvas.getContext("2d");
context.canvas.width = 400;
context.canvas.height = 200;

context.clearRect(0, 0, context.canvas.width, context.canvas.height); // Clears the canvas

var scale = 2;
context.scale(scale, scale);
context.beginPath();
context.fillStyle = "#ff2626"; // Red color
context.arc(context.canvas.width / 2, context.canvas.height / 2, 10, 0, Math.PI * 2); //center
context.fill();
context.closePath();
canvas {
	border: solid 1px #ccc;
}
<HTML>
<body>

<canvas id="mycanvas"></canvas>

</body>
</HTML>

您可能知道,画布的宽度和高度与其中的内容无关,尤其是在缩放时。换句话说,当您使用context.scale(scale_x, scale_y); 缩放画布时,它将缩放画布内的所有形状。我想知道,有什么办法可以得到画布像素范围?

当画布被缩放时,我想知道左右边缘的 X 和上下边缘的 Y。

【问题讨论】:

  • 既然您按 2 缩放,您是否尝试过考虑比例来居中?像 (width*scale)/2 一样获得缩放中心?试试让我知道!
  • @MadeInDreams 我真的知道如何使用 scale 属性集中它,但问题是我发现 X 和 Y 在缩放的画布中会发生变化。说来话长,但我真的需要画布的角落,而不是中心。

标签: javascript html canvas


【解决方案1】:

将坐标除以scale 应该可以解决问题:

var canvas = document.getElementById('mycanvas');
context = canvas.getContext("2d");
context.canvas.width = 400;
context.canvas.height = 200;

context.clearRect(0, 0, context.canvas.width, context.canvas.height); // Clears the canvas

var scale = 2;
context.scale(scale, scale);
context.beginPath();
context.fillStyle = "#ff2626"; // Red color
context.arc(context.canvas.width /2/scale, context.canvas.height / 2/scale, 10, 0, Math.PI * 2); //center
context.fill();
context.closePath();
canvas {
	border: solid 1px #ccc;
}
<HTML>
<body>

<canvas id="mycanvas"></canvas>

</body>
</HTML>

顺便说一句,context.canvas.width /(2*scale)context.canvas.width /2/scale 更干净,但我保留它只是为了显示scale 的划分。

【讨论】:

  • 那你的意思是左上角现在是0和0?
  • 左上角始终为 (0,0),与比例无关(除非您执行了sonme translate 操作)。
  • 一般来说,现在所有坐标都应该除以比例
  • 那么,也许最好问一下,如果我将画布转换为中心,然后对其进行缩放,边缘像素是多少?
  • 那么我需要给你看一些东西,因为我发现角落的比例并没有完全按照他们应该的方式进行
【解决方案2】:

你不需要这个像素范围。

您必须了解画布转换的工作原理并接受它,而不是尝试自己计算。

如果我们把画布当作一个真正的画布,或者是一张纸,那么我们可以说变换矩阵控制了这张纸相对于固定相机的位置。

关键是,你提供给画布的坐标绘图方法仍然是未转换的纸上的坐标,无论你如何旋转、平移或缩放它。

此外,最初,我们确实握住这张纸的左上角,这被称为 transformation-origin;旋转和缩放等所有变换都将从这一点完成,这就是为什么当您缩放 2 时,中心坐标现在位于相机所见的右下角。

所以如果你想缩放到画布的中心,你需要首先移动 transformation-origin 使其位于我们相机的中心,然后你可以缩放你的画布,最后您只需再次返回画布大小的一半,以便您的绘图位于中心。这可以通过两个调用很容易地实现:一个是绝对的setTransform,它能够应用缩放和初始平移来设置我们的变换原点,另一个是translate,它是相对于当前的变换矩阵:

const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );

const scale = 2;
const cx = canvas.width / 2;
const cy = canvas.height / 2;

// before transformation in red
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc( cx, cy, 30, 0, Math.PI * 2);
ctx.fill();

// with transformation in semi-opaque green
ctx.globalAlpha = 0.5;
ctx.fillStyle = 'green';
// scale with origin set to the center of canvas
ctx.setTransform(scale, 0, 0, scale, cx, cy);
// move back origin to the new top left corner of the visible area
ctx.translate( -cx, -cy );

/* the two previous lines are effectively the same as
  ctx.translate( cx, cy );
  ctx.scale( scale, scale );
  ctx.translate( -cx, -cy );
and as 
  ctx.setTransform(
    scale, 0, 0,
    scale, cx - (cx * scale) , cy - (cy * scale)
  );
*/

ctx.beginPath();
ctx.arc( cx, cy, 30, 0, Math.PI * 2);
ctx.fill();
canvas { border: 1px solid }
&lt;canvas id="canvas"&gt;&lt;/canvas&gt;

正如您在这个小示例中已经看到的那样,您不仅限于每帧单个变换矩阵,您可以通过分层几个不同的变换来很好地组合图像:

const canvas = document.getElementById( 'canvas' );
const ctx = canvas.getContext( '2d' );
const { width, height } = canvas;
const cx = width / 2;
const cy = height / 2;

const transform = {
  angle: 0,
  scale: 1,
  x: 0,
  y: 0
};

const img = new Image();
img.onload = anim;
img.src = "https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png";

function anim() {
  updateTransform();
  draw();
  requestAnimationFrame( anim );
}
function updateTransform() {
  transform.x += Math.cos( transform.angle );
  transform.y += Math.sin( transform.angle );
  transform.scale = (Math.sin( transform.angle ) / 3) + 1;
  transform.angle += Math.PI / 180;
}

function draw() {
  // reset the transformation matrix
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect( 0, 0, width, height );
  
  drawImage();
  
  drawCircleOnImage();
  
  drawCentralSquare();
  
  drawCameraCross();
}

// the image is moved by our 'tranform' object
function drawImage() {
  ctx.setTransform( transform.scale, 0, 0, transform.scale, transform.x, transform.y );
  ctx.drawImage( img, 0, 0 );
}

// A circle which will be moved with the image
function drawCircleOnImage() {
  ctx.setTransform( transform.scale, 0, 0, transform.scale, transform.x, transform.y );
  ctx.beginPath();
  ctx.arc( cx, cy, 50, 0, Math.PI * 2 );
  ctx.stroke()
}


// a square, always at the center of view,
// but which scale follows our transform object
function drawCentralSquare() {
  ctx.setTransform( transform.scale, 0, 0, transform.scale, cx, cy );
  ctx.translate( -cx, -cy );
  ctx.strokeRect( cx - 50, cy - 50, 100, 100 );
}

// a cross, always at the center of the view, and untransformed
function drawCameraCross() {
  ctx.setTransform( 1, 0, 0, 1, 0, 0 );
  ctx.beginPath();
  ctx.moveTo( cx - 10, cy );
  ctx.lineTo( cx + 10, cy );
  ctx.moveTo( cx, cy - 10 );
  ctx.lineTo( cx, cy + 10 );
  ctx.stroke();
}
canvas { border: 1px solid }
&lt;canvas id="canvas" width="800" height="600"&gt;&lt;/canvas&gt;

而这与我们无关。

【讨论】:

  • 感谢您的解决方案,但有什么方法可以获取范围吗?
【解决方案3】:

你必须考虑你的比例,所以 ex (width/2)/scale

var canvas = document.getElementById('mycanvas');
context = canvas.getContext("2d");
context.canvas.width = 400;
context.canvas.height = 200;

context.clearRect(context.canvas.width, context.canvas.height, context.canvas.width, context.canvas.height); // Clears the canvas

var scale = 2;
context.scale(scale, scale);
context.beginPath();
context.fillStyle = "#ff2626"; // Red color
context.arc((context.canvas.width/2)/scale , (context.canvas.height/2)/scale, 10, 0, Math.PI * 2); //center
context.fill();
context.closePath();
canvas {
	border: solid 1px #ccc;
}
<HTML>
<body>

<canvas id="mycanvas"></canvas>

</body>
</HTML>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-08
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多