2

I have my own JavaScript Slider library, which I've developed. It works well, when I only initialize one slider, but has some problems, when there's more than one Slider initialized.

As you can see here: http://jsfiddle.net/bingo14/bhymxrqr/6/

The LAST slider works smoothly and perfectly, but the first two don't and I can't see where the problem is. If you start dragging the first slider and do some circular motions with the cursor while dragging, the Slider stops! Doesn't happen with the last one for some reason.

Could something be wrong with my event handlers?

dragger.onmousedown = dragStart; 
dragger.onmousemove = dragMove; 
dragger.onmouseup = dragStop; 

window.onmousemove = dragMove; 
window.onmouseup = dragStop; 
.....
Alex Kulinkovich
  • 4,408
  • 15
  • 46
  • 50
ctrlz
  • 1,073
  • 1
  • 10
  • 12

2 Answers2

2

When you write: window.onmousemove = dragMove; window.onmouseup = dragStop;

you actually SET the window.onmousemove / onmouseup functions. That is, if some functions were previously set, the next call replaces the previous one. You must have some sort of draggers container that holds references of your dragger, so that the events on window can address all of them. Or alternatively you can also replace this (although it may not be the best for performances):

window.onmousemove = dragMove; 
window.onmouseup = dragStop; 

with this:

var oldWinMouseMove = window.onmousemove;
var oldWinMouseUp = window.onmouseup;
window.onmousemove = function(e) {
    if (typeof oldWinMouseMove === 'function') {
        oldWinMouseMove(e);
    }
    dragMove(e);
};
window.onmouseup = function(e) {
    if (typeof oldWinMouseUp === 'function') {
        oldWinMouseUp(e);
    }
    dragStop(e);
};


Better solution

As requested, here is a better option which avoid to create a big calling stack like the solution above : http://jsfiddle.net/bhymxrqr/10/

The idea is to register the "mousedown" event on the sliders only, and the "mousemove" and "mouseup" events on window only.

// In "Slider":
dragger.onmousedown = dragStart;
// (nothing here about mousemove/up)

On mouse down, the current slider info is stored (to be exact, the mouseup and mousemove callback are stored):

window.activeSlider = {
    dragMove: dragMove,
    dragStop: dragStop
};

On window mouse move, the stored "mouse move" callback is called ; and same for mouse up, with in addition removal of the stored callbacks.

///////////////////////////
// Register window global slide handlers

window.onmousemove = function(e) {
    if (window.activeSlider !== undefined) {
        window.activeSlider.dragMove(e);
    }
}
window.onmouseup = function(e) {
    if (window.activeSlider !== undefined) {
        window.activeSlider.dragStop(e);
    }
}
Joel
  • 2,374
  • 17
  • 26
  • Yes it works! Wow thanks a lot. I would never have figure that out. But for performance wise I would try to attempt the alternative solution you suggested. What do you mean by "have draggers container that holds references of your dragger so that events on window can address all of them"? – ctrlz Oct 31 '14 at 16:03
  • Actually I'm wrong, you don't need to store them all in a container. When a slider get clicked (mousedown), store its reference in a single variable (kind of global). When window receives move or mouseup event and this variable is defined, call this variable's move/mouseup. And of course on mouseup, remove this variable reference. – Joel Oct 31 '14 at 16:15
  • I attempted that but it didn't seem to work.. Any chance you can demonstrate with psuedo code or with the jsfiddle please? – ctrlz Nov 03 '14 at 17:54
  • Awesome! What I also did before I read your solution was to put the: window.onmousemove = dragMove and window.onmouseup = dragStop inside the dragStart function and then I initialised the window.onmousemove and window.onmouseup to null in the dragStop function. That aslo worked nicely :) Thanks man – ctrlz Nov 04 '14 at 00:16
0

Each time you create a new slider you are overwriting the window and document mouse event handlers, so the last one is a bit greedy and gets to call it's function when the mouse leaves the el and the others don't. My advice would be to not place handlers on the window or document and call dragstop when the mouse leaves the sliders div

  //bind event handlers 
            dragger.onmousedown = dragStart;
            dragger.onmousemove = dragMove;
            dragger.onmouseup = dragStop;




            holder.onmousemove = dragMove;
            holder.onmouseup = dragStop;

            line.onmousemove = dragMove;
            line.onmouseup = dragStop;

            el.onmousemove = dragMove;
            el.onmouseup = dragStop;

            el.onmouseleave = dragStop;

I was also seeing some ghosting of the dgragger in chrome but this can easly fixed by adding a transparent outline to the gragger

.slider-dragger {
    position: absolute;
    width: 26px;
    height: 11px;
    border-radius: 3px;
    background-color: #555;
    top: -3px;
    left: 0px;
    cursor: pointer;
    z-index: 10;
    outline: 1px solid transparent;
}

here is a fiddle showing the end result http://jsfiddle.net/leighking2/bhymxrqr/9/

Quince
  • 14,790
  • 6
  • 60
  • 69
  • yeah I was considering something like that but in terms of Usability its not ideal. Users should be able to drag sliders if their cursor is outside the container otherwise it starts to become a bit annoying if you have a shaky hand! Thanks though :) – ctrlz Oct 31 '14 at 16:11