UNPKG

chartnew.js

Version:

Simple HTML5 Charts using the canvas element

1,198 lines (1,091 loc) 488 kB
/* * ChartNew.js * * Vancoppenolle Francois - January 2014 * francois.vancoppenolle@favomo.be * * GitHub community : https://github.com/FVANCOP/ChartNew.js * * This file is originally an adaptation of the chart.js source developped by Nick Downie (2013) * https://github.com/nnnick/Chart.js. But since june 2014, Nick puts a new version with a * refunded code. Current code of ChartNew.js is no more comparable to the code of Chart.js * * new charts compared to Chart.js * * horizontalBar * horizontalStackedBar * * Added items compared to Chart.js: * * Title, Subtitle, footnotes, axis labels, unit label * Y Axis on the right and/or the left * canvas Border * Legend * crossText, crossImage * graphMin, graphMax * logarithmic y-axis (for line and bar) * rotateLabels * and lot of others... * */ // ctx.firstPass=0 or "undefined" : Chart has never been drawn (because dynamicDisplay = true and ctx has never been displayed in current screen) // ctx.firstPass=1 : Chart has to be drawn with animation (if config.animation = true); // ctx.firstPass=2 : chart has to be drawn without animation; // ctx.firstPass=9 : chart is completely drawn; // If chartJsResize called : increment the value of ctx.firstPass with a value of 10. // non standard functions; var annotate_shape='divCursor' var chartJSLineStyle=[]; chartJSLineStyle["solid"]=[]; chartJSLineStyle["dotted"]=[1,4]; chartJSLineStyle["shortDash"]=[2,1]; chartJSLineStyle["dashed"]=[4,2]; chartJSLineStyle["dashSpace"]=[4,6]; chartJSLineStyle["longDashDot"]=[7,2,1,2]; chartJSLineStyle["longDashShortDash"]=[10,4,4,4]; chartJSLineStyle["gradient"]=[1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,9,9,8,8,7,7,6,6,5,5,4,4,3,3,2,2,1]; function lineStyleFn(data) { if ((typeof chartJSLineStyle[data]) === "object")return chartJSLineStyle[data]; else return chartJSLineStyle["solid"]; }; if (typeof String.prototype.trim !== 'function') { String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); } }; if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(searchElement /*, fromIndex */ ) { "use strict"; if (this == null) { throw new TypeError(); } var t = Object(this); var len = t.length >>> 0; if (len === 0) { return -1; } var n = 0; if (arguments.length > 0) { n = Number(arguments[1]); if (n != n) { // shortcut for verifying if it's NaN n = 0; } else if (n != 0 && n != Infinity && n != -Infinity) { n = (n > 0 || -1) * Math.floor(Math.abs(n)); } } if (n >= len) { return -1; } var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); for (; k < len; k++) { if (k in t && t[k] === searchElement) { return k; } } return -1; } }; var charJSPersonalDefaultOptions = {}; var charJSPersonalDefaultOptionsLine = {} ; var charJSPersonalDefaultOptionsRadar = {} ; var charJSPersonalDefaultOptionsPolarArea = {} ; var charJSPersonalDefaultOptionsPie = {}; var charJSPersonalDefaultOptionsDoughnut = {}; var charJSPersonalDefaultOptionsBar = {}; var charJSPersonalDefaultOptionsStackedBar = {}; var charJSPersonalDefaultOptionsHorizontalBar = {}; var charJSPersonalDefaultOptionsHorizontalStackedBar = {}; ///////// FUNCTIONS THAN CAN BE USED IN THE TEMPLATES /////////////////////////////////////////// function roundToWithThousands(config, num, place) { var newval = 1 * unFormat(config, num); if (typeof(newval) == "number" && place != "none") { var roundVal; if (place <= 0) { roundVal = -place; newval = +(Math.round(newval + "e+" + roundVal) + "e-" + roundVal); } else { roundVal = place; var divval = "1e+" + roundVal; newval = +(Math.round(newval / divval)) * divval; } } newval = fmtChartJS(config, newval, "none"); return (newval); }; function unFormat(config, num) { if ((config.decimalSeparator != "." || config.thousandSeparator != "") && typeof(num) == "string") { var v1 = "" + num; if (config.thousandSeparator != "") { while (v1.indexOf(config.thousandSeparator) >= 0) v1 = "" + v1.replace(config.thousandSeparator, ""); } if (config.decimalSeparator != ".") v1 = "" + v1.replace(config.decimalSeparator, ".") return 1 * v1; } else { return num; } }; ///////// ANNOTATE PART OF THE SCRIPT /////////////////////////////////////////// /******************************************************************************** Copyright (C) 1999 Thomas Brattli This script is made by and copyrighted to Thomas Brattli Visit for more great scripts. This may be used freely as long as this msg is intact! I will also appriciate any links you could give me. Distributed by Hypergurl ********************************************************************************/ var cachebis = {}; function fmtChartJSPerso(config, value, fmt) { switch (fmt) { case "SampleJS_Format": if (typeof(value) == "number") return_value = "My Format : " + value.toString() + " $"; else return_value = value + "XX"; break; case "Change_Month": if (typeof(value) == "string") return_value = value.toString() + " 2014"; else return_value = value.toString() + "YY"; break; default: return_value = value; break; } return (return_value); }; function fmtChartJS(config, value, fmt) { var return_value; if (fmt == "notformatted") { return_value = value; } else if ((fmt == "none" || fmt=="money") && typeof(value) == "number") { if (config.roundNumber != "none") { var roundVal; if (config.roundNumber <= 0) { roundVal = -config.roundNumber; value = +(Math.round(value + "e+" + roundVal) + "e-" + roundVal); } else { roundVal = config.roundNumber; var divval = "1e+" + roundVal; value = +(Math.round(value / divval)) * divval; } } if (config.decimalSeparator != "." || config.thousandSeparator != "") { return_value = value.toString().replace(/\./g, config.decimalSeparator); if (config.thousandSeparator != "") { var part1 = return_value; var part2 = ""; var posdec = part1.indexOf(config.decimalSeparator); if (posdec >= 0) { part2 = part1.substring(posdec + 1, part1.length); part2 = part2.split('').reverse().join(''); // reverse string part1 = part1.substring(0, posdec); } part1 = part1.toString().replace(/\B(?=(\d{3})+(?!\d))/g, config.thousandSeparator); part2 = part2.split('').reverse().join(''); // reverse string return_value = part1 if (part2 != "") return_value = return_value + config.decimalSeparator + part2; } } else return_value = value; if(fmt=="money") { if(config.currencyPosition=="before")return_value=config.currency+return_value; else return_value=return_value+config.currency; } } else if (fmt != "none" && fmt != "notformatted") { return_value = fmtChartJSPerso(config, value, fmt); } else { return_value = value; } return (return_value); }; function addParameters2Function(data, fctName, fctList) { var mathFunctions = { mean: { data: data.data, datasetNr: data.v11 }, varianz: { data: data.data, datasetNr: data.v11 }, stddev: { data: data.data, datasetNr: data.v11 }, cv: { data: data.data, datasetNr: data.v11 }, median: { data: data.data, datasetNr: data.v11 } }; // difference to current value (v3) dif = false; if (fctName.substr(-3) == "Dif") { fctName = fctName.substr(0, fctName.length - 3); dif = true; } if (typeof eval(fctName) == "function") { var parameter = eval(fctList + "." + fctName); if (dif) { // difference between v3 (current value) and math function return data.v3 - window[fctName](parameter); } return window[fctName](parameter); } return null; }; function isNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n); }; function tmplbis(str, data,config) { newstr=str; if(newstr.substr(0,config.templatesOpenTag.length)==config.templatesOpenTag)newstr="<%="+newstr.substr(config.templatesOpenTag.length,newstr.length-config.templatesOpenTag.length); if(newstr.substr(newstr.length-config.templatesCloseTag.length,config.templatesCloseTag.length)==config.templatesCloseTag)newstr=newstr.substr(0,newstr.length-config.templatesCloseTag.length)+"%>"; return tmplter(newstr,data); } function tmplter(str, data) { var mathFunctionList = ["mean", "varianz", "stddev", "cv", "median"]; var regexMath = new RegExp('<%=((?:(?:.*?)\\W)??)((?:' + mathFunctionList.join('|') + ')(?:Dif)?)\\(([0-9]*?)\\)(.*?)%>', 'g'); while (regexMath.test(str)) { str = str.replace(regexMath, function($0, $1, $2, $3, $4) { var rndFac; if ($3) rndFac = $3; else rndFac = 2; var value = addParameters2Function(data, $2, "mathFunctions"); if (isNumber(value)) return '<%=' + $1 + '' + Math.round(Math.pow(10, rndFac) * value) / Math.pow(10, rndFac) + '' + $4 + '%>'; return '<%= %>'; }); } // Figure out if we're getting a template, or if we need to // load the template - and be sure to cache the result. // first check if it's can be an id var fn = /^[A-Za-z][-A-Za-z0-9_:.]*$/.test(str) ? cachebis[str] = cachebis[str] || tmplter(document.getElementById(str).innerHTML) : // Generate a reusable function that will serve as a template // generator (and which will be cached). new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + // Introduce the data as local variables using with(){} "with(obj){p.push('" + // Convert the template into pure JavaScript str .replace(/[\r\n]/g, "\\n") .replace(/[\t]/g, " ") .split("<%").join("\t") .replace(/((^|%>)[^\t]*)'/g, "$1\r") .replace(/\t=(.*?)%>/g, "',$1,'") .split("\t").join("');") .split("%>").join("p.push('") .split("\r").join("\\'") + "');}return p.join('');"); // Provide some basic currying to the user return data ? fn(data) : fn; }; if (typeof CanvasRenderingContext2D !== 'undefined') { /** * ctx.prototype * fillText option for canvas Multiline Support * @param text string \n for newline * @param x x position * @param y y position * @param yLevel = "bottom" => last line has this y-Pos [default], = "middle" => the middle line has this y-Pos) * @param lineHeight lineHeight * @param horizontal horizontal */ CanvasRenderingContext2D.prototype.fillTextMultiLine = function(text, x, y, yLevel, lineHeight,horizontal,detectMouseOnText,ctx,idText,rotate,x_decal,y_decal,posi,posj) { var lines = ("" + text).split("\n"); // if its one line => in the middle // two lines one above the mid one below etc. if (yLevel == "middle") { if(horizontal)y -= ((lines.length - 1) / 2) * lineHeight; } else if (yLevel == "bottom") { // default if(horizontal)y -= (lines.length - 1) * lineHeight; } var y_pos=y-lineHeight; for (var i = 0; i < lines.length; i++) { this.fillText(lines[i], x, y); y += lineHeight; } if(detectMouseOnText) { var txtSize=ctx.measureTextMultiLine(text,lineHeight); var x_pos=[]; var y_pos=[]; x_pos.p1=x_decal+x; y_pos.p1=y_decal+y-lineHeight; var rotateRV=(Math.PI/2)+rotate; if(ctx.textAlign=="left" && yLevel=="top"){ x_pos.p1+=lineHeight*Math.cos(rotateRV); y_pos.p1+=lineHeight*Math.sin(rotateRV); } else if(ctx.textAlign=="left" && yLevel=="middle"){ x_pos.p1+=(lineHeight/2)*Math.cos(rotateRV); y_pos.p1+=(lineHeight/2)*Math.sin(rotateRV); } else if(ctx.textAlign=="left" && yLevel=="bottom"){ // nothing to adapt; } else if(ctx.textAlign=="center" && yLevel=="top"){ x_pos.p1+=lineHeight*Math.cos(rotateRV)-(txtSize.textWidth/2)*Math.cos(rotate); y_pos.p1+=lineHeight*Math.sin(rotateRV)-(txtSize.textWidth/2)*Math.sin(rotate); } else if(ctx.textAlign=="center" && yLevel=="middle"){ x_pos.p1+=(lineHeight/2)*Math.cos(rotateRV)-(txtSize.textWidth/2)*Math.cos(rotate); y_pos.p1+=(lineHeight/2)*Math.sin(rotateRV)-(txtSize.textWidth/2)*Math.sin(rotate); } else if(ctx.textAlign=="center" && yLevel=="bottom"){ x_pos.p1-=(txtSize.textWidth/2)*Math.cos(rotate); y_pos.p1-=(txtSize.textWidth/2)*Math.sin(rotate); } else if(ctx.textAlign=="right" && yLevel=="top"){ x_pos.p1+=(lineHeight*Math.cos(rotateRV)-txtSize.textWidth*Math.cos(rotate)); y_pos.p1+=(lineHeight*Math.sin(rotateRV)-txtSize.textWidth*Math.sin(rotate)); } else if(ctx.textAlign=="right" && yLevel=="middle"){ x_pos.p1+=(lineHeight/2)*Math.cos(rotateRV)-txtSize.textWidth*Math.cos(rotate); y_pos.p1+=(lineHeight/2)*Math.sin(rotateRV)-txtSize.textWidth*Math.sin(rotate); } else if(ctx.textAlign=="right" && yLevel=="bottom"){ x_pos.p1-=txtSize.textWidth*Math.cos(rotate); y_pos.p1-=txtSize.textWidth*Math.sin(rotate); } // Other corners of the rectangle; x_pos.p2=x_pos.p1+txtSize.textWidth*Math.cos(rotate); y_pos.p2=y_pos.p1+txtSize.textWidth*Math.sin(rotate); x_pos.p3=x_pos.p1-lineHeight*Math.cos(rotateRV); y_pos.p3=y_pos.p1-lineHeight*Math.sin(rotateRV); x_pos.p4=x_pos.p3+txtSize.textWidth*Math.cos(rotate); y_pos.p4=y_pos.p3+txtSize.textWidth*Math.sin(rotate); jsTextMousePos[ctx.ChartNewId][jsTextMousePos[ctx.ChartNewId].length] = [idText,text,x_pos,y_pos,rotate,txtSize.textWidth,txtSize.textHeight,posi,posj]; } }; CanvasRenderingContext2D.prototype.measureTextMultiLine = function(text, lineHeight) { var textWidth = 0; var textHeight = 0; var lg; var lines = ("" + text).replace(/<BR>/ig, "\n").split("\n"); if (lines.length>0)textHeight=lineHeight+1.5*(lines.length-1)*textHeight; var textHeight = lines.length * lineHeight; // if its one line => in the middle // two lines one above the mid one below etc. for (var i = 0; i < lines.length; i++) { lg = this.measureText(lines[i]).width; if (lg > textWidth) textWidth = lg; } return { textWidth: textWidth, textHeight: textHeight }; }; if (typeof CanvasRenderingContext2D.prototype.setLineDash !== 'function') { CanvasRenderingContext2D.prototype.setLineDash = function( listdash) { return 0; }; }; CanvasRenderingContext2D.prototype.drawRectangle = function(TheRectangle){ var originalfillStyle =this.fillStyle; if(typeof TheRectangle.x=='undefined'){TheRectangle.x=0;} if(TheRectangle.width<0){TheRectangle.x+=TheRectangle.width;TheRectangle.width*=-1;} if(TheRectangle.height<0){TheRectangle.y+=TheRectangle.height;TheRectangle.height*=-1;} if(typeof TheRectangle.y=='undefined'){TheRectangle.y=0;} if(typeof TheRectangle.y=='undefined'){TheRectangle.y=0;} if(typeof TheRectangle.backgroundColor!='undefined'){this.fillStyle=TheRectangle.backgroundColor;} if(typeof TheRectangle.borderRadius=='undefined'){TheRectangle.borderRadius=0;} if(typeof TheRectangle.borderSelection=='undefined'){TheRectangle.borderSelection=15;} var rectangleRadius=parseInt(TheRectangle.borderRadius); // The radius correction has been set to avoid problems when there is a big border and a color inside the rectangle; if(TheRectangle.borders && TheRectangle.bordersWidth > 5 && this.fillStyle != "rgba(0,0,0,0)")rectangleRadius=0; if(TheRectangle.borders && TheRectangle.fill && TheRectangle.borderSelection==15 && rectangleRadius>0)return this; if(rectangleRadius==0 && TheRectangle.fill==true){this.fillRect(TheRectangle.x,TheRectangle.y,TheRectangle.width,TheRectangle.height);} if(rectangleRadius==0 && TheRectangle.borderSelection>=15 && TheRectangle.stroke==true){this.strokeRect(TheRectangle.x,TheRectangle.y,TheRectangle.width,TheRectangle.height);} if(rectangleRadius!=0 || (TheRectangle.borderSelection<15 && TheRectangle.stroke==true)){ if(rectangleRadius>TheRectangle.width/2 ){rectangleRadius=TheRectangle.width/2} if(TheRectangle.height<TheRectangle.width &&rectangleRadius>TheRectangle.height/2 ){rectangleRadius=TheRectangle.height/2}; if(TheRectangle.fill) { this.beginPath(); this.lineWidth=0; this.strokeStyle="rgba(0,0,0,0)"; this.moveTo(TheRectangle.x+rectangleRadius,TheRectangle.y); this.lineTo(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y); this.arc(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y+rectangleRadius,rectangleRadius,1.5*Math.PI,0); this.lineTo(TheRectangle.x+TheRectangle.width,TheRectangle.y+TheRectangle.height-rectangleRadius); this.arc(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y+TheRectangle.height-rectangleRadius,rectangleRadius,0,0.5*Math.PI); this.lineTo(TheRectangle.x+rectangleRadius,TheRectangle.y+TheRectangle.height); this.arc(TheRectangle.x+rectangleRadius,TheRectangle.y+TheRectangle.height-rectangleRadius,rectangleRadius,0.5*Math.PI,1*Math.PI); this.lineTo(TheRectangle.x,TheRectangle.y+rectangleRadius); this.arc(TheRectangle.x+rectangleRadius,TheRectangle.y+rectangleRadius,rectangleRadius,1*Math.PI,1.5*Math.PI); this.closePath(); this.fill(); this.stroke(); } if(TheRectangle.stroke==true) { var dleft=(isBorder(TheRectangle.borderSelection,"LEFT")==false); var dright=(isBorder(TheRectangle.borderSelection,"RIGHT")==false); var dtop=(isBorder(TheRectangle.borderSelection,"TOP")==false); var dbottom=(isBorder(TheRectangle.borderSelection,"BOTTOM")==false); if(dtop==false && (dleft==true || TheRectangle.borderSelection==15)){ dtop=true; this.beginPath(); this.moveTo(TheRectangle.x+rectangleRadius,TheRectangle.y); this.lineTo(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y); if(isBorder(TheRectangle.borderSelection,"RIGHT")) this.arc(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y+rectangleRadius,rectangleRadius,1.5*Math.PI,0); else this.stroke() } if(dright==false && (dtop==true || TheRectangle.borderSelection==15)){ dright=true; if(isBorder(TheRectangle.borderSelection,"TOP")==false) { this.beginPath(); this.moveTo(TheRectangle.x+TheRectangle.width,TheRectangle.y+rectangleRadius); } this.lineTo(TheRectangle.x+TheRectangle.width,TheRectangle.y+TheRectangle.height-rectangleRadius); if(isBorder(TheRectangle.borderSelection,"BOTTOM")) this.arc(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y+TheRectangle.height-rectangleRadius,rectangleRadius,0,0.5*Math.PI); else this.stroke() } if(dbottom==false && (dright==true || TheRectangle.borderSelection==15)){ dbottom=true; if(isBorder(TheRectangle.borderSelection,"RIGHT")==false) { this.beginPath(); this.moveTo(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y+TheRectangle.height); } this.lineTo(TheRectangle.x+rectangleRadius,TheRectangle.y+TheRectangle.height); if(isBorder(TheRectangle.borderSelection,"LEFT"))this.arc(TheRectangle.x+rectangleRadius,TheRectangle.y+TheRectangle.height-rectangleRadius,rectangleRadius,0.5*Math.PI,1*Math.PI); else this.stroke() } if(dleft==false && (dbottom==true || TheRectangle.borderSelection==15)){ dleft=true; if(isBorder(TheRectangle.borderSelection,"BOTTOM")==false) { this.beginPath(); this.moveTo(TheRectangle.x,TheRectangle.y+TheRectangle.height-rectangleRadius); } this.lineTo(TheRectangle.x,TheRectangle.y+rectangleRadius); if(isBorder(TheRectangle.borderSelection,"TOP")){ this.arc(TheRectangle.x+rectangleRadius,TheRectangle.y+rectangleRadius,rectangleRadius,1*Math.PI,1.5*Math.PI); if(TheRectangle.borderSelection==15){ this.closePath(); this.stroke(); } } else this.stroke() } if(dtop==false && (dleft==true || TheRectangle.borderSelection==15)){ dtop=true; if(isBorder(TheRectangle.borderSelection,"LEFT")==false) { this.beginPath(); this.moveTo(TheRectangle.x+rectangleRadius,TheRectangle.y); } this.lineTo(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y); if(isBorder(TheRectangle.borderSelection,"RIGHT")) this.arc(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y+rectangleRadius,rectangleRadius,1.5*Math.PI,0); else this.stroke() } if(dright==false && (dtop==true || TheRectangle.borderSelection==15)){ dright=true; if(isBorder(TheRectangle.borderSelection,"TOP")==false) { this.beginPath(); this.moveTo(TheRectangle.x+TheRectangle.width,TheRectangle.y+rectangleRadius); } this.lineTo(TheRectangle.x+TheRectangle.width,TheRectangle.y+TheRectangle.height-rectangleRadius); if(isBorder(TheRectangle.borderSelection,"BOTTOM")) this.arc(TheRectangle.x+TheRectangle.width-rectangleRadius,TheRectangle.y+TheRectangle.height-rectangleRadius,rectangleRadius,0,0.5*Math.PI); else this.stroke() } if(this.fillStyle != "rgba(0,0,0,0)" && TheRectangle.borderSelection==15)this.fill(); }; } this.fillStyle= originalfillStyle; return this; }; }; cursorDivCreated = false; function createCursorDiv(config) { if (cursorDivCreated == false) { var div = document.createElement(annotate_shape); div.id = annotate_shape; div.style.position = 'absolute'; document.body.appendChild(div); cursorDivCreated = true; } }; initChartJsResize = false; var jsGraphResize = new Array(); function addResponsiveChart(id,ctx,data,config) { if(initChartJsResize==false) { if (window.addEventListener) { window.addEventListener("resize", chartJsResize); } else { window.attachEvent("resize", chartJsResize); } } jsGraphResize[jsGraphResize.length]= [id,ctx.tpchart,ctx,data,config]; }; var container; function getMaximumWidth(domNode){ if(domNode.parentNode!=null) if(domNode.parentNode!=undefined) container = domNode.parentNode; return container.clientWidth; }; function getMaximumHeight(domNode){ if(domNode.parentNode!=null) if(domNode.parentNode!=undefined) container = domNode.parentNode; return container.clientHeight; }; function resizeCtx(ctx,config) { if (isIE() < 9 && isIE() != false) return(true); if(config.responsive) { if(typeof config.maintainAspectRatio == "undefined")config.maintainAspectRatio=true; if(typeof config.responsiveMinWidth == "undefined")config.responsiveMinWidth=0; if(typeof config.responsiveMinHeight == "undefined")config.responsiveMinHeight=0; if(typeof config.responsiveMaxWidth == "undefined")config.responsiveMaxWidth=9999999; if(typeof config.responsiveMaxHeight == "undefined")config.responsiveMaxHeight=9999999; var canvas; if(typeof ctx.vctx != "undefined"){ canvas=ctx.vctx.canvas; } else { canvas=ctx.canvas; } if(typeof ctx.aspectRatio == "undefined") { ctx.aspectRatio = canvas.width / canvas.height; } var newWidth = getMaximumWidth(canvas); var newHeight = config.maintainAspectRatio ? newWidth / ctx.aspectRatio : getMaximumHeight(canvas); newWidth=Math.min(config.responsiveMaxWidth,Math.max(config.responsiveMinWidth,newWidth)); newHeight=Math.min(config.responsiveMaxHeight,Math.max(config.responsiveMinHeight,newHeight)); if(typeof ctx.DefaultchartTextScale=="undefined")ctx.DefaultchartTextScale=config.chartTextScale; if(typeof ctx.DefaultchartLineScale=="undefined")ctx.DefaultchartLineScale=config.chartLineScale; if(typeof ctx.DefaultchartSpaceScale=="undefined")ctx.DefaultchartSpaceScale=config.chartSpaceScale; /* new ratio */ if(typeof ctx.chartTextScale != "undefined" && config.responsiveScaleContent) { ctx.chartTextScale=ctx.DefaultchartTextScale*(newWidth/ctx.initialWidth); ctx.chartLineScale=ctx.DefaultchartLineScale*(newWidth/ctx.initialWidth); ctx.chartSpaceScale=ctx.DefaultchartSpaceScale*(newWidth/ctx.initialWidth); } if (window.devicePixelRatio>1) { ctx.canvas.style.width = newWidth + "px"; ctx.canvas.style.height = newHeight + "px"; } ctx.canvas.height = newHeight * Math.max(1,window.devicePixelRatio); ctx.canvas.width = newWidth * Math.max(1,window.devicePixelRatio); ctx.scale(Math.max(1,window.devicePixelRatio), Math.max(1,window.devicePixelRatio)); } else if (window.devicePixelRatio>1) { if(typeof ctx.original_width=="undefined") { ctx.original_width=ctx.canvas.width; ctx.original_height=ctx.canvas.height; } ctx.canvas.style.width = ctx.original_width + "px"; ctx.canvas.style.height = ctx.original_height + "px"; ctx.canvas.height = ctx.original_height * window.devicePixelRatio; ctx.canvas.width = ctx.original_width * window.devicePixelRatio; ctx.scale(window.devicePixelRatio, window.devicePixelRatio); } }; function chartJsResize() { for (var i=0;i<jsGraphResize.length;i++) { if(jsGraphResize[i][2].firstPass ==0) { } else if(jsGraphResize[i][2].firstPass ==9) { jsGraphResize[i][2].firstPass=2; redrawGraph(jsGraphResize[i][2],jsGraphResize[i][3],jsGraphResize[i][4]); } else if(jsGraphResize[i][2].firstPass < 10 ) { jsGraphResize[i][2].firstPass+=10; } } }; function testRedraw(ctx,data,config) { if (ctx.firstPass>10) { ctx.firstPass=2; redrawGraph(ctx,data,config) ; return true; } else { return false; } }; function updateChart(ctx,data,config,animation,runanimationcompletefunction) { if (ctx.firstPass==9) { ctx.runanimationcompletefunction=runanimationcompletefunction; if(animation)ctx.firstPass=1; else ctx.firstPass=2; if(config.responsive) { // update jsGraphResize; for (var i=0;i<jsGraphResize.length;i++) { if(jsGraphResize[i][2].ChartNewId== ctx.ChartNewId) { jsGraphResize[i][3]=data; jsGraphResize[i][4]=config; } } } redrawGraph(ctx,data,config); } }; function redrawGraph(ctx,data,config) { if((ctx.firstPass==2 || ctx.firstPass==9) && !(isIE() < 9 && isIE() != false) && (navigator.userAgent.indexOf("Safari")==-1)) { var OSC; var tmpctx; OSC= document.createElement("canvas"); tmpctx=OSC.getContext("2d"); tmpctx.vctx=ctx; OSC.width=ctx.canvas.width; OSC.height=ctx.canvas.height; tmpctx.ChartNewId=ctx.ChartNewId; tmpctx.tpchart=ctx.tpchart; tmpctx.tpdata=ctx.tpdata; tmpctx.initialWidth=ctx.initialWidth; tmpctx.chartTextScale=ctx.chartTextScale; tmpctx.chartLineScale=ctx.chartLineScale; tmpctx.chartSpaceScale=ctx.chartSpaceScale; tmpctx.firstPass=ctx.firstPass; tmpctx.runanimationcompletefunction=ctx.runanimationcompletefunction; tmpctx.aspectRatio=ctx.aspectRatio; tmpctx.widthAtSetMeasures=ctx.widthAtSetMeasures; tmpctx.heightAtSetMeasures=ctx.heightAtSetMeasures; tmpctx.pieces_drawn=ctx.pieces_drawn; var myGraph = new Chart(tmpctx); eval("myGraph."+tmpctx.tpchart+"(data,config);"); ctx.tpchart=tmpctx.tpchart; ctx.tpdata=tmpctx.tpdata; ctx.initialWidth=tmpctx.initialWidth; ctx.chartTextScale=tmpctx.chartTextScale; ctx.chartLineScale=tmpctx.chartLineScale; ctx.chartSpaceScale=tmpctx.chartSpaceScale; ctx.firstPass=tmpctx.firstPass; ctx.runanimationcompletefunction=tmpctx.runanimationcompletefunction; ctx.ChartNewId=tmpctx.ChartNewId; ctx.aspectRatio=tmpctx.aspectRatio; ctx.widthAtSetMeasures=tmpctx.widthAtSetMeasures; ctx.heightAtSetMeasures=tmpctx.heightAtSetMeasures; ctx.canvas.width=tmpctx.canvas.width; ctx.canvas.height=tmpctx.canvas.height; ctx.pieces_drawn=tmpctx.pieces_drawn; ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); ctx.drawImage(OSC,0,0); } else { var myGraph = new Chart(ctx); eval("myGraph."+ctx.tpchart+"(data,config);"); } }; //Default browsercheck, added to all scripts! function checkBrowser() { this.ver = navigator.appVersion this.dom = document.getElementById ? 1 : 0 this.ie5 = (this.ver.indexOf("MSIE 5") > -1 && this.dom) ? 1 : 0; this.ie4 = (document.all && !this.dom) ? 1 : 0; this.ns5 = (this.dom && parseInt(this.ver) >= 5) ? 1 : 0; this.ns4 = (document.layers && !this.dom) ? 1 : 0; this.bw = (this.ie5 || this.ie4 || this.ns4 || this.ns5) return this }; bw = new checkBrowser(); //Set these variables: fromLeft = 10; // How much from the left of the cursor should the div be? fromTop = 10; // How much from the top of the cursor should the div be? /******************************************************************** Initilizes the objects *********************************************************************/ function cursorInit() { scrolled = bw.ns4 || bw.ns5 ? "window.pageYOffset" : "document.body.scrollTop" if (bw.ns4) document.captureEvents(Event.MOUSEMOVE) }; /******************************************************************** Contructs the cursorobjects *********************************************************************/ function makeCursorObj(config,obj, nest) { createCursorDiv(config); nest = (!nest) ? '' : 'document.' + nest + '.' this.css = bw.dom ? document.getElementById(obj).style : bw.ie4 ? document.all[obj].style : bw.ns4 ? eval(nest + "document.layers." + obj) : 0; this.moveIt = b_moveIt; cursorInit(); return this }; function b_moveIt(x, y) { this.x = x; this.y = y; this.css.left = this.x + "px"; this.css.top = this.y + "px"; }; function isIE() { var myNav = navigator.userAgent.toLowerCase(); return (myNav.indexOf('msie') != -1) ? parseInt(myNav.split('msie')[1]) : false; }; function mergeChartConfig(defaults, userDefined) { var returnObj = {}; for (var attrname in defaults) { returnObj[attrname] = defaults[attrname]; } for (var attrnameBis in userDefined) { returnObj[attrnameBis] = userDefined[attrnameBis]; } return returnObj; }; function sleep(ms) { var dt = new Date(); dt.setTime(dt.getTime() + ms); while (new Date().getTime() < dt.getTime()) {}; }; function saveCanvas(ctx, data, config) { cvSave = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height); var saveCanvasConfig1 = { savePng: false, annotateDisplay: false, animation: false, dynamicDisplay: false }; savePngConfig1 = mergeChartConfig(config, saveCanvasConfig1); savePngConfig1.clearRect = false; /* And ink them */ redrawGraph(ctx,data,savePngConfig1); var image; if (config.savePngOutput == "NewWindow") { image = ctx.canvas.toDataURL(); ctx.putImageData(cvSave, 0, 0); window.open(image, '_blank'); } if (config.savePngOutput == "CurrentWindow") { image = ctx.canvas.toDataURL(); ctx.putImageData(cvSave, 0, 0); window.location.href = image; } if (config.savePngOutput == "Save") { image = ctx.canvas.toDataURL(); var downloadLink = document.createElement("a"); downloadLink.href = image; downloadLink.download = config.savePngName + ".png"; document.body.appendChild(downloadLink); downloadLink.click(); document.body.removeChild(downloadLink); } }; if (typeof String.prototype.trim !== 'function') { String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); } }; var dynamicDisplay = new Array(); var dynamicDisplayList = new Array(); function dynamicFunction(data, config, ctx) { if (isIE() < 9 && isIE() != false) return(true); if (config.dynamicDisplay && ctx.firstPass==0) { if (ctx.canvas.id == "") { var cvdate = new Date(); var cvmillsec = cvdate.getTime(); ctx.canvas.id = "Canvas_" + cvmillsec; } if (typeof(dynamicDisplay[ctx.canvas.id]) == "undefined") { dynamicDisplayList[dynamicDisplayList["length"]] = ctx.canvas.id; dynamicDisplay[ctx.canvas.id] = [ctx, data, config]; window.onscroll = scrollFunction; } if (!isScrolledIntoView(ctx.canvas,config)) return false; } return true; }; function isScrolledIntoView(element,config) { var xPosition = 0; var yPosition = 0; var eltWidth, eltHeight; if(typeof element.recomputedHeight=="undefined") { if (window.devicePixelRatio) { // 31/12/2015 - On retina display, the size of the canvas changes after the canvas is displayed. // before it is displayd, the size on the screen is the size on non retina display; // If we do not divide the height & width by the devicePixelRatio, and if the // value of config.dynamicDisplayYPartOfChart and if there is a chart on to bottom of the // web page, this chart will never be displayed.... // If the Size of the canvas was directly the real size displayed on the web page, we should not // divide the height/width by the devicePixelRatio.... (Bug in Brosers ?) element.recomputedHeight=element.height/window.devicePixelRatio; element.recomputedWidth=element.width/window.devicePixelRatio; } else { element.recomputedHeight=element.height; element.recomputedWidth=element.width; } } eltWidth=element.recomputedWidth; eltHeight=element.recomputedHeight; elem = element; while (elem) { xPosition += (elem.offsetLeft + elem.clientLeft); yPosition += (elem.offsetTop + elem.clientTop); elem = elem.offsetParent; } if (xPosition + (eltWidth * config.dynamicDisplayXPartOfChart) >= window.pageXOffset && xPosition + (eltWidth * config.dynamicDisplayXPartOfChart) <= window.pageXOffset + window.innerWidth && yPosition + (eltHeight * config.dynamicDisplayYPartOfChart) >= window.pageYOffset && yPosition + (eltHeight * config.dynamicDisplayYPartOfChart) <= window.pageYOffset + window.innerHeight ) { return (true); } else { return false; } }; function scrollFunction() { for (var i = 0; i < dynamicDisplayList["length"]; i++) { if ((dynamicDisplay[dynamicDisplayList[i]][0]).firstPass==0) { redrawGraph(dynamicDisplay[dynamicDisplayList[i]][0],dynamicDisplay[dynamicDisplayList[i]][1], dynamicDisplay[dynamicDisplayList[i]][2]); } } }; var jsGraphAnnotate = new Array(); var jsTextMousePos = new Array(); var mouseActionData=new Array(); function clearAnnotate(ctxid) { jsGraphAnnotate[ctxid] = []; jsTextMousePos[ctxid] = []; }; function getMousePos(canvas, evt) { var rect = canvas.getBoundingClientRect(); return { x: evt.clientX - rect.left, y: evt.clientY - rect.top }; }; function isHighLighted(reference,ctx,data,statData,posi,posj,othervars){ var i; if(typeof data.special=="object") { for(i=data.special.length-1;i>=0;i--){ if(data.special[i].typespecial=="highLight" && data.special[i].posi==posi && data.special[i].posj==posj) return true; } } return false; }; function isNotHighLighted(reference,ctx,data,statData,posi,posj,othervars) { return(!isHighLighted(reference,ctx,data,statData,posi,posj,othervars)); } function deleteHighLight(ctx,data) { var i; if(typeof data.special=="object") { for(i=data.special.length-1;i>=0;i--){ if(data.special[i].typespecial=="highLight") data.special.splice(i,1); } } }; function highLightAction(action,ctx,data,config,v1,v2) { if (ctx.firstPass!=9)return; var currentlyDisplayed=[-1,-1]; var redisplay=false; var i,j; if(typeof data.special=="object") { for(i=0;i<data.special.length && currentlyDisplayed[0]==-1;i++){ if(data.special[i].typespecial=="highLight") currentlyDisplayed=[data.special[i].posi,data.special[i].posj]; } } var deleteOld=false; var addNew=false; var property; var output; var fndoldspec=false; var fndnewspec=false; if(action=="HIDE" && currentlyDisplayed[0]!=-1)deleteOld=true; else if(action!="HIDE" && config.highLightFullLine== "group" && (currentlyDisplayed[1]!=v2 )) { if(currentlyDisplayed[0]!=-1)deleteOld=true; addNew=true;} else if(action!="HIDE" && config.highLightFullLine== false && (currentlyDisplayed[0]!=v1 || currentlyDisplayed[1]!=v2)) { if(currentlyDisplayed[0]!=-1)deleteOld=true; addNew=true;} else if(action!="HIDE" && config.highLightFullLine== true && (currentlyDisplayed[0]!=v1 )) { if(currentlyDisplayed[0]!=-1)deleteOld=true; addNew=true;} if(deleteOld) { redisplay=true; for(i=data.special.length-1;i>=0;i--){ if(data.special[i].typespecial=="highLight") { data.special.splice(i,1); fndoldspec=true; } } } if(addNew) { redisplay=true; if(typeof data.special == "undefined") data.special=[]; if(config.highLightFullLine == "group") { for(j=0;j<data.datasets.length;j++) { if(!(data.datasets[j].mouseDetection==false)) { output=""; for (property in config.highLightSet) { if (output !="") output=output+","; if(typeof config.highLightSet[property]=="string")output += property + ': "' + config.highLightSet[property]+'"'; else output += property + ': ' + config.highLightSet[property]; } fndnewspec=true; eval("data.special[data.special.length]={"+output+"};"); data.special[data.special.length-1].posi=j; data.special[data.special.length-1].posj=v2; data.special[data.special.length-1].typespecial="highLight"; } } } else if(config.highLightFullLine == true) { if(!(data.datasets[v1].mouseDetection==false)) { for(j=0;j<data.datasets[v1].data.length;j++) { output=""; for (property in config.highLightSet) { if (output !="") output=output+","; if(typeof config.highLightSet[property]=="string")output += property + ': "' + config.highLightSet[property]+'"'; else output += property + ': ' + config.highLightSet[property]; } fndnewspec=true; eval("data.special[data.special.length]={"+output+"};"); data.special[data.special.length-1].posi=v1; data.special[data.special.length-1].posj=j; data.special[data.special.length-1].typespecial="highLight"; } } } else if(!(data.datasets[v1].mouseDetection==false)) { output=""; for (property in config.highLightSet) { if (output !="") output=output+","; if(typeof config.highLightSet[property]=="string")output += property + ': "' + config.highLightSet[property]+'"'; else output += property + ': ' + config.highLightSet[property]; } fndnewspec=true; eval("data.special[data.special.length]={"+output+"};"); data.special[data.special.length-1].posi=v1; data.special[data.special.length-1].posj=v2; data.special[data.special.length-1].typespecial="highLight"; } } if(redisplay==true) { updateChart(ctx,data,config,false,config.highLightRerunEndFunction); } }; var inMouseAction=new Array(); function initAnnotateDiv(annotateDIV,config,ctx) { annotateDIV.className = (config.annotateClassName) ? config.annotateClassName : ''; annotateDIV.style.border = (config.annotateClassName) ? '' : config.annotateBorder; annotateDIV.style.padding = (config.annotateClassName) ? '' : config.annotatePadding; annotateDIV.style.borderRadius = (config.annotateClassName) ? '' : config.annotateBorderRadius; annotateDIV.style.backgroundColor = (config.annotateClassName) ? '' : config.annotateBackgroundColor; annotateDIV.style.color = (config.annotateClassName) ? '' : config.annotateFontColor; annotateDIV.style.fontFamily = (config.annotateClassName) ? '' : config.annotateFontFamily; annotateDIV.style.fontSize = (config.annotateClassName) ? '' : (Math.ceil(ctx.chartTextScale*config.annotateFontSize)).toString() + "pt"; annotateDIV.style.fontStyle = (config.annotateClassName) ? '' : config.annotateFontStyle; annotateDIV.style.zIndex = 999; }; function displayAnnotate(ctx,data,config,rect,event,annotateDIV,jsGraphAnnotate,piece,myStatData,statData) { if (jsGraphAnnotate[ctx.ChartNewId][piece.piece][0] == "ARC") dispString = tmplbis(setOptionValue(true,true,1,"ANNOTATELABEL",ctx,data,jsGraphAnnotate[ctx.ChartNewId][piece.piece][3],undefined,config.annotateLabel,"annotateLabel",jsGraphAnnotate[ctx.ChartNewId][piece.piece][1],-1,{otherVal:true}), myStatData,config); else dispString = tmplbis(setOptionValue(true,true,1,"ANNOTATELABEL",ctx,data,jsGraphAnnotate[ctx.ChartNewId][piece.piece][3],undefined,config.annotateLabel,"annotateLabel",jsGraphAnnotate[ctx.ChartNewId][piece.piece][1],jsGraphAnnotate[ctx.ChartNewId][piece.piece][2],{otherVal:true}), myStatData,config); textMsr=ctx.measureTextMultiLine(dispString,1*annotateDIV.style.fontSize.replace("pt","")); ctx.restore(); annotateDIV.innerHTML = dispString; x = bw.ns4 || bw.ns5 ? event.pageX : event.x; y = bw.ns4 || bw.ns5 ? event.pageY : event.y; if (bw.ie4 || bw.ie5) y = y + eval(scrolled); if(config.annotateRelocate===true) { var relocateX, relocateY; relocateX=0;relocateY=0; if(x+fromLeft+textMsr.textWidth > window.innerWidth-rect.left-fromLeft)relocateX=-textMsr.textWidth; if(y+fromTop+textMsr.textHeight > 1*window.innerHeight-1*rect.top+fromTop)relocateY-=(textMsr.textHeight+2*fromTop); oCursor.moveIt(Math.max(8-rect.left,x + fromLeft+relocateX), Math.max(8-rect.top,y + fromTop + relocateY)); } else oCursor.moveIt(x + fromLeft, y + fromTop); annotateDIV.style.display = true ? '' : 'none'; }; function doMouseAction(event, ctx, action) { if (ctx.firstPass != 9)return; if(action=="mousedown") action=action+" "+event.which; if(ctx.mouseAction.indexOf(action)<0){return;} var config=mouseActionData[ctx.ChartNewId].config; var data=mouseActionData[ctx.ChartNewId].data; var i,prevShown,prevShowSaved; var inRect,P12,D12,D34,P13,D13,D24, y1,y2,y3,y4; var pieceOfChartFound=[]; var textOnChartFound=[]; var distance, angle,topY, bottomY,leftX, rightX; var mousewheelevt=(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel" var canvas_pos = getMousePos(ctx.canvas, event); var realAction; var annotateDIV,showDiv; if(action=="mousedown 1")realAction="mousedown left"; else if(action=="mousedown 2")realAction="mousedown middle"; else if(action=="mousedown 3")realAction="mousedown right"; else if(action==mousewheelevt)realAction="mousewheel"; else realAction=action; // search if mouse over one or more pieces of chart; for (i = 0; i < jsGraphAnnotate[ctx.ChartNewId]["length"]; i++) { if (jsGraphAnnotate[ctx.ChartNewId][i][0] == "ARC") { myStatData=jsGraphAnnotate[ctx.ChartNewId][i][3][jsGraphAnnotate[ctx.ChartNewId][i][1]]; distance = Math.sqrt((canvas_pos.x - myStatData.midPosX) * (canvas_pos.x - myStatData.midPosX) + (canvas_pos.y - myStatData.midPosY) * (canvas_pos.y - myStatData.midPosY)); if (distance > myStatData.int_radius && distance < myStatData.radiusOffset) { angle = (Math.acos((canvas_pos.x - myStatData.midPosX) / distance) % (2* Math.PI) + 2*Math.PI) % (2*Math.PI); if (canvas_pos.y < myStatData.midPosY) angle = -angle; angle = (((angle + 2 * Math.PI) % (2 * Math.PI)) + 2* Math.PI) % (2* Math.PI) ; myStatData.startAngle=(((myStatData.startAngle + 2 * Math.PI) % (2 * Math.PI)) + 2* Math.PI) % (2* Math.PI); myStatData.endAngle=(((myStatData.endAngle + 2 * Math.PI) % (2 * Math.PI)) + 2* Math.PI) % (2* Math.PI); if(myStatData.endAngle<myStatData.startAngle)myStatData.endAngle+=2 * Math.PI; if ((angle > myStatData.startAngle && angle < myStatData.endAngle) || (angle > myStatData.startAngle - 2 * Math.PI && angle < myStatData.endAngle - 2 * Math.PI) || (angle > myStatData.startAngle + 2 * Math.PI && angle < myStatData.endAngle + 2 * Math.PI)) { myStatData.graphPosX = canvas_pos.x; myStatData.graphPosY = canvas_pos.y; pieceOfChartFound[pieceOfChartFound.length]={ piece : i, i : jsGraphAnnotate[ctx.ChartNewId][i][1], j : jsGraphAnnotate[ctx.ChartNewId][i][2], myStatData: myStatData }; } } } else if (jsGraphAnnotate[ctx.ChartNewId][i][0] == "MARC") { myStatData=jsGraphAnnotate[ctx.ChartNewId][i][3][jsGraphAnnotate[ctx.ChartNewId][i][1]][jsGraphAnnotate[ctx.ChartNewId][i][2]]; distance = Math.sqrt((canvas_pos.x - myStatData.midPosX) * (canvas_pos.x - myStatData.midPosX) + (canvas_pos.y - myStatData.midPosY) * (canvas_pos.y - myStatData.midPosY)); if (distance > myStatData.int_radius && distance < myStatData.radiusOffset) { angle = (Math.acos((canvas_pos.x - myStatData.midPosX) / distance) % (2* Math.PI) + 2*Math.PI) % (2*Math.PI); if (canvas_pos.y < myStatData.midPosY) angle = -angle; angle = (((angle + 2 * Math.PI) % (2 * Math.PI)) + 2* Math.PI) % (2* Math.PI) ; myStatData.startAngle=(((myStatData.startAngle + 2 * Math.PI) % (2 * Math.PI)) + 2* Math.PI) % (2* Math.PI); myStatData.endAngle=(((myStatData.endAngle + 2 * Math.PI) % (2 * Math.PI)) + 2* Math.PI) % (2* Math.PI); if(myStatData.endAngle<myStatData.startAngle)myStatData.endAngle+=2 * Math.PI; if ((angle > myStatData.startAngle && angle < myStatData.endAngle) || (angle > myStatData.startAngle - 2 * Math.PI && angle < myStatData.endAngle - 2 * Math.PI) || (angle > myStatData.startAngle + 2 * Math.PI && angle < myStatData.endAngle + 2 * Math.PI)) { myStatData.graphPosX = canvas_pos.x; myStatData.graphPosY = canvas_pos.y; pieceOfChartFound[pieceOfChartFound.length]={ piece : i, i : jsGraphAnnotate[ctx.ChartNewId][i][1], j : jsGraphAnnotate[ctx.ChartNewId][i][2], myStatData: myStatData }; } } } else if (jsGraphAnnotate[ctx.ChartNewId][i][0] == "RECT") { myStatData=jsGraphAnnotate[ctx.ChartNewId][i][3][jsGraphAnnotate[ctx.ChartNewId][i][1]][jsGraphAnnotate[ctx.ChartNewId][i][2]]; topY=Math.max(myStatData.yPosBottom,myStatData.yPosTop); bottomY=Math.min(myStatData.yPosBottom,myStatData.yPosTop); if (topY-bottomY <config.annotateBarMinimumDetectionHeight) { topY=(topY+bottomY+config.annotateBarMinimumDetectionHeight)/2; bottomY=topY-config.annotateBarMinimumDetectionHeight; } leftX=Math.min(myStatData.xPosLeft,myStatData.xPosRight); rightX=Math.max(myStatData.xPosLeft,myStatData.xPosRight); if (rightX-leftX <config.annotateBarMinimumDetectionHeight) { rightX=(rightX+leftX+config.annotateBarMinimumDetectionHeight)/2; leftX=rightX-config.annotateBarMinimumDetectionHeight; } if (canvas_pos.x > leftX && canvas_pos.x < rightX && canvas_pos.y < topY && canvas_pos.y > bottomY) { myStatData.graphPosX = canvas_pos.x; myStatData.graphPosY = canvas_pos.y; pieceOfChartFound[pieceOfChartFound.length]={ piece : i, i : jsGraphAnnotate[ctx.ChartNewId][i][1], j : jsGraphAnnotate[ctx.ChartNewId][i][2], myStatData: myStatData }; } } else if (jsGraphAnnotate[ctx.ChartNewId][i][0] == "POINT") { myStatData=jsGraphAnnotate[ctx.ChartNewId][i][3][jsGraphAnnotate[ctx.ChartNewId][i][1]][jsGraphAnnotate[ctx.ChartNewId][i][2]]; if(config.detectAnnotateOnFullLine) { if(canvas_pos.x < Math.min(myStatData.annotateStartPosX,myStatData.annotateEndPosX)-Math.ceil(ctx.chartSpaceScale*config.pointHitDetectionRadius) || canvas_pos.x > Math.max(myStatData.annotateStartPosX,myStatData.annotateEndPosX)+Math.ceil(ctx.chartSpaceScale*config.pointHitDetectionRadius) || canvas_pos.y < Math.min(myStatData.annotateStartPosY,myStatData.annotateEndPosY)-Math.ceil(ctx.chartSpaceScale*config.pointHitDetectionRadius) || canvas_pos.y > Math.max(myStatData.annotateStartPosY,myStatData.annotateEndPosY)+Math.ceil(ctx.chartSpaceScale*config.pointHitDetectionRadius)) { distance=Math.ceil(ctx.chartSpaceScale*config.pointHitDetectionRadius)+1; } else { if(typeof myStatData.D1A=="undefined") { distance=Math.abs(canvas_pos.x-myStatData.posX); } else if(typeof myStatData.D2A=="undefined") { distance=Math.abs(canvas_pos.y-myStatData.posY); } else { var D2B=-myStatData.D2A*canvas_pos.x+canvas_pos.y; var g=-(myStatData.D1B-D2B)/(myStatData.D1A-myStatData.D2A); var h=myStatData.D2A*g+D2B; distance=Math.sqrt((canvas_pos.x - g) * (canvas_pos.x - g) + (canvas_pos.y - h) * (canvas_pos.y - h)); } } } else { distance = Math.sqrt((canvas_pos.x - myStatData.posX) * (canvas_pos.x - myStatData.posX) + (canvas_pos.y - myStatData.posY) * (canvas_pos.y - myStatData.posY)); } if (distance < Math.ceil(ctx.chartSpaceScale*config.pointHitDetectionRadius)) { myStatData.graphPosX = canvas_pos.x; myStatData.graphPosY = canvas_pos.y; pieceOfChartFound[pieceOfChartFound.length]={ piece : i, i : jsGraphAnnotate[ctx.ChartNewId][i][1], j : jsGraphAnnotate[ctx.ChartNewId][i][2], myStatData: myStatData }; } } } // search if mouse over one or more text; if(config.detectMouseOnText) { for(i=0;i<jsTextMousePos[ctx.ChartNewId]["length"];i++){ inRect=true; if(Math.abs(jsTextMousePos[ctx.ChartNewId][i][3].p1 - jsTextMousePos[ctx.ChartNewId][i][3].p2) < config.zeroValue) { // Horizontal; if(canvas_pos.x < Math.min(jsTextMousePos[ctx.ChartNewId][i][2].p1,jsTextMousePos[ctx.ChartNewId][i][2].p2))inRect=false; if(canvas_pos.x > Math.max(jsTextMousePos[ctx.ChartNewId][i][2].p1,jsTextMousePos[ctx.ChartNewId][i][2].p2))inRect=false; if(canvas_pos.y < Math.min(jsTextMousePos[ctx.ChartNewId][i][3].p1,jsTextMousePos[ctx.ChartNewId][i][3].p3))inRect=false; if(canvas_pos.y > Math.max(jsTextMo