J'essaie de mettre en œuvre des gestes de pincement pour zoomer exactement comme dans Google Maps. J'ai assisté à une présentation de Stephen Woods - "Création d'interfaces Responsive HTML5 Touch" - sur le problème et utilisé la technique mentionnée. L'idée est de définir l'origine de la transformation de l'élément cible à (0, 0) et son échelle à le point de la transformation, puis traduisez l'image pour la maintenir centrée sur le point de la transformation.
Dans mon code de test, la mise à l'échelle fonctionne bien. L'image effectue un zoom avant et arrière entre les traductions suivantes. Le problème est que je ne calcule pas correctement les valeurs de traduction. J'utilise jQuery et Hammer.js pour les événements tactiles. Comment puis-je ajuster mon calcul dans le rappel de transformation afin que l'image reste centrée au point de transformation?
CoffeeScript (#test-resize
est une div
avec une image d'arrière-plan)
image = $('#test-resize')
hammer = image.hammer ->
prevent_default: true
scale_treshold: 0
width = image.width()
height = image.height()
toX = 0
toY = 0
translateX = 0
translateY = 0
prevScale = 1
scale = 1
hammer.bind 'transformstart', (event) ->
toX = (event.touches[0].x + event.touches[0].x) / 2
toY = (event.touches[1].y + event.touches[1].y) / 2
hammer.bind 'transform', (event) ->
scale = prevScale * event.scale
shiftX = toX * ((image.width() * scale) - width) / (image.width() * scale)
shiftY = toY * ((image.height() * scale) - height) / (image.height() * scale)
width = image.width() * scale
height = image.height() * scale
translateX -= shiftX
translateY -= shiftY
css = 'translateX(' + @translateX + 'px) translateY(' + @translateY + 'px) scale(' + scale + ')'
image.css '-webkit-transform', css
image.css '-webkit-transform-Origin', '0 0'
hammer.bind 'transformend', () ->
prevScale = scale
J'ai réussi à le faire fonctionner.
Dans la démo jsFiddle, cliquer sur l'image représente un geste de pincement centré sur le point de clic. Les clics ultérieurs augmentent le facteur d'échelle d'une quantité constante. Pour rendre cela utile, vous voudriez faire la balance et traduire les calculs beaucoup plus souvent sur un événement de transformation (hammer.js en fournit un).
La clé pour le faire fonctionner était de calculer correctement les coordonnées du point d'échelle par rapport à l'image. J'ai utilisé event.clientX/Y
pour obtenir les coordonnées de l'écran. Les lignes suivantes convertissent l'écran en coordonnées d'image:
x -= offset.left + newX
y -= offset.top + newY
Ensuite, nous calculons une nouvelle taille pour l'image et trouvons les distances à traduire. L'équation de traduction est tirée de le discours de Stephen Woods .
newWidth = image.width() * scale
newHeight = image.height() * scale
newX += -x * (newWidth - image.width) / newWidth
newY += -y * (newHeight - image.height) / newHeight
Enfin, nous adaptons et traduisons
image.css '-webkit-transform', "scale3d(#{scale}, #{scale}, 1)"
wrap.css '-webkit-transform', "translate3d(#{newX}px, #{newY}px, 0)"
Nous faisons toutes nos traductions sur un élément wrapper pour nous assurer que translate-Origin reste en haut à gauche de notre image.
J'ai utilisé avec succès cet extrait pour redimensionner des images sur phonegap, en utilisant hammer et jquery.
Si cela intéresse quelqu'un, je l'ai traduit en JS.
function attachPinch(wrapperID,imgID)
{
var image = $(imgID);
var wrap = $(wrapperID);
var width = image.width();
var height = image.height();
var newX = 0;
var newY = 0;
var offset = wrap.offset();
$(imgID).hammer().on("pinch", function(event) {
var photo = $(this);
newWidth = photo.width() * event.gesture.scale;
newHeight = photo.height() * event.gesture.scale;
// Convert from screen to image coordinates
var x;
var y;
x -= offset.left + newX;
y -= offset.top + newY;
newX += -x * (newWidth - width) / newWidth;
newY += -y * (newHeight - height) / newHeight;
photo.css('-webkit-transform', "scale3d("+event.gesture.scale+", "+event.gesture.scale+", 1)");
wrap.css('-webkit-transform', "translate3d("+newX+"px, "+newY+"px, 0)");
width = newWidth;
height = newHeight;
});
}
J'ai regardé partout sur Internet et sur quoi que ce soit, jusqu'à ce que je tombe sur le seul plugin/bibliothèque qui fonctionne - http://cubiq.org/iscroll-4
var myScroll;
myScroll = new iScroll('wrapper');
où wrapper est votre identifiant comme dans id = "wrapper"
<div id="wrapper">
<img src="smth.jpg" />
</div>
Pas une vraie réponse, mais un lien vers un plug = in qui fait tout pour vous. Bon travail!
https://github.com/timmywil/jquery.panzoom
(Merci 'Timmywil', qui que vous soyez)
C'est quelque chose que j'ai écrit il y a quelques années en Java et que j'ai récemment converti en JavaScript.
function View()
{
this.pos = {x:0,y:0};
this.Z = 0;
this.zoom = 1;
this.scale = 1.1;
this.Zoom = function(delta,x,y)
{
var X = x-this.pos.x;
var Y = y-this.pos.y;
var scale = this.scale;
if(delta>0) this.Z++;
else
{
this.Z--;
scale = 1/scale;
}
this.zoom = Math.pow(this.scale, this.Z);
this.pos.x+=X-scale*X;
this.pos.y+=Y-scale*Y;
}
}
this.Zoom = function(delta,x,y)
prend:
delta
= zoom avant ou arrièrex
= x position du zoom Originey
= y position du zoom OrigineUn petit exemple:
<script>
var view = new View();
var DivStyle = {x:-123,y:-423,w:300,h:200};
function OnMouseWheel(event)
{
event.preventDefault();
view.Zoom(event.wheelDelta,event.clientX,event.clientY);
div.style.left = (DivStyle.x*view.zoom+view.pos.x)+"px";
div.style.top = (DivStyle.y*view.zoom+view.pos.y)+"px";
div.style.width = (DivStyle.w*view.zoom)+"px";
div.style.height = (DivStyle.h*view.zoom)+"px";
}
function OnMouseMove(event)
{
view.pos = {x:event.clientX,y:event.clientY};
div.style.left = (DivStyle.x*view.zoom+view.pos.x)+"px";
div.style.top = (DivStyle.y*view.zoom+view.pos.y)+"px";
div.style.width = (DivStyle.w*view.zoom)+"px";
div.style.height = (DivStyle.h*view.zoom)+"px";
}
</script>
<body onmousewheel="OnMouseWheel(event)" onmousemove="OnMouseMove(event)">
<div id="div" style="position:absolute;left:-123px;top:-423px;width:300px;height:200px;border:1px solid;"></div>
</body>
Cela a été fait avec l'intention d'être utilisé avec une toile et des graphiques, mais cela devrait fonctionner parfaitement pour une mise en page HTML normale