Skip to content

Instantly share code, notes, and snippets.

@mistic100
Created April 8, 2015 18:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mistic100/4e8655a2c04bd40dd728 to your computer and use it in GitHub Desktop.
Save mistic100/4e8655a2c04bd40dd728 to your computer and use it in GitHub Desktop.
Computes distance and angle between the cursor and a DOM element.
/**
* jQuery amusesMoi! 1.0
*
* Copyright 2012-2013, Damien "Mistic" Sorel
* http://www.strangeplanet.fr
*
* License:
* MIT and GPL dual licensing
*
* Depends:
* jquery.js
*/
(function($) {
/**
* Plugin declaration
*/
$.fn.amusesMoi = function(options) {
// callable public methods
var callable = ['updateTargetPosition','updateAngle','setOptions'];
var plugin = $(this).data('amusesMoi');
// already instantiated and trying to execute a method
if (plugin && typeof options === 'string') {
if ($.inArray(options,callable)!==-1) {
return plugin[options].apply(plugin, Array.prototype.slice.call(arguments, 1));
}
else {
throw 'Method "' + options + '" does not exist on jQuery.amusesMoi';
}
}
// not instantiated and trying to pass options object (or nothing)
else if (!plugin && (typeof options === 'object' || typeof options === 'function' || !options)) {
if (typeof options === 'function') {
options = {onChange: options};
}
else if (!options) {
options = {};
}
// extend defaults
options = $.extend({}, $.fn.amusesMoi.defaults, options);
// for each element instantiate the plugin
return this.each(function() {
var plugin = $(this).data('amusesMoi');
// create new instance of the plugin if the plugin isn't initialised
if (!plugin) {
plugin = new $.amusesMoi($(this), options);
plugin.init();
$(this).data('amusesMoi', plugin);
}
});
}
}
/**
* Defaults
*/
$.fn.amusesMoi.defaults = {
offsetX: 0, // pixels
offsetY: 0, // pixels
offsetAngle: 0, // radians
direction: "anticlockwise",
onInit: null,
onChange: null,
onTargetMove: null
};
/**
* Main plugin function
*/
$.amusesMoi = function(element, options) {
this.options = options;
if (element instanceof jQuery) {
this.$target = element;
}
else {
this.$target = $(element);
}
this.target_position = new Object;
this.mouse_position = {'x':0, 'y':0};
/*
* init the plugin
* scope: private
*/
this.init = function() {
// target position
this.updateTargetPosition();
this.$target.on({
'resize.amusesMoi' : $.proxy(function(){ this.updateTargetPosition(); }, this)
});
$(window).on({
'resize.amusesMoi' : $.proxy(function(){ this.updateTargetPosition(); }, this)
});
// mouse position
$(document).on({
'mousemove.amusesMoi' : $.proxy(function(e){ this.updateMousePosition(e); }, this)
});
// callback
if (typeof this.options.onInit == 'function') {
this.options.onInit(this.target_position, this.options);
}
}
/*
* update plugin options
* scope: public
*/
this.setOptions = function(options) {
if (typeof options != 'object') {
options = {};
}
this.options = $.extend({}, this.options, options);
this.updateTargetPosition();
}
/*
* update target position
* scope: public
*/
this.updateTargetPosition = function() {
pos = this.$target.offset();
this.target_position = {
'x': pos.left + this.options.offsetX + this.$target.outerWidth(true)/2,
'y': pos.top + this.options.offsetY + this.$target.outerHeight(true)/2
};
// callback
if (typeof this.options.onTargetMove == 'function') {
this.options.onTargetMove(this.target_position, this.options);
}
this.updateAngle();
}
/*
* update mouse position
* scope: private
*/
this.updateMousePosition = function(e) {
this.mouse_position = {
'x': e.pageX,
'y': e.pageY
};
this.updateAngle();
}
/*
* update angle and fire the callback
* scope: public
*/
this.updateAngle = function() {
delta = {
'x': this.mouse_position.x-this.target_position.x,
'y': this.target_position.y-this.mouse_position.y
};
distance = Math.sqrt(delta.x*delta.x + delta.y*delta.y);
angle = -Math.atan2(delta.x, delta.y)+Math.PI/2;
if (this.options.direction=="clockwise") {
angle=2*Math.PI-angle;
}
angle-= this.options.offsetAngle;
if (angle<0) {
angle+=2*Math.PI;
}
else if (angle>=2*Math.PI) {
angle-=2*Math.PI;
}
// callback
if (typeof this.options.onChange == 'function') {
this.options.onChange(distance, angle, this.target_position, this.mouse_position, this.options);
}
}
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment