这似乎有效。我想这基本上就是K3N所说的。
function getRelativeMousePosition(event, target) {
target = target || event.target;
var rect = target.getBoundingClientRect();
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top,
}
}
function getStyleSize(style, propName) {
return parseInt(style.getPropertyValue(propName));
}
// assumes target or event.target is canvas
function getCanvasRelativeMousePosition(event, target) {
target = target || event.target;
var pos = getRelativeMousePosition(event, target);
// you can remove this if padding is 0.
// I hope this always returns "px"
var style = window.getComputedStyle(target);
var nonContentWidthLeft = getStyleSize(style, "padding-left") +
getStyleSize(style, "border-left");
var nonContentWidthTop = getStyleSize(style, "padding-top") +
getStyleSize(style, "border-top");
var nonContentWidthRight = getStyleSize(style, "padding-right") +
getStyleSize(style, "border-right");
var nonContentWidthBottom = getStyleSize(style, "padding-bottom") +
getStyleSize(style, "border-bottom");
var rect = target.getBoundingClientRect();
var contentDisplayWidth = rect.width - nonContentWidthLeft - nonContentWidthRight;
var contentDisplayHeight = rect.height - nonContentWidthTop - nonContentWidthBottom;
pos.x = (pos.x - nonContentWidthLeft) * target.width / contentDisplayWidth;
pos.y = (pos.y - nonContentWidthTop ) * target.height / contentDisplayHeight;
return pos;
}
如果您运行下面的示例并将鼠标移到蓝色区域上,它将在光标下绘制。边框(黑色)、填充(红色)、宽度和高度都设置为非像素值。蓝色区域是实际的画布像素。画布的分辨率未设置,因此无论拉伸到多大,它都是 300x150。
将鼠标移到蓝色区域上,它将在其下方绘制一个像素。
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
function clearCanvas() {
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
clearCanvas();
var posNode = document.createTextNode("");
document.querySelector("#position").appendChild(posNode);
function getRelativeMousePosition(event, target) {
target = target || event.target;
var rect = target.getBoundingClientRect();
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top,
}
}
function getStyleSize(style, propName) {
return parseInt(style.getPropertyValue(propName));
}
// assumes target or event.target is canvas
function getCanvasRelativeMousePosition(event, target) {
target = target || event.target;
var pos = getRelativeMousePosition(event, target);
// you can remove this if padding is 0.
// I hope this always returns "px"
var style = window.getComputedStyle(target);
var nonContentWidthLeft = getStyleSize(style, "padding-left") +
getStyleSize(style, "border-left");
var nonContentWidthTop = getStyleSize(style, "padding-top") +
getStyleSize(style, "border-top");
var nonContentWidthRight = getStyleSize(style, "padding-right") +
getStyleSize(style, "border-right");
var nonContentWidthBottom = getStyleSize(style, "padding-bottom") +
getStyleSize(style, "border-bottom");
var rect = target.getBoundingClientRect();
var contentDisplayWidth = rect.width - nonContentWidthLeft - nonContentWidthRight;
var contentDisplayHeight = rect.height - nonContentWidthTop - nonContentWidthBottom;
pos.x = (pos.x - nonContentWidthLeft) * target.width / contentDisplayWidth;
pos.y = (pos.y - nonContentWidthTop ) * target.height / contentDisplayHeight;
return pos;
}
function handleMouseEvent(event) {
var pos = getCanvasRelativeMousePosition(event);
posNode.nodeValue = JSON.stringify(pos, null, 2);
ctx.fillStyle = "white";
ctx.fillRect(pos.x | 0, pos.y | 0, 1, 1);
}
canvas.addEventListener('mousemove', handleMouseEvent);
canvas.addEventListener('click', clearCanvas);
* {
box-sizing: border-box;
cursor: crosshair;
}
html, body {
width: 100%;
height: 100%;
color: white;
}
.outer {
background-color: green;
display: flex;
display: -webkit-flex;
-webkit-justify-content: center;
-webkit-align-content: center;
-webkit-align-items: center;
justify-content: center;
align-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.inner {
border: 1em solid black;
background-color: red;
padding: 1.5em;
width: 90%;
height: 90%;
}
#position {
position: absolute;
left: 1em;
top: 1em;
z-index: 2;
pointer-events: none;
}
<div class="outer">
<canvas class="inner"></canvas>
</div>
<pre id="position"></pre>
那么,最好的建议是?, 除非您想完成所有这些步骤,否则始终将画布的边框和内边距设为 0。如果边界和填充为零你可以canvas.clientWidth
和canvas.clientHeight
为contentDisplayWidth
和contentDisplayHeight
在下面的例子中,所有的nonContextXXX
值变为0。
function getRelativeMousePosition(event, target) {
target = target || event.target;
var rect = target.getBoundingClientRect();
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top,
}
}
// assumes target or event.target is canvas
function getNoPaddingNoBorderCanvasRelativeMousePosition(event, target) {
target = target || event.target;
var pos = getRelativeMousePosition(event, target);
pos.x = pos.x * target.width / canvas.clientWidth;
pos.y = pos.y * target.height / canvas.clientHeight;
return pos;
}
var canvas = document.querySelector("canvas");
var ctx = canvas.getContext("2d");
function clearCanvas() {
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
clearCanvas();
var posNode = document.createTextNode("");
document.querySelector("#position").appendChild(posNode);
function getRelativeMousePosition(event, target) {
target = target || event.target;
var rect = target.getBoundingClientRect();
return {
x: event.clientX - rect.left,
y: event.clientY - rect.top,
}
}
// assumes target or event.target is canvas
function getNoPaddingNoBorderCanvasRelativeMousePosition(event, target) {
target = target || event.target;
var pos = getRelativeMousePosition(event, target);
pos.x = pos.x * target.width / canvas.clientWidth;
pos.y = pos.y * target.height / canvas.clientHeight;
return pos;
}
function handleMouseEvent(event) {
var pos = getNoPaddingNoBorderCanvasRelativeMousePosition(event);
posNode.nodeValue = JSON.stringify(pos, null, 2);
ctx.fillStyle = "white";
ctx.fillRect(pos.x | 0, pos.y | 0, 1, 1);
}
canvas.addEventListener('mousemove', handleMouseEvent);
canvas.addEventListener('click', clearCanvas);
* {
box-sizing: border-box;
cursor: crosshair;
}
html, body {
width: 100%;
height: 100%;
color: white;
}
.outer {
background-color: green;
display: flex;
display: -webkit-flex;
-webkit-justify-content: center;
-webkit-align-content: center;
-webkit-align-items: center;
justify-content: center;
align-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.inner {
background-color: red;
width: 90%;
height: 80%;
display: block;
}
#position {
position: absolute;
left: 1em;
top: 1em;
z-index: 2;
pointer-events: none;
}
<div class="outer">
<canvas class="inner"></canvas>
</div>
<pre id="position"></pre>