![](/img/trans.png)
[英]How to get the 2d dimensions of the object being drawn for hit test on webgl after model view transform
[英]How to get the 2d dimensions of the object being drawn for hit test on canvas 2d after canvas transformations?
我在2d画布上绘制简单的形状,同时对以下形状应用变换:
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 });
});
};
现在,我需要知道画布空间中此矩形的尺寸,以便可以对鼠标单击位置进行测试。
之前我曾问过这个问题, 如何在关于Webgl命中测试检测的模型视图转换之后,如何获取要在Webgl上进行命中测试的绘制对象的二维尺寸 。 但是该解决方案不适用于此处,因为我没有转换矩阵。
一种可能的解决方案是,我在另一个名为“碰撞画布”的画布上绘制同一对象,并使用与该对象相关的特定颜色,稍后当我想对画布上的某个位置进行测试时,我查询该位置上的碰撞画布颜色,然后看看颜色是否与对象特定的颜色匹配,那是个好主意吗?
我看到最好的解决方案是使用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;
}
这真的取决于您的问题是什么。 你写了:
如何获得被绘制对象的二维尺寸
你写了
用于命中测试。
你想要哪一个。 您想要二维尺寸还是想要进行命中测试?
对于尺寸,在变换之前,您需要自己知道形状的大小。 然后您可以使用ctx.currentTransform
获得当前变换
不幸的是,截至2019年8月,Chrome仅支持currentTransform
,因此您需要某种形式的polyfill,但是如果您搜索“ currentTransform polyfill”,则其中有几种。
对于命中测试,可以使用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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.