Zoom avant sur un point (en utilisant l'échelle et la translation)

156

Je veux pouvoir zoomer sur le point sous la souris dans un canevas HTML 5, comme un zoom sur Google Maps . Comment puis-je y parvenir?

csiz
la source
2
Je l'ai utilisé pour zoomer sur ma toile et cela fonctionne très bien! La seule chose que je dois ajouter est que le calcul du montant du zoom n'est pas ce à quoi vous vous attendez. "var zoom = 1 + roue / 2;" c'est-à-dire que cela donne 1,5 pour le zoom avant et 0,5 pour le zoom arrière. J'ai modifié ceci dans ma version afin d'avoir 1,5 pour le zoom avant et 1 / 1,5 pour le zoom arrière, ce qui rend la quantité de zoom avant et de zoom arrière égale. Donc, si vous effectuez un zoom avant et un zoom arrière, vous aurez la même image qu'avant le zoom.
Chris
2
Notez que cela ne fonctionne pas sur Firefox, mais la méthode peut facilement être appliquée au plugin jQuery mousewheel . Merci d'avoir partagé!
johndodo
2
var zoom = Math.pow (1.5f, roue); // Utilisez ceci pour calculer le zoom. Il présente l'avantage que le zoom avec roue = 2 équivaut à zoomer deux fois avec roue = 1. De plus, un zoom avant de +2 et un zoom arrière de +2 rétablit l'échelle d'origine.
Matt

Réponses:

126

La meilleure solution consiste simplement à déplacer la position de la fenêtre en fonction de la modification du zoom. Le point de zoom est simplement le point de l'ancien zoom et du nouveau zoom que vous souhaitez conserver. C'est-à-dire que la fenêtre pré-zoomée et la fenêtre post-zoomée ont le même point de zoom par rapport à la fenêtre. Étant donné que nous mettons à l'échelle par rapport à l'origine. Vous pouvez ajuster la position de la fenêtre en conséquence:

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

Donc, vraiment, vous pouvez simplement faire un panoramique vers le bas et vers la droite lorsque vous effectuez un zoom avant, en fonction du facteur de zoom avant, par rapport au point sur lequel vous avez zoomé.

entrez la description de l'image ici

Tatarize
la source
2
Plus précieuse que le copier-coller du code est l'explication de la meilleure solution et de la raison pour laquelle elle fonctionne sans bagage, surtout s'il fait trois lignes.
Tatarize le
2
scalechange = newscale / oldscale?
Tejesh Alimilli
4
aussi, je voudrais ajouter pour ceux qui cherchent à obtenir une carte comme un composant pan-zoom, que la souris X, Y devrait être (mousePosRelativeToContainer - currentTransform) / currentScale sinon elle traitera la position actuelle de la souris comme relative au conteneur.
Gilad
1
Oui, ce calcul suppose que le zoom ainsi que le panoramique sont dans les coordonnées correspondant à l'origine. S'ils sont relatifs à la fenêtre, vous devez les ajuster de manière appropriée. Bien que je suppose que le calcul correct est zoomPoint = (mousePosRelativeToContainer + currentTranslation). Ce calcul suppose également que le point d'origine se trouve généralement dans le coin supérieur gauche du champ. Mais, s'adapter à des situations légèrement atypiques est beaucoup plus facile compte tenu de la simplicité.
Tatarize le
1
@ C.Finke La deuxième façon de procéder est d'utiliser les traductions dans le ctx. Vous dessinez tout de la même taille et dans les mêmes positions. Mais, vous utilisez simplement les multiplications matricielles dans le canevas javascript pour définir le panoramique et l'échelle (zoom) du contexte. Donc plutôt que de redessiner toutes les formes dans un endroit différent. Vous les dessinez au même endroit et déplacez la fenêtre dans javascript. Cette méthode nécessiterait également que vous preniez les événements de la souris et les traduisiez à l'envers. Donc, vous soustrayez le panoramique, puis inversez le facteur par le zoom.
Tatarize le
68

Enfin résolu:

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>

La clé, comme l' a souligné @Tatarize , est de calculer la position de l'axe de telle sorte que le point de zoom (pointeur de la souris) reste au même endroit après le zoom.

À l'origine, la souris est à une distance mouse/scaledu coin, nous voulons que le point sous la souris reste au même endroit après le zoom, mais celui-ci est mouse/new_scaleéloigné du coin. Par conséquent, nous devons décaler les origin(coordonnées du coin) pour en tenir compte.

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

Le code restant doit ensuite appliquer la mise à l'échelle et se traduire dans le contexte de dessin afin que son origine coïncide avec le coin du canevas.

csiz
la source
Merci mec, presque perdu 2 jours, avant de trouver votre code
Velaro le
Hé, je cherchais juste quelque chose comme ça et je voulais juste dire que tu as craqué!
chrisallick
26

C'est en fait un problème très difficile (mathématiquement), et je travaille presque sur la même chose. J'ai posé une question similaire sur Stackoverflow mais je n'ai obtenu aucune réponse, mais j'ai posté dans DocType (StackOverflow pour HTML / CSS) et j'ai obtenu une réponse. Découvrez-le http://doctype.com/javascript-image-zoom-css3-transforms-calculate-origin-example

Je suis en train de créer un plugin jQuery qui fait cela (zoom de style Google Maps à l'aide des transformations CSS3). J'ai le zoom sur le curseur de la souris qui fonctionne bien, en essayant toujours de comprendre comment permettre à l'utilisateur de faire glisser la toile comme vous pouvez le faire dans Google Maps. Quand je le ferai fonctionner, je publierai le code ici, mais consultez le lien ci-dessus pour la partie souris-zoom-point.

Je ne savais pas qu'il y avait des méthodes de mise à l'échelle et de traduction sur le contexte de Canvas, vous pouvez obtenir la même chose en utilisant CSS3 par exemple. en utilisant 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)');

Assurez-vous de définir l'origine de la transformation CSS3 sur 0, 0 (-moz-transform-origin: 0 0). L'utilisation de la transformation CSS3 vous permet de zoomer sur n'importe quoi, assurez-vous simplement que le conteneur DIV est défini sur overflow: hidden pour empêcher les bords zoomés de se répandre sur les côtés.

Que vous utilisiez les transformations CSS3 ou les propres méthodes de mise à l'échelle et de traduction du canevas dépend de vous, mais vérifiez le lien ci-dessus pour les calculs.


Mise à jour: Meh! Je vais simplement poster le code ici plutôt que de vous faire suivre un lien:

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

Vous devrez bien sûr l'adapter pour utiliser l'échelle du canevas et les méthodes de traduction.


Mise à jour 2: Je viens de remarquer que j'utilise transform-origin avec translate. J'ai réussi à mettre en œuvre une version qui utilise simplement l'échelle et la traduction seule, vérifiez-la ici http://www.dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html Attendez que les images soient téléchargées puis utilisez votre molette de la souris pour zoomer, prend également en charge le panoramique en faisant glisser l'image autour. Il utilise des transformations CSS3, mais vous devriez pouvoir utiliser les mêmes calculs pour votre canevas.

Dimanche Ironfoot
la source
Je l'ai finalement résolu, il m'a fallu 3 minutes maintenant après environ 2 semaines de faire autre chose
csiz
Le lien @Synday Ironfoot sur sa mise à jour ne fonctionne pas. Ce lien: dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html je veux cette impelementation. Pouvez-vous poster ici le code? merci
Bogz
2
à partir d'aujourd'hui (septembre 2014), le lien vers MosaicTest.html est mort.
Chris
la démo de mosaïque est partie. J'utilise généralement vanilla js et non jQuery. à quoi fait référence $ (this)? le document.body.offsetTop? Je veux vraiment voir la démo de la mosaïque que mon projet foreverscape.com pourrait vraiment en profiter.
FlavorScape
2
La page de démonstration de la mosaïque est enregistrée sur archive.org: web.archive.org/web/20130126152008/http
Chris
9

J'ai rencontré ce problème en utilisant C ++, que je n'aurais probablement pas dû avoir Je viens d'utiliser des matrices OpenGL pour commencer ... de toute façon, si vous utilisez un contrôle dont l'origine est le coin supérieur gauche, et que vous voulez un panoramique / zoom comme google maps, voici la mise en page (en utilisant allegro comme gestionnaire d'événements):

// 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
la source
9

J'aime la réponse de Tatarize , mais je vais proposer une alternative. C'est un problème trivial d'algèbre linéaire, et la méthode que je présente fonctionne bien avec le panoramique, le zoom, l'inclinaison, etc. Autrement dit, cela fonctionne bien si votre image est déjà transformée.

Lorsqu'une matrice est mise à l'échelle, l'échelle est au point (0, 0). Donc, si vous avez une image et que vous la mettez à l'échelle d'un facteur 2, le point en bas à droite doublera dans les directions x et y (en utilisant la convention selon laquelle [0, 0] est le coin supérieur gauche de l'image).

Si, à la place, vous souhaitez agrandir l'image autour du centre, la solution est la suivante: (1) traduisez l'image de telle sorte que son centre soit à (0, 0); (2) mettre l'image à l'échelle par des facteurs x et y; (3) traduire l'image en arrière. c'est à dire

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

Plus abstraitement, la même stratégie fonctionne pour n'importe quel point. Si, par exemple, vous souhaitez mettre l'image à l'échelle en un point P:

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

Et enfin, si l'image est déjà transformée d'une manière ou d'une autre (par exemple, si elle est tournée, inclinée, traduite ou mise à l'échelle), la transformation actuelle doit être préservée. Plus précisément, la transformation définie ci-dessus doit être post-multipliée (ou multipliée à droite) par la transformation actuelle.

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

Voilà. Voici un plunk qui montre cela en action. Faites défiler avec la molette de la souris sur les points et vous verrez qu'ils restent toujours en place. (Testé dans Chrome uniquement.) Http://plnkr.co/edit/3aqsWHPLlSXJ9JCcJzgH?p=preview

Avejidah
la source
1
Je dois dire que si vous disposez d'une matrice de transformation affine, utilisez-la avec enthousiasme. De nombreuses matrices de transformation auront même des fonctions de zoom (sx, sy, x, y) qui font exactement cela. Cela vaut presque la peine d'en préparer un si vous n'en avez pas besoin.
Tatarize
En fait, j'avoue que dans le code dans lequel j'ai utilisé cette solution, elle a depuis été remplacée par une classe de matrice. Et j'ai fait cette chose exacte plusieurs fois et j'ai concocté des classes matricielles pas moins de deux fois. ( github.com/EmbroidePy/pyembroidery/blob/master/pyembroidery/… ), ( github.com/EmbroidePy/EmbroidePy/blob/master/embroidepy/… ). Si vous voulez quelque chose de plus complexe que ces opérations, une matrice est fondamentalement la bonne réponse et une fois que vous avez une poignée sur l'algèbre linéaire, vous réalisez que cette réponse est en fait la meilleure réponse.
Tatarize
6

Voici ma solution pour une image centrée:

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
la source
4

Voici une autre façon de le faire qui utilise setTransform () au lieu de scale () et translate (). Tout est stocké dans le même objet. Le canevas est supposé être à 0,0 sur la page, sinon vous devrez soustraire sa position des coordonnées de la page.

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

Code d'accompagnement pour gérer le panoramique:

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

Pour obtenir la réponse vous-même, considérez que les mêmes coordonnées de page doivent correspondre aux mêmes coordonnées de canevas avant et après le zoom. Ensuite, vous pouvez faire de l'algèbre à partir de cette équation:

(pageCoords - translation) / scale = canvasCoords

tchad
la source
3

Je veux mettre ici quelques informations pour ceux qui font séparément le dessin de l'image et le zoom en mouvement.

Cela peut être utile lorsque vous souhaitez stocker des zooms et la position de la fenêtre.

Voici le tiroir:

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

L' échelle de notification DOIT être la première .

Et voici 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
    }

et, bien sûr, nous aurions besoin d'un 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();

    }


})
Vasiliy Stavenko
la source
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
la source
2

Voici une implémentation de code de la réponse de @ tatarize, en utilisant PIXI.js. J'ai une fenêtre qui regarde une partie d'une très grande image (par exemple le style 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 est mon conteneur html.
  • imageContainer est mon conteneur PIXI qui contient l'image.
  • mousePosOnImage est la position de la souris par rapport à l'image entière (pas seulement le port de vue).

Voici comment j'ai obtenu la position de la souris:

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

Vous devez obtenir le point dans l'espace mondial (par opposition à l'espace écran) avant et après le zoom, puis traduire par le delta.

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;

La position de la souris est dans l'espace d'écran, vous devez donc la transformer en espace mondial. La transformation simple devrait être similaire à ceci:

world_position = screen_position / scale - translation
Enhex
la source
0

vous pouvez utiliser la fonction scrollto (x, y) pour gérer la position de la barre de défilement jusqu'au point que vous devez afficher après le zoom.pour trouver la position de la souris, utilisez event.clientX et event.clientY. cela t'aidera

Mamo Ghandi
la source
0

Une chose importante ... si vous avez quelque chose comme:

body {
  zoom: 0.9;
}

Vous devez faire la chose équivalente dans la toile:

canvas {
  zoom: 1.1;
}
Lucas Moyano Angelini
la source