2 回答

TA贡献1831条经验 获得超10个赞
igh ...尚不是肯定的答案,但显然event.offsetX,event.offsetY即使根据MDN,它们仍不是标准值。
测试它似乎可以在Chrome和Firefox中使用。Safari在某些测试中处于关闭状态。同样不幸的是,在触摸事件上不存在offsetX和offsetY。它们确实存在于指针事件上,但自2019/05起Safari不支持指针事件
[...document.querySelectorAll('canvas')].forEach((canvas) => {
const ctx = canvas.getContext('2d');
let count = 0;
canvas.addEventListener('mousemove', (e) => {
const pos = {
x: e.offsetX * ctx.canvas.width / ctx.canvas.clientWidth,
y: e.offsetY * ctx.canvas.height / ctx.canvas.clientHeight,
};
ctx.fillStyle = hsl((count++ % 10) / 10, 1, 0.5);
ctx.fillRect(pos.x - 1, pos.y - 1, 3, 3);
});
});
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
canvas {
display: block;
background: yellow;
transform: scale(0.75);
}
#c1 {
margin: 20px;
background: red;
transform: translateX(-50px);
display: inline-block;
}
#c2 {
margin: 20px;
background: green;
transform: rotate(45deg);
display: inline-block;
}
#c3 {
margin: 20px;
background: blue;
display: inline-block;
}
#c4 {
position: absolute;
top: 0;
background: cyan;
transform: translateX(-250px) rotate(55deg);
display: inline-block;
}
#c5 {
background: magenta;
transform: translate(50px);
display: inline-block;
}
#c6 {
background: pink;
transform: rotate(45deg) rotateX(45deg); /* changed */
display: inline-block;
}
<p>
foo
</p>
<div id="c1">
<div id="c2">
<div id="c3">
<canvas></canvas>
</div>
</div>
</div>
<div id="c4">
<div id="c5">
<div id="c6">
<canvas></canvas>
</div>
</div>
</div>
不幸的是,我们仍然有一个问题,有时我们想要事件外部的画布相对位置。在下面的示例中,即使指针不移动,我们也希望将其保持在鼠标指针下方。
[...document.querySelectorAll('canvas')].forEach((canvas) => {
const ctx = canvas.getContext('2d');
ctx.canvas.width = ctx.canvas.clientWidth;
ctx.canvas.height = ctx.canvas.clientHeight;
let count = 0;
function draw(e, radius = 1) {
const pos = {
x: e.offsetX * ctx.canvas.width / ctx.canvas.clientWidth,
y: e.offsetY * ctx.canvas.height / ctx.canvas.clientHeight,
};
document.querySelector('#debug').textContent = count;
ctx.beginPath();
ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
ctx.fillStyle = hsl((count++ % 100) / 100, 1, 0.5);
ctx.fill();
}
function preventDefault(e) {
e.preventDefault();
}
if (window.PointerEvent) {
canvas.addEventListener('pointermove', (e) => {
draw(e, Math.max(Math.max(e.width, e.height) / 2, 1));
});
canvas.addEventListener('touchstart', preventDefault, {passive: false});
canvas.addEventListener('touchmove', preventDefault, {passive: false});
} else {
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mousedown', preventDefault);
}
});
function hsl(h, s, l) {
return `hsl(${h * 360 | 0},${s * 100 | 0}%,${l * 100 | 0}%)`;
}
.scene {
width: 200px;
height: 200px;
perspective: 600px;
}
.cube {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
animation-duration: 16s;
animation-name: rotate;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
@keyframes rotate {
from { transform: translateZ(-100px) rotateX( 0deg) rotateY( 0deg); }
to { transform: translateZ(-100px) rotateX(360deg) rotateY(720deg); }
}
.cube__face {
position: absolute;
width: 200px;
height: 200px;
display: block;
}
.cube__face--front { background: rgba(255, 0, 0, 0.2); transform: rotateY( 0deg) translateZ(100px); }
.cube__face--right { background: rgba(0, 255, 0, 0.2); transform: rotateY( 90deg) translateZ(100px); }
.cube__face--back { background: rgba(0, 0, 255, 0.2); transform: rotateY(180deg) translateZ(100px); }
.cube__face--left { background: rgba(255, 255, 0, 0.2); transform: rotateY(-90deg) translateZ(100px); }
.cube__face--top { background: rgba(0, 255, 255, 0.2); transform: rotateX( 90deg) translateZ(100px); }
.cube__face--bottom { background: rgba(255, 0, 255, 0.2); transform: rotateX(-90deg) translateZ(100px); }
<div class="scene">
<div class="cube">
<canvas class="cube__face cube__face--front"></canvas>
<canvas class="cube__face cube__face--back"></canvas>
<canvas class="cube__face cube__face--right"></canvas>
<canvas class="cube__face cube__face--left"></canvas>
<canvas class="cube__face cube__face--top"></canvas>
<canvas class="cube__face cube__face--bottom"></canvas>
</div>
</div>
<pre id="debug"></pre>
添加回答
举报