first commit
This commit is contained in:
271
MessagesMap/Scripts/utilities.js
Normal file
271
MessagesMap/Scripts/utilities.js
Normal file
@@ -0,0 +1,271 @@
|
||||
module.exports = {
|
||||
/**
|
||||
* Extends an object
|
||||
*
|
||||
* @param {Object} target object to extend
|
||||
* @param {Object} source object to take properties from
|
||||
* @return {Object} extended object
|
||||
*/
|
||||
extend: function(target, source) {
|
||||
target = target || {};
|
||||
for (var prop in source) {
|
||||
// Go recursively
|
||||
if (this.isObject(source[prop])) {
|
||||
target[prop] = this.extend(target[prop], source[prop])
|
||||
} else {
|
||||
target[prop] = source[prop]
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an object is a DOM element
|
||||
*
|
||||
* @param {Object} o HTML element or String
|
||||
* @return {Boolean} returns true if object is a DOM element
|
||||
*/
|
||||
, isElement: function(o){
|
||||
return (
|
||||
o instanceof HTMLElement || o instanceof SVGElement || o instanceof SVGSVGElement || //DOM2
|
||||
(o && typeof o === 'object' && o !== null && o.nodeType === 1 && typeof o.nodeName === 'string')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an object is an Object
|
||||
*
|
||||
* @param {Object} o Object
|
||||
* @return {Boolean} returns true if object is an Object
|
||||
*/
|
||||
, isObject: function(o){
|
||||
return Object.prototype.toString.call(o) === '[object Object]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if variable is Number
|
||||
*
|
||||
* @param {Integer|Float} n
|
||||
* @return {Boolean} returns true if variable is Number
|
||||
*/
|
||||
, isNumber: function(n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for an SVG element
|
||||
*
|
||||
* @param {Object|String} elementOrSelector DOM Element or selector String
|
||||
* @return {Object|Null} SVG or null
|
||||
*/
|
||||
, getSvg: function(elementOrSelector) {
|
||||
var element
|
||||
, svg;
|
||||
|
||||
if (!this.isElement(elementOrSelector)) {
|
||||
// If selector provided
|
||||
if (typeof elementOrSelector === 'string' || elementOrSelector instanceof String) {
|
||||
// Try to find the element
|
||||
element = document.querySelector(elementOrSelector)
|
||||
|
||||
if (!element) {
|
||||
throw new Error('Provided selector did not find any elements. Selector: ' + elementOrSelector)
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
throw new Error('Provided selector is not an HTML object nor String')
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
element = elementOrSelector
|
||||
}
|
||||
|
||||
if (element.tagName.toLowerCase() === 'svg') {
|
||||
svg = element;
|
||||
} else {
|
||||
if (element.tagName.toLowerCase() === 'object') {
|
||||
svg = element.contentDocument.documentElement;
|
||||
} else {
|
||||
if (element.tagName.toLowerCase() === 'embed') {
|
||||
svg = element.getSVGDocument().documentElement;
|
||||
} else {
|
||||
if (element.tagName.toLowerCase() === 'img') {
|
||||
throw new Error('Cannot script an SVG in an "img" element. Please use an "object" element or an in-line SVG.');
|
||||
} else {
|
||||
throw new Error('Cannot get SVG.');
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return svg
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a given context to a function
|
||||
* @param {Function} fn Function
|
||||
* @param {Object} context Context
|
||||
* @return {Function} Function with certain context
|
||||
*/
|
||||
, proxy: function(fn, context) {
|
||||
return function() {
|
||||
return fn.apply(context, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object type
|
||||
* Uses toString that returns [object SVGPoint]
|
||||
* And than parses object type from string
|
||||
*
|
||||
* @param {Object} o Any object
|
||||
* @return {String} Object type
|
||||
*/
|
||||
, getType: function(o) {
|
||||
return Object.prototype.toString.apply(o).replace(/^\[object\s/, '').replace(/\]$/, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* If it is a touch event than add clientX and clientY to event object
|
||||
*
|
||||
* @param {Event} evt
|
||||
* @param {SVGSVGElement} svg
|
||||
*/
|
||||
, mouseAndTouchNormalize: function(evt, svg) {
|
||||
// If no clientX then fallback
|
||||
if (evt.clientX === void 0 || evt.clientX === null) {
|
||||
// Fallback
|
||||
evt.clientX = 0
|
||||
evt.clientY = 0
|
||||
|
||||
// If it is a touch event
|
||||
if (evt.touches !== void 0 && evt.touches.length) {
|
||||
if (evt.touches[0].clientX !== void 0) {
|
||||
evt.clientX = evt.touches[0].clientX
|
||||
evt.clientY = evt.touches[0].clientY
|
||||
} else if (evt.touches[0].pageX !== void 0) {
|
||||
var rect = svg.getBoundingClientRect();
|
||||
|
||||
evt.clientX = evt.touches[0].pageX - rect.left
|
||||
evt.clientY = evt.touches[0].pageY - rect.top
|
||||
}
|
||||
// If it is a custom event
|
||||
} else if (evt.originalEvent !== void 0) {
|
||||
if (evt.originalEvent.clientX !== void 0) {
|
||||
evt.clientX = evt.originalEvent.clientX
|
||||
evt.clientY = evt.originalEvent.clientY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an event is a double click/tap
|
||||
* TODO: For touch gestures use a library (hammer.js) that takes in account other events
|
||||
* (touchmove and touchend). It should take in account tap duration and traveled distance
|
||||
*
|
||||
* @param {Event} evt
|
||||
* @param {Event} prevEvt Previous Event
|
||||
* @return {Boolean}
|
||||
*/
|
||||
, isDblClick: function(evt, prevEvt) {
|
||||
// Double click detected by browser
|
||||
if (evt.detail === 2) {
|
||||
return true;
|
||||
}
|
||||
// Try to compare events
|
||||
else if (prevEvt !== void 0 && prevEvt !== null) {
|
||||
var timeStampDiff = evt.timeStamp - prevEvt.timeStamp // should be lower than 250 ms
|
||||
, touchesDistance = Math.sqrt(Math.pow(evt.clientX - prevEvt.clientX, 2) + Math.pow(evt.clientY - prevEvt.clientY, 2))
|
||||
|
||||
return timeStampDiff < 250 && touchesDistance < 10
|
||||
}
|
||||
|
||||
// Nothing found
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current timestamp as an integer
|
||||
*
|
||||
* @return {Number}
|
||||
*/
|
||||
, now: Date.now || function() {
|
||||
return new Date().getTime();
|
||||
}
|
||||
|
||||
// From underscore.
|
||||
// Returns a function, that, when invoked, will only be triggered at most once
|
||||
// during a given window of time. Normally, the throttled function will run
|
||||
// as much as it can, without ever going more than once per `wait` duration;
|
||||
// but if you'd like to disable the execution on the leading edge, pass
|
||||
// `{leading: false}`. To disable execution on the trailing edge, ditto.
|
||||
// jscs:disable
|
||||
// jshint ignore:start
|
||||
, throttle: function(func, wait, options) {
|
||||
var that = this;
|
||||
var context, args, result;
|
||||
var timeout = null;
|
||||
var previous = 0;
|
||||
if (!options) options = {};
|
||||
var later = function() {
|
||||
previous = options.leading === false ? 0 : that.now();
|
||||
timeout = null;
|
||||
result = func.apply(context, args);
|
||||
if (!timeout) context = args = null;
|
||||
};
|
||||
return function() {
|
||||
var now = that.now();
|
||||
if (!previous && options.leading === false) previous = now;
|
||||
var remaining = wait - (now - previous);
|
||||
context = this;
|
||||
args = arguments;
|
||||
if (remaining <= 0 || remaining > wait) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
previous = now;
|
||||
result = func.apply(context, args);
|
||||
if (!timeout) context = args = null;
|
||||
} else if (!timeout && options.trailing !== false) {
|
||||
timeout = setTimeout(later, remaining);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
// jshint ignore:end
|
||||
// jscs:enable
|
||||
|
||||
/**
|
||||
* Create a requestAnimationFrame simulation
|
||||
*
|
||||
* @param {Number|String} refreshRate
|
||||
* @return {Function}
|
||||
*/
|
||||
, createRequestAnimationFrame: function(refreshRate) {
|
||||
var timeout = null
|
||||
|
||||
// Convert refreshRate to timeout
|
||||
if (refreshRate !== 'auto' && refreshRate < 60 && refreshRate > 1) {
|
||||
timeout = Math.floor(1000 / refreshRate)
|
||||
}
|
||||
|
||||
if (timeout === null) {
|
||||
return window.requestAnimationFrame || requestTimeout(33)
|
||||
} else {
|
||||
return requestTimeout(timeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a callback that will execute after a given timeout
|
||||
*
|
||||
* @param {Function} timeout
|
||||
* @return {Function}
|
||||
*/
|
||||
function requestTimeout(timeout) {
|
||||
return function(callback) {
|
||||
window.setTimeout(callback, timeout)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user