Zoom Canvas to Mouse Cursor

77

Ich programmiere ein HTML5-<Leinwand> -Projekt, bei dem Bilder mit dem Scrollrad vergrößert und verkleinert werden. Ich möchte wie bei Google Maps auf den Cursor zoomen, bin aber völlig verloren, wie man die Bewegungen berechnet.

Was ich habe: Bild x und y (obere linke Ecke); Bildbreite und -höhe; Cursor x und y relativ zur Mitte der Leinwand.

S2am
quelle
15
Sie sollten diese Antwort akzeptieren oder Ihre Frage überarbeiten
Ghayes

Antworten:

234

Kurz gesagt, Sie möchten translate()den Canvas-Kontext anhand Ihres Versatzes scale()vergrößern oder verkleinern und dann translate()um das Gegenteil des Mausversatzes zurück. Beachten Sie, dass Sie die Cursorposition vom Bildschirmbereich in den transformierten Canvas-Kontext umwandeln müssen.

ctx.translate(pt.x,pt.y);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);

Demo: http://phrogz.net/tmp/canvas_zoom_to_cursor.html

Ich habe auf meiner Website ein voll funktionsfähiges Beispiel erstellt, das Sie untersuchen können, indem Sie das Ziehen unterstützen, zum Vergrößern klicken, bei gedrückter Umschalttaste nach außen klicken oder das Rad nach oben / unten scrollen.

Das einzige (aktuelle) Problem ist, dass Safari im Vergleich zu Chrome oder Firefox zu schnell zoomt .

Phrogz
quelle
2
Gute Mühe mit dem Beispiel. Vielen Dank!
Mikael Eliasson
4
Wow, @phrogz, du hast alles getan!
Snapfractalpop
1
Hey @Phrogz das ist großartig! Ich frage mich nur, ob wir das Ziehen so begrenzen können, dass man das Bild nicht aus den Grenzen ziehen kann. Wenn kein Bild mehr zum Ziehen übrig ist, sollte das Ziehen dort einfach aufhören, anstatt das Ziehen auf unbestimmte Zeit zuzulassen. Ich habe es versucht, aber es scheint, dass ich die Mathematik nicht richtig verstehen kann :-(
Christoph
2
@Christoph es ist einfach. Holen Sie sich die Skala - Sie können die Skala nehmen von: var scale = ctx.getTransform (). a; Nehmen Sie dann die aktuelle Position des Bildes oben links: var curX = ctx.getTransform (). e; var curY = ctx.getTransform (). f; Schätzen Sie die Positionsänderung: var deltaX = pt.x - dragStart.x; var deltaY = pt.y - dragStart.y; dann gibt es die ursprüngliche Bildgröße, nehmen wir zum Beispiel die Breite (wenn scale = 1): imageW und es gibt die Canvas-Breite: canvasW, dann sollte die Bedingung falsch sein, damit Drag: curX + deltaX + imageW * scale <canvasW und eine weitere ( curX + deltaX> 0 || curY + deltaY> 0)
maximus
1
Wäre es schwierig, dies mit Gesten auf Mobilgeräten zu implementieren? Erlauben Sie 2 Finger Prise, nur das Bild, aber nicht die gesamte Website zu vergrößern?
Thomas Stock
10

Ich musste kürzlich dieselben Ergebnisse archivieren, die Phrogz bereits erstellt hatte, aber anstatt sie zu verwenden context.scale(), berechnete ich jede Objektgröße basierend auf dem Verhältnis.

Das habe ich mir ausgedacht. Die Logik dahinter ist sehr einfach. Vor dem Skalieren berechne ich den Punktabstand von der Kante in Prozent und passe das Ansichtsfenster später an die richtige Stelle an.

Ich habe eine ganze Weile gebraucht, um darauf zu kommen, hoffe, es spart jemandem Zeit.

Kristian
quelle
6

Ich habe die Antwort von @ Phrogz als Grundlage genommen und eine kleine Bibliothek erstellt, die das Ziehen, Zoomen und Drehen von Leinwand ermöglicht. Hier ist das Beispiel.

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

Sie können mehr detaillierten Beispiele und Dokumentation des Projektes finden Seite

vogdb
quelle