Vergrößern Sie einen Punkt (mithilfe von Skalierung und Übersetzung).

156

Ich möchte in der Lage sein, den Punkt unter der Maus in einer HTML 5-Zeichenfläche zu vergrößern, wie z. B. das Zoomen in Google Maps . Wie kann ich das erreichen?

csiz
quelle
2
Ich habe dies zum Zoomen meiner Leinwand verwendet und es funktioniert großartig! Das einzige, was ich hinzufügen muss, ist, dass die Berechnung des Zoombetrags nicht so ist, wie Sie es erwarten würden. "var zoom = 1 + Rad / 2;" Dies ergibt 1,5 zum Vergrößern und 0,5 zum Verkleinern. Ich habe dies in meiner Version so bearbeitet, dass ich 1,5 zum Vergrößern und 1 / 1,5 zum Verkleinern habe, wodurch die Anzahl der Vergrößerungen und Verkleinerungen gleich ist. Wenn Sie also einmal hineinzoomen und zurückzoomen, erhalten Sie das gleiche Bild wie vor dem Zoomen.
Chris
2
Beachten Sie, dass dies unter Firefox nicht funktioniert, die Methode jedoch problemlos auf das jQuery-Mausrad-Plugin angewendet werden kann . Danke für das Teilen!
Johndodo
2
var zoom = Math.pow (1.5f, Rad); // Verwenden Sie diese Option, um den Zoom zu berechnen. Dies hat den Vorteil, dass das Zoomen mit dem Rad = 2 dasselbe ist wie das zweimalige Zoomen mit dem Rad = 1. Durch Heranzoomen um +2 und Verkleinern um +2 wird außerdem die ursprüngliche Skala wiederhergestellt.
Matt

Antworten:

126

Die bessere Lösung besteht darin, die Position des Ansichtsfensters basierend auf der Änderung des Zooms einfach zu verschieben. Der Zoompunkt ist einfach der Punkt im alten Zoom und im neuen Zoom, den Sie beibehalten möchten. Das heißt, das vorgezoomte Ansichtsfenster und das nachgezoomte Ansichtsfenster haben denselben Zoompunkt relativ zum Ansichtsfenster. Vorausgesetzt, wir skalieren relativ zum Ursprung. Sie können die Position des Ansichtsfensters entsprechend anpassen:

scalechange = newscale - oldscale;
offsetX = -(zoomPointX * scalechange);
offsetY = -(zoomPointY * scalechange);

Sie können also beim Vergrößern einfach nach unten und rechts schwenken, um einen Faktor, um wie viel Sie hineingezoomt haben, relativ zu dem Punkt, auf den Sie gezoomt haben.

Geben Sie hier die Bildbeschreibung ein

Tatarisieren
quelle
2
Wertvoller als das Ausschneiden und Einfügen von Code ist die Erklärung, was die beste Lösung ist und warum sie ohne Gepäck funktioniert, insbesondere wenn sie drei Zeilen lang ist.
Tatarize
2
scalechange = newscale / oldscale?
Tejesh Alimilli
4
Außerdem möchte ich für diejenigen, die eine Karte wie eine Pan-Zoom-Komponente erzielen möchten, hinzufügen, dass die Maus X, Y (mousePosRelativeToContainer - currentTransform) / currentScale sein sollte, andernfalls wird die aktuelle Mausposition relativ zum Container behandelt.
Gilad
1
Ja, diese Mathematik geht davon aus, dass sich sowohl der Zoom als auch der Schwenk in den für den Ursprung relevanten Koordinaten befinden. Wenn sie relativ zum Ansichtsfenster sind, müssen Sie sie entsprechend anpassen. Obwohl ich annehmen würde, dass die richtige Mathematik zoomPoint = (mousePosRelativeToContainer + currentTranslation) ist. Diese Mathematik geht auch davon aus, dass sich der Ursprungspunkt normalerweise oben links im Feld befindet. Aufgrund der Einfachheit ist es jedoch viel einfacher, sich auf leicht atypische Situationen einzustellen.
Tatarize
1
@ C.Finke Der zweite Weg, dies zu tun, ist die Verwendung der Übersetzungen innerhalb des ctx. Sie zeichnen alles in der gleichen Größe und an den gleichen Positionen. Sie verwenden jedoch einfach die Matrixmultiplikationen innerhalb der Javascript-Zeichenfläche, um das Schwenken und den Maßstab (Zoom) des Kontexts festzulegen. Also anstatt alle Formen an einem anderen Ort neu zu zeichnen. Sie zeichnen sie an derselben Stelle und verschieben das Ansichtsfenster in Javascript. Diese Methode würde auch erfordern, dass Sie die Mausereignisse nehmen und sie rückwärts übersetzen. Sie würden also die Pfanne subtrahieren und dann den Faktor durch den Zoom umkehren.
Tatarize
67

Endlich gelöst:

var zoomIntensity = 0.2;

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = 600;
var height = 200;

var scale = 1;
var originx = 0;
var originy = 0;
var visibleWidth = width;
var visibleHeight = height;


function draw(){
    // Clear screen to white.
    context.fillStyle = "white";
    context.fillRect(originx,originy,800/scale,600/scale);
    // Draw the black square.
    context.fillStyle = "black";
    context.fillRect(50,50,100,100);
}
// Draw loop at 60FPS.
setInterval(draw, 1000/60);

canvas.onwheel = function (event){
    event.preventDefault();
    // Get mouse offset.
    var mousex = event.clientX - canvas.offsetLeft;
    var mousey = event.clientY - canvas.offsetTop;
    // Normalize wheel to +1 or -1.
    var wheel = event.deltaY < 0 ? 1 : -1;

    // Compute zoom factor.
    var zoom = Math.exp(wheel*zoomIntensity);
    
    // Translate so the visible origin is at the context's origin.
    context.translate(originx, originy);
  
    // Compute the new visible origin. Originally the mouse is at a
    // distance mouse/scale from the corner, we want the point under
    // the mouse to remain in the same place after the zoom, but this
    // is at mouse/new_scale away from the corner. Therefore we need to
    // shift the origin (coordinates of the corner) to account for this.
    originx -= mousex/(scale*zoom) - mousex/scale;
    originy -= mousey/(scale*zoom) - mousey/scale;
    
    // Scale it (centered around the origin due to the trasnslate above).
    context.scale(zoom, zoom);
    // Offset the visible origin to it's proper position.
    context.translate(-originx, -originy);

    // Update scale and others.
    scale *= zoom;
    visibleWidth = width / scale;
    visibleHeight = height / scale;
}
<canvas id="canvas" width="600" height="200"></canvas>

Wie @Tatarize hervorhob , besteht der Schlüssel darin, die Achsenposition so zu berechnen, dass der Zoompunkt (Mauszeiger) nach dem Zoom an derselben Stelle bleibt.

Ursprünglich befindet sich die Maus in einem Abstand mouse/scalevon der Ecke. Wir möchten, dass der Punkt unter der Maus nach dem Zoom an derselben Stelle bleibt, aber dies ist mouse/new_scalevon der Ecke entfernt. Deshalb müssen wir die origin(Koordinaten der Ecke) verschieben, um dies zu berücksichtigen.

originx -= mousex/(scale*zoom) - mousex/scale;
originy -= mousey/(scale*zoom) - mousey/scale;
scale *= zoom

Der verbleibende Code muss dann die Skalierung anwenden und in den Zeichnungskontext übersetzen, damit sein Ursprung mit der Canvas-Ecke übereinstimmt.

csiz
quelle
Vielen Dank, Alter, fast 2 Tage verloren, bevor Sie Ihren Code gefunden haben
Velaro
Hey, ich habe nur nach so etwas gesucht und wollte nur sagen, dass du es geknackt hast!
Chrisallick
26

Dies ist tatsächlich ein sehr schwieriges Problem (mathematisch), und ich arbeite fast an der gleichen Sache. Ich habe eine ähnliche Frage zu Stackoverflow gestellt, aber keine Antwort erhalten, aber in DocType (StackOverflow für HTML / CSS) gepostet und eine Antwort erhalten. Überprüfen Sie es heraus http://doctype.com/javascript-image-zoom-css3-transforms-calculate-origin-example

Ich bin gerade dabei, ein jQuery-Plugin zu erstellen, das dies tut (Zoom im Google Maps-Stil mithilfe von CSS3-Transformationen). Ich habe das Zoom-zu-Maus-Cursor-Bit in Ordnung und versuche immer noch herauszufinden, wie der Benutzer die Leinwand wie in Google Maps verschieben kann. Wenn es funktioniert, werde ich hier eine Postleitzahl veröffentlichen, aber den obigen Link für den Maus-Zoom-to-Point-Teil lesen.

Ich wusste nicht, dass es Skalierungs- und Übersetzungsmethoden im Canvas-Kontext gibt. Mit CSS3 können Sie dasselbe erreichen, z. Verwenden von jQuery:

$('div.canvasContainer > canvas')
    .css('-moz-transform', 'scale(1) translate(0px, 0px)')
    .css('-webkit-transform', 'scale(1) translate(0px, 0px)')
    .css('-o-transform', 'scale(1) translate(0px, 0px)')
    .css('transform', 'scale(1) translate(0px, 0px)');

Stellen Sie sicher, dass Sie den CSS3-Transformationsursprung auf 0, 0 setzen (-moz-Transformationsursprung: 0 0). Mit der CSS3-Transformation können Sie alles vergrößern. Stellen Sie lediglich sicher, dass der Container-DIV auf Überlauf eingestellt ist: Ausgeblendet, um zu verhindern, dass die gezoomten Kanten aus den Seiten herauslaufen.

Es liegt an Ihnen, ob Sie CSS3-Transformationen oder Canvas-eigene Skalierungs- und Übersetzungsmethoden verwenden. Überprüfen Sie jedoch den obigen Link für die Berechnungen.


Update: Meh! Ich werde nur den Code hier posten, anstatt Sie dazu zu bringen, einem Link zu folgen:

$(document).ready(function()
{
    var scale = 1;  // scale of the image
    var xLast = 0;  // last x location on the screen
    var yLast = 0;  // last y location on the screen
    var xImage = 0; // last x location on the image
    var yImage = 0; // last y location on the image

    // if mousewheel is moved
    $("#mosaicContainer").mousewheel(function(e, delta)
    {
        // find current location on screen 
        var xScreen = e.pageX - $(this).offset().left;
        var yScreen = e.pageY - $(this).offset().top;

        // find current location on the image at the current scale
        xImage = xImage + ((xScreen - xLast) / scale);
        yImage = yImage + ((yScreen - yLast) / scale);

        // determine the new scale
        if (delta > 0)
        {
            scale *= 2;
        }
        else
        {
            scale /= 2;
        }
        scale = scale < 1 ? 1 : (scale > 64 ? 64 : scale);

        // determine the location on the screen at the new scale
        var xNew = (xScreen - xImage) / scale;
        var yNew = (yScreen - yImage) / scale;

        // save the current screen location
        xLast = xScreen;
        yLast = yScreen;

        // redraw
        $(this).find('div').css('-moz-transform', 'scale(' + scale + ')' + 'translate(' + xNew + 'px, ' + yNew + 'px' + ')')
                           .css('-moz-transform-origin', xImage + 'px ' + yImage + 'px')
        return false;
    });
});

Sie müssen es natürlich anpassen, um die Canvas-Skala zu verwenden und Methoden zu übersetzen.


Update 2: Ich habe gerade bemerkt, dass ich transform-origin zusammen mit translate verwende. Ich habe es geschafft, eine Version zu implementieren, die nur Skalierung und Übersetzung selbst verwendet. Schauen Sie hier nach: http://www.dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html Warten Sie, bis die Bilder heruntergeladen wurden, und verwenden Sie dann Ihre Mausrad zum Zoomen, unterstützt auch das Schwenken durch Ziehen des Bildes. Es werden CSS3-Transformationen verwendet, aber Sie sollten in der Lage sein, dieselben Berechnungen für Ihre Leinwand zu verwenden.

Sonntag Eisenfuß
quelle
Ich habe es endlich gelöst und brauchte 3 Minuten, nachdem ich ungefähr 2 Wochen lang etwas anderes gemacht hatte
csiz
@Synday Ironfoot Link auf seinem Update funktioniert nicht. Dieser Link: dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html Ich möchte diese Impelementation. Kannst du hier den Code posten? danke
Bogz
2
Ab heute (September 2014) ist der Link zu MosaicTest.html tot.
Chris
Mosaik-Demo ist weg. Ich benutze normalerweise Vanille js und nicht jQuery. Worauf bezieht sich $ (dies)? das document.body.offsetTop? Ich möchte unbedingt die Mosaik-Demo sehen, von der mein Projekt foreverscape.com wirklich profitieren könnte.
FlavorScape
2
Die Mosaik- Demoseite
Chris
9

Ich bin auf dieses Problem mit C ++ gestoßen, was ich wahrscheinlich nicht hätte tun sollen. Ich habe zunächst nur OpenGL-Matrizen verwendet. Wie auch immer, wenn Sie ein Steuerelement verwenden, dessen Ursprung in der oberen linken Ecke liegt, und Sie möchten schwenken / zoomen Hier ist wie bei Google Maps das Layout (mit Allegro als Event-Handler):

// initialize
double originx = 0; // or whatever its base offset is
double originy = 0; // or whatever its base offset is
double zoom = 1;

.
.
.

main(){

    // ...set up your window with whatever
    //  tool you want, load resources, etc

    .
    .
    .
    while (running){
        /* Pan */
        /* Left button scrolls. */
        if (mouse == 1) {
            // get the translation (in window coordinates)
            double scroll_x = event.mouse.dx; // (x2-x1) 
            double scroll_y = event.mouse.dy; // (y2-y1) 

            // Translate the origin of the element (in window coordinates)      
            originx += scroll_x;
            originy += scroll_y;
        }

        /* Zoom */ 
        /* Mouse wheel zooms */
        if (event.mouse.dz!=0){    
            // Get the position of the mouse with respect to 
            //  the origin of the map (or image or whatever).
            // Let us call these the map coordinates
            double mouse_x = event.mouse.x - originx;
            double mouse_y = event.mouse.y - originy;

            lastzoom = zoom;

            // your zoom function 
            zoom += event.mouse.dz * 0.3 * zoom;

            // Get the position of the mouse
            // in map coordinates after scaling
            double newx = mouse_x * (zoom/lastzoom);
            double newy = mouse_y * (zoom/lastzoom);

            // reverse the translation caused by scaling
            originx += mouse_x - newx;
            originy += mouse_y - newy;
        }
    }
}  

.
.
.

draw(originx,originy,zoom){
    // NOTE:The following is pseudocode
    //          the point is that this method applies so long as
    //          your object scales around its top-left corner
    //          when you multiply it by zoom without applying a translation.

    // draw your object by first scaling...
    object.width = object.width * zoom;
    object.height = object.height * zoom;

    //  then translating...
    object.X = originx;
    object.Y = originy; 
}
Aleksandr Albert
quelle
9

Ich mag die Antwort von Tatarize , aber ich werde eine Alternative anbieten . Dies ist ein triviales lineares Algebra-Problem, und die von mir vorgestellte Methode funktioniert gut mit Schwenken, Zoomen, Neigen usw. Das heißt, es funktioniert gut, wenn Ihr Bild bereits transformiert ist.

Wenn eine Matrix skaliert wird, befindet sich die Skalierung am Punkt (0, 0). Wenn Sie also ein Bild haben und es um den Faktor 2 skalieren, verdoppelt sich der Punkt unten rechts sowohl in x- als auch in y-Richtung (unter Verwendung der Konvention, dass [0, 0] oben links im Bild ist).

Wenn Sie stattdessen das Bild um die Mitte zoomen möchten, lautet die Lösung wie folgt: (1) Verschieben Sie das Bild so, dass seine Mitte bei (0, 0) liegt. (2) Skalieren des Bildes um x- und y-Faktoren; (3) Übersetzen Sie das Bild zurück. dh

myMatrix
  .translate(image.width / 2, image.height / 2)    // 3
  .scale(xFactor, yFactor)                         // 2
  .translate(-image.width / 2, -image.height / 2); // 1

Noch abstrakter funktioniert dieselbe Strategie für jeden Punkt. Wenn Sie beispielsweise das Bild an einem Punkt P skalieren möchten:

myMatrix
  .translate(P.x, P.y)
  .scale(xFactor, yFactor)
  .translate(-P.x, -P.y);

Und wenn das Bild bereits auf irgendeine Weise transformiert wurde (z. B. wenn es gedreht, verzerrt, übersetzt oder skaliert wurde), muss die aktuelle Transformation beibehalten werden. Insbesondere muss die oben definierte Transformation mit der aktuellen Transformation nachmultipliziert (oder rechtsmultipliziert) werden.

myMatrix
  .translate(P.x, P.y)
  .scale(xFactor, yFactor)
  .translate(-P.x, -P.y)
  .multiply(myMatrix);

Hier hast du es. Hier ist ein Plunk, der dies in Aktion zeigt. Scrollen Sie mit dem Mausrad auf den Punkten und Sie werden sehen, dass sie konstant stehen bleiben. (Nur in Chrome getestet.) Http://plnkr.co/edit/3aqsWHPLlSXJ9JCcJzgH?p=preview

avejidah
quelle
1
Ich muss sagen, wenn Ihnen eine affine Transformationsmatrix zur Verfügung steht, verwenden Sie diese mit Begeisterung. Viele Transformationsmatrizen haben sogar Zoomfunktionen (sx, sy, x, y), die genau das tun. Es lohnt sich fast, einen zu kochen, wenn Sie keinen haben, den Sie verwenden können.
Tatarize
Tatsächlich gestehe ich, dass der Code, in dem ich diese Lösung verwendet habe, seitdem durch eine Matrixklasse ersetzt wurde. Und genau das habe ich mehrmals gemacht und Matrixklassen nicht weniger als zweimal zusammengestellt. ( github.com/EmbroidePy/pyembroidery/blob/master/pyembroidery/… ), ( github.com/EmbroidePy/EmbroidePy/blob/master/embroidepy/… ). Wenn Sie etwas Komplexeres als genau diese Operationen wünschen, ist eine Matrix im Grunde die richtige Antwort. Sobald Sie die lineare Algebra im Griff haben, erkennen Sie, dass diese Antwort tatsächlich die beste Antwort ist.
Tatarize
6

Hier ist meine Lösung für ein zentrumsorientiertes Bild:

var MIN_SCALE = 1;
var MAX_SCALE = 5;
var scale = MIN_SCALE;

var offsetX = 0;
var offsetY = 0;

var $image     = $('#myImage');
var $container = $('#container');

var areaWidth  = $container.width();
var areaHeight = $container.height();

$container.on('wheel', function(event) {
    event.preventDefault();
    var clientX = event.originalEvent.pageX - $container.offset().left;
    var clientY = event.originalEvent.pageY - $container.offset().top;

    var nextScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, scale - event.originalEvent.deltaY / 100));

    var percentXInCurrentBox = clientX / areaWidth;
    var percentYInCurrentBox = clientY / areaHeight;

    var currentBoxWidth  = areaWidth / scale;
    var currentBoxHeight = areaHeight / scale;

    var nextBoxWidth  = areaWidth / nextScale;
    var nextBoxHeight = areaHeight / nextScale;

    var deltaX = (nextBoxWidth - currentBoxWidth) * (percentXInCurrentBox - 0.5);
    var deltaY = (nextBoxHeight - currentBoxHeight) * (percentYInCurrentBox - 0.5);

    var nextOffsetX = offsetX - deltaX;
    var nextOffsetY = offsetY - deltaY;

    $image.css({
        transform : 'scale(' + nextScale + ')',
        left      : -1 * nextOffsetX * nextScale,
        right     : nextOffsetX * nextScale,
        top       : -1 * nextOffsetY * nextScale,
        bottom    : nextOffsetY * nextScale
    });

    offsetX = nextOffsetX;
    offsetY = nextOffsetY;
    scale   = nextScale;
});
body {
    background-color: orange;
}
#container {
    margin: 30px;
    width: 500px;
    height: 500px;
    background-color: white;
    position: relative;
    overflow: hidden;
}
img {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    max-width: 100%;
    max-height: 100%;
    margin: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="container">
    <img id="myImage" src="http://s18.postimg.org/eplac6dbd/mountain.jpg">
</div>

Chris
quelle
4

Hier ist eine alternative Methode, bei der setTransform () anstelle von scale () und translate () verwendet wird. Alles ist im selben Objekt gespeichert. Es wird angenommen, dass sich die Zeichenfläche auf der Seite bei 0,0 befindet. Andernfalls müssen Sie ihre Position von den Seitenkoordinaten abziehen.

this.zoomIn = function (pageX, pageY) {
    var zoomFactor = 1.1;
    this.scale = this.scale * zoomFactor;
    this.lastTranslation = {
        x: pageX - (pageX - this.lastTranslation.x) * zoomFactor,
        y: pageY - (pageY - this.lastTranslation.y) * zoomFactor
    };
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    this.lastTranslation.x,
                                    this.lastTranslation.y);
};
this.zoomOut = function (pageX, pageY) {
    var zoomFactor = 1.1;
    this.scale = this.scale / zoomFactor;
    this.lastTranslation = {
        x: pageX - (pageX - this.lastTranslation.x) / zoomFactor,
        y: pageY - (pageY - this.lastTranslation.y) / zoomFactor
    };
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    this.lastTranslation.x,
                                    this.lastTranslation.y);
};

Begleitcode für das Schwenken:

this.startPan = function (pageX, pageY) {
    this.startTranslation = {
        x: pageX - this.lastTranslation.x,
        y: pageY - this.lastTranslation.y
    };
};
this.continuePan = function (pageX, pageY) {
    var newTranslation = {x: pageX - this.startTranslation.x,
                          y: pageY - this.startTranslation.y};
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    newTranslation.x, newTranslation.y);
};
this.endPan = function (pageX, pageY) {
    this.lastTranslation = {
        x: pageX - this.startTranslation.x,
        y: pageY - this.startTranslation.y
    };
};

Um die Antwort selbst abzuleiten, müssen Sie berücksichtigen, dass dieselben Seitenkoordinaten vor und nach dem Zoom mit denselben Canvas-Koordinaten übereinstimmen müssen. Dann können Sie ausgehend von dieser Gleichung eine Algebra machen:

(pageCoords - Übersetzung) / scale = canvasCoords

Tschad
quelle
3

Ich möchte hier einige Informationen für diejenigen einfügen, die Bilder separat zeichnen und bewegen - zoomen.

Dies kann nützlich sein, wenn Sie Zooms und die Position des Ansichtsfensters speichern möchten.

Hier ist Schublade:

function redraw_ctx(){
   self.ctx.clearRect(0,0,canvas_width, canvas_height)
   self.ctx.save()
   self.ctx.scale(self.data.zoom, self.data.zoom) // 
   self.ctx.translate(self.data.position.left, self.data.position.top) // position second
   // Here We draw useful scene My task - image:
   self.ctx.drawImage(self.img ,0,0) // position 0,0 - we already prepared
   self.ctx.restore(); // Restore!!!
}

Hinweis Skala muss zuerst sein .

Und hier ist Zoomer:

function zoom(zf, px, py){
    // zf - is a zoom factor, which in my case was one of (0.1, -0.1)
    // px, py coordinates - is point within canvas 
    // eg. px = evt.clientX - canvas.offset().left
    // py = evt.clientY - canvas.offset().top
    var z = self.data.zoom;
    var x = self.data.position.left;
    var y = self.data.position.top;

    var nz = z + zf; // getting new zoom
    var K = (z*z + z*zf) // putting some magic

    var nx = x - ( (px*zf) / K ); 
    var ny = y - ( (py*zf) / K);

    self.data.position.left = nx; // renew positions
    self.data.position.top = ny;   
    self.data.zoom = nz; // ... and zoom
    self.redraw_ctx(); // redraw context
    }

und natürlich brauchen wir einen schlepper:

this.my_cont.mousemove(function(evt){
    if (is_drag){
        var cur_pos = {x: evt.clientX - off.left,
                       y: evt.clientY - off.top}
        var diff = {x: cur_pos.x - old_pos.x,
                    y: cur_pos.y - old_pos.y}

        self.data.position.left += (diff.x / self.data.zoom);  // we want to move the point of cursor strictly
        self.data.position.top += (diff.y / self.data.zoom);

        old_pos = cur_pos;
        self.redraw_ctx();

    }


})
Vasiliy Stavenko
quelle
3
if(wheel > 0) {
    this.scale *= 1.1; 
    this.offsetX -= (mouseX - this.offsetX) * (1.1 - 1);
    this.offsetY -= (mouseY - this.offsetY) * (1.1 - 1);
}
else {
    this.scale *= 1/1.1; 
    this.offsetX -= (mouseX - this.offsetX) * (1/1.1 - 1);
    this.offsetY -= (mouseY - this.offsetY) * (1/1.1 - 1);
}
Daniel
quelle
2

Hier ist eine Code-Implementierung der Antwort von @ tatarize unter Verwendung von PIXI.js. Ich habe ein Ansichtsfenster, das einen Teil eines sehr großen Bildes betrachtet (z. B. Google Maps-Stil).

$canvasContainer.on('wheel', function (ev) {

    var scaleDelta = 0.02;
    var currentScale = imageContainer.scale.x;
    var nextScale = currentScale + scaleDelta;

    var offsetX = -(mousePosOnImage.x * scaleDelta);
    var offsetY = -(mousePosOnImage.y * scaleDelta);

    imageContainer.position.x += offsetX;
    imageContainer.position.y += offsetY;

    imageContainer.scale.set(nextScale);

    renderer.render(stage);
});
  • $canvasContainer ist mein HTML-Container.
  • imageContainer ist mein PIXI-Container, der das Bild enthält.
  • mousePosOnImage ist die Mausposition relativ zum gesamten Bild (nicht nur zum Ansichtsfenster).

So habe ich die Mausposition erhalten:

  imageContainer.on('mousemove', _.bind(function(ev) {
    mousePosOnImage = ev.data.getLocalPosition(imageContainer);
    mousePosOnViewport.x = ev.data.originalEvent.offsetX;
    mousePosOnViewport.y = ev.data.originalEvent.offsetY;
  },self));
Mirror318
quelle
0

Sie müssen den Punkt im Weltraum (im Gegensatz zum Bildschirmbereich) vor und nach dem Zoomen ermitteln und dann durch das Delta übersetzen.

mouse_world_position = to_world_position(mouse_screen_position);
zoom();
mouse_world_position_new = to_world_position(mouse_screen_position);
translation += mouse_world_position_new - mouse_world_position;

Die Mausposition befindet sich im Bildschirmbereich, daher müssen Sie sie in den Weltraum umwandeln. Die einfache Transformation sollte folgendermaßen aussehen:

world_position = screen_position / scale - translation
Enhex
quelle
0

Mit der Funktion scrollto (x, y) können Sie die Position der Bildlaufleiste bis zu dem Punkt behandeln, der nach dem Zoomen angezeigt werden muss. Um die Position der Maus zu ermitteln, verwenden Sie event.clientX und event.clientY. das wird dir helfen

Mamo Gandhi
quelle
0

Eine wichtige Sache ... wenn Sie etwas haben wie:

body {
  zoom: 0.9;
}

Sie müssen das Äquivalente auf Leinwand machen:

canvas {
  zoom: 1.1;
}
Lucas Moyano Angelini
quelle