chartnew.js
Version:
Simple HTML5 Charts using the canvas element
516 lines (445 loc) • 18.7 kB
JavaScript
var moreInChartData_default= {
position : "INCHART",
iter : "last",
link : "Line",
// default values for Line;
linkStrokeColorLine: "black",
linkStrokeStyleLine : "solid",
linkStrokeSizeLine: 2,
paddingValXLine : 4,
paddingValYLine : 0,
piePaddingY : 0.1,
paddingX : 0,
paddingY : 0,
// default values for Triangle;
arrowWidth : 2,
arrowHeight : 0.1,
// linkFillColorTriangle : null,
linkStrokeColorTriangle: "rgba(0,0,0,0)",
linkStrokeStyleTriangle : "solid",
linkStrokeSizeTriangle: 0,
paddingValXTriangle : 4,
paddingValYTriangle : -16,
// default for text;
text : "<Value>",
fontColor : "black",
fontStyle : "normal",
fontSize : 25,
fontFamily : "'Arial'",
// default for Image;
imageLoad : null,
imagePos : 1, // 0 before text, 1 after text;
imageWidth : 20,
imageHeight: 20,
spaceBetweenTextAndImage : 5,
// relativeImagePosition : "smart",
// rotate : 0,
// Point position;
limitToChart : false,
x1 : null,
y1 : null,
x2 : null,
y2 : null,
x3 : null,
y3 : null,
x4 : null,
y4 : null,
x5 : null,
y5 : null,
x6 : null,
y6 : null,
x7 : null,
y7 : null,
x8 : null,
y8 : null,
x9 : null,
y9 : null,
x10 : null,
y10 : null,
paddingX1 : null,
paddingY1 : null,
paddingX2 : null,
paddingY2 : null,
paddingX3 : null,
paddingY3 : null,
paddingX4 : null,
paddingY4 : null,
paddingX5 : null,
paddingY5 : null,
paddingX6 : null,
paddingY6 : null,
paddingX7 : null,
paddingY7 : null,
paddingX8 : null,
paddingY8 : null,
paddingX9 : null,
paddingY9 : null,
paddingX10 : null,
paddingY10 : null,
// Special values;
avoidOverwrite : true
};
function pushInGraphData(type_chart,data,config,pushInfoDefault) {
var pushconfig = (pushInfoDefault) ? mergeChartConfig(moreInChartData_default, pushInfoDefault) : moreInChartData_default;
var resconfig;
var pushInfo,shapesInChart;
if(typeof data.datasets == "object") {
pushInfo=data.datasets;
if(typeof data.shapesInChart == "undefined") data.shapesInChart=[];
shapesInChart=data.shapesInChart;
for (var i=0;i<data.datasets.length;i++){
for(var j=0;j<data.datasets[i].data.length;j++) {
if(typeof data.datasets[i].data[j]!="undefined") {
resconfig = mergeChartConfig(data.datasets[i], pushconfig);
pushInGraphDataSub(type_chart.toUpperCase(),data.datasets[i],i,j,shapesInChart,data,config,resconfig);
}
}
}
data.shapesInChart[0].avoidOverwrite=pushconfig.avoidOverwrite;
}
else {
pushInfo=data;
if(typeof data[0].shapesInChart == "undefined") data[0].shapesInChart=[];
shapesInChart=data[0].shapesInChart;
for (var i=0;i<data.length;i++){
if(typeof data[i].value !="undefined") {
resconfig = mergeChartConfig(data[i], pushconfig);
pushInGraphDataSub(type_chart.toUpperCase(),data[i],i,-1,shapesInChart,data,config,resconfig);
}
}
data[0].shapesInChart[0].avoidOverwrite=pushconfig.avoidOverwrite;
}
function mergeOptionConfig(defaults, userDefined,posj) {
var returnObj = {};
for (var attrname in defaults) {
returnObj[attrname] = defaults[attrname];
}
for (var attrnameBis in userDefined) {
if(typeof userDefined[attrnameBis]=="object") returnObj[attrnameBis] = userDefined[attrnameBis][Math.min(j,userDefined[attrnameBis].length-1)];
else returnObj[attrnameBis] = userDefined[attrnameBis];
}
return returnObj;
};
function pushInGraphDataSub(type_chart,pushInfoI,i,j,shapesInChart,data,config,resconfig) {
var addRadius;
shapesInChart[shapesInChart.length]=mergeOptionConfig(resconfig,pushInfoI,j);
// push shapesInChart info for the pointer;
var newShapes=shapesInChart[shapesInChart.length-1];
if (newShapes.text.indexOf("<Title>") >= 0) newShapes.text=newShapes.text.replace(/<Title>/g,pushInfoI.title);
if (newShapes.text.indexOf("<Value>") >= 0){
if(j==-1)newShapes.text=newShapes.text.replace(/<Value>/g,""+pushInfoI.value);
else newShapes.text=newShapes.text.replace(/<Value>/g,""+pushInfoI.data[j]);
}
if (newShapes.text.indexOf("<i>") >= 0) newShapes.text=newShapes.text.replace(/<i>/g,i);
if (newShapes.text.indexOf("<j>") >= 0) newShapes.text=newShapes.text.replace(/<j>/g,j);
switch(newShapes.link.toUpperCase()) {
case "TRIANGLE" :
var cumval=0;
if(typeof data.length!="undefined") {
for(var vi=0;vi<data.length;vi++){
if(data[vi].value>0)cumval=cumval+1*data[vi].value;
}
} else {
for(var vi=0;vi<data.datasets.length;vi++){
if(data.datasets[vi].data[j]>0)cumval=cumval+1*data.datasets[vi].data[j];
}
}
var arrowWidth=(cumval/360)*newShapes.arrowWidth;
newShapes.shape = annotateTriangleFunction;
newShapes.strokeColor=newShapes.linkStrokeColorLine;
newShapes.strokeStyle=newShapes.linkStrokeStyleLine;
newShapes.strokeSize=newShapes.linkStrokeSizeLine;
switch(type_chart) {
case "DELPIE" :
case "DELDOUGHNUT" :
var multRadius;
var percentageInnerCutout=50;
if(typeof config.percentageInnerCutout != "undefined")percentageInnerCutout=config.percentageInnerCutout;
if(type_chart.toUpperCase()=="DOUGHNUT" || type_chart.toUpperCase()=="MDOUGHNUT")multRadius=100/(100-percentageInnerCutout);
else multRadius=1;
addRadius=0;
if(typeof pushInfoI.expandOutRadius!="undefined")addRadius=1*pushInfoI.expandOutRadius;
if(newShapes.x1==null)newShapes.x1= (pushInfoI.data[j]==0 ? i : Math.max(i-0.5,i-(arrowWidth/pushInfoI.data[j])));
if(newShapes.y1==null)newShapes.y1= 0.99+addRadius;
if(newShapes.x2==null)newShapes.x2= i;
if(newShapes.y2==null)newShapes.y2 =1+newShapes.arrowHeight+addRadius;
if(newShapes.x3==null)newShapes.x3= (pushInfoI.data[j]==0 ? i : Math.min(i+0.5,i+(arrowWidth/pushInfoI.data[j])));
if(newShapes.y3==null)newShapes.y3 = 0.99+addRadius;
if(newShapes.x4==null)newShapes.x4 = i;
if(newShapes.y4==null)newShapes.y4 = 1.2+addRadius;
if(newShapes.fillColor==null)newShapes.fillColor =pushInfoI.color;
break;
case "PIE" :
case "DOUGHNUT" :
case "MPIE" :
case "MDOUGHNUT" :
var multRadius;
var percentageInnerCutout=50;
if(typeof config.percentageInnerCutout != "undefined")percentageInnerCutout=config.percentageInnerCutout;
if(type_chart.toUpperCase()=="MDOUGHNUT")multRadius=100/(100-percentageInnerCutout);
else multRadius=1;
addRadius=0;
if(typeof pushInfoI.expandOutRadius!="undefined")addRadius=1*pushInfoI.expandOutRadius;
if(newShapes.x1==null)newShapes.x1= (pushInfoI.data[j]==0 ? i : Math.max(i-0.5,i-(arrowWidth/pushInfoI.data[j])));
if(newShapes.y1==null)newShapes.y1= 0.99+addRadius;
if(newShapes.x2==null)newShapes.x2= i;
if(newShapes.y2==null)newShapes.y2 =1+newShapes.arrowHeight+addRadius;
if(newShapes.x3==null)newShapes.x3= (pushInfoI.data[j]==0 ? i : Math.min(i+0.5,i+(arrowWidth/pushInfoI.data[j])));
if(newShapes.y3==null)newShapes.y3 = 0.99+addRadius;
if(newShapes.x4==null)newShapes.x4 = i;
if(newShapes.y4==null)newShapes.y4 = 1.2+addRadius;
if(newShapes.posj==null)newShapes.posj = j;
if(newShapes.fillColor==null)newShapes.fillColor =pushInfoI.fillColor;
break;
case "POLARAREA" :
case "LINE" :
case "RADAR" :
case "BAR" :
case "HORIZONTALBAR" :
case "STACKEDBAR" :
case "HORIZONTALSTACKEDBAR" :
// not implemented;
break;
};
break;
case "LINE" :
default:
newShapes.shape = annotateLineFunction;
newShapes.strokeColor=newShapes.linkStrokeColorLine;
newShapes.strokeStyle=newShapes.linkStrokeStyleLine;
newShapes.strokeSize=newShapes.linkStrokeSizeLine;
switch(type_chart) {
case "PIE" :
case "DOUGHNUT" :
case "MPIE" :
case "MDOUGHNUT" :
var multRadius;
var percentageInnerCutout=50;
if(typeof config.percentageInnerCutout != "undefined")percentageInnerCutout=config.percentageInnerCutout;
if(type_chart.toUpperCase()=="MDOUGHNUT")multRadius=100/(100-percentageInnerCutout);
else multRadius=1;
addRadius=0;
if(typeof pushInfoI.expandOutRadius!="undefined")addRadius=1*pushInfoI.expandOutRadius;
if(newShapes.x1==null)newShapes.x1=i;
if(newShapes.y1==null)newShapes.y1=1+addRadius;
if(newShapes.x2==null)newShapes.x2=i;
if(newShapes.y2==null)newShapes.y2=1+newShapes.piePaddingY*multRadius;
// x10=center of circle;
if(newShapes.x10==null)newShapes.x10=i;
if(newShapes.y10==null)newShapes.y10=-999;
if(newShapes.posj==null)newShapes.posj = j;
break;
case "DELPIE" :
case "DELDOUGHNUT" :
var multRadius;
var percentageInnerCutout=50;
if(typeof config.percentageInnerCutout != "undefined")percentageInnerCutout=config.percentageInnerCutout;
if(type_chart.toUpperCase()=="DOUGHNUT" || type_chart.toUpperCase()=="DOUGHNUT")multRadius=100/(100-percentageInnerCutout);
else multRadius=1;
addRadius=0;
if(typeof pushInfoI.expandOutRadius!="undefined")addRadius=1*pushInfoI.expandOutRadius;
if(newShapes.x1==null)newShapes.x1=i;
if(newShapes.y1==null)newShapes.y1=1+addRadius;
if(newShapes.x2==null)newShapes.x2=i;
if(newShapes.y2==null)newShapes.y2=1+newShapes.piePaddingY*multRadius;
if(newShapes.x10==null)newShapes.x10=i;
if(newShapes.y10==null)newShapes.y10=1-multRadius;
break;
case "POLARAREA" :
case "LINE" :
case "RADAR" :
case "BAR" :
case "HORIZONTALBAR" :
case "STACKEDBAR" :
case "HORIZONTALSTACKEDBAR" :
// not implemented;
break;
};
break;
}
// push shapesInChart info for the text and Image;
} ;
};
function annotateLineFunction(area, ctx, data, statData, posi,posj,othervars){
if (typeof ctx.specialInChartData=="undefined"){
ctx.specialInChartData=[];
ctx.specialInChartData.prevMsr=[];
ctx.specialInChartData.textAlign=[];
ctx.specialInChartData.textBaseline=[];
ctx.specialInChartData.prevXln=[];
ctx.specialInChartData.prevYln=[];
}
/* compute radius */
var radius= (Math.sqrt(Math.pow(othervars.xypos2.xpos-othervars.xypos10.xpos,2)+ Math.pow(othervars.xypos2.ypos-othervars.xypos10.ypos,2)));
var xln, yln;
var xip, yip;
var paddingX, paddingY;
var paddingValX=othervars.shapesInChart.paddingValXLine;
var paddingValY=othervars.shapesInChart.paddingValYLine;
// line to label;
ctx.beginPath();
xip=othervars.xypos2.xpos;
yip=othervars.xypos2.ypos;
if(othervars.xypos10.xpos>othervars.xypos2.xpos) {
ctx.textAlign="right";
paddingX=-paddingValX;
xln=othervars.xypos10.xpos-radius+othervars.shapesInChart.paddingX;
yln=othervars.xypos2.ypos+othervars.shapesInChart.paddingY;
} else {
ctx.textAlign="left";
paddingX=paddingValX;
xln=radius + othervars.xypos10.xpos+othervars.shapesInChart.paddingX;
yln=othervars.xypos2.ypos+othervars.shapesInChart.paddingY;
}
var avoidOverwrite;
if(typeof data.length!="undefined")avoidOverwrite=data[0].shapesInChart[0].avoidOverwrite;
else avoidOverwrite=data.shapesInChart[0].avoidOverwrite;
if (typeof ctx.specialInChartData.prevYln=="undefined") {
ctx.specialInChartData.prevXln=[];
ctx.specialInChartData.prevYln=[];
}
if(avoidOverwrite) {
if (typeof ctx.specialInChartData.prevYln[othervars.posj]!="undefined") {
if(Math.abs(ctx.specialInChartData.prevYln[othervars.posj]-yln)<1.5*othervars.shapesInChart.fontSize) {
if(othervars.xypos10.xpos<othervars.xypos2.xpos)yln=Math.max(yln,ctx.specialInChartData.prevYln[othervars.posj]+1.5*othervars.shapesInChart.fontSize);
else yln=Math.min(yln,ctx.specialInChartData.prevYln[othervars.posj]-1.5*othervars.shapesInChart.fontSize);
}
};
ctx.specialInChartData.prevXln[othervars.posj]=xln;
ctx.specialInChartData.prevYln[othervars.posj]=yln;
};
ctx.beginPath();
ctx.moveTo(othervars.xypos1.xpos, othervars.xypos1.ypos);
ctx.quadraticCurveTo(xip, yip,xln, yln);
ctx.lineWidth = othervars.shapesInChart.strokeSize;
ctx.strokeStyle = othervars.shapesInChart.strokeColor;
ctx.setLineDash(lineStyleFn(othervars.shapesInChart.strokeStyle));
ctx.stroke();
// set text/shape position;
ctx.beginPath();
ctx.textBaseline="middle";
if(othervars.xypos2.ypos<othervars.xypos1.ypos) {
paddingY=-paddingValY;
} else {
paddingY=1*paddingValY;
}
// draw labels/images;
drawTextAndImage(area, ctx, data,statData, posi,posj,othervars,xln+paddingX, yln+paddingY);
};
function annotateTriangleFunction(area, ctx, data,statData, posi,posj,othervars){
if (typeof ctx.specialInChartData=="undefined"){
ctx.specialInChartData=[];
ctx.specialInChartData.prevMsr=[];
ctx.specialInChartData.textAlign=[];
ctx.specialInChartData.textBaseline=[];
ctx.specialInChartData.prevXln=[];
ctx.specialInChartData.prevYln=[];
}
// triangle to label;
ctx.beginPath();
if(othervars.xypos1.xpos==othervars.xypos3.xpos && othervars.xypos1.ypos==othervars.xypos3.ypos) {
ctx.strokeStyle = othervars.shapesInChart.fillColor;
ctx.lineWidth = 2;
ctx.moveTo(othervars.xypos1.xpos, othervars.xypos1.ypos);
ctx.lineTo(othervars.xypos2.xpos, othervars.xypos2.ypos);
} else {
ctx.moveTo(othervars.xypos1.xpos, othervars.xypos1.ypos);
ctx.lineWidth = 0;
ctx.strokeStyle = "rgba(0,0,0,0)";
ctx.lineTo(othervars.xypos2.xpos, othervars.xypos2.ypos);
ctx.lineTo(othervars.xypos3.xpos, othervars.xypos3.ypos);
ctx.closePath();
ctx.fillStyle=othervars.shapesInChart.fillColor;
ctx.fill();
}
ctx.stroke();
// set Label/image position;
var paddingX=0;
var paddingY=0;
var paddingValX=othervars.shapesInChart.paddingValXTriangle;
var paddingValY=othervars.shapesInChart.paddingValYTriangle;
var xln=othervars.xypos4.xpos;
var yln=othervars.xypos4.ypos;
ctx.beginPath();
if(othervars.xypos4.xpos>=othervars.xypos2.xpos) {
paddingX=paddingValX;
ctx.textAlign="left";
} else {
paddingX=-paddingValX;
ctx.textAlign="right";
}
ctx.textBaseline="middle";
var avoidOverwrite;
if(typeof data.length!="undefined")avoidOverwrite=data[0].shapesInChart[0].avoidOverwrite;
else avoidOverwrite=data.shapesInChart[0].avoidOverwrite;
if(avoidOverwrite) {
if (typeof ctx.specialInChartData.prevYln[othervars.posj]!="undefined" && ctx.textAlign==ctx.specialInChartData.textAlign[othervars.posj]) {
if(othervars.xypos4.xpos>=othervars.xypos2.xpos) {
yln=Math.max(yln,ctx.specialInChartData.prevYln[othervars.posj]+1.5*othervars.shapesInChart.fontSize);
} else {
yln=Math.min(yln,ctx.specialInChartData.prevYln[othervars.posj]-1.5*othervars.shapesInChart.fontSize);
}
}
ctx.specialInChartData.prevXln[othervars.posj]=xln;
ctx.specialInChartData.prevYln[othervars.posj]=yln;
};
// draw labels/images;
ctx.specialInChartData.prevMsr[othervars.posj]=drawTextAndImage(area, ctx, data,statData, posi,posj,othervars,xln+paddingX, yln+paddingY);
ctx.specialInChartData.textAlign[othervars.posj]=ctx.textAlign;
ctx.specialInChartData.textBaseline[othervars.posj]=ctx.textBaseline;
};
function drawTextAndImage(area, ctx, data,statData, posi,posj,othervars,xpos,ypos) {
var paddingTextX=0;
var paddingTextY=0;
var paddingImageX=0;
var paddingImageY=0;
var lgt=0;
var hgt=0;
var txtSize=0;
// compute padding values;
if(othervars.shapesInChart.imageLoad != null && othervars.shapesInChart.text != "") {
ctx.save();
var fontSize=othervars.shapesInChart.fontSize;
ctx.font = othervars.shapesInChart.fontStyle + " " + othervars.shapesInChart.fontSize.toString() + "px " + othervars.shapesInChart.fontFamily;
ctx.fillStyle = othervars.shapesInChart.fontColor;
txtSize=ctx.measureTextMultiLine(othervars.shapesInChart.text,othervars.shapesInChart.fontSize);
if(othervars.shapesInChart.imagePos==1 && ctx.textAlign=="right") {
paddingTextX=-(othervars.shapesInChart.imageWidth+othervars.shapesInChart.spaceBetweenTextAndImage);
paddingImageX=-(othervars.shapesInChart.imageWidth);
} else if(othervars.shapesInChart.imagePos==0 && ctx.textAlign=="left") {
paddingTextX=othervars.shapesInChart.imageWidth+othervars.shapesInChart.spaceBetweenTextAndImage;
} else if(othervars.shapesInChart.imagePos==0 && ctx.textAlign=="right") {
paddingImageX=-(txtSize.textWidth+othervars.shapesInChart.spaceBetweenTextAndImage+othervars.shapesInChart.imageWidth);
} else if(othervars.shapesInChart.imagePos==1 && ctx.textAlign=="left") {
paddingImageX=txtSize.textWidth+othervars.shapesInChart.spaceBetweenTextAndImage;
}
ctx.restore();
lgt=othervars.shapesInChart.spaceBetweenTextAndImage;
};
// draw text;
if(othervars.shapesInChart.text!="") {
ctx.save();
ctx.translate(xpos+paddingTextX,ypos+paddingTextY);
var fontSize=othervars.shapesInChart.fontSize;
ctx.font = othervars.shapesInChart.fontStyle + " " + othervars.shapesInChart.fontSize.toString() + "px " + othervars.shapesInChart.fontFamily;
ctx.fillStyle = othervars.shapesInChart.fontColor;
if (othervars.shapesInChart.iter !=="all" || (othervars.shapesInChart.iter === "all" && othervars.cntiter != othervars.config.animationSteps) || othervars.config.animation==false) {
ctx.fillTextMultiLine(othervars.shapesInChart.text, 0, 0, ctx.textBaseline, Math.ceil(ctx.chartTextScale*fontSize),true,othervars.config.detectMouseOnText,ctx,"SHAPESINCHART_TEXTMOUSE",0,xpos+paddingTextX,ypos+paddingTextY,-1,-1);
} else ctx.fillTextMultiLine(othervars.shapesInChart.text, 0, 0, ctx.textBaseline, Math.ceil(ctx.chartTextScale*fontSize),true,false,ctx,"SHAPESINCHART_TEXTMOUSE",0,xpos+paddingTextX,ypos+paddingTextY,-1,-1);
ctx.restore();
lgt+=txtSize;
hgt=Math.max(hgt,1.5* othervars.shapesInChart.fontSize);
}
// draw image;
if(othervars.shapesInChart.imageLoad != null) {
paddingImageY=-(othervars.shapesInChart.imageHeight-((2/3)*txtSize.textHeight/2));
ctx.save();
// ctx.translate(xpos+paddingImageX, ypos+paddingImageY -(othervars.shapesInChart.fontSize/2)+imageAfterPaddingY-(othervars.shapesInChart.imageAfterHeight/2));
ctx.translate(xpos+paddingImageX, ypos+paddingImageY);
ctx.drawImage(othervars.shapesInChart.imageLoad, 0, 0,othervars.shapesInChart.imageLoad.width,othervars.shapesInChart.imageLoad.height,0, 0,othervars.shapesInChart.imageWidth,othervars.shapesInChart.imageHeight);
ctx.restore();
lgt+=othervars.shapesInChart.imageWidth;
hgt=Math.max(hgt,othervars.shapesInChart.imageWidth.imageHeight);
}
return {height : hgt,width : lgt};
};