gpt4 book ai didi

javascript - Canvas 变换后,如何获取正在绘制的对象的 2d 尺寸,以便在 Canvas 2d 上进行 HitTest ?

转载 作者:太空宇宙 更新时间:2023-11-04 01:25:27 27 4
gpt4 key购买 nike

我在 2d Canvas 上绘制简单的形状,同时对形状应用变换,如下所示:

  const rect = ({ x, y, width, height }) => {
ctx.fillStyle = 'black';
ctx.fillRect(x, y, width, height);
};

const transform = ({ translate, rotate, scale }, f) => {
// ctx is a 2d canvas context
ctx.save();

if (translate) {
ctx.translate(translate[0], translate[1]);
}
if (rotate) {
ctx.rotate(rotate);
}

if (scale) {
ctx.scale(scale[0], scale[1]);
}

f(ctx);

ctx.restore();
};
const draw = () => {
transform({ translate: [10, 10] }, () => {
rect({ x: 0, y: 0, width: 10, height: 10 });
});
};

现在我需要知道 Canvas 空间中该矩形的尺寸,以便我可以针对鼠标单击位置进行测试。

之前我问过这个问题How to get the 2d dimensions of the object being drawn for hit test on webgl after model view transform关于 webgl HitTest 检测。但该解决方案不适用于此处,因为我没有变换矩阵。

一种可能的解决方案是,我在称为碰撞 Canvas 的不同 Canvas 上绘制相同的对象,并使用与对象相关的特定颜色,稍后当我想对 Canvas 上的某个位置进行测试时,我查询该位置上的碰撞 Canvas 颜色并查看颜色是否与对象特定颜色匹配,这是一个好主意吗?

我认为最好的解决方案是使用 ctx.currentTransform方法。根据物体的尺寸已知,可以通过以下函数找到变换后的尺寸:

function applyTransform(bounds, currentTransform) {
bounds.x = ct.e + bounds.x * ct.a;
bounds.y = ct.f + bounds.y * ct.d;
bounds.width = bounds.width * ct.a;
bounds.height = bounds.height * ct.d;
}

最佳答案

这实际上取决于您的问题是什么。您写道:

How to get the 2d dimensions of the object being drawn

你写了

for hit testing.

你想要哪个。您想要二维尺寸还是想要 HitTest ?

对于尺寸,您需要在转换之前自行了解形状的大小。然后你可以通过ctx.currentTransform获得当前的变换

不幸的是,截至 2019 年 8 月,currentTransform 仅在 Chrome 上受支持,因此您需要某种填充,但如果您搜索 "currentTransform polyfill"那里有几个。

对于 HitTest ,您可以使用 ctx.isPointInPath

您定义一条路径。它不必与您正在绘制的东西相同,但如果是的话当然它是有意义的。然后你就可以调用

ctx.isPointInPath(pathToCheck, canvasRelativeX, canvasRelativeY);

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

const path = new Path2D();
const points = [
[10, 0],
[20, 0],
[20, 10],
[30, 10],
[30, 20],
[20, 20],
[20, 30],
[10, 30],
[10, 20],
[0, 20],
[0, 10],
[10, 10],
];
points.forEach(p => path.lineTo(...p));
path.closePath();

let mouseX;
let mouseY;

function render(time) {
const t = time / 1000;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.translate(
150 + Math.sin(t * 0.1) * 100,
75 + Math.cos(t * 0.2) * 50);
ctx.rotate(t * 0.3);
ctx.scale(
2 + Math.sin(t * 0.4) * 0.5,
2 + Math.cos(t * 0.5) * 0.5);

const inpath = ctx.isPointInPath(path, mouseX, mouseY);
ctx.fillStyle = inpath ? 'red' : 'blue';

ctx.fill(path);
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform

requestAnimationFrame(render);
}
requestAnimationFrame(render);

ctx.canvas.addEventListener('mousemove', (e) => {
mouseX = e.offsetX * ctx.canvas.width / ctx.canvas.clientWidth;
mouseY = e.offsetY * ctx.canvas.height / ctx.canvas.clientHeight;
});
canvas { border: 1px solid black; }
<canvas></canvas>

关于javascript - Canvas 变换后,如何获取正在绘制的对象的 2d 尺寸,以便在 Canvas 2d 上进行 HitTest ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57707311/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com