mirror of
https://github.com/cds-astro/aladin-lite.git
synced 2026-01-08 11:25:21 -08:00
314 lines
9.5 KiB
JavaScript
314 lines
9.5 KiB
JavaScript
// Copyright 2013 - UDS/CNRS
|
|
// The Aladin Lite program is distributed under the terms
|
|
// of the GNU General Public License version 3.
|
|
//
|
|
// This file is part of Aladin Lite.
|
|
//
|
|
// Aladin Lite is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 3 of the License.
|
|
//
|
|
// Aladin Lite is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// The GNU General Public License is available in COPYING file
|
|
// along with Aladin Lite.
|
|
//
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* Aladin Lite project
|
|
*
|
|
* File Utils
|
|
*
|
|
* Author: Thomas Boch[CDS]
|
|
*
|
|
*****************************************************************************/
|
|
|
|
Utils = Utils || {};
|
|
|
|
Utils.cssScale = undefined;
|
|
// adding relMouseCoords to HTMLCanvasElement prototype (see http://stackoverflow.com/questions/55677/how-do-i-get-the-coordinates-of-a-mouse-click-on-a-canvas-element )
|
|
function relMouseCoords(event) {
|
|
var totalOffsetX = 0;
|
|
var totalOffsetY = 0;
|
|
var canvasX = 0;
|
|
var canvasY = 0;
|
|
var currentElement = this;
|
|
|
|
if (event.offsetX) {
|
|
return {x: event.offsetX, y:event.offsetY};
|
|
}
|
|
else {
|
|
if (!Utils.cssScale) {
|
|
var st = window.getComputedStyle(document.body, null);
|
|
var tr = st.getPropertyValue("-webkit-transform") ||
|
|
st.getPropertyValue("-moz-transform") ||
|
|
st.getPropertyValue("-ms-transform") ||
|
|
st.getPropertyValue("-o-transform") ||
|
|
st.getPropertyValue("transform");
|
|
var matrixRegex = /matrix\((-?\d*\.?\d+),\s*0,\s*0,\s*(-?\d*\.?\d+),\s*0,\s*0\)/;
|
|
var matches = tr.match(matrixRegex);
|
|
if (matches) {
|
|
Utils.cssScale = parseFloat(matches[1]);
|
|
}
|
|
else {
|
|
Utils.cssScale = 1;
|
|
}
|
|
}
|
|
var e = event;
|
|
var canvas = e.target;
|
|
// http://www.jacklmoore.com/notes/mouse-position/
|
|
var target = e.target || e.srcElement;
|
|
var style = target.currentStyle || window.getComputedStyle(target, null);
|
|
var borderLeftWidth = parseInt(style['borderLeftWidth'], 10);
|
|
var borderTopWidth = parseInt(style['borderTopWidth'], 10);
|
|
var rect = target.getBoundingClientRect();
|
|
|
|
var clientX = e.clientX;
|
|
var clientY = e.clientY;
|
|
if (e.clientX == undefined) {
|
|
clientX = e.originalEvent.changedTouches[0].clientX;
|
|
clientY = e.originalEvent.changedTouches[0].clientY;
|
|
}
|
|
|
|
var offsetX = clientX - borderLeftWidth - rect.left;
|
|
var offsetY = clientY - borderTopWidth - rect.top
|
|
|
|
return {x: parseInt(offsetX/Utils.cssScale), y: parseInt(offsetY/Utils.cssScale)};
|
|
}
|
|
}
|
|
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
|
|
|
|
|
|
|
|
//Function.prototype.bind polyfill from
|
|
//https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
|
|
if (!Function.prototype.bind) {
|
|
Function.prototype.bind = function (obj) {
|
|
// closest thing possible to the ECMAScript 5 internal IsCallable function
|
|
if (typeof this !== 'function') {
|
|
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
|
|
}
|
|
|
|
var slice = [].slice,
|
|
args = slice.call(arguments, 1),
|
|
self = this,
|
|
nop = function () { },
|
|
bound = function () {
|
|
return self.apply(this instanceof nop ? this : (obj || {}),
|
|
args.concat(slice.call(arguments)));
|
|
};
|
|
|
|
bound.prototype = this.prototype;
|
|
|
|
return bound;
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$ = $ || jQuery;
|
|
|
|
/* source : http://stackoverflow.com/a/8764051 */
|
|
$.urlParam = function(name, queryString){
|
|
if (queryString===undefined) {
|
|
queryString = location.search;
|
|
}
|
|
return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(queryString)||[,""])[1].replace(/\+/g, '%20'))||null;
|
|
};
|
|
|
|
/* source: http://stackoverflow.com/a/1830844 */
|
|
Utils.isNumber = function(n) {
|
|
return !isNaN(parseFloat(n)) && isFinite(n);
|
|
};
|
|
|
|
Utils.isInt = function(n) {
|
|
return Utils.isNumber(n) && Math.floor(n)==n;
|
|
};
|
|
|
|
/* a debounce function, used to prevent multiple calls to the same function if less than delay milliseconds have passed */
|
|
Utils.debounce = function(fn, delay) {
|
|
var timer = null;
|
|
return function () {
|
|
var context = this, args = arguments;
|
|
clearTimeout(timer);
|
|
timer = setTimeout(function () {
|
|
fn.apply(context, args);
|
|
}, delay);
|
|
};
|
|
};
|
|
|
|
/* return a throttled function, to rate limit the number of calls (by default, one call every 250 milliseconds) */
|
|
Utils.throttle = function(fn, threshhold, scope) {
|
|
threshhold || (threshhold = 250);
|
|
var last,
|
|
deferTimer;
|
|
return function () {
|
|
var context = scope || this;
|
|
|
|
var now = +new Date,
|
|
args = arguments;
|
|
if (last && now < last + threshhold) {
|
|
// hold on to it
|
|
clearTimeout(deferTimer);
|
|
deferTimer = setTimeout(function () {
|
|
last = now;
|
|
fn.apply(context, args);
|
|
}, threshhold);
|
|
} else {
|
|
last = now;
|
|
fn.apply(context, args);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
/* A LRU cache, inspired by https://gist.github.com/devinus/409353#file-gistfile1-js */
|
|
// TODO : utiliser le LRU cache pour les tuiles images
|
|
Utils.LRUCache = function (maxsize) {
|
|
this._keys = [];
|
|
this._items = {};
|
|
this._expires = {};
|
|
this._size = 0;
|
|
this._maxsize = maxsize || 1024;
|
|
};
|
|
|
|
Utils.LRUCache.prototype = {
|
|
set: function (key, value) {
|
|
var keys = this._keys,
|
|
items = this._items,
|
|
expires = this._expires,
|
|
size = this._size,
|
|
maxsize = this._maxsize;
|
|
|
|
if (size >= maxsize) { // remove oldest element when no more room
|
|
keys.sort(function (a, b) {
|
|
if (expires[a] > expires[b]) return -1;
|
|
if (expires[a] < expires[b]) return 1;
|
|
return 0;
|
|
});
|
|
|
|
size--;
|
|
delete expires[keys[size]];
|
|
delete items[keys[size]];
|
|
}
|
|
|
|
keys[size] = key;
|
|
items[key] = value;
|
|
expires[key] = Date.now();
|
|
size++;
|
|
|
|
this._keys = keys;
|
|
this._items = items;
|
|
this._expires = expires;
|
|
this._size = size;
|
|
},
|
|
|
|
get: function (key) {
|
|
var item = this._items[key];
|
|
if (item) this._expires[key] = Date.now();
|
|
return item;
|
|
},
|
|
|
|
keys: function() {
|
|
return this._keys;
|
|
}
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////:
|
|
|
|
/**
|
|
Make an AJAX call, given a list of potential mirrors
|
|
First successful call will result in options.onSuccess being called back
|
|
If all calls fail, onFailure is called back at the end
|
|
|
|
This method assumes the URL are CORS-compatible, no proxy will be used
|
|
*/
|
|
Utils.loadFromMirrors = function(urls, options) {
|
|
var data = options && options.data || null;
|
|
var method = options && options.method || 'GET';
|
|
var dataType = options && options.dataType || null;
|
|
var timeout = options && options.timeout || 20;
|
|
|
|
var onSuccess = options && options.onSuccess || null;
|
|
var onFailure = options && options.onFailure || null;
|
|
|
|
if (urls.length === 0) {
|
|
(typeof onFailure === 'function') && onFailure();
|
|
}
|
|
else {
|
|
var ajaxOptions = {
|
|
url: urls[0],
|
|
data: data
|
|
}
|
|
if (dataType) {
|
|
ajaxOptions.dataType = dataType;
|
|
}
|
|
|
|
$.ajax(ajaxOptions)
|
|
.done(function(data) {
|
|
(typeof onSuccess === 'function') && onSuccess(data);
|
|
})
|
|
.fail(function() {
|
|
Utils.loadFromMirrors(urls.slice(1), options);
|
|
});
|
|
}
|
|
}
|
|
|
|
// return the jquery ajax object configured with the requested parameters
|
|
// by default, we use the proxy (safer, as we don't know if the remote server supports CORS)
|
|
Utils.getAjaxObject = function(url, method, dataType, useProxy) {
|
|
if (useProxy!==false) {
|
|
useProxy = true;
|
|
}
|
|
|
|
if (useProxy===true) {
|
|
var urlToRequest = Aladin.JSONP_PROXY + '?url=' + encodeURIComponent(url);
|
|
}
|
|
else {
|
|
urlToRequest = url;
|
|
}
|
|
method = method || 'GET';
|
|
dataType = dataType || null;
|
|
|
|
return $.ajax({
|
|
url: urlToRequest,
|
|
method: method,
|
|
dataType: dataType
|
|
});
|
|
};
|
|
|
|
// return true if script is executed in a HTTPS context
|
|
// return false otherwise
|
|
Utils.isHttpsContext = function() {
|
|
return ( window.location.protocol === 'https:' );
|
|
};
|
|
|
|
// generate an absolute URL from a relative URL
|
|
// example: getAbsoluteURL('foo/bar/toto') return http://cds.unistra.fr/AL/foo/bar/toto if executed from page http://cds.unistra.fr/AL/
|
|
Utils.getAbsoluteURL = function(url) {
|
|
var a = document.createElement('a');
|
|
a.href = url;
|
|
|
|
return a.href;
|
|
};
|
|
|
|
// generate a valid v4 UUID
|
|
Utils.uuidv4 = function() {
|
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
|
return v.toString(16);
|
|
});
|
|
}
|
|
|