将画布缩放到鼠标光标

IT技术 javascript html canvas zooming scrollwheel
2021-01-18 21:18:30

我正在编写一个 HTML5 <canvas > 项目,该项目涉及使用滚轮放大和缩小图像。我想像谷歌地图一样放大光标,但我完全不知道如何计算运动。

我所拥有的:图像 x 和 y(左上角);图像宽度和高度;相对于画布中心的光标 x 和 y。

5个回答

简而言之,您希望translate()通过偏移scale()来放大或缩小画布上下文,然后translate()通过鼠标偏移的相反位置返回。请注意,您需要将光标位置从屏幕空间转换为转换后的画布上下文。

ctx.translate(pt.x,pt.y);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);

演示:http : //phrogz.net/tmp/canvas_zoom_to_cursor.html

在我的网站上提供了一个完整的工作示例供您检查、支持拖动、单击放大、按住 shift 单击缩小或向上/向下滚动滚轮。

唯一的(当前)问题是与 Chrome 或 Firefox 相比Safari 的缩放速度太快

嘿@Phrogz 这太棒了!我只是想知道我们是否可以限制拖动,这样就不能将图像拖出边界。如果没有更多的图像可以拖动,拖动应该停止,而不是允许无限拖动。我尝试了一下,但似乎我无法正确计算数学:-(
2021-03-19 21:18:30
这很难通过手势在移动设备上实现吗?像,允许 2 指捏只放大图像而不是整个网站?
2021-03-26 21:18:30
很好的例子。谢谢!
2021-04-01 21:18:30
@Christoph 这很容易。获取比例 - 您可以从以下内容获取比例:var scale = ctx.getTransform().a; 然后取图像的当前左上角位置: var curX = ctx.getTransform().e; var curY = ctx.getTransform().f; 估计位置的变化:var deltaX = pt.x - dragStart.x;var deltaY = pt.y - dragStart.y; 然后是原始图像大小,让我们以宽度为例(当 scale=1 时):imageW 并且有画布宽度:canvasW 那么条件应该为假以允许拖动:curX + deltaX + imageW * scale < canvasW 和一个( curX + deltaX > 0 || curY + deltaY > 0)
2021-04-05 21:18:30
哇,@phrogz,你超越了!
2021-04-09 21:18:30

我希望,这些 JS 库会帮助你:(HTML5, JS)

  1. 放大镜

http://www.netzgesta.de/loupe/

  1. 画布缩放

https://github.com/akademy/CanvasZoom

  1. 滚动条

https://github.com/zynga/scroller

至于我,我正在使用放大镜。这很棒!对你来说最好的情况 - 滚动条。

我最近需要归档与 Phrogz 已经完成的相同的结果,但context.scale()没有使用而是根据比率计算每个对象的大小。

这就是我想出的。其背后的逻辑非常简单。在缩放之前,我以百分比计算与边缘的点距离,然后将视口调整到正确的位置。

我花了很长时间才想出它,希望它可以节省某人的时间。

我以@Phrogz 的回答为基础,制作了一个小型库,使画布能够拖动、缩放和旋转。这是示例。

var canvas = document.getElementById('canvas')
//assuming that @param draw is a function where you do your main drawing.
var control = new CanvasManipulation(canvas, draw)
control.init()
control.layout()
//now you can drag, zoom and rotate in canvas

您可以在项目页面上找到更详细的示例和文档

快点

使用ctx.setTransform为您提供了比多个矩阵调用更多的性能ctx.translatectx.scalectx.translate

不需要复杂的转换反转,因为昂贵的 DOM 矩阵调用 tp 在缩放和屏幕坐标系之间转换点。

灵活的

灵活性,因为您不需要使用,ctx.save并且ctx.restore如果您使用不同的转换来渲染内容。返回到转换ctx.setTransform而不是潜在的帧率ctx.restore调用

易于反转变换并获得(屏幕)像素位置的世界坐标,反之亦然。

例子

使用鼠标和鼠标滚轮在鼠标位置放大和缩小

使用此方法通过 CSS 转换在答案底部的 CSS 演示点(鼠标)缩放页面内容的示例也有下一个示例中演示的副本。

以及使用 setTransform 在某个点缩放画布内容的此方法的示例

如何

给定比例和像素位置,您可以按如下方式获得新比例...

const origin = {x:0, y:0};         // canvas origin
var scale = 1;                     // current scale
function scaleAt(x, y, scaleBy) {  // at pixel coords x, y scale by scaleBy
    scale *= scaleBy;
    origin.x = x - (x - origin.x) * scaleBy;
    origin.y = y - (y - origin.y) * scaleBy;
}

定位画布并绘制内容

ctx.setTransform(scale, 0, 0, scale, origin.x, origin.y);
ctx.drawImage(img, 0, 0);

如果您有鼠标坐标,则使用

const zoomBy = 1.1;                    // zoom in amount
scaleAt(mouse.x, mouse.y, zoomBy);     // will zoom in at mouse x, y
scaleAt(mouse.x, mouse.y, 1 / zoomBy); // will zoom out by same amount at mouse x,y

恢复默认转换

ctx.setTransform(1,0,0,1,0,0);

倒置

获取缩放坐标系中某个点的坐标和缩放坐标系中某个点的屏幕位置

屏幕到世界

function toWorld(x, y) {  // convert to world coordinates
    x = (x - origin.x) / scale;
    y = (y - origin.y) / scale;
    return {x, y};
}

屏幕上的世界

function toScreen(x, y) {
    x = x * scale + origin.x;
    y = y * scale + origin.y;
    return {x, y};
}