|
// Define packages: |
|
var sigma = {}; |
|
sigma.tools = {}; |
|
sigma.classes = {}; |
|
sigma.instances = {}; |
|
|
|
// Adding Array helpers, if not present yet: |
|
(function() { |
|
if (!Array.prototype.some) { |
|
Array.prototype.some = function(fun /*, thisp*/) { |
|
var len = this.length; |
|
if (typeof fun != 'function') { |
|
throw new TypeError(); |
|
} |
|
|
|
var thisp = arguments[1]; |
|
for (var i = 0; i < len; i++) { |
|
if (i in this && |
|
fun.call(thisp, this[i], i, this)) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
}; |
|
} |
|
|
|
if (!Array.prototype.forEach) { |
|
Array.prototype.forEach = function(fun /*, thisp*/) { |
|
var len = this.length; |
|
if (typeof fun != 'function') { |
|
throw new TypeError(); |
|
} |
|
|
|
var thisp = arguments[1]; |
|
for (var i = 0; i < len; i++) { |
|
if (i in this) { |
|
fun.call(thisp, this[i], i, this); |
|
} |
|
} |
|
}; |
|
} |
|
|
|
if (!Array.prototype.map) { |
|
Array.prototype.map = function(fun /*, thisp*/) { |
|
var len = this.length; |
|
if (typeof fun != 'function') { |
|
throw new TypeError(); |
|
} |
|
|
|
var res = new Array(len); |
|
var thisp = arguments[1]; |
|
for (var i = 0; i < len; i++) { |
|
if (i in this) { |
|
res[i] = fun.call(thisp, this[i], i, this); |
|
} |
|
} |
|
|
|
return res; |
|
}; |
|
} |
|
|
|
if (!Array.prototype.filter) { |
|
Array.prototype.filter = function(fun /*, thisp*/) { |
|
var len = this.length; |
|
if (typeof fun != 'function') |
|
throw new TypeError(); |
|
|
|
var res = new Array(); |
|
var thisp = arguments[1]; |
|
for (var i = 0; i < len; i++) { |
|
if (i in this) { |
|
var val = this[i]; // in case fun mutates this |
|
if (fun.call(thisp, val, i, this)) { |
|
res.push(val); |
|
} |
|
} |
|
} |
|
|
|
return res; |
|
}; |
|
} |
|
|
|
if (!Object.keys) { |
|
Object.keys = (function() { |
|
var hasOwnProperty = Object.prototype.hasOwnProperty, |
|
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), |
|
dontEnums = [ |
|
'toString', |
|
'toLocaleString', |
|
'valueOf', |
|
'hasOwnProperty', |
|
'isPrototypeOf', |
|
'propertyIsEnumerable', |
|
'constructor' |
|
], |
|
dontEnumsLength = dontEnums.length; |
|
|
|
return function(obj) { |
|
if (typeof obj !== 'object' && |
|
typeof obj !== 'function' || |
|
obj === null |
|
) { |
|
throw new TypeError('Object.keys called on non-object'); |
|
} |
|
|
|
var result = []; |
|
|
|
for (var prop in obj) { |
|
if (hasOwnProperty.call(obj, prop)) result.push(prop); |
|
} |
|
|
|
if (hasDontEnumBug) { |
|
for (var i = 0; i < dontEnumsLength; i++) { |
|
if (hasOwnProperty.call(obj, dontEnums[i])) { |
|
result.push(dontEnums[i]); |
|
} |
|
} |
|
} |
|
return result; |
|
} |
|
})(); |
|
} |
|
})(); |
|
|
|
/** |
|
* A jQuery like properties management class. It works like jQuery .css() |
|
* method: You can call it with juste one string to get the corresponding |
|
* property, with a string and anything else to set the corresponding property, |
|
* or directly with an object, and then each pair string / object (or any type) |
|
* will be set in the properties. |
|
* @constructor |
|
* @this {sigma.classes.Cascade} |
|
*/ |
|
sigma.classes.Cascade = function() { |
|
/** |
|
* This instance properties. |
|
* @protected |
|
* @type {Object} |
|
*/ |
|
this.p = {}; |
|
|
|
/** |
|
* The method to use to set/get any property of this instance. |
|
* @param {(string|Object)} a1 If it is a string and if a2 is undefined, |
|
* then it will return the corresponding |
|
* property. |
|
* If it is a string and if a2 is set, then it |
|
* will set a2 as the property corresponding to |
|
* a1, and return this. |
|
* If it is an object, then each pair string / |
|
* object (or any other type) will be set as a |
|
* property. |
|
* @param {*?} a2 The new property corresponding to a1 if a1 is |
|
* a string. |
|
* @return {(*|sigma.classes.Cascade)} Returns itself or the corresponding |
|
* property. |
|
*/ |
|
this.config = function(a1, a2) { |
|
if (typeof a1 == 'string' && a2 == undefined) { |
|
return this.p[a1]; |
|
} else { |
|
var o = (typeof a1 == 'object' && a2 == undefined) ? a1 : {}; |
|
if (typeof a1 == 'string') { |
|
o[a1] = a2; |
|
} |
|
|
|
for (var k in o) { |
|
if (this.p[k] != undefined) { |
|
this.p[k] = o[k]; |
|
} |
|
} |
|
return this; |
|
} |
|
}; |
|
}; |
|
|
|
/** |
|
* sigma.js custom event dispatcher class. |
|
* @constructor |
|
* @this {sigma.classes.EventDispatcher} |
|
*/ |
|
sigma.classes.EventDispatcher = function() { |
|
/** |
|
* An object containing all the different handlers bound to one or many |
|
* events, indexed by these events. |
|
* @private |
|
* @type {Object.<string,Object>} |
|
*/ |
|
var _h = {}; |
|
|
|
/** |
|
* Represents "this", without the well-known scope issue. |
|
* @private |
|
* @type {sigma.classes.EventDispatcher} |
|
*/ |
|
var _self = this; |
|
|
|
/** |
|
* Will execute the handler the next (and only the next) time that the |
|
* indicated event (or the indicated events) will be triggered. |
|
* @param {string} events The name of the event (or the events |
|
* separated by spaces). |
|
* @param {function(Object)} handler The handler to bind. |
|
* @return {sigma.classes.EventDispatcher} Returns itself. |
|
*/ |
|
function one(events, handler) { |
|
if (!handler || !events) { |
|
return _self; |
|
} |
|
|
|
var eArray = ((typeof events) == 'string') ? events.split(' ') : events; |
|
|
|
eArray.forEach(function(event) { |
|
if (!_h[event]) { |
|
_h[event] = []; |
|
} |
|
|
|
_h[event].push({ |
|
'h': handler, |
|
'one': true |
|
}); |
|
}); |
|
|
|
return _self; |
|
} |
|
|
|
/** |
|
* Will execute the handler everytime that the indicated event (or the |
|
* indicated events) will be triggered. |
|
* @param {string} events The name of the event (or the events |
|
* separated by spaces). |
|
* @param {function(Object)} handler The handler to bind. |
|
* @return {sigma.classes.EventDispatcher} Returns itself. |
|
*/ |
|
function bind(events, handler) { |
|
if (!handler || !events) { |
|
return _self; |
|
} |
|
|
|
var eArray = ((typeof events) == 'string') ? events.split(' ') : events; |
|
|
|
eArray.forEach(function(event) { |
|
if (!_h[event]) { |
|
_h[event] = []; |
|
} |
|
|
|
_h[event].push({ |
|
'h': handler, |
|
'one': false |
|
}); |
|
}); |
|
|
|
return _self; |
|
} |
|
|
|
/** |
|
* Unbinds the handler from a specified event (or specified events). |
|
* @param {?string} events The name of the event (or the events |
|
* separated by spaces). If undefined, |
|
* then all handlers are unbound. |
|
* @param {?function(Object)} handler The handler to unbind. If undefined, |
|
* each handler bound to the event or the |
|
* events will be unbound. |
|
* @return {sigma.classes.EventDispatcher} Returns itself. |
|
*/ |
|
function unbind(events, handler) { |
|
if (!events) { |
|
_h = {}; |
|
} |
|
|
|
var eArray = typeof events == 'string' ? events.split(' ') : events; |
|
|
|
if (handler) { |
|
eArray.forEach(function(event) { |
|
if (_h[event]) { |
|
_h[event] = _h[event].filter(function(e) { |
|
return e['h'] != handler; |
|
}); |
|
} |
|
|
|
if (_h[event] && _h[event].length == 0) { |
|
delete _h[event]; |
|
} |
|
}); |
|
}else { |
|
eArray.forEach(function(event) { |
|
delete _h[event]; |
|
}); |
|
} |
|
|
|
return _self; |
|
} |
|
|
|
/** |
|
* Executes each handler bound to the event |
|
* @param {string} type The type of the event. |
|
* @param {?Object} content The content of the event (optional). |
|
* @return {sigma.classes.EventDispatcher} Returns itself. |
|
*/ |
|
function dispatch(type, content) { |
|
if (_h[type]) { |
|
_h[type].forEach(function(e) { |
|
e['h']({ |
|
'type': type, |
|
'content': content, |
|
'target': _self |
|
}); |
|
}); |
|
|
|
_h[type] = _h[type].filter(function(e) { |
|
return !e['one']; |
|
}); |
|
} |
|
|
|
return _self; |
|
} |
|
|
|
/* PUBLIC INTERFACE: */ |
|
this.one = one; |
|
this.bind = bind; |
|
this.unbind = unbind; |
|
this.dispatch = dispatch; |
|
}; |
|
|
|
(function() { |
|
// Define local shortcut: |
|
var id = 0; |
|
|
|
// Define local package: |
|
var local = {}; |
|
local.plugins = []; |
|
|
|
sigma.init = function(dom) { |
|
var inst = new Sigma(dom, (++id).toString()); |
|
sigma.instances[id] = new SigmaPublic(inst); |
|
return sigma.instances[id]; |
|
}; |
|
|
|
/** |
|
* This class listen to all the different mouse events, to normalize them and |
|
* dispatch action events instead (from "startinterpolate" to "isdragging", |
|
* etc). |
|
* @constructor |
|
* @extends sigma.classes.Cascade |
|
* @extends sigma.classes.EventDispatcher |
|
* @param {element} dom The DOM element to bind the handlers on. |
|
* @this {MouseCaptor} |
|
*/ |
|
function MouseCaptor(dom) { |
|
sigma.classes.Cascade.call(this); |
|
sigma.classes.EventDispatcher.call(this); |
|
|
|
/** |
|
* Represents "this", without the well-known scope issue. |
|
* @private |
|
* @type {MouseCaptor} |
|
*/ |
|
var self = this; |
|
|
|
/** |
|
* The DOM element to bind the handlers on. |
|
* @type {element} |
|
*/ |
|
var dom = dom; |
|
|
|
/** |
|
* The different parameters that define how this instance should work. |
|
* @see sigma.classes.Cascade |
|
* @type {Object} |
|
*/ |
|
this.p = { |
|
minRatio: 1, |
|
maxRatio: 32, |
|
marginRatio: 1, |
|
zoomDelta: 0.1, |
|
dragDelta: 0.3, |
|
zoomMultiply: 2, |
|
directZooming: false, |
|
blockScroll: true, |
|
inertia: 1.1, |
|
mouseEnabled: true |
|
}; |
|
|
|
var oldMouseX = 0; |
|
var oldMouseY = 0; |
|
var startX = 0; |
|
var startY = 0; |
|
|
|
var oldStageX = 0; |
|
var oldStageY = 0; |
|
var oldRatio = 1; |
|
|
|
var targetRatio = 1; |
|
var targetStageX = 0; |
|
var targetStageY = 0; |
|
|
|
var lastStageX = 0; |
|
var lastStageX2 = 0; |