简体   繁体   English

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

[英]Zoom image to cursor breaks when mouse is moved

This is a followup question to How to zoom to mouse pointer while using my own mousewheel smoothscroll? 这是如何在使用我自己的鼠标滚轮smoothscroll时缩放到鼠标指针的后续问题

I am using css transforms to zoom an image to the mouse pointer. 我正在使用css变换将图像缩放到鼠标指针。 I am also using my own smooth scroll algorithm to interpolate and provide momentum to the mousewheel. 我也使用自己的平滑滚动算法来插值并为鼠标滚轮提供动量。

With Bali Balo's help in my previous question I have managed to get 90% of the way there. 随着Bali Balo在我之前的问题中的帮助,我已经成功地获得了90%的收益。

You can now zoom the image all the way in to the mouse pointer while still having smooth scrolling as the following JSFiddle illustrates: 您现在可以将图像一直放大到鼠标指针,同时仍然具有平滑滚动,如下面的JSFiddle所示:

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

However, the functionality is broken when the mouse pointer is moved. 但是,移动鼠标指针时功能会中断。

To further clarify, If I zoom in one notch on the mousewheel the image is zoomed around the correct position. 为了进一步说明,如果我放大鼠标滚轮上的一个凹口,图像会缩放到正确的位置。 This behavior continues for every notch I zoom in on the mousewheel, completely as intended. 对于我在鼠标滚轮上放大的每个凹口,此行为都会继续,完全按照预期进行。 If however, after zooming part way in, I move the mouse to a different position, the functionality breaks and I have to zoom out completely in order to change the zoom position. 但是,如果在部分缩放后,我将鼠标移动到其他位置,功能会中断,我必须完全缩小才能更改缩放位置。

The intended behavior is for any changes in mouse position during the zooming process to be correctly reflected in the zoomed image. 预期的行为是缩放过程中鼠标位置的任何变化都可以在缩放图像中正确反映。

The two main functions that control the current behavior are as follows: 控制当前行为的两个主要功能如下:

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

This function collects the current position of the mouse at the current scale of the zoomed image. 此功能收集鼠标在缩放图像的当前比例下的当前位置。

It then starts my smooth scroll algorithm which results in the next function being called for every 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;
},

This function takes the scale amount (1-10) and applies the css transforms, repositioning the image using transform-origin. 此函数采用比例量(1-10)并应用css变换,使用transform-origin重新定位图像。

Although this works perfectly for a stationary mouse position chosen when the image is completely zoomed out; 虽然这对于在图像完全缩小时选择的静止鼠标位置非常有效; as stated above it breaks when the mouse cursor is moved after a partial zoom. 如上所述,在部分缩放后移动鼠标光标时会中断。

Huge thanks in advance to anyone who can help. 非常感谢任何可以提供帮助的人。

Actually, not too complicated. 其实,不是太复杂。 You just need to separate the mouse location updating logic from the zoom updating logic. 您只需将鼠标位置更新逻辑与缩放更新逻辑分开即可。 Check out my fiddle: http://jsfiddle.net/qGGwx/41/ 看看我的小提琴: http//jsfiddle.net/qGGwx/41/

All I have done here is add a 'mousemove' listener on the container, and put the self.mouseLocation updating logic in there. 我在这里所做的只是在容器上添加一个'mousemove'监听器,并将self.mouseLocation更新逻辑放在那里。 Since it is no longer required, I also took out the mouseLocation updating logic from the 'mousewheel' handler. 由于不再需要,我还从'mousewheel'处理程序中取出了mouseLocation更新逻辑。 The animation code stays the same, as does the decision of when to start/stop the animation loop. 动画代码保持不变,决定何时开始/停止动画循环。

here's the 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;
    });

Before you check this fiddle out; 在你检查这个小提琴之前; I should mention: 我应该提一下:

First of all , within your .zoom() method; 首先 ,在.zoom()方法中; you shouldn't divide by currentscale : 你不应该除以currentscale

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

because; 因为; you already use that factor when calculating the mouseLocation inside the initmousewheel() method like this: 你在initmousewheel()方法中计算mouseLocation时已经使用了这个因子,如下所示:

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

So instead; 所以与其; (in the .zoom() method), you should: (在.zoom()方法中),你应该:

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

But (for example) a += b - a will always produce b so the code above equals to: 但是(例如) a += b - a将始终产生b因此上面的代码等于:

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

in short: 简而言之:

self.currentLocation = self.mouseLocation;

Then, it seems you don't even need self.currentLocation . 然后,你似乎甚至不需要self.currentLocation (2 variables for the same value). (2个变量为相同的值)。 So why not use mouseLocation variable in the line where you set the transform-origin instead and get rid of currentLocation variable? 那么为什么不在你设置transform-origin的行中使用mouseLocation变量来摆脱currentLocation变量呢?

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

Secondly , you should include a mousemove event listener within the initmousewheel() method (just like other devs here suggest) but it should update the transform continuously, not just when the user wheels. 其次 ,你应该在initmousewheel()方法中包含一个mousemove事件监听initmousewheel()就像这里建议的其他开发者一样),但它应该连续更新转换,而不仅仅是当用户initmousewheel()时。 Otherwise the tip of the pointer will never catch up while you're zooming out on "any" random point. 否则当你缩小“任意”随机点时,指针的尖端永远不会赶上。

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

So; 所以; you wouldn't need to calculate this anymore within the mousewheel event handler so, your initmousewheel() method would look like this: 你不需要给内不再计算该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
    });
}

One Issue: 一个问题:

This solution works as expected but with a small issue. 此解决方案按预期工作但有一个小问题。 When the user moves the mouse in regular or fast speed; 当用户以常规或快速移动鼠标时; the mousemove event seems to miss the final position (tested in Chrome). mousemove事件似乎错过了最终位置(在Chrome中测试)。 So the zooming will be a little off the pointer location. 因此缩放将略微偏离指针位置。 Otherwise, when you move the mouse slowly, it gets the exact point. 否则,当您慢慢移动鼠标时,它会获得准确的点。 It should be easy to workaround this though. 尽管如此,应该很容易解决这个问题。

Other Notes and Suggestions: 其他注意事项和建议:

  • You have a duplicate property ( prevscale ). 您有重复的属性( prevscale )。
  • I suggest you always use JSLint or JSHint (which is available on jsFiddle too) to validate your code. 我建议你总是使用的JSLintJSHint (这可以用的jsfiddle太)来验证你的代码。
  • I highly suggest you to use closures (often refered to as Immediately Invoked Function Expression (IIFE)) to avoid the global scope when possible; 我强烈建议您使用闭包(通常称为立即调用函数表达式 (IIFE))以尽可能避免全局范围; and hide your internal/private properties and methods. 并隐藏您的内部/私有属性和方法。

Add a mousemover method and call it in the init method: 添加一个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);
    });
},

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

Zoom point is not exactly right because of scaling of an image ( 0.9 in ratio ). 变焦点是不完全正确的,因为图像(的缩放的0.9ratio )。 In fact mouse are pointing in particular point in container but we scale image . 事实上鼠标指向container中的特定点,但我们缩放image See this fiddle http://jsfiddle.net/qGGwx/99/ I add marker with position equal to transform-origin . 看到这个小提琴http://jsfiddle.net/qGGwx/99/我添加的位置等于transform-origin marker As you can see if image size is equal to container size there is no issue. 正如您所看到的,图像大小是否等于容器大小,没有问题。 You need this scaling? 你需要这个缩放? Maybe you can add second container? 也许你可以添加第二个容器? In fiddle I also added condition in mousemove 在小提琴我也添加了mousemove条件

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

That is preventing from moving image during zooming but also create an issue. 这样可以防止在缩放过程中移动图像,但也会产生问题。 You can't change zooming point if zoom is still running. 如果zoom仍在运行,则无法更改缩放点。

Extending @jordancpaul's answer I have added a constant mouse_coord_weight which gets multiplied to delta of the mouse coordinates. 扩展@jordancpaul的答案我添加了一个常量mouse_coord_weight ,它乘以鼠标坐标的delta。 This is aimed at making the zoom transition less responsive to the change in mouse coordinates. 这旨在使变焦过渡对鼠标坐标的变化的响应较小。 Check it out http://jsfiddle.net/7dWrw/ 看看http://jsfiddle.net/7dWrw/

I have rewritten the onmousemove event hander as: 我已经将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;
        }

    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM