Je programme un projet HTML5 <canvas> qui implique un zoom avant et arrière sur les images à l'aide de la molette de défilement. Je veux zoomer vers le curseur comme le fait Google Maps, mais je suis complètement perdu sur la façon de calculer les mouvements.
Ce que j'ai: image x et y (coin supérieur gauche); largeur et hauteur de l'image; curseur x et y par rapport au centre du canevas.
En bref, vous voulez translate()
le contexte du canevas par votre décalage, scale()
pour zoomer ou dézoomer, puis translate()
en arrière à l'opposé de la souris décalage. Notez que vous devez transformer la position du curseur de l'espace d'écran dans le contexte de canevas transformé.
ctx.translate(pt.x,pt.y);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);
J'ai mis un exemple de travail complet sur mon site Web pour que vous puissiez l'examiner, prendre en charge le glissement, cliquer pour zoomer, cliquer-déplacer vers l'arrière ou faire défiler la molette vers le haut/vers le bas.
Le seul problème (actuel) est que Safari zoome trop vite par rapport à Chrome ou Firefox.
J'espère que ces bibliothèques JS vous aideront: (HTML5, JS)
http://www.netzgesta.de/loupe/
https://github.com/akademy/CanvasZoom
https://github.com/zynga/scroller
Quant à moi, j'utilise de la loupe. C'est génial! Pour vous le meilleur cas - scroller.
J'ai récemment dû archiver les mêmes résultats que Phrogz l'avait déjà fait, mais au lieu d'utiliser context.scale()
, j'ai calculé chaque taille d'objet en fonction du ratio.
C'est ce que j'ai trouvé. La logique derrière c'est très simple. Avant la mise à l'échelle, je calcule la distance en points à partir d'Edge en pourcentages et ajuste plus tard la fenêtre d'affichage à l'emplacement correct.
Il m'a fallu un certain temps pour le proposer, j'espère que cela fera gagner du temps à quelqu'un.
$(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>
J'ai pris la réponse de @ Phrogz comme base et créé une petite bibliothèque qui permet le canevas avec glisser, zoomer et tourner. Voici l'exemple.
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
Vous pouvez trouver des exemples plus détaillés et de la documentation sur le projet page