javascript - Zoom de lienzo al cursor del mouse
html5 canvas (4)
Espero que estas bibliotecas JS te ayuden: (HTML5, JS)
- Lupa
http://www.netzgesta.de/loupe/
- CanvasZoom
https://github.com/akademy/CanvasZoom
- Scroller
https://github.com/zynga/scroller
En cuanto a mí, estoy usando lupa. ¡Es impresionante! Para ti es el mejor caso: scroller.
Estoy programando un proyecto HTML5 <canvas> que implica acercar y alejar imágenes usando la rueda de desplazamiento. Quiero acercarme al cursor como lo hace google maps, pero estoy completamente perdido en cómo calcular los movimientos.
Lo que tengo: imagen xey (esquina superior izquierda); ancho y altura de la imagen; cursor xey en relación con el centro del lienzo.
Recientemente necesité archivar los mismos resultados que Phrogz, pero en lugar de usar context.scale()
, calculé el tamaño de cada objeto en función de la proporción.
Esto es lo que se me ocurrió. La lógica detrás de esto es muy simple. Antes de escalar, calculo la distancia del punto desde el borde en porcentajes y luego ajusto la ventana gráfica para corregir el lugar.
Me tomó bastante tiempo llegar a eso, espero que ahorre tiempo a alguien.
$(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
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>
Tomé como base la respuesta de @ Phrogz e hice una pequeña biblioteca que permite al lienzo arrastrar, hacer zoom y rotar. Aquí está el ejemplo.
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
Puede encontrar ejemplos más detallados y documentación en la page del proyecto
En resumen, desea translate()
el contexto del lienzo por su desplazamiento, scale()
para acercar o alejar, y luego translate()
nuevo por el lado opuesto al desplazamiento del mouse. Tenga en cuenta que debe transformar la posición del cursor del espacio de la pantalla en el contexto del lienzo transformado.
ctx.translate(pt.x,pt.y);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);
Demostración: http://phrogz.net/tmp/canvas_zoom_to_cursor.html
He puesto un http://phrogz.net/tmp/canvas_zoom_to_cursor.html en mi sitio web para que pueda examinar, admitir el arrastre, hacer clic para acercar, desplazar-clic hacia afuera, o desplazar la rueda hacia arriba / abajo.
El único problema (actual) es que Safari amplía demasiado rápido en comparación con Chrome o Firefox.