src/util.js
import Const from './const';
export default class util {
static getAnimationFrame() {
}
/**
* use promise to implement xmlHttpRequest process
* promise.then receive 2 params.(resolve func, reject func)
*/
// static xhr(){
// // promise will excute immediately after init.
// let promise = new Promise(() => {
// })
// }
/**
* Promise.prototype.then()
* receive resolve callback and reject callback.
* SO important, if series of Async Process is required,
* Promise is better than callback hell !
*
* xhr().then(data => { // resolve actions.. },
* err => { // reject actions.. }
* ).then()
*
*/
/**
* return promise obj.
*/
static getJSON(url, resolve, reject) {
let promise = new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = handler;
xhr.responseType = "json";
xhr.setRequestHeader("Accept", "application/json");
xhr.send();
function handler() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
// if server response success
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
})
return promise;
}
static deepClone(obj) {
let cloned = {};
if (typeof obj !== 'object') return null;
for(let k in obj){
if (obj.hasOwnProperty(k) && typeof obj[k] !== 'object') {
cloned[k] = obj[k];
} else if (obj[k].constructor.toString().indexOf("Object") > 0) {
cloned[k] = this.deepClone(obj[k]);
} else if (Array.isArray(obj[k])) {
cloned[k] = obj[k].map((ele) => {
// let ret = null;
if (typeof ele !== 'object') return ele;
else return this.deepClone(ele);
});
// cloned[k] = [].concat(obj[k]);
}
}
return cloned;
}
static isChanged(lastData, data) {
if (JSON.stringify(lastData) == JSON.stringify(data))
return false;
else {
console.warn('chartData changed..')
return true;
}
}
/**
* return iconposition style by iconName
*/
static setIconDiv(dom, iconName) {
let icons = Const.Sprites;
if (iconName && icons[iconName]) {
let iconStyle = icons[iconName],
iconDiv = document.createElement("div");
iconDiv.style.width = iconStyle.width + "px";
iconDiv.style.height = iconStyle.height + "px";
iconDiv.style.overflow = 'hidden';
let iconImg = document.createElement("img");
iconImg.src = Const.SpritesUrl + ".png";
iconImg.style.marginLeft = "-" + iconStyle.x + "px";
iconImg.style.marginTop = "-" + iconStyle.y + "px";
iconDiv.appendChild(iconImg);
dom.appendChild(iconDiv);
}
}
/**
* add img, video element to domContainer.
* @param {*domEle} dom, dom container..
* @param {*Array} res, urls of img/video loaded to dom.
*/
static setResource(dom, res) {
if (!(res instanceof Array)) return;
for (let i = 0; i < res.length; i ++) {
let filetype = this.getFiletype(res[i]);
if (filetype !== "") {
let ele = document.createElement(filetype);
ele.style.width = ele.style.height = dom.style.width = dom.style.height = '60px';
ele.style.borderRadius = "50%";
ele.src = res[i];
dom.style.borderRadius = "50%";
dom.appendChild(ele);
}
if (filetype == 'video') {
ele.setAttribute('autoplay', true);
}
}
}
static getFiletype(uri) {
let isIMG = uri.match(/\.(jpg)|(png)|(gif)/g) ? true: false;
let isMP4 = uri.match(/\.mp4\?+/g) ? true: false;
if (isIMG) return 'img';
else if (isMP4) return 'video';
else {
console.log(`filetype of ${uri} is not supported`);
return '';
}
}
static setChart(dom, data, type, height) {
if (Chart == undefined) {
console.warn(`Chart module ${Chart.toString()} not defined or data invalid: ${data.toString()}`);
return;
}
let canv = document.createElement('canvas'),
ctx = canv.getContext('2d');
let piechart = new Chart(ctx, {
type: type,
data: data,
options: {
legend: {
display: false
}
}
});
canv.height = height; canv.style.height = canv.height + 'px';
canv.width = height; canv.style.width = canv.width + 'px';
dom.appendChild(canv);
}
// random point objs with given number
static rdObjs(num, mapCenter) {
var objs = [], index = 0;
if (!mapCenter) return objs;
for(var i=0;i<num;i++) {
objs.push({
name: "line" + i.toString(),
lon: parseInt(((Math.random()*8)+mapCenter[0]-4).toFixed(2)),
lat: parseInt(((Math.random()*4)+mapCenter[1]-2).toFixed(2)),
color: 'rgba(10,200,'+ (Math.random()*251).toFixed(0) +',0.7)',
});
}
objs.push({
name: "circle1",
lon: mapCenter[0],
lat: mapCenter[1],
radius: parseInt(Math.random()*10),
color: 'rgba(251,200,20,0.6)',
});
return objs;
}
/**
* getJSON("somedata.json").then((data) => {
* console.log("got data: " + data);
* })
* .catch((err) => {
* console.error("encounter error..");
* })
*/
/**
* compared with traditional imageload. what is the advantage ?
*/
static loadImageAsync(url, resolve, reject) {
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = resolve;
image.onerror = reject;
image.src = url;
})
}
/**
* This decorator func.
*/
static readonly(target, name, descriptor) {
descriptor.writable = false;
return descriptor;
}
/**
* target.descriptor..
* this decorator used for log before calling target function.
*/
static log(target, name, descriptor) {
let oldValue = descriptor.value;
descriptor.value = function() {
console.log(`Calling "${name}" with`, arguments);
// descriptor.value refer to the target itself.. func or attri
return oldValue.apply(null, arguments);
}
}
/**
* @param fn {Function}
* @param delay {Number}
* @return {Function}
*/
static debounce(fn, delay) {
let timer;
// timer is closure in mem.. returned function is the listener..
return function() {
var context = this;
var args = arguments;
// clear the previous timer to prevent the function call.
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(context, args)
}, delay);
}
}
}