javascript html5 canvas zoom scrollwheel

javascript - Zoom de lienzo al cursor del mouse



html5 canvas (4)

Espero que estas bibliotecas JS te ayuden: (HTML5, JS)

  1. Lupa

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

  1. CanvasZoom

https://github.com/akademy/CanvasZoom

  1. 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.