File "donutChart.js"
Full Path: /home/romayxjt/public_html/wp-content/plugins/vikbooking/admin/resources/donutChart.js
File size: 16.09 KB
MIME-type: text/plain
Charset: utf-8
/*
The MIT License (MIT)
Copyright (c) 2014 Valerio Neri
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
var donutChart = function(chartElementID){
var centerx = 0;
var centery = 0;
var sizex = 0;
var sizey = 0;
var scaling = 0;
var radius = 0;
var startx = 0;
var starty = 0;
var endx = 0;
var endy = 0;
var animationSpeed = 1;
var firedAnimation = false;
var innerCircleColor = "#666666";
var outerCircleColor = "#aade87";
var textColor = "#ffffff";
var unitText = "%";
var innerCircleDOM = undefined;
var outerCircleDOM = undefined;
var tNumberDOM = undefined;
var textDOM = undefined;
var tUnitDOM = undefined;
var titleDOM = undefined;
var svg = undefined;
var chartID = chartElementID;
var chart = undefined;
var lastValue = -1;
var startValue = 0;
var endValue = 0;
var loaded = false;
var that=this;
var maxValue = 100;
var titleText ="";
var titlePosition = "top";
var titleColor = "#ffffff";
var textShift = 20; // this is required for moving the chart
var textScaling = 1;
// update: unfortunately in some cases the event is fired, and nobody tells us - that's why we just wait for the element to be available
// wait for the DOM, otherwise you won't find the reference to elements
//document.addEventListener("DOMContentLoaded", onLoad);
onLoad();
// this is used for refreshing the animation
(function() {
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
this.getValue = function(){
if (lastValue>-1)
return Math.round(lastValue/360*maxValue*10)/10;
else
return 0;
}
this.setValue = function(value){
that.draw({end:value, animationSpeed:0});
}
function setAnimate(fromD, toD, duration){
dAct = fromD;
// determine direction (up or down)
if (dAct<toD)
doIt(dAct, toD, duration, "up");
else
doIt(dAct, toD, duration, "down");
}
// this function is used for the animation - it uses an exponential acceleration
function calculateAccValue(xx, m){
var mxValue = m;
var x=Math.round(xx);
if (m==0){
mxValue=1;
}
if (x==0){
x=1;
}
if (Math.abs(x)>=mxValue){
return mxValue;
}else{
//return ( Math.pow( (-2),( (-1*x) + (Math.log(maxValue)/Math.log(2)) ) ) + maxValue);
var num1 = -2;
var num2 = Math.round( ((-1*x)+(Math.log(mxValue)/Math.log(2))) );
return Math.pow(num1 , num2 )+mxValue;
}
}
function textSetter(DOM, text){
// text scaling
if ((text>=1000)&&(textScaling=1)){
textScaling=1-((Math.floor( (Math.log(text)/Math.log(10))-2))/10)-0.1;
tNumberDOM.setAttribute('font-size', 50*scaling*textScaling);
tUnitDOM.setAttribute('font-size', 30*scaling*textScaling);
} else{
textScaling = 1;
tNumberDOM.setAttribute('font-size', 50*scaling*textScaling);
tUnitDOM.setAttribute('font-size', 30*scaling*textScaling);
}
DOM.textContent = text;
}
function doIt(dAct, toD, duration, direction){
var toString = "";
// -0.0001 is used for preventing IE reach 360 and close the circle
toString = getD(dAct-0.0001);
outerCircleDOM.setAttribute('d',toString);
//force the value to be an integer
var anim_cur_val = Math.round(dAct/360*maxValue*10)/10;
//textSetter(tNumberDOM, Math.round(dAct/360*maxValue*10)/10);
textSetter(tNumberDOM, anim_cur_val.toFixed(0));
//console.log('dAct '+dAct+ ' toD'+toD);
// determine direction (up or down)
if (direction=="up")
dAct = dAct + 5.5;
else
dAct = dAct - 5.5;
duration = duration - calculateAccValue(duration, 500);
if (direction=="up"){
if (dAct < toD){
setTimeout(function(){
// animate it according to refresh rate
requestAnimationFrame(function(){
doIt(dAct, toD, duration, direction);
})
},duration);
} else {
outerCircleDOM.setAttribute('d',getD((toD-0.0001)));
textSetter(tNumberDOM, Math.round(toD/360*maxValue*10)/10);
}
} else {
if (dAct >= toD){
setTimeout(function(){
// animate it according to refresh rate
requestAnimationFrame(function(){
doIt(dAct, toD, duration, direction);
})
},duration);
} else {
outerCircleDOM.setAttribute('d',getD(toD-0.0001));
textSetter(tNumberDOM ,Math.round(toD/360*maxValue*10)/10);
}
}
};
// this function gives us the circle coordinates
function getCoordinates(radius,offset,degrees){
var radians = degreesToRadians(degrees);
var x = offset.x + radius * Math.cos(radians)
var y = offset.y + radius * Math.sin(radians)
return {x:x,y:y};
};
// small converstion beween degrees and radians
function degreesToRadians(degrees){
var radians = (degrees * Math.PI) / 180;
return radians
};
// this function returns the "d" string for the path, according to the degrees
function getD(degree){
radius = 100*scaling;
startx = centerx+radius;
starty = centery;
var coor = getCoordinates(radius, {x:startx,y:starty},degree);
endx = coor.x;
endy = coor.y;
var largearc = 0;
if (degree>180){
largearc=1;
} else {
largearc=0;
}
// don't ask me how I did it folks
d="M "+startx+" "+starty+" a "+radius+" "+radius+" 0 "+largearc+" 1 "+(endx-startx-radius)+" "+(endy-starty)+" L "+(centerx)+" "+(centery)+" Z";
//console.log('GETd '+degree+ " "+d);
return d;
}
// this function checks, if an element is fully visible (according to the scrolling)
function checkVisible(){
if (firedAnimation){
// animation has already fired, detach the event listeners
document.removeEventListener("scroll", checkVisible, false);
window.removeEventListener("resize", checkVisible, false);
return;
}
var rect = chart.getBoundingClientRect();
var top = window.pageYOffset || document.documentElement.scrollTop;
var left = window.pageXOffset || document.documentElement.scrollLeft;
if ((rect.top>=0)&&(rect.top+rect.height<window.innerHeight) &&
(rect.left>=0)&&(rect.left+rect.width<window.innerWidth)){
// this means that we fully see the chart
// fire the animation (only once)
firedAnimation = true;
setAnimate(startValue, endValue, (500/animationSpeed));
}
}
var waitingLoad =0;
function onLoad(){
// get the container for the chart
chart = document.getElementById(chartID);
// if the container is not ready in the DOM, then retry
// try for around 20secs, then throw an exception
if (chart==null){
// after 10 seconds, pause a little bit
if ((waitingLoad > 10000)&&(waitingLoad<20000)){
setTimeout(onLoad, 1000);
waitingLoad = waitingLoad +1000;
return;
}
if (waitingLoad > 20000){
throw('donutChart: onLoad() - The chart element "'+chartID+'" could not be loaded in the last 20 seconds');
}
setTimeout(onLoad, 500);
waitingLoad = waitingLoad +500;
return;
}
// create an svg object and all other things - thanks to Thoka
svg = document.createElementNS('http://www.w3.org/2000/svg','svg');
innerCircleDOM = document.createElementNS('http://www.w3.org/2000/svg','circle');
outerCircleDOM = document.createElementNS('http://www.w3.org/2000/svg','path');
textDOM = document.createElementNS('http://www.w3.org/2000/svg','text');
tNumberDOM = document.createElementNS('http://www.w3.org/2000/svg','tspan');
tUnitDOM = document.createElementNS('http://www.w3.org/2000/svg','tspan');
titleDOM = document.createElementNS('http://www.w3.org/2000/svg','text');
// append to the chart
chart.appendChild(svg);
svg.appendChild(outerCircleDOM);
svg.appendChild(innerCircleDOM);
svg.appendChild(textDOM);
svg.appendChild(titleDOM);
textDOM.appendChild(tNumberDOM);
textDOM.appendChild(tUnitDOM);
loaded = true;
}
this.reload = function(){
if (!loaded)
onLoad();
}
this.clear = function(){
// reinitialize some parameters
firedAnimation = false;
animationSpeed = 1;
maxValue = 100;
unitText = "%";
lastValue = -1;
this.setValue(0);
}
this.delete = function(){
// remove everything
this.clear();
textDOM.removeChild(tNumberDOM);
textDOM.removeChild(tUnitDOM);
svg.removeChild(textDOM);
svg.removeChild(titleDOM);
svg.removeChild(outerCircleDOM);
svg.removeChild(innerCircleDOM);
chart.removeChild(svg);
loaded = false;
// yes but we leave chart, because it was provided
}
this.draw = function(options){
// check if main function has already loaded, if not, reiterate
if (!loaded){
setTimeout(function(){
that.draw(options);
}, 500);
return;
}
// OPTION CHECK - contains the options
// check if all options are set
var oTester = [];
oTester.options = typeof(options)!="undefined";
if (! (oTester.options)){
throw('donutChart: draw() - Not enough parameters or no parameters set in object');
return;
}
oTester.end = typeof(options.end)!="undefined";
oTester.start = typeof(options.start)!="undefined";
oTester.scaling = typeof(options.scaling)!="undefined";
oTester.size = typeof(options.size)!="undefined";
oTester.animationSpeed = typeof(options.animationSpeed)!="undefined";
oTester.textColor = typeof(options.textColor)!="undefined";
oTester.innerCircleColor = typeof(options.innerCircleColor)!="undefined";
oTester.outerCircleColor = typeof(options.outerCircleColor)!="undefined";
oTester.unitText = typeof(options.unitText)!="undefined";
oTester.maxValue = typeof(options.maxValue)!="undefined";
oTester.titleText = typeof(options.titleText)!="undefined";
oTester.titleColor = typeof(options.titleColor)!="undefined";
oTester.titlePosition = typeof(options.titlePosition)!="undefined";
if (! (oTester.end)){
throw('donutChart: draw() - No "end" value specified');
return;
}
// reinitialize some parameters
firedAnimation = false;
animationSpeed = 1;
maxValue = 100;
unitText = "%";
textShift = 20;
textScaling = 1;
// if the values are not set, set the standard
if (!oTester.size){
options.size = 200;
}
if (!oTester.scaling){
options.scaling = 1;
}
// if size ist not set, then take the options.scaling and the standard size of 200x200
if (!oTester.size){
svg.setAttribute('width', 200*options.scaling);
svg.setAttribute('height', 200*options.scaling);
options.size = 200*options.scaling;
}
// if scaling not set, then take the size anc calculate the options.scaling
if (!oTester.scaling){
svg.setAttribute('width', options.size);
svg.setAttribute('height', options.size);
if (svg.getAttribute('width')<svg.getAttribute('height')){
options.scaling = svg.getAttribute('width') / 200;
} else{
options.scaling = svg.getAttribute('height') / 200;
}
}
// set the colors, if set
if (oTester.outerCircleColor){
outerCircleColor = options.outerCircleColor;
}
if (oTester.innerCircleColor){
innerCircleColor = options.innerCircleColor;
}
if (oTester.textColor){
textColor = options.textColor;
}
// set the unitText, if set
if (oTester.unitText){
unitText = options.unitText;
}
// set the title, if set
if (oTester.titleText){
titleText = options.titleText;
}
if (oTester.titleColor){
titleColor = options.titleColor;
}
if (oTester.titlePosition){
titlePosition = options.titlePosition;
}
// set the maxValue, if set
if (oTester.maxValue){
maxValue = options.maxValue;
}
// set the starting position, if set
if (oTester.start){
options.start = Math.round(parseFloat(options.start)*10)/10;
if (options.start>maxValue)
options.start = maxValue;
if (options.start<0)
options.start = 0;
if (isNaN(options.start)){
// not a number and not parseable, ignore
options.start = 0;
oTester.start = false;
}
startValue = options.start/maxValue*360;
}
options.end = Math.round(parseFloat(options.end)*10)/10;
if (options.end>maxValue)
options.end = maxValue;
if (options.end<0)
options.end = 0;
if (isNaN(options.end)){
// not a number and not parseable, ignore
return;
}
options.end = options.end/maxValue*360;
endValue = options.end;
textShift = textShift*options.scaling;
// set the size and the center
sizex = options.size;
sizey = options.size+2*textShift;
centerx = sizex/2;
centery = (sizey/2);
scaling = options.scaling;
// set animation speed (0 = no animation), standard is one
if(oTester.animationSpeed){
animationSpeed = options.animationSpeed;
}
//e4j
var innerCircleStroke = typeof(options.innerCircleStroke)!="undefined" ? options.innerCircleStroke : 'none';
var outerCircleStroke = typeof(options.outerCircleStroke)!="undefined" ? options.outerCircleStroke : 'none';
//
// initialise with start position
outerCircleDOM.setAttribute('d', getD(startValue));
chart.style.width = sizex;
chart.style.height = sizey;
svg.setAttribute('height', sizey);
svg.setAttribute('class', 'donutChart');
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
svg.setAttribute('version', '1.1');
innerCircleDOM.setAttribute('cx', centerx);
innerCircleDOM.setAttribute('cy', centery);
innerCircleDOM.setAttribute('r', 80*options.scaling);
innerCircleDOM.setAttribute('stroke', innerCircleStroke);
innerCircleDOM.setAttribute('stroke-width', '2');
innerCircleDOM.setAttribute('fill', innerCircleColor);
outerCircleDOM.setAttribute('fill', outerCircleColor);
outerCircleDOM.setAttribute('stroke', outerCircleStroke);
outerCircleDOM.setAttribute('stroke-width', '36');
tNumberDOM.setAttribute('x', centerx);
tNumberDOM.setAttribute('y', centery+Math.round(18.75*options.scaling));
tNumberDOM.setAttribute('font-size', 50*options.scaling);
tNumberDOM.setAttribute('fill', textColor);
tNumberDOM.setAttribute('font-family', 'arial');
tNumberDOM.setAttribute('font-weight', 'normal');
tNumberDOM.setAttribute('text-anchor', 'middle');
tUnitDOM.setAttribute('font-size', 30*options.scaling);
tUnitDOM.textContent = unitText;
tUnitDOM.setAttribute('fill', textColor);
tUnitDOM.setAttribute('text-anchor', 'middle');
tUnitDOM.setAttribute('font-family', 'arial');
tUnitDOM.setAttribute('font-weight', 'normal');
titleDOM.setAttribute('x', centerx);
// set the position of the title
switch(titlePosition){
case "inner-bottom":
if (!oTester.titleColor)
titleColor = "#ffffff";
titleDOM.setAttribute('y', centery+sizey/5+textShift/2);
break;
case "outer-bottom":
if (!oTester.titleColor)
titleColor = "#666666";
titleDOM.setAttribute('y', sizey-textShift/2);
break;
case "inner-top":
if (!oTester.titleColor)
titleColor = "#ffffff";
titleDOM.setAttribute('y', centery-sizey/5-textShift/2);
break;
default:
case "outer-top":
if (!oTester.titleColor)
titleColor = "#666666";
titleDOM.setAttribute('y', textShift/2);
break;
}
titleDOM.setAttribute('font-size', 12*options.scaling);
titleDOM.setAttribute('fill', titleColor);
titleDOM.setAttribute('font-family', 'arial');
titleDOM.setAttribute('font-weight', 'normal');
titleDOM.setAttribute('text-anchor', 'middle');
titleDOM.textContent = titleText;
// if the animation has been chosen
if (animationSpeed>0){
// ignore start value if lastvalue is already set
if (lastValue>-1){
startValue = lastValue;
}
window.addEventListener("resize", checkVisible, false);
document.addEventListener("scroll", checkVisible, false);
tNumberDOM.textContent = Math.round(startValue/360*maxValue*10)/10;
checkVisible();
} else {
// set the circle to the end position, without animation
// the 0.0001 is for avoiding the circle to disappear, due to some browser
outerCircleDOM.setAttribute('d', getD(options.end-0.0001));
tNumberDOM.textContent = Math.round(options.end/360*maxValue*10)/10;
}
lastValue = endValue;
}
}