Le Zoom de l'image sur le curseur se brise lorsque la souris est déplacée

il s'agit d'une question de suivi à comment zoomer sur le pointeur de la souris en utilisant mon propre smoothscroll?

j'utilise CSS transforme pour zoomer une image sur le pointeur de la souris. J'utilise aussi mon propre algorithme smooth scroll pour interpoler et donner de l'élan à la mouse.

avec L'aide de Bali Balo dans ma question précédente, j'ai réussi à obtenir 90% du chemin.

vous pouvez maintenant zoomez l'image jusqu'au pointeur de la souris tout en continuant à faire défiler en douceur comme L'illustre le JSFiddle suivant:

http://jsfiddle.net/qGGwx/7 /

cependant, la fonctionnalité est brisée lorsque le pointeur de la souris est déplacé.

pour plus de clarté, si je zoome d'un cran sur la souris, l'image est zoomée autour de la position correcte. Ce comportement continue pour chaque pas que je zoome sur la roulette de la souris, complètement comme prévu. Si toutefois, après zoomer en partie, je déplace la souris à une position différente, la fonctionnalité se casse et je dois zoomer complètement pour changer la position du zoom.

le comportement prévu est que tout changement de position de la souris durant le processus de zoom soit correctement reflété dans l'image zoomée.

les deux principales fonctions qui contrôlent le comportement actuel sont les suivantes:

self.container.on('mousewheel', function (e, delta) {
        var offset = self.image.offset();

        self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
        self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;

        if (!self.running) {
            self.running = true;
            self.animateLoop();
        }
        self.delta = delta
        self.smoothWheel(delta);
        return false;
    });

Cette fonction recueille la position actuelle de la souris à la taille actuelle de l'image zoomée.

il démarre alors mon algorithme de défilement lisse qui se traduit par la fonction suivante étant appelé pour chaque interpolation:

zoom: function (scale) {

    var self = this;
    self.currentLocation.x += ((self.mouseLocation.x - self.currentLocation.x) / self.currentscale);
    self.currentLocation.y += ((self.mouseLocation.y - self.currentLocation.y) / self.currentscale);

    var compat = ['-moz-', '-webkit-', '-o-', '-ms-', ''];
    var newCss = {};
    for (var i = compat.length - 1; i; i--) {
        newCss[compat[i] + 'transform'] = 'scale(' + scale + ')';
        newCss[compat[i] + 'transform-origin'] = self.currentLocation.x + 'px ' + self.currentLocation.y + 'px';
    }
    self.image.css(newCss);


    self.currentscale = scale;
},

cette fonction prend la valeur de l'échelle (1-10) et applique les transformations css, repositionnant l'image en utilisant transform-origin.

bien que cela fonctionne parfaitement pour un position fixe de la souris choisie lorsque l'image est complètement zoomée; comme indiqué ci-dessus, il se brise lorsque le curseur de la souris est déplacé après un zoom partiel.

Énorme merci d'avance à tous ceux qui peuvent aider.

22
demandé sur Community 2013-01-21 14:04:54

5 réponses

avant de vérifier ce violon dehors; je devrais mentionner:

tout D'abord , dans votre méthode .zoom() ; vous ne devez pas diviser par currentscale :

self.currentLocation.x += ((self.mouseLocation.x - self.currentLocation.x) / self.currentscale);
self.currentLocation.y += ((self.mouseLocation.y - self.currentLocation.y) / self.currentscale);

parce que; vous utilisez déjà ce facteur pour calculer le mouseLocation à l'intérieur de la méthode initmousewheel() comme ceci:

self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;

donc à la place; (dans le .zoom() méthode), vous devez:

self.currentLocation.x += (self.mouseLocation.x - self.currentLocation.x);
self.currentLocation.y += (self.mouseLocation.y - self.currentLocation.y);

mais (par exemple) a += b - a produira toujours b donc le code ci-dessus est égal à:

self.currentLocation.x = self.mouseLocation.x;
self.currentLocation.y = self.mouseLocation.y;

en bref:

self.currentLocation = self.mouseLocation;

alors, il semble que vous n'avez même pas besoin de self.currentLocation . (2 variables pour la même valeur). Alors pourquoi ne pas utiliser la variable mouseLocation dans la ligne où vous définissez la variable transform-origin à la place et vous débarrasser de la variable currentLocation ?

newCss[compat[i] + 'transform-origin'] = self.mouseLocation.x + 'px ' + self.mouseLocation.y + 'px';

Deuxièmement , vous devez inclure un mousemove event listener dans la méthode initmousewheel() (comme d'autres devs ici suggèrent), mais il devrait mettre à jour la transformation en continu, pas seulement lorsque l'utilisateur roule. Sinon le bout du pointeur ne rattrapera jamais pendant que vous zoomez sur "n'importe quel" point aléatoire.

self.container.on('mousemove', function (e) {
    var offset = self.image.offset();
    self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
    self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
    self.zoom(self.currentscale);
});

donc, vous n'auriez plus besoin de calculer ceci dans le mousewheel gestionnaire d'événement de la sorte, votre initmousewheel() méthode devrait ressembler à ceci:

initmousewheel: function () {
    var self = this;

    self.container.on('mousewheel', function (e, delta) {
        if (!self.running) {
            self.running = true;
            self.animateLoop();
        }
        self.delta = delta;
        self.smoothWheel(delta);
        return false;
    });

    self.container.on('mousemove', function (e) {
        var offset = self.image.offset();
        self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
        self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
        self.zoom(self.currentscale); // <--- update transform origin dynamically
    });
}

Une Question:

Cette solution fonctionne comme prévu, mais avec un petit problème. Lorsque l'utilisateur déplace la souris en vitesse régulière ou rapide; l'événement mousemove semble manquer la position finale (testé dans Chrome). Donc le zoom sera un peu hors de l'emplacement du pointeur. Sinon, lorsque vous déplacez la souris lentement, il obtient l' point exact. Il devrait être facile de contourner ce bien.

Autres Notes et Suggestions:

  • vous avez une propriété dupliquée ( prevscale ).
  • je vous suggère d'utiliser toujours JSLint ou JSHint jsFiddle too) pour valider votre code.
  • je vous suggère fortement d'utiliser des fermetures (souvent appelées expression de fonction immédiatement invoquée (IIFE)) pour éviter la portée globale lorsque cela est possible; et de cacher vos propriétés et méthodes internes/privées.
5
répondu Onur Yıldırım 2013-02-12 12:21:28

en Fait, pas trop compliqué. Vous avez juste besoin de séparer la logique de mise à jour de l'emplacement de la souris de la logique de mise à jour du zoom. Découvrez mon violon: http://jsfiddle.net/qGGwx/41 /

tout ce que j'ai fait ici est d'ajouter un auditeur 'mousemove' sur le conteneur, et de mettre le soi.la mise à jour de la logique de mouseLocation. Comme il n'est plus nécessaire, j'ai également retiré la logique de mise à jour de la mousselocation du handler 'mousewheel'. Le code d'animation reste le même, comme le fait la décision de quand démarrer/arrêter la boucle d'animation.

voici le code:

    self.container.on('mousewheel', function (e, delta) {
        if (!self.running) {
            self.running = true;
            self.animateLoop();
        }
        self.delta = delta
        self.smoothWheel(delta);
        return false;
    });

    self.container.on('mousemove', function (e) {
        var offset = self.image.offset();

        self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
        self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;
    });
8
répondu jordancpaul 2013-01-27 09:14:13

ajouter une méthode mousemover et l'appeler dans la méthode init :

mousemover: function() {
    var self = this;
    self.container.on('mousemove', function (e) {

        var offset = self.image.offset();

        self.mouseLocation.x = (e.pageX - offset.left) / self.currentscale;
        self.mouseLocation.y = (e.pageY - offset.top) / self.currentscale;

        self.zoom(self.currentscale);
    });
},

violon: http://jsfiddle.net/powtac/qGGwx/34 /

4
répondu powtac 2013-01-23 10:59:35
condition mousemove

if(self.running && self.currentscale>1 && self.currentscale != self.lastscale) return;

qui empêche de déplacer l'image pendant le zoom mais crée aussi un problème. Vous ne pouvez pas changer de point de zoom si zoom est toujours en cours d'exécution.

3
répondu abc667 2013-02-08 15:47:46

prolongeant la réponse de @jordancpaul j'ai ajouté une constante mouse_coord_weight qui se multiplie par delta des coordonnées de la souris. Ceci vise à rendre la transition zoom moins sensible au changement de coordonnées de la souris. Regarde ça http://jsfiddle.net/7dWrw /

j'ai réécrit l'événement onmousemove hander comme:

    self.container.on('mousemove', function (e) {
        var offset = self.image.offset();
        console.log(offset);

        var x = (e.pageX - offset.left) / self.currentscale,
            y = (e.pageY - offset.top) / self.currentscale;

        if(self.running) {
            self.mouseLocation.x += (x - self.mouseLocation.x) * self.mouse_coord_weight;
            self.mouseLocation.y += (y - self.mouseLocation.y) * self.mouse_coord_weight;
        } else {
            self.mouseLocation.x = x;
            self.mouseLocation.y = y;
        }

    });
3
répondu Birla 2013-02-10 19:31:16