移动鼠标时,将图像缩放到光标中断

时间:2013-01-21 10:04:54

标签: javascript image zoom css-transforms

这是How to zoom to mouse pointer while using my own mousewheel smoothscroll?

的后续问题

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

在我之前提出的问题中,巴厘巴洛的帮助让我获得了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重新定位图像。

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

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

5 个答案:

答案 0 :(得分:8)

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

我在这里所做的就是在容器上添加一个'mousemove'监听器,并将self.mouseLocation更新逻辑放在那里。由于不再需要,我还从'mousewheel'处理程序中取出了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;
    });

答案 1 :(得分:5)

在检查this fiddle之前;我应该提一下:

首先,在您的.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))以尽可能避免全局范围;并隐藏您的内部/私有属性和方法。

答案 2 :(得分: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/

答案 3 :(得分:3)

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

中添加了条件
if(self.running && self.currentscale>1 && self.currentscale != self.lastscale) return;

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

答案 4 :(得分:3)

扩展@ jordancpaul的答案我添加了一个常量mouse_coord_weight,它乘以鼠标坐标的delta。这旨在使变焦过渡对鼠标坐标的变化的响应较小。查看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;
        }

    });