Powiększ punkt (używając skali i translacji)

156

Chcę mieć możliwość powiększenia punktu znajdującego się pod myszą na płótnie HTML 5, tak jak w Mapach Google . Jak mogę to osiągnąć?

csiz
źródło
2
Użyłem tego do powiększenia mojego płótna i działa świetnie! Jedyne, co muszę dodać, to to, że obliczenie wielkości zoomu nie jest takie, jakiego można się spodziewać. "var zoom = 1 + wheel / 2;" tzn. daje to 1,5 dla powiększenia i 0,5 dla pomniejszenia. Edytowałem to w mojej wersji tak, że mam 1,5 do powiększania i 1 / 1,5 do pomniejszania, co sprawia, że ​​wielkość powiększania i pomniejszania jest równa. Więc jeśli powiększysz raz i powiększysz wstecz, otrzymasz ten sam obraz, co przed powiększeniem.
Chris,
2
Zauważ, że to nie działa w przeglądarce Firefox, ale metodę można łatwo zastosować do wtyczki jQuery mousewheel . Dzięki za udostępnienie!
johndodo
2
var zoom = Math.pow (1.5f, kółko); // Użyj tego do obliczenia powiększenia. Ma tę zaletę, że powiększanie o koło = 2 jest tym samym, co dwukrotne powiększanie o koło = 1. Ponadto powiększenie o +2 i pomniejszenie o +2 przywraca oryginalną skalę.
Matt,

Odpowiedzi:

126

Lepszym rozwiązaniem jest po prostu przesunięcie pozycji rzutni na podstawie zmiany powiększenia. Punkt powiększenia to po prostu punkt w starym powiększeniu i nowym powiększeniu, który ma pozostać taki sam. To znaczy, że rzutnia powiększona wstępnie i rzutnia powiększona po powiększeniu mają ten sam punkt powiększenia w stosunku do rzutni. Biorąc pod uwagę, że skalujemy się w stosunku do pochodzenia. Możesz odpowiednio dostosować położenie rzutni:

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

Tak naprawdę możesz po prostu przesuwać w dół iw prawo podczas powiększania, o współczynnik powiększenia, w stosunku do punktu, w którym powiększyłeś.

wprowadź opis obrazu tutaj

Tatarize
źródło
2
Bardziej wartościowe niż kod „wytnij i wklej” jest wyjaśnienie, jakie jest najlepsze rozwiązanie i dlaczego działa bez bagażu, zwłaszcza jeśli ma on trzy wiersze.
Tatarize
2
scalechange = newscale / oldscale?
Tejesh Alimilli
4
chciałbym również dodać dla tych, którzy chcą uzyskać mapę taką jak komponent pan-zoom, że mysz X, Y powinna być (mousePosRelativeToContainer - currentTransform) / currentScale, w przeciwnym razie potraktuje bieżącą pozycję myszy jako względem kontenera.
Gilad
1
Tak, ta matematyka zakłada, że ​​zarówno powiększenie, jak i panorama znajdują się we współrzędnych odpowiednich dla początku. Jeśli odnoszą się do rzutni, należy je odpowiednio dostosować. Chociaż przypuszczam, że poprawna matematyka to zoomPoint = (mousePosRelativeToContainer + currentTranslation). Ta matematyka zakłada również, że punkt początkowy znajduje się zwykle w lewym górnym rogu pola. Jednak dostosowanie się do nieco nietypowych sytuacji jest znacznie łatwiejsze, biorąc pod uwagę prostotę.
Tatarize
1
@ C.Finke Drugim sposobem, w jaki można to zrobić, jest użycie tłumaczeń w ctx. Rysujesz wszystko tego samego rozmiaru i w tych samych pozycjach. Ale po prostu używasz mnożenia macierzy w kanwie JavaScript, aby ustawić panoramę i skalę (powiększenie) kontekstu. Więc zamiast przerysowywać wszystkie kształty w innym miejscu. Rysujesz je w tym samym miejscu i przesuwasz rzutnię w javascript. Ta metoda wymagałaby również wzięcia zdarzeń myszy i przetłumaczenia ich wstecz. Więc odejmowałbyś panoramę, a następnie odwracał współczynnik o powiększenie.
Tatarize
67

Wreszcie rozwiązałem to:

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>

Kluczem, jak wskazał @Tatarize , jest obliczenie pozycji osi w taki sposób, aby punkt powiększenia (wskaźnik myszy) pozostał w tym samym miejscu po powiększeniu.

Oryginalnie mysz jest w pewnej odległości mouse/scaleod rogu, chcemy, aby punkt pod myszą pozostał w tym samym miejscu po powiększeniu, ale jest to z mouse/new_scaledala od rogu. Dlatego musimy przesunąć origin(współrzędne narożnika), aby to uwzględnić.

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

Pozostały kod musi następnie zastosować skalowanie i przetłumaczyć na kontekst rysowania, aby jego początek pokrywał się z rogiem płótna.

csiz
źródło
Dziękuję stary, prawie straciłem 2 dni, zanim znalazłem kod
Velaro
Hej, właśnie szukałem czegoś takiego i chciałem tylko powiedzieć, że podekscytowany, że to złamałeś!
chrisallick
26

W rzeczywistości jest to bardzo trudny problem (matematycznie) i pracuję prawie nad tym samym. Zadałem podobne pytanie na Stackoverflow, ale nie otrzymałem odpowiedzi, ale wysłałem je w DocType (StackOverflow dla HTML / CSS) i otrzymałem odpowiedź. Sprawdź to http://doctype.com/javascript-image-zoom-css3-transforms-calculate-origin-example

Jestem w trakcie tworzenia wtyczki jQuery, która to robi (zoom w stylu Google Maps przy użyciu transformacji CSS3). Mam trochę powiększenie do kursora myszy, ale wciąż próbuję wymyślić, jak pozwolić użytkownikowi przeciągać płótno, tak jak można to zrobić w Mapach Google. Kiedy zacznę działać, wyślę tutaj kod, ale sprawdź powyższy link, aby uzyskać część dotyczącą powiększania myszą do punktu.

Nie zdawałem sobie sprawy, że istnieją metody skalowania i tłumaczenia w kontekście Canvas, możesz osiągnąć to samo używając CSS3 np. przy użyciu 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)');

Upewnij się, że ustawiłeś początek transformacji CSS3 na 0, 0 (-moz-transform-origin: 0 0). Korzystanie z transformacji CSS3 umożliwia powiększanie wszystkiego, po prostu upewnij się, że kontener DIV jest ustawiony na przepełnienie: ukryty, aby powiększone krawędzie nie wysypywały się z boków.

Niezależnie od tego, czy używasz transformacji CSS3, czy własnych metod skalowania i translacji kanwy, zależy od Ciebie, ale sprawdź powyższe łącze, aby uzyskać obliczenia.


Aktualizacja: Meh! Po prostu opublikuję kod tutaj, zamiast skłaniać Cię do podążania za linkiem:

$(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;
    });
});

Będziesz oczywiście musiał dostosować go do użycia skali płótna i metod tłumaczenia.


Aktualizacja 2: Właśnie zauważyłem, że używam transform-origin razem z translate. Udało mi się zaimplementować wersję, która po prostu używa skali i samodzielnie tłumaczy, sprawdź to tutaj http://www.dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html Poczekaj na pobranie obrazów, a następnie użyj kółko myszy do powiększania, obsługuje również przesuwanie przez przeciąganie obrazu. Używa transformacji CSS3, ale powinieneś być w stanie użyć tych samych obliczeń dla swojego płótna.

Niedziela Ironfoot
źródło
w końcu to rozwiązałem, zajęło mi to 3 minuty po około 2 tygodniach robienia czegoś innego
csiz
Link @Synday Ironfoot w jego aktualizacji nie działa. Ten link: dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html Chcę tego impelementacji. Czy możesz zamieścić tutaj kod? dzięki
Bogz
2
na dzień dzisiejszy (wrzesień 2014) link do MosaicTest.html jest martwy.
Chris,
demo mozaiki zniknęło. Zwykle używam vanilla js, a nie jQuery. do czego się odnosi $ (this)? document.body.offsetTop? Naprawdę chcę zobaczyć demo mozaiki, na którym mój projekt foreverscape.com mógłby naprawdę skorzystać na tym.
FlavorScape
2
Strona demonstracyjna mozaiki została zapisana na archive.org: web.archive.org/web/20130126152008/http://…
Chris
9

Natknąłem się na ten problem przy użyciu c ++, którego prawdopodobnie nie powinienem był po prostu użyć macierzy OpenGL na początek ... w każdym razie, jeśli używasz kontrolki, której źródłem jest lewy górny róg i chcesz przesuwać / powiększać podobnie jak mapy google, oto układ (używając allegro jako mojej obsługi zdarzeń):

// 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
źródło
9

Podoba mi się odpowiedź Tatarize , ale podam alternatywę. Jest to trywialny problem z algebry liniowej, a metoda, którą przedstawiam, działa dobrze z panoramowaniem, powiększaniem, pochylaniem itp. Oznacza to, że działa dobrze, jeśli obraz jest już przekształcony.

Gdy macierz jest skalowana, skala znajduje się w punkcie (0, 0). Tak więc, jeśli masz obraz i przeskalujesz go 2-krotnie, prawy dolny punkt podwoi się w obu kierunkach (zgodnie z konwencją, że [0, 0] to lewy górny róg obrazu).

Jeśli zamiast tego chcesz powiększyć obraz wokół środka, rozwiązanie jest następujące: (1) przesuń obraz tak, aby jego środek znajdował się w punkcie (0, 0); (2) przeskaluj obraz za pomocą współczynników x i y; (3) przetłumaczyć obraz z powrotem. to znaczy

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

Mówiąc bardziej abstrakcyjnie, ta sama strategia działa w każdym punkcie. Jeśli na przykład chcesz przeskalować obraz w punkcie P:

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

I wreszcie, jeśli obraz jest już w jakiś sposób przekształcony (na przykład, jeśli jest obrócony, pochylony, przesunięty lub przeskalowany), to bieżąca transformacja musi zostać zachowana. W szczególności transformacja zdefiniowana powyżej musi zostać pomnożona post (lub pomnożona w prawo) przez transformację prądową.

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

Masz to. Oto plunk, który pokazuje to w akcji. Przewiń kółkiem myszy na kropkach, a zobaczysz, że konsekwentnie pozostają na miejscu. (Testowane tylko w Chrome). Http://plnkr.co/edit/3aqsWHPLlSXJ9JCcJzgH?p=preview

avejidah
źródło
1
Muszę powiedzieć, że jeśli masz dostępną macierz transformacji afinicznej, używaj jej z entuzjazmem. Wiele macierzy transformacji będzie miało nawet funkcje zoom (sx, sy, x, y), które dokładnie to robią. Prawie warto go ugotować, jeśli nie masz go do użycia.
Tatarize
Tak naprawdę przyznaję, że w kodzie, w którym zastosowałem to rozwiązanie, zostało ono od tego czasu zastąpione klasą matrix. Robiłem to dokładnie wiele razy i przygotowałem klasy macierzy nie mniej niż dwa razy. ( github.com/EmbroidePy/pyembroidery/blob/master/pyembroidery/… ), ( github.com/EmbroidePy/EmbroidePy/blob/master/embroidepy/ ... ). Jeśli chcesz czegoś bardziej złożonego niż dokładnie te operacje, macierz jest w zasadzie poprawną odpowiedzią, a kiedy już opanujesz algebrę liniową, zdasz sobie sprawę, że ta odpowiedź jest w rzeczywistości najlepszą odpowiedzią.
Tatarize
6

Oto moje rozwiązanie dla obrazu zorientowanego na środek:

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
źródło
4

Oto alternatywny sposób na zrobienie tego, który używa setTransform () zamiast scale () i translate (). Wszystko jest przechowywane w tym samym obiekcie. Zakłada się, że płótno znajduje się w punkcie 0,0 na stronie, w przeciwnym razie będziesz musiał odjąć jego pozycję od współrzędnych strony.

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

Towarzyszący kod do obsługi panoramowania:

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

Aby samodzielnie uzyskać odpowiedź, weź pod uwagę, że te same współrzędne strony muszą odpowiadać tym samym współrzędnym kanwy przed i po powiększeniu. Następnie możesz wykonać algebrę, zaczynając od tego równania:

(pageCoords - tłumaczenie) / scale = canvasCoords

czad
źródło
3

Chcę tu zamieścić kilka informacji dla tych, którzy wykonują oddzielnie rysowanie obrazu i przenoszenie - powiększanie go.

Może to być przydatne, gdy chcesz przechowywać powiększenia i położenie rzutni.

Oto szuflada:

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

Uwaga: skala MUSI być pierwsza .

A oto 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
    }

i oczywiście potrzebowalibyśmy dragger:

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();

    }


})
Wasilij Stavenko
źródło
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
źródło
2

Oto implementacja kodu odpowiedzi @ tatarize przy użyciu PIXI.js. Mam okno robocze, które patrzy na część bardzo dużego obrazu (np. W stylu Google Maps).

$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 jest moim kontenerem html.
  • imageContainer to mój kontener PIXI, w którym znajduje się obraz.
  • mousePosOnImage to pozycja myszy względem całego obrazu (nie tylko portu widoku).

Oto jak uzyskałem pozycję myszy:

  imageContainer.on('mousemove', _.bind(function(ev) {
    mousePosOnImage = ev.data.getLocalPosition(imageContainer);
    mousePosOnViewport.x = ev.data.originalEvent.offsetX;
    mousePosOnViewport.y = ev.data.originalEvent.offsetY;
  },self));
Lustro318
źródło
0

Musisz uzyskać punkt w przestrzeni świata (w przeciwieństwie do przestrzeni ekranu) przed i po powiększeniu, a następnie przetłumaczyć przez deltę.

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;

Pozycja myszy jest w przestrzeni ekranu, więc musisz ją przekształcić w przestrzeń świata. Proste przekształcenie powinno wyglądać podobnie do tego:

world_position = screen_position / scale - translation
Enhex
źródło
0

możesz użyć funkcji scrollto (x, y), aby obsłużyć położenie paska przewijania w prawo do punktu, który ma zostać pokazany po powiększeniu. do znalezienia pozycji myszy użyj event.clientX i event.clientY. to ci pomoże

Mamo Ghandi
źródło
0

Jedna ważna rzecz ... jeśli masz coś takiego:

body {
  zoom: 0.9;
}

Musisz zrobić coś równoważnego w płótnie:

canvas {
  zoom: 1.1;
}
Lucas Moyano Angelini
źródło