22

这是如何在使用我自己的鼠标滚轮平滑滚动时缩放到鼠标指针的后续问题?

我正在使用 css 转换将图像缩放到鼠标指针。我还使用我自己的平滑滚动算法来插入并为鼠标滚轮提供动量。

在我之前的问题中,在 Bali Balo 的帮助下,我已经成功完成了 90% 的工作。

您现在可以将图像一直缩放到鼠标指针,同时仍然可以平滑滚动,如下面的 JSFiddle 所示:

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

但是,移动鼠标指针时功能会中断。

为了进一步澄清,如果我在鼠标滚轮上放大一个槽口,图像会围绕正确的位置进行缩放。对于我在鼠标滚轮上放大的每个缺口,这种行为都会继续,完全符合预期。但是,如果在部分放大后,我将鼠标移动到不同的位置,则功能会中断,我必须完全缩小才能更改缩放位置。

预期行为是为了在缩放过程中正确反映缩放过程中鼠标位置的任何变化。

控制当前行为的两个主要函数如下:

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

该函数在缩放图像的当前比例下收集鼠标的当前位置。

然后它启动我的平滑滚动算法,导致每次插值都调用下一个函数:

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

此函数采用缩放量 (1-10) 并应用 css 变换,使用 transform-origin 重新定位图像。

尽管这对于在图像完全缩小时选择的静止鼠标位置非常有效;如上所述,当鼠标光标在部分缩放后移动时,它会中断。

非常感谢任何可以提供帮助的人。

4

5 回答 5

8

其实也不算太复杂。您只需要将鼠标位置更新逻辑与缩放更新逻辑分开即可。看看我的小提琴:http: //jsfiddle.net/qGGwx/41/

我在这里所做的只是在容器上添加一个“mousemove”侦听器,并将 self.mouseLocation 更新逻辑放在那里。由于不再需要它,我还从“鼠标滚轮”处理程序中取出了 mouseLocation 更新逻辑。动画代码保持不变,决定何时开始/停止动画循环也是如此。

这是代码:

    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;
    });
于 2013-01-27T09:14:13.213 回答
5

在你检查这个小提琴之前;我应该提到:

首先,在你的.zoom()方法内;你不应该除以currentscale

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

因为; mouseLocation在计算内部方法时,您已经使用了该因子,initmousewheel()如下所示:

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

所以与其; (在.zoom()方法中),您应该:

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

但是(例如)a += b - a总是会产生b,所以上面的代码等于:

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

简而言之:

self.currentLocation = self.mouseLocation;

然后,似乎您甚至不需要self.currentLocation. (相同值的 2 个变量)。那么为什么不在mouseLocation设置变量的行中使用变量transform-origin并摆脱currentLocation变量呢?

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

其次,您应该mousemove在方法中包含一个事件侦听initmousewheel()器(就像这里的其他开发人员建议的那样),但它应该不断更新转换,而不仅仅是在用户转动时。否则,当您缩小“任何”随机点时,指针的尖端永远不会赶上。

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

所以; 您不再需要在mousewheel事件处理程序中计算它,因此您的initmousewheel()方法如下所示:

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

一个问题:

此解决方案按预期工作,但有一个小问题。当用户以常规或快速移动鼠标时;该mousemove事件似乎错过了最终位置(在 Chrome 中测试)。所以缩放会稍微偏离指针位置。否则,当您缓慢移动鼠标时,它会得到准确的点。不过,解决这个问题应该很容易。

其他注意事项和建议:

  • 您有一个重复的属性 ( prevscale)。
  • 我建议您始终使用JSLintJSHint(也可在 jsFiddle 上使用)来验证您的代码。
  • 我强烈建议您尽可能使用闭包(通常称为立即调用函数表达式(IIFE))来避免全局范围;并隐藏您的内部/私有属性和方法。
于 2013-02-12T05:04:00.123 回答
4

添加mousemover方法并在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);
    });
},

小提琴:http: //jsfiddle.net/powtac/qGGwx/34/

于 2013-01-23T10:59:35.877 回答
3

0.9由于图像的缩放( in ratio),缩放点并不完全正确。事实上,鼠标是指向特定点的,container但我们会缩放image。请参阅这个小提琴http://jsfiddle.net/qGGwx/99/我添加marker的位置等于transform-origin. 如您所见,如果图像大小等于容器大小,则没有问题。你需要这种缩放吗?也许你可以添加第二个容器?在小提琴中,我还添加了条件mousemove

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

这可以防止在缩放期间移动图像,但也会产生问题。zoom如果仍在运行,则无法更改缩放点。

于 2013-02-08T15:47:46.133 回答
3

扩展@jordancpaul 的答案我添加了一个常数mouse_coord_weight,该常数乘以鼠标坐标的增量。这样做的目的是使缩放过渡对鼠标坐标的变化反应更小。看看http://jsfiddle.net/7dWrw/

我已将onmousemove事件处理程序重写为:

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

    });
于 2013-02-10T19:31:16.307 回答