javascript - 有没有办法在 JavaScript 中获得画布的自然偏移量?
问题描述
我正在尝试像这样获得鼠标 x 和 y 位置:
canvas.addEventListener('mousemove', (e) => {
mouse.x = e.clientX - canvas.offsetLeft;
mouse.y = e.clientY - canvas.offsetTop;
});
但是由于我使用的样式表居中并调整画布大小,因此位置非常不准确,甚至不一致!
解决方案
我创建了一个较小的演示(如果我理解正确的话) ,当您移动和/或缩放周围时bounds
,如何canvas
获取 以及它如何变化。canvas
我希望它能帮助你得到你想要的。
笔记:
为了使此演示按预期工作,请单击右侧的“整页”按钮,此时您将运行代码片段。
// get the canvas and store its original dimensions
var canvas = document.querySelector('.canvas');
var originalWidth = canvas.width; // px
var originalHeight = canvas.height; // px
// draw something on the canvas
var context = canvas.getContext('2d');
var blockSize = originalWidth / 5; // px
context.fillStyle = '#6495ED'; // nice cornflowerblue
for (var i = 0; i < originalWidth; i += blockSize) {
for (var j = 0; j < originalHeight; j += blockSize) {
context.fillRect(i, j, blockSize / 2, blockSize / 2);
}
}
// get the bounds of the canvas element
function getBounds() {
return canvas.getBoundingClientRect();
}
// get the offset of the canvas relative to the document
function getOffset() {
var bounds = getBounds();
return {
x: bounds.left + window.scrollX,
y: bounds.top + window.scrollY,
};
}
// init the buttons for demonstration purposes
var resizeButton = document.querySelector('.resize');
var isResized = false;
resizeButton.addEventListener('click', function() {
var newWidth = 50; // px
var newHeight = 50; // px
if (!isResized) {
canvas.setAttribute('style', 'width: ' + newWidth + 'px; height: ' + newHeight + 'px');
} else {
canvas.removeAttribute('style');
}
updateDataList();
isResized = !isResized;
});
var toggleButton = document.querySelector('.toggle');
var container = document.querySelector('.container');
var alignment = 'center'; // centered by default
// align the container element between left, center, and right
function alignContainer() {
var label = '';
switch (alignment) {
// align to center
case 'center':
container.setAttribute('class', 'container');
label = 'Centered';
// next alingment;
alignment = 'right';
break;
// align to right
case 'right':
container.setAttribute('class', 'container to-right');
label = 'Right Aligned';
// next alingment;
alignment = 'bottom';
break;
// align to bottom
case 'bottom':
container.setAttribute('class', 'container to-bottom');
label = 'Bottom Aligned';
// next alingment;
alignment = 'left';
break;
// align to left
case 'left':
container.setAttribute('class', 'container to-left');
label = 'Left Aligned';
// next alingment;
alignment = 'top';
break;
// align to top
case 'top':
container.setAttribute('class', 'container to-top');
label = 'Top Aligned';
// next alingment;
alignment = 'center';
break;
}
toggleButton.innerHTML = label;
updateDataList();
}
toggleButton.addEventListener('click', function() {
alignContainer();
});
// update the data list according to the given data
var list = document.querySelector('.data');
function updateDataList(data) {
var bounds = getBounds();
var offset = getOffset();
var currentWidth = bounds.width;
var currentHeight = bounds.height;
var scaleX = currentWidth / originalWidth;
var scaleY = currentHeight / originalHeight;
var value;
var mouse;
var mouseScaledX;
var mouseScaledY;
// update original dimensions
value = 'width: ' + originalWidth + 'px, height: ' + originalHeight + 'px';
list.querySelector('.original .value').innerHTML = value;
// update scale
value = 'x: ' + scaleX + ', y: ' + scaleY;
list.querySelector('.scale .value').innerHTML = value;
// update bounds
value = 'x: ' + bounds.x + 'px, y: ' + bounds.y + 'px, ' +
'width: ' + bounds.width + 'px, height: ' + bounds.height + 'px';
list.querySelector('.bounds .value').innerHTML = value;
// update mouse
if (data && data.mouse) {
mouse = data.mouse;
mouseScaledX = mouse.unscaled.x * (1 / scaleX);
mouseScaledY = mouse.unscaled.y * (1 / scaleY);
value = 'unscaledX: ' + mouse.unscaled.x + 'px, unscaledY: ' + mouse.unscaled.y + 'px, ' +
'scaledX: ' + mouseScaledX + 'px, scaledY: ' + mouseScaledY + 'px';
list.querySelector('.mouse .value').innerHTML = value;
}
}
// initially align container
alignContainer();
// update data according to the event
canvas.addEventListener('mousemove', (e) => {
var mouseX = e.clientX - canvas.offsetLeft;
var mouseY = e.clientY - canvas.offsetTop;
updateDataList({
mouse: {
unscaled: {
x: mouseX,
y: mouseY
}
}
});
});
.container {
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #eee;
}
.container.to-top {
justify-content: flex-start;
}
.container.to-bottom {
justify-content: flex-end;
}
.container.to-left {
align-items: flex-start;
}
.container.to-right {
align-items: flex-end;
}
.wrapper {
display: flex;
justify-content: center;
align-items: center;
}
.canvas {
background: white;
}
.button {
margin-left: 30px;
padding: 8px 14px;
line-height: 1.5;
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
}
.data {
list-style-type: none;
display: block;
margin-top: 25px;
}
.data li + li {
margin-top: 5px;
}
.data .title {
color: #777;
font-size: 13px;
font-weight: bold;
text-transform: uppercase;
}
.data .value {
font-size: 12px;
font-weight: bold;
}
<div class="container">
<div class="wrapper">
<canvas class="canvas" width="100" height="100"></canvas>
<button class="button resize">resize<br>canvas</button>
<button class="button toggle">toggle<br>alignment</button>
</div>
<ul class="data">
<li class="original">
<span class="title">Original:</span>
<span class="value">width: 0, height: 0</span>
</li>
<li class="scale">
<span class="title">Scale:</span>
<span class="value">x: 0, y: 0</span>
</li>
<li class="bounds">
<span class="title">Bounds:</span>
<span class="value">[...]</span>
</li>
<li class="mouse">
<span class="title">Mouse:</span>
<span class="value">[...]</span>
</li>
</ul>
</div>
推荐阅读
- python-3.x - ValueError:与块值的无效广播比较-如何以pythonic方式解决它
- javascript - babel-loader 没有在转译文件中插值
- javascript - 在 ant 表中以展开形式显示动态添加的行
- r - R - 创建具有相同值频率的变量矩阵
- python - Python网页抓取访问值之间
- c - gcc:如何强制在 variadic_function 中存在参数(也可能是已知集合中的类型)
- sql - 如何在 SQL 表中存储长列表?
- reactjs - React 容器道具子传递
- javascript - 幻灯片代码 - 显示第一张幻灯片并延长淡入淡出持续时间?
- drawing - C#:避免显示闪烁