首先,我想指出,从您的代码看来,您正在监听画布上的“鼠标滚轮”事件。如此处所述,“鼠标滚轮”事件是非标准的,并且不会成为标准。因此,在聆听时,您会得到充其量是混合的结果。“滚动”事件几乎在每个平台上都可用,并且可能是捕获用户输入的更好途径。
至于你的问题,你正在寻找你正在寻找的行为的正确轨道,但你错过了一步。
当您调用scale
画布上下文对象时,行为非常简单。从左上角 (0,0) 开始,该方法通过提供的因子缩放画布的点。假设您有一个 10x10 的画布,在 1,1 处有一个黑点。如果画布在两个轴上都按 2 倍缩放,则 0,0 点将保持在同一位置,但点 1,1 将是缩放前点 2,2 所在的位置。
为了实现您正在寻找的“缩放”行为,必须在缩放之后翻译上下文,以便参考点占据与缩放之前相同的物理位置。在您的情况下,参考点是执行缩放操作时用户光标所在的点。
幸运的是,画布上下文对象提供了一种translate(x,y)
方法,可以相对于画布的 0,0 点移动上下文的原点。要将其翻译为正确的数量,您必须:
- 缩放前计算鼠标光标到画布原点的距离
- 将该距离除以比例因子
- 按该值翻译原点
由于您的代码并未指明 HTML 的结构,因此我在下面用一些注释和伪代码对其进行了标记,以展示您如何实现此算法:
//You'll need to get a reference to your canvas in order to calculate the relative position of
//the cursor to its top-left corner, and save it to a variable that is in scope inside of your
//event handler function
var canvas = document.getElementById('id_of_your_canvas');
//We're also going to set up a little helper function for returning an object indicating
//the position of the top left corner of your canvas element (or any other element)
function getElementOrigin(el){
var boundingBox = el.getBoundingClientRect();
return { x: boundingBox.left, y: boundingbox.top};
}
function OnMouseWheel (event) {
//you probably want to prevent scrolling from happening or from bubbling so:
event.preventDefault();
event.stopPropagation();
var delta = event.wheelDelta ? event.wheelDelta/40 : event.detail ? -event.detail : 0;
var canvasCorner = getElementOrigin(canvas)
//JavaScript doesn't offer a 'vector' or 'point' class natively but we don't need them
var mousePosition = {x: event.clientX, y: event.clientY};
var diff = {x: mousePostion.x - canvasCorner.x, y: mousePosition.y - canvasCorner.y};
var scaleFactor = 1.1;
if (delta) {
var factor = Math.pow(scaleFactor,delta);
var transX = (-1/factor) * diff.x;
var transY = (-1/factor) * diff.y;
context.scale(factor,factor);
context.translate(transX, transY);
}
}