UNPKG

doevisualizations

Version:

Data Visualization Library based on RequireJS and D3.js (v4+)

332 lines (323 loc) 9.36 kB
steal('jquery', 'jquerypp/event/livehack', function ($) { /** * @constructor jQuery.Hover * @plugin jquerypp/event/hover * @download http://jmvcsite.heroku.com/pluginify?plugins[]=jquerypp/event/hover/hover.js * @parent jQuery.event.hover * * Creates a new hover. The constructor should not be called directly. * * An instance of `$.Hover` is passed as the second argument to each * [jQuery.event.hover] event handler: * * $('#menu').on("hoverinit", function(ev, hover) { * // Set the hover distance to 20px * hover.distance(20); * }); */ $.Hover = function () { this._delay = $.Hover.delay; this._distance = $.Hover.distance; this._leave = $.Hover.leave; }; /** * @static */ $.extend($.Hover, { /** * @property {Number} jQuery.Hover.delay delay * @parent jQuery.Hover.static * * @body * * `$.Hover.delay` is the delay (in milliseconds) after which the hover is * activated by default. * * Set this value as a global default. The default is 100ms. * * // Set the global hover delay to 1 second * $.Hover.delay = 1000; */ delay : 100, /** * @property {Number} jQuery.Hover.distance distance * @parent jQuery.Hover.static * * @body * * `$.Hover.distance` is the maximum distance (in pixels) that the mouse is allowed to * travel within the time of [jQuery.Hover.delay] in order to activate a hover. * * Set this value as a global default. The default is 10px. * * // Set the global hover distance to 1 pixel * $.Hover.distance = 1; */ distance : 10, leave : 0 }); /** * @prototype */ $.extend($.Hover.prototype, { /** * @function jQuery.Hover.prototype.delay * @parent jQuery.Hover.prototype * * Sets the delay (in ms) for this hover. * * @signature `hover.delay(delay)` * @param {Number} delay the number of milliseconds used to determine a hover * @return {$.Hover} The hover object * * @body * * This method should only be used in [jQuery.event.hover.hoverinit hoverinit]: * * $('.hoverable').on('hoverinit', function(ev, hover) { * // Set the delay to 500ms * hover.delay(500); * }); * * */ delay : function (delay) { this._delay = delay; return this; }, /** * @function jQuery.Hover.prototype.distance * @parent jQuery.Hover.prototype * * `hover.distance(px) sets the maximum distance (in pixels) the mouse is allowed to travel in order to activate * the hover. This method should only be used in [jQuery.event.hover.hoverinit hoverinit]: * * @signature `hover.distance(distance)` * @param {Number} distance the max distance in pixels a mouse can move to be considered a hover * @return {jQuery.Hover} The hover object * @body * * * $('.hoverable').on('hoverinit', function(ev, hover) { * // Set the distance to 1px * hover.distance(1); * }); * */ distance : function (distance) { this._distance = distance; return this; }, /** * @function jQuery.Hover.prototype.leave * @parent jQuery.Hover.prototype * * Sets the delay value. * * @signature `hover.leave(delay)` * * Sets the delay value. * * @param {Number} delay the number of milliseconds * the hover should stay active after the mouse leaves. * * @return {jQuery.Hover} The hover object. * * @body * `hover.leave(delay)` sets a delay for how long the hover should stay active after the mouse left. * This method should only be used in [jQuery.event.hover.hoverinit hoverinit]: * * $('.hoverable').on('hoverinit', function(ev, hover) { * // Stay active for another second after the mouse left * hover.leave(1000); * }); * */ leave : function (leave) { this._leave = leave; return this; } }); var event = $.event, handle = event.handle, onmouseenter = function (ev) { // now start checking mousemoves to update location var delegate = ev.delegateTarget || ev.currentTarget; var selector = ev.handleObj.selector; var pending = $.data(delegate,"_hover"+selector); // prevents another mouseenter until current has run its course if(pending) { // Under some circumstances, mouseleave may never fire // (e.g., the element is removed while hovered) // so if we've entered another element, wait the leave time, // then force it to release. if(!pending.forcing) { pending.forcing = true; clearTimeout(pending.leaveTimer); var leaveTime = pending.leaving ? Math.max(0,pending.hover.leave - (new Date() - pending.leaving)) : pending.hover.leave; var self = this; setTimeout(function() { pending.callHoverLeave(); onmouseenter.call(self,ev); },leaveTime); } return; } var loc = { pageX : ev.pageX, pageY : ev.pageY }, // The current distance dist = 0, // Timer that checks for the distance travelled timer, enteredEl = this, // If we are hovered hovered = false, // The previous event lastEv = ev, // The $.Hover instance passed to events hover = new $.Hover(), // timer if hover.leave has been called leaveTimer, // Callback for triggering hoverleave callHoverLeave = function () { $.each(event.find(delegate, ["hoverleave"], selector), function () { this.call(enteredEl, ev, hover); }); cleanUp(); }, mousemove = function (ev) { clearTimeout(leaveTimer); // Update the distance and location dist += Math.pow(ev.pageX - loc.pageX, 2) + Math.pow(ev.pageY - loc.pageY, 2); loc = { pageX : ev.pageX, pageY : ev.pageY }; lastEv = ev }, mouseleave = function (ev) { clearTimeout(timer); if (hovered) { // go right away if (hover._leave === 0) { callHoverLeave(); } else { clearTimeout(leaveTimer); // leave the hover after the time set in hover.leave(time) pending.leaving = new Date(); leaveTimer = pending.leaveTimer = setTimeout(function(){ callHoverLeave(); }, hover._leave) } } else { cleanUp(); } }, cleanUp = function () { // Unbind all events and data $(enteredEl).unbind("mouseleave", mouseleave) $(enteredEl).unbind("mousemove", mousemove); $.removeData(delegate, "_hover" + selector) }, hoverenter = function() { $.each(event.find(delegate, ["hoverenter"], selector), function () { this.call(enteredEl, lastEv, hover) }) hovered = true; }; pending = { callHoverLeave: callHoverLeave, hover: hover }; $.data(delegate,"_hover"+selector, pending); // Bind the mousemove event $(enteredEl).bind("mousemove", mousemove).bind("mouseleave", mouseleave); // call hoverinit for each element with the hover instance $.each(event.find(delegate, ["hoverinit"], selector), function () { this.call(enteredEl, ev, hover) }) if (hover._delay === 0) { hoverenter(); } else { timer = setTimeout(function () { // check that we aren't moving around if (dist < hover._distance && $(enteredEl).queue().length == 0) { hoverenter(); return; } else { // Reset distance and timer dist = 0; timer = setTimeout(arguments.callee, hover._delay) } }, hover._delay); } }; // Attach events event.setupHelper([ /** * @function jQuery.event.special.hoverinit hoverinit * @parent jQuery.event.hover * * @body * * `hoverinit` is called when a hover is about to start (on `mouseenter`). Listen for `hoverinit` events to configure * [jQuery.Hover::delay delay] and [jQuery.Hover::distance distance] * for this specific event: * * $(".option").on("hoverinit", function(ev, hover){ * //set the distance to 10px * hover.distance(10); * //set the delay to 200ms * hover.delay(10); * // End the hover one second after the mouse leaves * hover.leave(1000); * }) */ "hoverinit", /** * @function jQuery.event.special.hoverenter hoverenter * @parent jQuery.event.hover * * @body * * `hoverenter` events are called when the mouses less than [jQuery.Hover.prototype.distance] pixels in * [jQuery.Hover.prototype.delay delay] milliseconds. * * $(".option").on("hoverenter", function(ev, hover){ * $(this).addClass("hovering"); * }) */ "hoverenter", /** * @function jQuery.event.special.hoverleave hoverleave * @parent jQuery.event.hover * * @body * * `hoverleave` is called when the mouse leaves an element that has been hovered. * * $(".option").on("hoverleave", function(ev, hover){ * $(this).removeClass("hovering"); * }) */ "hoverleave", /** * @function jQuery.event.special.hovermove hovermove * @parent jQuery.event.hover * * @body * * `hovermove` is called when a `mousemove` occurs on an element that has been hovered. * * $(".option").on("hovermove", function(ev, hover){ * // not sure why you would want to listen for this * // but we provide it just in case * }) */ "hovermove"], "mouseenter", onmouseenter); return $; });