2012-05-29 7 views
23

Ich versuche Pinch-to-Zoom-Gesten genau wie in Google Maps zu implementieren. Ich sah einen Vortrag von Stephen Woods - "Creating Responsive HTML5 Touch Interfaces” - über das Thema und verwendete die erwähnte Technik. Die Idee ist, den Transformationsursprung des Zielelements auf (0, 0) zu setzen und an dem Punkt der Transformation zu skalieren. Dann übersetze das Bild, um es am Transformationspunkt zentriert zu halten.Prise zum Zoomen mit CSS3

In meiner Testcode-Skalierung funktioniert gut. Das Bild vergrößert und verkleinert sich zwischen nachfolgenden Übersetzungen. Das Problem ist, dass ich die Übersetzungswerte nicht richtig berechne. Ich verwende jQuery und Hammer.js für Berührungsereignisse. Wie kann ich meine Berechnung im Transform Callback so anpassen, dass das Bild zum Zeitpunkt der Transformation zentriert bleibt?

The Coffeescript (#test-resize ist ein div mit einem Hintergrundbild)

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 

Antwort

19

ich es geschafft, zum Laufen zu bringen.

jsFiddle demo

Im jsFiddle Demo steht am Klickpunkt eine Pinch-Geste zentriert auf das Bild klicken. Nachfolgende Klicks erhöhen den Skalierungsfaktor um einen konstanten Betrag. Um dies sinnvoll zu gestalten, sollten Sie die Berechnungen für die Skalierung und die Transla- tion viel häufiger bei einem Transformationsereignis durchführen (hammer.js bietet einen).

Der Schlüssel, um es zur Arbeit zu bringen, war die korrekte Berechnung der Punktkoordinaten relativ zum Bild. Ich habe event.clientX/Y verwendet, um die Bildschirmkoordinaten zu erhalten. Die folgenden Zeilen konvertieren von Bildschirm zu Bildkoordinaten:

x -= offset.left + newX 
y -= offset.top + newY 

Dann haben wir eine neue Größe für das Bild berechnen und die Abstände von übersetzen zu finden. Die Übersetzungsgleichung stammt aus Stephen Woods' talk.

newWidth = image.width() * scale 
newHeight = image.height() * scale 

newX += -x * (newWidth - image.width)/newWidth 
newY += -y * (newHeight - image.height)/newHeight 

Schließlich haben wir skalieren und übersetzen

image.css '-webkit-transform', "scale3d(#{scale}, #{scale}, 1)"   
wrap.css '-webkit-transform', "translate3d(#{newX}px, #{newY}px, 0)" 

Wir alle unsere Übersetzungen auf einem Wrapper-Element, um sicherzustellen, dass der translate-Ursprung in der linken oberen unseres Bildes bleibt.

+10

das ist meine Katze! !! ?? –

+0

2. Verbindung ist unterbrochen. –

+0

Es gibt wirklich einen guten Punkt von Stephen Woods: Absolut nichts anderes in Code während der Transformation mit CSS (nicht laden Zeug usw.). Hat viel in meinem eigenen Projekt geholfen. – Hardy

6

Ich habe diesen Ausschnitt erfolgreich verwendet, um Bilder auf Phonegap mit hammer und jquery zu skalieren.

Wenn es jemanden interessiert, übersetzte ich dies in 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; 
    }); 

} 
+0

Kannst du lesen? "** Ich habe diesen Ausschnitt erfolgreich verwendet, um die Größe von Bildern zu ändern **" Ich habe _Dragging_ nie erwähnt. '$ (imgID) .hammer(). on (" Pinch ", Funktion (Ereignis) [...] Funktion attachPinch (WrapperID, imgID) [...]" –

+0

Dies ist ein großartiges Skript, aber für alle, die es wollen replizieren Sie es - beachten Sie, dass (a) es das Jquery - Plugin für Hammer und (b) Sie müssen das Plugin ändern, weil * müssen Sie Pinch innerhalb Hammer für die Arbeit aktivieren *. \t \t \t \t {hamObj = neue Hammer ($ el [0], Optionen); \t \t \t \t hamObj.get ('pinch') Satz ({aktivieren: true}.); \t \t \t \t $ el.data ("Hammer", hamObj);} – Ukuser32

2

Ich sah alle über das Internet, und Outernet was auch immer, bis ich auf die einzige funktionierende Plugin/Bibliothek kam - http://cubiq.org/iscroll-4

var myScroll; 
myScroll = new iScroll('wrapper'); 

wo Wrapper Ihre ID ist wie in id = "Wrapper"

<div id="wrapper"> 
    <img src="smth.jpg" /> 
</div> 
0

Dies ist etwas, das ich vor ein paar Jahren in Java geschrieben und vor kurzem in JavaScript umgesetzt

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; 
} 
} 

Die this.Zoom = function(delta,x,y) nimmt:

  • delta = Vergrößern oder Verkleinern
  • x = X-Position des Zoom-Ursprungs
  • y = Y-Position des Zoom-Ursprungs

A kleines Beispiel:

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

Dies wurde mit der Absicht gemacht mit einer Leinwand und Grafiken verwendet werden, aber es sollte perfekt für normales HTML-Layout