Introduction

We see a lot of JavaScript libraries floating around. A JavaScript library makes developers' life easy by avoiding the need to directly deal with the dirty waters of browser compatibility issues. They save a lot of time by allowing programmers to code what they intend to do and not worry about browsers.

jQuery is one of the libraries I admire. It's light-weight, easy to use, beautiful, and so on. An interesting feature of jQuery is plug-ins; they are JavaScript files that can be plugged in when needed.

In this article, we will see how to create a simple plug-in called Map Scroller that lets any overflowing HTML element to scroll like in Google Maps.

Let's dive into the article

Requirements

jQuery v1.4.2

jquery.DisableTextSelect.js

Tips in jQuery

$ is the main object in jQuery. Everything in jQuery is based upon this, or uses this in some way.

$ wraps an object called fn. To add a plug-in to jQuery, we have to add our method(s) into this object.

$("myDiv").scrollTop(20);
//scrolls the element down to 20 pixels from the top position.

scrollLeft() scrolls the element horizontally.

$("myDiv").scrollLeft(20);
//scrolls the element right to 20 pixels from the left position.

Map Scroller

Higher Level Plan

Create a method called mapScroll(direction).

The input parameter direction can be any of these values: "vertical", "horizontal", or "both". It represents which direction the scrolling should happen. If you don't pass any parameter, then it is taken as "both".

Add this method into jQuery's fn object, so any overflowing HTML element can achieve this scrolling by:

$("#OverflowingDiv").mapScroll("vertical");

Lower Level Plan

For achieving this scrolling, we have to disable then text selection for that element. A plug-in named DisableTextSelect helps us do that.

Bind event handlers to the mousedown, mousemove, and mouseup events of the element.

Enable scrolling in the mousedown event handler.

Disable scrolling in the mouseup event handler.

Calculate the distance the mouse moved from the old and new mouse positions, and scroll the element in the mousemove event handler.

Code

Let's create the skeleton first:

$.fn.mapScroll = function(direction){
//implementation starts
};

Calling $ directly is not safe in the global scope, because there may be some other libraries that have their own implementation of $. So to avoid global variable collisions, we have to create a private space.

Wait! What do return and each() do above? $() returns an array of HTML elements, so we have to iterate all of them, and for that, we use the each() method. return makes our plug-in chainable. jQuery is famous for Chaining. Chaining allows us to call a set of methods on an object like below:

We have to talk about the mouse-move event handler right here. In the mouse-move event, we need to know the direction. If the direction is "vertical", then we should scroll only in the vertical direction. Likewise, if it is "horizontal", then scroll only in the horizontal direction, else both.

Somehow if we pass the direction parameter to the mouse-move handler, then by writing a set of if-else statements, we can do that. But I'm not so happy with that approach because every time the mouse moves, the conditions get evaluated. It would be nice if it happens only once.

I thought of putting the scroll logic in a separate method called scrollFn. The trick is, the implementation of scrollFn is dynamically decided based on the direction parameter. Little confusing? See the code below:

The same closure concept! But this time, a different thing than the private scope. This approach is called Memoizing. The body part of the function scrollFn is dynamically created at initialization time.

Where $this is the object, and x and y are the distance in pixels the object has to be scrolled either horizontally and vertically. We have to find a way to get this method in the mouse-move handler. That is really simple! We just have to store it using the data() method:

$(this).data("scrollFn", scrollFn);
//"scrollFn" is the key, scrollFn is the value.

In the mousedown event handler, we enable the scrolling by setting the flag scroll to true. The flag and initial mouse positions are stored using data(). Also, we swap the CSS classes to change the cursor.

In the mousemove event handler, we calculate the differences between the old and new mouse positions and scroll the content using the scrollFn method that is stored. Finally, we overwrite the old mouse position with the new one.

Before seeing the complete code, I found an issue during mouse-out, the event we are not listening to... So I did the same thing that we did in mouse-up, that is disable the scrolling when the user brings the mouse-out of the element.

Share

About the Author

I'm a software developer from south tip of India. I spent most of the time in learning new technologies. I've a keen interest in client-side technologies especially JavaScript and admire it is the most beautiful language ever seen.

I like sharing my knowledge and written some non-popular articles. I believe in quality and standards but blames myself for lagging them.