最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - mouseMove very laggy - Stack Overflow

programmeradmin1浏览0评论

I am trying to obtain the image effect that 99designs is obtaining when hovering a mouse over a design.. [99designs.ca] Logo design contest: Runningbug Needs Logo 220626

I am currently obtaining the position of the mouse on mousemove, then using that to move my popover <img>, and everything works fine, but it is very laggy.. and presumably its from so many calls being made.

To get the position of the mouse:

jQuery(document).ready(function(){
   //$("#special").click(function(e){
   $(".imgWrap").mousemove(function(e){
      //$('#status2').html(e.pageX +', '+ e.pageY);
      //alert(e.pageX + ', ' + e.pageY);
      mouseX = e.pageX;
      mouseY = e.pageY;
   }); 
})

I'm not sure of another way I can do this.. any ideas?

On the full course of events is the following:

  1. User mouses over an img tag.
  2. I get the position of the mouse as per above.
  3. The <img> tag also calls a js function which changes the position of an img tag to the position of the mouse.

Actually, you can check it here: pokemonsite

update: I see there is a bounty placed (thanks !). I'm a little busy at the moment and can't check all the other answers, but I'll make sure to check them asap

I am trying to obtain the image effect that 99designs is obtaining when hovering a mouse over a design.. [99designs.ca] Logo design contest: Runningbug Needs Logo 220626

I am currently obtaining the position of the mouse on mousemove, then using that to move my popover <img>, and everything works fine, but it is very laggy.. and presumably its from so many calls being made.

To get the position of the mouse:

jQuery(document).ready(function(){
   //$("#special").click(function(e){
   $(".imgWrap").mousemove(function(e){
      //$('#status2').html(e.pageX +', '+ e.pageY);
      //alert(e.pageX + ', ' + e.pageY);
      mouseX = e.pageX;
      mouseY = e.pageY;
   }); 
})

I'm not sure of another way I can do this.. any ideas?

On the full course of events is the following:

  1. User mouses over an img tag.
  2. I get the position of the mouse as per above.
  3. The <img> tag also calls a js function which changes the position of an img tag to the position of the mouse.

Actually, you can check it here: pokemonsite

update: I see there is a bounty placed (thanks !). I'm a little busy at the moment and can't check all the other answers, but I'll make sure to check them asap

Share Improve this question edited Jun 19, 2018 at 18:39 Teo Dragovic 3,51821 silver badges36 bronze badges asked Jun 1, 2013 at 1:19 penguinsourcepenguinsource 1,1903 gold badges16 silver badges41 bronze badges 5
  • You could try handling the vanilla JavaScript mousemove event. What exactly is your code doing every mousemove? It shouldn't be that laggy, because you shouldn't have to do "many calls being made". As you say, you're just grabbing the position of the mouse, and moving another element. That shouldn't make anything laggy – Ian Commented Jun 1, 2013 at 1:23
  • Please add the img move code to your question. (Don't just link to an external site, and if you do link to an external site please use a clickable link.) – nnnnnn Commented Jun 1, 2013 at 1:32
  • sorry this is the updated link: pokemonpacific.com/index2 – penguinsource Commented Jun 1, 2013 at 1:33
  • 3 I don't know if it helps, but if you used code like this: jsfiddle.net/nmPcw , it doesn't seem to lag. I tried looking through your code on the site, but it's spread out and is confusing – Ian Commented Jun 1, 2013 at 1:36
  • If it's jQuery use the jQuery tag, not JavaScript. – John Commented Mar 22, 2015 at 0:17
Add a comment  | 

8 Answers 8

Reset to default 7

There are several ways to improve performance when using mousemove events.

  1. Use backface-visibility: hidden on popover element to force hardware acceleration. Same thing can be achived with transform: translate3d(0,0,0) but that makes difficult to use CSS transform function (see point #2).

  2. Use CSS transform function for absolute positioning to avoid repaints but keep popover element absolute or fixed positioned.

  3. When setting inline CSS via JS use requestAnimationFrame to avoid unnecesary layout trashing.

  4. (maybe, optionally) hide cursor when hovering and use popover element as position indicator.

  5. Move everything you can from JS to CSS ie. :hover state can be used to toggle display of popover element.

I made demo example combining all things listed. There is still some latency between cursor position and popover image and none of example links in original question work so I can't compare against it but I hope someone finds this useful.

DEMO

<div id="imgHolder" class="imgHolder">
    <img src="//placehold.it/200x200" alt="" />
</div>

<div id="bigImgHolder" class="imgHover">
   <img src="//placehold.it/500x500" alt="" />
</div>

 

.imgHover { 
    display: none;
    backface-visibility: hidden;
    position: fixed;
    top: 0; left: 0;
    pointer-events: none;
}

.imgHolder:hover ~ .imgHover { display: block; }

// uncomment if it makes sense
//.imgHolder:hover { cursor: none; }

 

var posX, posY;

$('#imgHolder').mousemove(HoverImg);

function HoverImg(e) {
    posX = e.pageX;
    posY = e.pageY;
    window.requestAnimationFrame(showBigImg);  
}

function showBigImg() {
    $('#bigImgHolder').css({'-webkit-transform': 'translateX(' + posX + 'px) translateY(' + posY + 'px)', 'transform': 'translateX(' + posX + 'px) translateY(' + posY + 'px)' });
}

references:

  • http://davidwalsh.name/translate3d
  • http://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/
  • https://css-tricks.com/using-requestanimationframe/

Try this:

jQuery(document).ready(function(){
     $(".imgWrap").mousemove(function(e){
     e.stopPropagation();

     mouseX = e.pageX;
     mouseY = e.pageY;
    }); 
})

Use e.offsetX and e.offsetY or (recommended) e.clientX and e.clientY instead of pageX and pageY. Maybe this will be a better solution. Note: offsetx and offsety do not work in Firefox as far as I know.

If the absolute (x, y) position is not so important (meaning: some pixel-values can be omitted without destroying your logic), you could try to skip some frames of your mousemove-event.

var globalSkipCounter = 0;
var globalSkipRate = 5;
$(".imgWrap").mousemove(function(e){
   if(globalSkipCounter >= globalSkipRate){
     var mouseX = e.pageX;
     var mouseY = e.pageY;
     do_stuff(mouseX, mouseY);
     globalSkipCounter = 0;
   }
   else{
     globalSkipCounter+=1;
   }
});

This way, you omit redrawing your image on every mousemove-event, instead your draw-routines (do_stuff) are only invoked, once every 5 events.

Cache the position and wrap the update in an if(oldpos !== newpos) type check (remembering to update oldpos inside it).

Use requestAnimationFrame to handle the update - if you have a normal function and pass that as the callback then it will only get called once per frame (ie, don't use an anonymous function).

Finally make use of transform:translate(x,y) to set the position and make better use of the GPU etc. Related to this, there's no harm in making use of the css will-change keyword if you want to use top/left instead.

try a maximum event per second based approach:

jQuery(document).ready(function(){
   var now, then, delta, interval = 1000/60; //maximum 60 eps, you can change
   //$("#special").click(function(e){
   $(".imgWrap").mousemove(function(e){
     now = Date.now();
     delta = now - then;
     if (delta > interval) {
       then = now - delta % interval; //subtract extra waited time
       //$('#status2').html(e.pageX +', '+ e.pageY);
       //alert(e.pageX + ', ' + e.pageY);
       mouseX = e.pageX;
       mouseY = e.pageY;
       // do your thing
     }
   }); 
})

EDIT: didn't know then is a reserved word in javascript, you can rename it.

I have a sortable listview in angular, but dragging items with the mouse in chrome was lagging a lot. I tried disabling all chrome extensions and now the lag is totally gone.

It turned out that TamperMonkey was causing it.

Instead of using "left" or "right" property of CSS rather try to use "transform" I was trying to do the same thing as asked in question, and using "transform" worked for me like a charm.

for example:

transform: translate(30px);

this will move the element, 30px to the right.

by using transform we can move elements to left, right, top and bottom according to the need.

发布评论

评论列表(0)

  1. 暂无评论