Javascript move element with mousemove event 60 FPS requestAnimationFrame - javascript

there! i have a problem for getting #drag element moving smoothly.
i look at this article : http://www.html5rocks.com/en/tutorials/speed/animations/#debouncing-mouse-events
it said that : "the problem with mousemove event when moving element was mousemove event fired too much
so, i try to used their method : using requestAnimationFrame + boolean checking.
look at this fiddle for live action : https://jsfiddle.net/5f181w9t/
HTML :
<div id="drag">this is draggable</div>
CSS :
#drag {width:100px; height:50px; background-color:red; transform:translate3d(0, 0, 0); }
JS :
var el = document.getElementById("drag"),
startPosition = 0, // start position mousedown event
currentPosition = 0, // count current translateX value
distancePosition = 0, // count distance between "down" & "move" event
isMouseDown = false; // check if mouse is down or not
function mouseDown(e) {
e.preventDefault(); // reset default behavior
isMouseDown = true;
startPosition = e.pageX; // get position X
currentPosition = getTranslateX(); // get current translateX value
requestAnimationFrame(update); // request 60fps animation
}
function mouseMove(e) {
e.preventDefault();
distancePosition = (e.pageX - startPosition) + currentPosition; // count it!
}
function mouseUp(e) {
e.preventDefault();
isMouseDown = false; // reset mouse is down boolean
}
function getTranslateX() {
var translateX = parseInt(getComputedStyle(el, null).getPropertyValue("transform").split(",")[4]);
return translateX; // get translateX value
}
function update() {
if (isMouseDown) { // check if mouse is down
requestAnimationFrame(update); // request 60 fps animation
}
el.style.transform = "translate3d(" + distancePosition + "px, 0, 0)";
// move it!
}
el.addEventListener("mousedown", mouseDown);
document.addEventListener("mousemove", mouseMove);
document.addEventListener("mouseup", mouseUp);
is this the correct way to accompolished it?
what's wrong with my code?
thanks

The problem is that you are using requestAnimationFrame() in the mouseDown event listener. You should do all you updates in the mouseMove event listener because you want to update your display when the mouse moves not when mouse clicks. Accordingly you should update all your variables under the isMouseDown conditional in the update function. i would suggest correcting the code as follows.
HTML
<div id="drag">this is draggable</div>
CSS
#drag {
width:100px;
height:50px;
background-color:red;
transform:translateX(0);
}
JS
var el = drag,
startPosition = 0, // start position mousedown event
currentPosition = 0, // count current translateX value
distancePosition = 0, // count distance between "down" & "move" event
isMouseDown = false, // check if mouse is down or not
needForRAF = true; // to prevent redundant rAF calls
function mouseDown(e) {
e.preventDefault(); // reset default behavior
isMouseDown = true;
currentPosition = getTranslateX(); // get current translateX value
startPosition = e.clientX; // get position X
}
function mouseMove(e) {
e.preventDefault();
distancePosition = (e.clientX - startPosition) + currentPosition; // count it!
if (needForRAF && isMouseDown) {
needForRAF = false; // no need to call rAF up until next frame
requestAnimationFrame(update); // request 60fps animation
};
}
function mouseUp(e) {
e.preventDefault();
isMouseDown = false; // reset mouse is down boolean
}
function getTranslateX() {
var translateX = parseInt(getComputedStyle(el, null).getPropertyValue("transform").split(",")[4]);
return translateX; // get translateX value
}
function update() {
needForRAF = true; // rAF now consumes the movement instruction so a new one can come
el.style.transform = "translateX(" + distancePosition + "px)";// move it!
}
el.addEventListener("mousedown", mouseDown);
document.addEventListener("mousemove", mouseMove);
document.addEventListener("mouseup", mouseUp);
check it up here

Your code should already work fine. However, here's another way to do it:
You need to make sure you only let one requestAnimationFrame call go through per frame, otherwise update() will be called multiple times at the next repaint, which can cause lag and decrease your fps. To do this, you want to save the requested frame and on each mousemove event check if there's already a frame lined up. If there is, you'll want to use cancelAnimationFrame to cancel it and make a new request. This way update() is only called as often as the browser is able to render changes (I.E. 60fps in most browsers).
function mouseDown(e) {
e.preventDefault(); // cancel default behavior
isMouseDown = true;
startPosition = e.pageX; // get position X
currentPosition = getTranslateX(); // get current translateX value
}
var lastUpdateCall=null;
function mouseMove(e){
if(isMouseDown){ //check if mousedown here, so there aren't any unnecessary animation frame requests when the user isn't dragging
e.preventDefault(); // You probably only want to preventDefault when the user is actually dragging
if(lastUpdateCall) cancelAnimationFrame(lastUpdateCall); //if an animation frame was already requested after last repaint, cancel it in favour of the newer event
lastUpdateCall=requestAnimationFrame(function(){ //save the requested frame so we can check next time if one was already requested
distancePosition = (e.clientX - startPosition) + currentPosition; // Do the distance calculation inside the animation frame request also, so the browser doesn't have to do it more often than necessary
update(); //all the function that handles the request
lastUpdateCall=null; // Since this frame didn't get cancelled, the lastUpdateCall should be reset so new frames can be called.
});
}
}
function update(){
el.style.transform = "translateX(" + distancePosition + "px)";// move it!
}
You could also just not call requestAnimationFrame again if lastUpdateCall isn't null, but that would mean you'd have to calculate the distance outside the animation frame call every time the event fires, or the animation would lag behind your mouse by up to 20ms. Either method is fine, I suppose.

Related

Executing a line in a conditional AND by default on start

I have this fiddle: http://jsfiddle.net/zhaem/Lyzrtefo/7/
var orangeMode = true
var isTracking = true
getMouseXY = function(e) {
if (isTracking) {
var tempX = e.pageX
var tempY = e.pageY
if (tempX < 0){tempX = 0}
if (tempY < 0){tempY = 0}
document.getElementById("circle1").style.top = (tempY - 25) + "px";
document.getElementById("circle1").style.left = (tempX - 25) + "px";
}
return true
}
document.onmousemove = getMouseXY;
var toggleTrackCircle = function() {
isTracking = !isTracking;
console.log(isTracking);
}
document.getElementById("circle1").addEventListener("click", toggleTrackCircle);
flip = function() {
orangeMode = !orangeMode;
if (orangeMode) {
document.getElementById("circle1").style.backgroundColor = "orange";
document.getElementById("circle1").addEventListener('mouseover', function() {isTracking = true;})
// When the above line is executed the circle will stick to your cursor on HOVER after clicking and setting it down.
} else {
document.getElementById("circle1").style.backgroundColor = "blue";
}
}
document.getElementById("box3").addEventListener("click", flip);
There is this one line, that when present will change the behavior of the interaction. (You can always click to stop the cursor from tracking you, but when this line is there, the circle will re-stick to it on hover, and when it's not, it will only restick on hover + click.
document.getElementById("circle1").addEventListener('mouseover', function() {isTracking = true;})
I'm trying to wrap it in some conditional logic in the flip function (which you can control by tapping the red box in the corner) so that orangeMode == it sticks on hover and not orangeMode it only re-sticks on click.
The flip function works fine for changing the color, but this event listener isn't performing like I'd want. (once you cycle through it does work but for either state and it's not running orangeMode unload.
Any help would be much appreciated.
You need to put 'isTracking=true;' inside a named function, so you can use "removeEventListener" to take the function off. That means you add this function:
var trackCircle = function() {
isTracking = true;
}
Then you reference that on click instead of the anonymous function:
circle.addEventListener('mouseover', trackCircle)
Then you simply remove that event in your else:
circle.removeEventListener('mouseover', trackCircle)
Oh, and I'd add this at the top so you don't need to keep repeating the getElementById phrase:
circle = document.getElementById("circle1");
Hope that helps. Oh, and here's the edit to your fiddle:
http://jsfiddle.net/Lyzrtefo/9/

JavaScript setTimeout() can't trigger itself

How can a function, which is triggered by another function, get the mouse's position? Here's my code:
function myFunction(e){
setTimeout(function(){
if(isMouseDown == true){
mouseX = e.clientX;
mouseY = e.clientY;
document.getElementById('myElement').innerHTML = mouseX + ' , ' + mouseY;
myFunction(event);
} else {}
}, 100);
}
What this does is to display the coordinates when clicked. I need it to display them every 100ms if isMouseDown == true.
Thanks
There is no way in Javascript for a random Javascript function to get the mouse position. The current mouse position only comes from an event object for a mouse-related event. So, if you want to keep track of the mouse position, then you can register an event handler for the mousemove event and for mousedown and mouseup to keep track of the button state.
If you only want to display the mouse position, ever 100ms, then you can set a timer so that it is only displayed that often, but you will need to keep track of the current mouse position in a mousemove event handler.
Here's a simple code example:
var lastMouseX = 0, lastMouseY = 0;
document.addEventListener("mousemove", function(e) {
lastMouseX = e.clientX;
lastMouseY = e.clientY;
});
var mouseTimer;
document.addEventListener("mousedown", function() {
if (!mouseTimer) {
mouseTimer = setInterval(function() {
document.getElementById("x").innerHTML = lastMouseX;
document.getElementById("y").innerHTML = lastMouseY;
}, 100);
}
});
document.addEventListener("mouseup", function() {
clearInterval(mouseTimer);
mouseTimer = null;
});
<div id="x"></div>
<div id="y"></div>
It's a bit fuzzy what you're trying to achieve, however you're not going to get a periodic event if you're usingsetTimeout(). It sounds like you're looking for setInterval(). See the below example:
var mouseX = 0;
var mouseY = 0;
var isMouseDown = true;
document.onmousemove = function(e){
mouseX = e.pageX;
mouseY = e.pageY;
}
setInterval("myFunction()", 100);
function myFunction(){
if(isMouseDown) {
document.getElementById('myElement').innerHTML = mouseX + ' , ' + mouseY;
}
}
<div id="myElement"></div>

Raphael: How to unbind the mousemove function on mouseup?

I am drawing a line with Raphael. I have a mousedown event where I store the starting position. While the mouse is down, if the user moves it, I have a mousemove event where I keep drawing the line as the mouse moves.
Now when the mouse button is released, the line should stop. This does not happen and line keeps going on if the mouse moves even though button is released. This line must stop on mouseup. If the user does mousedown again, it should begin a new line.
I have tried many combinations with the unmouse* events, but I am missing something here.
JSFiddle at: http://jsfiddle.net/zaphod013/P33FA/5/
(This is my first date with JS/Raphael. So if you think I am totally off track here, please tell me so)
var g_masterPaper;
var g_startX;
var g_startY;
var g_line;
function initDrawing() {
g_masterPaper = Raphael(10,10,700,500);
var masterBackground = g_masterPaper.rect(10,10,600,400);
masterBackground.attr("fill", "#eee");
var drawit = function(event) {
x = event.pageX - 10;
y = event.pageY - 10;
var linepath = ("M"+g_startX+" "+g_startY+" L"+x+" "+y);
g_line.attr("path", linepath);
};
var startit = function (event) {
g_startX = event.pageX - 10;
g_startY = event.pageY - 10;
g_line = g_masterPaper.path("M"+g_startX+" "+g_startY+" L"+g_startX+" "+g_startY);
masterBackground.mousemove(drawit);
};
masterBackground.mousedown(startit);
masterBackground.mouseup(function (event) {
this.unmousedown(startit);
this.unmousemove(drawit);
});
return g_masterPaper;
}
window.onload = function () {
var paper=initDrawing();
paper.text(15,475,'Use your mouse to draw.').attr({fill:'#ff0000', 'font-size':24, 'stroke-width':1,'text-anchor':'start' });
}
I think you're on track and mostly looks fine, I would possibly just simplify your handlers, and not keep removing/adding them, it keeps handlers hard to track and debug. So I would just have one handler for down/up/move...
Edit:
jsfiddle here or here which gets around other elements capturing the mouseup event and stopping it working properly.
var drawit = function(event) {
event.preventDefault();
x = event.pageX - 10;
y = event.pageY - 10;
var linepath = ("M"+g_startX+" "+g_startY+" L"+x+" "+y);
if( g_line ) { g_line.attr("path", linepath) };
};
var startit = function (event) {
event.preventDefault();
g_startX = event.pageX - 10;
g_startY = event.pageY - 10;
g_line = g_masterPaper.path("M"+g_startX+" "+g_startY+" L"+g_startX+" "+g_startY);
};
var finish = function ( event ) {
g_line = '';
}

JavaScript cannot get onmousemove script to work as intended

I have a function to follow the object after the mouse,
and I want to be able to stop and start following at will, without hiding the object.
It almost works as I wanted, and is following the mouse indeed, but I cannot make it move initial position without actually moving the mouse.
E.G. When I trigger the function, the object is still somewhere in another place, until I move the mouse, but what I'm trying to do is to move it the initial position first, before attaching the mousemove event.
Here is how I want to trigger the function:
showtrail();
function showtrail(shit){
//this is how I tried to set the initial position first, but this get me an error:..
//followmouse();
document.onmousemove=followmouse; //and this is how I attach the event.
}
This is a part of the actual function to move the object,
but, I can't get the coordinates if I try to initilize/imitate the first movement.
function followmouse(e){
var xcoord=offsetfrommouse[0]
var ycoord=offsetfrommouse[1]
if (typeof e != "undefined"){ //This- if triggered by mousemove, and it works
xcoord+=e.pageX
ycoord+=e.pageY
}
else { //this was meant for the initial call, but... for some reason
xcoord+=document.body.scrollLeft+event.clientX // it triggers an error,
ycoord+=document.body.scrollTop+event.clientY // saying event.clientX undefined.
}
}
So the event.clientX never seems to work, and I cannot figure out how to get the actual mouse position otherwise..
Please guide..
event.clientX and event.clientY are wrong. They should be e.clientX and e.clientY
A more elegant cross browser way to get xcoord and ycoord in followmouse(e) is:
xcoord = e.pageX||(e.clientX+(document.body.scrollLeft||document.documentElement.scrollLeft));
ycoord = e.pageY||(e.clientY+(document.body.scrollTop||document.documentElement.scrollTop));
Now if I'm getting it right, the object that follows is expected to have an initial absolute position and displayed as a block, meaning that you have initial x and y (left and top). Therefore by using a global bool var for currently following or not you're done.
<style>
...
#trail {position:absolute;left:0;top:0;display:none}
...
</style>
<script>
var following = false;
...
function followmouse(e){
if (!following){
document.getElementById('trail').style.display='none';
return;
}
...
document.getElementById('trail').style.display='block';
}
</script>
By changing display you have the option to move your #trail to its initial position and then follow the mouse, and the option to avoid the move and let it follow the mouse from its latest following position.
EDIT 1:
For this very purpose, I recommend using of requestAnimationFrame API, not classic DOM events. said API is more efficient for creating animations and pausing them.
take a look at this too: requestAnimationFrame for smart animating
This is sad, but true that you can not get mouse's initial position before moving mouse on a webpage. I mean you can't calibrate your object before mousemove event. this is what I will do in a similar project:
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
<script type="text/javascript">
var targetID = 'mydiv'; // div that is to follow the mouse
var pauseFollowing = false;
// (must be position:absolute)
var offX = 15; // X offset from mouse position
var offY = 15; // Y offset from mouse position
function mouseX(evt) {if (!evt) evt = window.event; if (evt.pageX) return evt.pageX; else if (evt.clientX)return evt.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft); else return 0;}
function mouseY(evt) {if (!evt) evt = window.event; if (evt.pageY) return evt.pageY; else if (evt.clientY)return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop); else return 0;}
function follow(evt) {
if(pauseFollowing) {
//or do something else at pause
return false;
}
var obj = document.getElementById(targetID).style;
obj.visibility = 'visible';
obj.left = (parseInt(mouseX(evt))+offX) + 'px';
obj.top = (parseInt(mouseY(evt))+offY) + 'px';
}
function toggleFollow() {
pauseFollowing = !pauseFollowing;
}
window.onload = function() {
window.onclick = toggleFollow;
document.onmousemove = follow;
}
</script>
</head>
<body>
<div id="mydiv" style="visibility: hidden; top:0; left:0 ;width: 100px; height: 100px; background: #ff0; position: absolute;"></div>
</body>
</html>
Alright that's how I done it.
The best Idea was to always capture a move to set position in a global var.
Now I have an option to display it fixed at any specific place (if I pass coords to showtrail)
or to actually follow the mouse;
I also added an event listener, so if the mouse gets outside the window while following- it will be hidden.
So far it works exactly as I wanted:
var trailimage=["scripts/loading_mouse.gif", 24, 24] //image path, plus width and height
var offsetfrommouse=[2,10] //image x,y offsets from cursor position in pixels. Enter 0,0 for no offset
var global_coord=[0,0]
var follow=false;
if (document.getElementById || document.all)
document.write('<div id="trailimageid" style="z-index: 10;position:absolute;display:none;left:0px;top:0px;width:1px;height:1px"><img src="'+trailimage[0]+'" border="0" width="'+trailimage[1]+'px" height="'+trailimage[2]+'px"></div>')
function gettrailobj(){
if (document.getElementById)
return document.getElementById("trailimageid").style
else if (document.all)
return document.all.trailimagid.style
}
function hidett(){ gettrailobj().display="none"; }
function showtt(){ gettrailobj().display="block"; }
function truebody(){ return (document.body||document.documentElement); }
function showtrail(shit){
if (typeof shit == "undefined"){ //Follow Mouse
follow=true;
setmousepos(global_coord[0],global_coord[1]);
}
else { //Set fixed in specific place
follow=false;
showtt()
gettrailobj().left=shit.left+6+"px"
gettrailobj().top=shit.top-5+"px"
}
}
function hidetrail(){
hidett()
follow=false;
}
function setcoord(e){
var xcoord=offsetfrommouse[0]
var ycoord=offsetfrommouse[1]
var xxcoord = e.pageX||(e.clientX+truebody().scrollLeft);
var yycoord = e.pageY||(e.clientY+truebody().scrollTop);
if (typeof xxcoord != "undefined"&&typeof yycoord != "undefined"){
xcoord+=xxcoord;
ycoord+=yycoord;
global_coord=[xcoord,ycoord];
if (follow) setmousepos(xcoord,ycoord);
}}
function setmousepos(xcoord,ycoord){
var docwidth=truebody().scrollLeft+truebody().clientWidth
var docheight=Math.max(truebody().scrollHeight, truebody().clientHeight)
if ((xcoord+trailimage[1]+3>docwidth || ycoord+trailimage[2]> docheight ||!follow)){
hidett()
}
else{
showtt();
gettrailobj().left=xcoord+"px"
gettrailobj().top=ycoord+"px"
}
}
window.addEventListener("mouseout",
function(e){
mouseX = e.pageX;
mouseY = e.pageY;
if ((mouseY >= 0 && mouseY <= window.innerHeight)
&& (mouseX >= 0 && mouseX <= window.innerWidth)){
return false;
}else{
if (follow) hidett()
}
},
false);
document.onmousemove=setcoord;

Is there something like Jquery memory or cache?

I've wrote a Script with jQuery for 360deg product preview. It works just fine. But if I "play" with it for a long time (dragging, zooming in, zooming out etc.) it becames slower and slower. If I'm dragging mouse slowly it works ok, but it freezes on fast mousemoves. After page reload it works again fine for several minutes and then become slower.
What can cause such behaviour? Is there something like jQuery memory that becomes full?
Per request, some parts of code:
Loading images:
$.getJSON("load.php", {dir: 'images/'}, function(output) {
var imagelist = jQuery.makeArray(output.imagelist);
var zoomlist = jQuery.makeArray(output.zoomlist);
var cache = [];
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
var im = $("<img>").attr("src",this);
cache.push(im);
image.attr('src', this);
});
}
preload(imagelist);
Rotation part
holder.mousedown(function(e){
var enterPosition = e.pageX - this.offsetLeft;
isDown = true;
$(document).mousemove(function(e){
if(isDown && !isZoom){
var cursorPosition = e.pageX - contOffset.left;
var xOffset = cursorPosition - enterPosition;
var step = Math.round(contWidth/countFrames);
var frameOffset = Math.round(xOffset/step);
var cycles = Math.abs(Math.floor((frameOffset+startFrame)/countFrames));
currentFrame = startFrame + frameOffset;
if(currentFrame >= countFrames){
currentFrame = currentFrame - countFrames*cycles;
}
if(currentFrame < 0){
currentFrame = countFrames*cycles + currentFrame;
}
image.attr('src', imagelist[currentFrame]);
$('#info').html(currentFrame);
var corner = Math.floor(360/countFrames);
var degrees = corner*currentFrame;
var radians=degrees*Math.PI/180;
var sine=Math.sin(radians);
var cose=Math.cos(radians);
var poinx = rotCenter+rotRadius*sine*-1;
var poiny = rotCenter+rotRadius*cose
$('#pointer').css('left',poinx);
$('#pointer').css('top',poiny);
};
});
$(document).mouseup(function(){
isDown = false;
startFrame = currentFrame;
});
});
Zooming part
$('#zoom').click(function(e){
var isZoom = true;
var offset = holder.offset();
var startXpos = e.pageX - offset.left;
var startYpos = e.pageY - offset.top;
var zoomImg = new Image();
zoomImg.onload = function() {
zoomHeight = zoomImg.height;
zoomWidth = zoomImg.width;
var leftOverflow = (zoomWidth - contWidth)/-2;
var topOverflow = (zoomHeight - contHeight)/-2;
image.attr('src', zoomlist[currentFrame]);
image.css('left', leftOverflow);
image.css('top', topOverflow);
$('#round').fadeOut();
$('#zoom').fadeOut();
holder.addClass('zoomout');
holder.mousemove(function(e){
if(isZoom){
var currentXpos = e.pageX - offset.left;
var currentYpos = e.pageY - offset.top;
var xlimit = (zoomWidth-contWidth)*-1;
var ylimit = (zoomHeight-contHeight)*-1;
var xSpeedCoeff = Math.floor(zoomWidth/contWidth);
var ySpeedCoeff = Math.floor(zoomHeight/contHeight);
var moveLeft = startXpos - currentXpos;
var moveTop = startYpos - currentYpos;
var leftOffset = leftOverflow + moveLeft*xSpeedCoeff;
var topOffset = topOverflow + moveTop*ySpeedCoeff;
var hMoveLock = false;
var vMoveLock = false;
if(leftOffset >= 0){
hMoveLock = true;
startXpos = startXpos - leftOffset;
}
if(leftOffset <= xlimit){
hMoveLock = true;
startXpos = startXpos - leftOffset + xlimit;
}
if(topOffset >= 0){
vMoveLock = true;
startYpos = startYpos - topOffset;
}
if(topOffset <= ylimit){
vMoveLock = true;
startYpos = startYpos - topOffset + ylimit;
}
if(!hMoveLock) {
image.css('left', leftOffset);
}
if(!vMoveLock) {
image.css('top', topOffset);
}
holder.mousedown(function(){
image.attr('src', imagelist[currentFrame]);
image.css('left', 0);
image.css('top', 0);
$('#round').fadeIn();
$('#zoom').fadeIn();
holder.removeClass('zoomout');
pan = false;
isZoom = false;
});
}
});
}
zoomImg.src = zoomlist[currentFrame];
});
I know, the code is not clear, and as it here now, I would be thankful for any advice.
There are lots of reasons this might happen, it's impossible to say without seeing the code see below for an update now that you've posted the code:
A couple of possibilities off the top of my head:
Yes, you could be allocating lots of objects and then either not releasing them, or the garbage collector is being slow.
You could be inadvertently re-attaching event handlers over and over, and so the events (which end up triggering all attached handlers) slow down because of the number of (redundant) handlers attached.
Update after you posted your code:
It's #2, this is the offending code (it may not be the only offending code):
holder.mousedown(function(e){
var enterPosition = e.pageX - this.offsetLeft;
isDown = true;
$(document).mousemove(function(e){
// ...
});
$(document).mouseup(function(){
// ...
});
});
What you're doing there is when the mousedown event fires on the holder element(s), you're adding a new handler for mousemove and mouseup to the document, on top of any handlers that are already there. So every mousedown introduces a new handler to the chain. Since mousemove happens a lot, that ever-increasing chain of handlers gets called a lot.
You should either only be attaching the mousemove and mouseup handlers once, not on every mousedown, or you should be sure to remove them on mouseup. (The latter will require that you don't use anonymous functions as you are currently, because you need to pass the same function reference into unbind that you passed [indirectly] into bind. Edit: Or you can use jQuery's "namespaced" event stuff.)
FWIW, this should get you started on the attach-it-once version:
(function() { // Scoping function so isDown and enterPosition aren't globals
var isDown = false,
enterPosition;
// I don't know where `holder` or `startFrame` come from, but presumably you do
// Hook up mousedown on holder
holder.mousedown(function(e){
enterPosition = e.pageX - this.offsetLeft;
isDown = true;
});
// Hook up mousemove on document (just once)
$(document).mousemove(function(e){
// Flag controls whether we do anything
if(isDown && !isZoom){
var cursorPosition = e.pageX - contOffset.left;
var xOffset = cursorPosition - enterPosition;
var step = Math.round(contWidth/countFrames);
var frameOffset = Math.round(xOffset/step);
var cycles = Math.abs(Math.floor((frameOffset+startFrame)/countFrames));
currentFrame = startFrame + frameOffset;
if(currentFrame >= countFrames){
currentFrame = currentFrame - countFrames*cycles;
}
if(currentFrame < 0){
currentFrame = countFrames*cycles + currentFrame;
}
image.attr('src', imagelist[currentFrame]);
$('#info').html(currentFrame);
var corner = Math.floor(360/countFrames);
var degrees = corner*currentFrame;
var radians=degrees*Math.PI/180;
var sine=Math.sin(radians);
var cose=Math.cos(radians);
var poinx = rotCenter+rotRadius*sine*-1;
var poiny = rotCenter+rotRadius*cose
$('#pointer').css('left',poinx);
$('#pointer').css('top',poiny);
};
});
// Hook mouseup on document (just once)
$(document).mouseup(function(){
isDown = false;
startFrame = currentFrame;
});
})();
If your code is already within a scoping function, you don't need the new one I introduced.
There is a cache - you can access it with $.cache. And as T.J. Crowder said - it's most likely cause of you aren't cleaning up after yourself properly.
Do a Object.keys($.cache).length; in your console to check the size of cache - play for a while and check again to confirm that the cache grows to confirm jquery based leaks
and you are leaking cause on mouseup you are not unbinding your mouseup and mmousemove events
$(document).mouseup(function(){
$(document).unbind('mouseup').unbind('mousemove');
isDown = false;
startFrame = currentFrame;
});
this should help a lot
Problem was that basically every time you were pressing mouse down you were binding mousemove and mouseup again and again so after clicking few times all the computation was multiplied by amount of times you've pressed mouse down. You could also namespace the mousemove and mouseup events to unbind by namespace rather then two events separately.
Also caching variables might help a bit - especially with this kind of heavy operations - mousemove fires a lot
edit:
to remove events with anonymous functions use namespaces
var doc = $(document);
doc.bind('mousedown', function(e) {
doc.bind('mousemove.namespace', function(e) { ... });
doc.bind('mouseup.namespace', function(e) {
doc.unbind('.namespace');
// do whatever else you need to do on mouseup
});
});
just change namespace to whatever fits you best! Check jQuery docs for more info on namespaced events http://docs.jquery.com/Namespaced_Events
apart of that if you don't pass any function to the event type you want to unbind it will unbind all the events of given type regardless of its namespace or if it was named function or anonymous one
So, the problem was caused by the zoom function. What i did to solve it:
I have moved this part
holder.mousedown(function(){
image.attr('src', imagelist[currentFrame]);
image.css('left', 0);
image.css('top', 0);
$('#round').fadeIn();
$('#zoom').fadeIn();
holder.removeClass('zoomout');
pan = false;
isZoom = false;
});
outside of
holder.mousemove(function(e){
if(isZoom){
I've used namespaces to unbind mouse events.
holder.on('mousemove.dragpan', (function(e){
}));
holder.mousedown(function(){
holder.off('mousemove.dragpan');
});
Thx again for all the tipps!

Categories