Javascript 将画布缩放到鼠标光标
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5189968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Zoom Canvas to Mouse Cursor
提问by S2am
I'm programming a HTML5 < canvas > project that involves zooming in and out of images using the scroll wheel. I want to zoom towards the cursor like google maps does but I'm completely lost on how to calculate the movements.
我正在编写一个 HTML5 <canvas > 项目,该项目涉及使用滚轮放大和缩小图像。我想像谷歌地图一样放大光标,但我完全不知道如何计算运动。
What I have: image x and y (top-left corner); image width and height; cursor x and y relative to the center of the canvas.
我所拥有的:图像 x 和 y(左上角);图像宽度和高度;相对于画布中心的光标 x 和 y。
回答by Phrogz
In short, you want to translate()
the canvas context by your offset, scale()
it to zoom in or out, and then translate()
back by the opposite of the mouse offset. Note that you need to transform the cursor position from screen space into the transformed canvas context.
简而言之,您希望translate()
通过偏移scale()
来放大或缩小画布上下文,然后translate()
通过鼠标偏移的相反位置返回。请注意,您需要将光标位置从屏幕空间转换为转换后的画布上下文。
ctx.translate(pt.x,pt.y);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);
Demo: http://phrogz.net/tmp/canvas_zoom_to_cursor.html
演示:http: //phrogz.net/tmp/canvas_zoom_to_cursor.html
I've put up a full working exampleon my website for you to examine, supporting dragging, click to zoom in, shift-click to out, or scroll wheel up/down.
我在我的网站上提供了一个完整的工作示例供您检查、支持拖动、单击放大、按住 shift 单击缩小或向上/向下滚轮。
The only (current) issue is that Safari zooms too fastcompared to Chrome or Firefox.
唯一的(当前)问题是与 Chrome 或 Firefox 相比,Safari 的缩放速度太快。
回答by Alexey
I hope, these JS libraries will help you: (HTML5, JS)
我希望,这些 JS 库会帮助你:(HTML5,JS)
- Loupe
- 放大镜
http://www.netzgesta.de/loupe/
http://www.netzgesta.de/loupe/
- CanvasZoom
- 画布缩放
https://github.com/akademy/CanvasZoom
https://github.com/akademy/CanvasZoom
- Scroller
- 滚动条
https://github.com/zynga/scroller
https://github.com/zynga/scroller
As for me, I'm using loupe. It's awesome! For you the best case - scroller.
至于我,我正在使用放大镜。这很棒!对你来说最好的情况 - 滚动条。
回答by Kristian
I recently needed to archive same results as Phrogz had already done but instead of using context.scale()
, I calculated each object size based on ratio.
我最近需要存档与 Phrogz 已经完成的相同的结果,但context.scale()
我没有使用,而是根据比率计算每个对象的大小。
This is what I came up with. Logic behind it is very simple. Before scaling, I calculate point distance from edge in percentages and later adjust viewport to correct place.
这就是我想出的。其背后的逻辑非常简单。在缩放之前,我以百分比计算与边缘的点距离,然后将视口调整到正确的位置。
It took me quite a while to come up with it, hope it saves someones time.
我花了很长时间才想出它,希望它可以节省某人的时间。
$(function () {
var canvas = $('canvas.main').get(0)
var canvasContext = canvas.getContext('2d')
var ratio = 1
var vpx = 0
var vpy = 0
var vpw = window.innerWidth
var vph = window.innerHeight
var orig_width = 4000
var orig_height = 4000
var width = 4000
var height = 4000
$(window).on('resize', function () {
$(canvas).prop({
width: window.innerWidth,
height: window.innerHeight,
})
}).trigger('resize')
$(canvas).on('wheel', function (ev) {
ev.preventDefault() // for stackoverflow
var step
if (ev.originalEvent.wheelDelta) {
step = (ev.originalEvent.wheelDelta > 0) ? 0.05 : -0.05
}
if (ev.originalEvent.deltaY) {
step = (ev.originalEvent.deltaY > 0) ? 0.05 : -0.05
}
if (!step) return false // yea..
var new_ratio = ratio + step
var min_ratio = Math.max(vpw / orig_width, vph / orig_height)
var max_ratio = 3.0
if (new_ratio < min_ratio) {
new_ratio = min_ratio
}
if (new_ratio > max_ratio) {
new_ratio = max_ratio
}
// zoom center point
var targetX = ev.originalEvent.clientX || (vpw / 2)
var targetY = ev.originalEvent.clientY || (vph / 2)
// percentages from side
var pX = ((vpx * -1) + targetX) * 100 / width
var pY = ((vpy * -1) + targetY) * 100 / height
// update ratio and dimentsions
ratio = new_ratio
width = orig_width * new_ratio
height = orig_height * new_ratio
// translate view back to center point
var x = ((width * pX / 100) - targetX)
var y = ((height * pY / 100) - targetY)
// don't let viewport go over edges
if (x < 0) {
x = 0
}
if (x + vpw > width) {
x = width - vpw
}
if (y < 0) {
y = 0
}
if (y + vph > height) {
y = height - vph
}
vpx = x * -1
vpy = y * -1
})
var is_down, is_drag, last_drag
$(canvas).on('mousedown', function (ev) {
is_down = true
is_drag = false
last_drag = { x: ev.clientX, y: ev.clientY }
})
$(canvas).on('mousemove', function (ev) {
is_drag = true
if (is_down) {
var x = vpx - (last_drag.x - ev.clientX)
var y = vpy - (last_drag.y - ev.clientY)
if (x <= 0 && vpw < x + width) {
vpx = x
}
if (y <= 0 && vph < y + height) {
vpy = y
}
last_drag = { x: ev.clientX, y: ev.clientY }
}
})
$(canvas).on('mouseup', function (ev) {
is_down = false
last_drag = null
var was_click = !is_drag
is_drag = false
if (was_click) {
}
})
$(canvas).css({ position: 'absolute', top: 0, left: 0 }).appendTo(document.body)
function animate () {
window.requestAnimationFrame(animate)
canvasContext.clearRect(0, 0, canvas.width, canvas.height)
canvasContext.lineWidth = 1
canvasContext.strokeStyle = '#ccc'
var step = 100 * ratio
for (var x = vpx; x < width + vpx; x += step) {
canvasContext.beginPath()
canvasContext.moveTo(x, vpy)
canvasContext.lineTo(x, vpy + height)
canvasContext.stroke()
}
for (var y = vpy; y < height + vpy; y += step) {
canvasContext.beginPath()
canvasContext.moveTo(vpx, y)
canvasContext.lineTo(vpx + width, y)
canvasContext.stroke()
}
canvasContext.strokeRect(vpx, vpy, width, height)
canvasContext.beginPath()
canvasContext.moveTo(vpx, vpy)
canvasContext.lineTo(vpx + width, vpy + height)
canvasContext.stroke()
canvasContext.beginPath()
canvasContext.moveTo(vpx + width, vpy)
canvasContext.lineTo(vpx, vpy + height)
canvasContext.stroke()
canvasContext.restore()
}
animate()
})
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<canvas class="main"></canvas>
</body>
</html>
回答by vogdb
I took @Phrogz's answer as a basis and made a small library that enables canvas with dragging, zooming and rotating. Here is the example.
我以@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
You can find more detailed examples and documentation on the project's page
您可以在项目页面上找到更详细的示例和文档