//------------------------------------------------------------------------------ function round(value, decimals) { return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals); } //------------------------------------------------------------------------------ function round1(value) { if (value !== 0) exponent = Math.floor(log10(Math.abs(value))); else return 0; if (exponent < 0) return round(value, Math.abs(exponent)); else return round(value, 0); } //------------------------------------------------------------------------------ function round2(value, step) { if (value !== 0) exponent = Math.floor(log10(Math.abs(step))); else return 0; if (exponent < 0) return round(value, Math.abs(exponent)); else return round(value, 0); } //------------------------------------------------------------------------------ function formatFloat(x, num_dig, isScientific) { return (isScientific ? x.toExponential(num_dig) : round(x, num_dig)).toString(); } ; //------------------------------------------------------------------------------ function getColor(index) { var Color = ["aqua", "black", "blue", "fuchsia", "green", "gray", "lime", "maroon", "navy", "olive", "purple", "red", "silver", "teal", "white", "yellow"]; if (index < 0) return Color[0]; if (index < Color.length) return Color[index]; else return Color[index % Color.length]; } //------------------------------------------------------------------------------ function getFillColor(index) { var Color = [ "rgb(25,20,151)", "rgb(6,50,173)", "rgb(11,69,187)", "rgb(12,93,197)", "rgb(11,110,199)", "rgb(14,140,204)", "rgb(4,153,173)", "rgb(10,179,150)", "rgb(21,176,121)", "rgb(6,175,78)", "rgb(92,191,20)", "rgb(185,212,15)", "rgb(220,222,2)", "rgb(245,212,2)", "rgb(251,201,11)", "rgb(231,176,18)", "rgb(250,157,16)", "rgb(244,122,4)", "rgb(247,108,0)", "rgb(244,83,2)", "rgb(248,54,36)", "rgb(240,33,55)", "rgb(232,11,62)", "rgb(216,8,52)" ]; if (index < 0) return Color[0]; if (index < Color.length) return Color[index]; else return Color[index % Color.length]; } //------------------------------------------------------------------------------ function getBasicColor(index) { var Color = [ "rgb(0,0,0)", "rgb(255,0,0)", "rgb(0,255,0)", "rgb(0,0,255)", "rgb(255,0,255)", "rgb(0,255,255)", "rgb(128,0,0)", "rgb(0,128,0)", "rgb(0,0,128)", "rgb(0,128,128)", "rgb(128,0,128)", "rgb(128,128,128)" ]; if (index < 0) return Color[0]; if (index < Color.length) return Color[index]; else return Color[index % Color.length]; } //------------------------------------------------------------------------------ function drawStar(cx, cy, spikes, outerRadius, innerRadius, ctx) { var rot = Math.PI / 2 * 3; var x = cx; var y = cy; var step = Math.PI / spikes; var i; ctx.strokeSyle = "#000"; ctx.beginPath(); ctx.moveTo(cx, cy - outerRadius); for (i = 0; i < spikes; i++) { x = cx + Math.cos(rot) * outerRadius; y = cy + Math.sin(rot) * outerRadius; ctx.lineTo(x, y); rot += step; x = cx + Math.cos(rot) * innerRadius; y = cy + Math.sin(rot) * innerRadius; ctx.lineTo(x, y); rot += step; } ctx.lineTo(cx, cy - outerRadius); ctx.closePath(); ctx.stroke(); } //------------------------------------------------------------------------------ function polygon(ctx, x, y, radius, sides, startAngle, anticlockwise) { if (sides < 3) return; var a = (Math.PI * 2) / sides; a = anticlockwise ? -a : a; ctx.save(); ctx.translate(x, y); ctx.rotate(startAngle); ctx.beginPath(); ctx.moveTo(radius, 0); for (var i = 1; i < sides; i++) { ctx.lineTo(radius * Math.cos(a * i), radius * Math.sin(a * i)); } ctx.closePath(); ctx.restore(); ctx.stroke(); } //------------------------------------------------------------------------------ function drawLine(x1, y1, x2, y2, context, strokeStyle, lineWidth) { context.beginPath(); x1 = Math.floor(x1) + 0.5; x2 = Math.floor(x2) + 0.5; y1 = Math.floor(y1) + 0.5; y2 = Math.floor(y2) + 0.5; /* x1 = Math.round(x1) + 0.5; x2 = Math.round(x2) + 0.5; y1 = Math.round(y1) + 0.5; y2 = Math.round(y2) + 0.5; */ /* if(x1-Math.floor(x1)>=0.5) x1=Math.floor(x1)+0.5; else x1=Math.floor(x1)-0.5; if(x2-Math.floor(x2)>=0.5) x2=Math.floor(x2)+0.5; else x2=Math.floor(x2)-0.5; if(y1-Math.floor(y1)>=0.5) y1=Math.floor(y1)+0.5; else y1=Math.floor(y1)-0.5; if(y2-Math.floor(y2)>=0.5) y2=Math.floor(y2)+0.5; else y2=Math.floor(y2)-0.5; */ context.moveTo(x1, y1); context.lineTo(x2, y2); context.strokeStyle = strokeStyle; context.lineWidth = lineWidth; context.stroke(); } //------------------------------------------------------------------------------ function drawHorizontalDashedLine(xx0, xx, yy0, dashLength, context, strokeStyle, lineWidth) { n = 0; if (xx0 > xx) { tmp = xx0; xx0 = xx; xx = tmp; } while (true) { x1 = xx0 + dashLength * n; if (x1 > xx) break; x2 = xx0 + dashLength * (n + 1); if (x2 > xx) x2 = xx; drawLine(x1, yy0, x2, yy0, context, strokeStyle, lineWidth); n += 2; } } //--------------------------------------------------------------------------- function drawVerticalDashedLine(xx0, yy0, yy, dashLength, context, strokeStyle, lineWidth) { n = 0; if (yy0 > yy) { tmp = yy0; yy0 = yy; yy = tmp; } while (true) { y1 = yy0 + dashLength * n; if (y1 > yy) break; y2 = yy0 + dashLength * (n + 1); if (y2 > yy) y2 = yy; drawLine(xx0, y1, xx0, y2, context, strokeStyle, lineWidth); n += 2; } } //--------------------------------------------------------------------------- //Draws dashed line //You can use this as //context.dashedLine(0, 0, 200, 200, 4); CanvasRenderingContext2D.prototype.dashedLine = function (x1, y1, x2, y2, dashLen) { if (dashLen === undefined) dashLen = 2; x1 = Math.floor(x1) + 0.5; x2 = Math.floor(x2) + 0.5; y1 = Math.floor(y1) + 0.5; y2 = Math.floor(y2) + 0.5; //this['beginPath'](); //this.beginPath(); this.moveTo(x1, y1); var dX = x2 - x1; var dY = y2 - y1; var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen); var dashX = dX / dashes; var dashY = dY / dashes; var q = 0; while (q++ < dashes) { //this['beginPath'](); x1 += dashX; y1 += dashY; //if (q % 2=== 0) this['beginPath'](); //if (q % 2=== 0) this.beginPath(); this[q % 2 === 0 ? 'moveTo' : 'lineTo'](x1, y1); // this[q % 2 === 0 ? 'moveTo' : 'lineTo'](Math.floor(x1)+0.5, Math.floor(y1)+0.5); } //if (q % 2=== 0) this['beginPath'](); //if (q % 2=== 0) this.beginPath(); this[q % 2 === 0 ? 'moveTo' : 'lineTo'](x2, y2); //beginPath(); // this[q % 2 === 0 ? 'moveTo' : 'lineTo'](Math.floor(x2)+0.5, Math.floor(y2)+0.5); }; //------------------------------------------------------------------------------ //Creates multidimensional array //You can use this as //var myArray=createArray(5,4); function createArray(length) { var arr = new Array(length || 0), i = length; if (arguments.length > 1) { var args = Array.prototype.slice.call(arguments, 1); while (i--) arr[length - 1 - i] = createArray.apply(this, args); } return arr; } //------------------------------------------------------------------------------ var ln10 = Math.log(10); //------------------------------------------------------------------------------ var log10 = function (x) { return Math.log(x) / ln10; }; //------------------------------------------------------------------------------ var calcStepSize = function (range, targetSteps) { // calculate an initial guess at step size var tempStep = range / targetSteps; //alert(tempStep); //alert(range); // get the magnitude of the step size var mag = Math.floor(Math.log(tempStep) / ln10); var magPow = Math.pow(10, mag); // calculate most significant digit of the new step size var magMsd = Math.round(tempStep / magPow + 0.5); // promote the MSD to either 1, 2, or 5 if (magMsd > 5.0) magMsd = 10.0; else if (magMsd > 2.0) magMsd = 5.0; else if (magMsd > 1.0) magMsd = 2.0; //console.log(magMsd); //{let ss=0;} return magMsd * magPow; }; //------------------------------------------------------------------------------ function NiceScale(min, max, type) { this.minPoint; this.maxPoint; //this.maxTicks = 10; this.maxTicks = 7; //this.maxTicks = 9; //this.maxTicks = 8; this.tickSpacing; this.range; this.niceMin; this.niceMax; var self = this; /** * Instantiates a new instance of the NiceScale class. * * @param min the minimum data point on the axis * @param max the maximum data point on the axis */ //this.NiceScale=function(min, max) { this.minPoint = min; this.maxPoint = max; //this.calculate(); //var my=new this.calculate(); //alert(this.maxPoint); calculate(); //alert(this.maxPoint); //}; /** * Returns a "nice" number approximately equal to range Rounds * the number if round = true Takes the ceiling if round = false. * * @param range the data range * @param round whether to round the result * @return a "nice" number to be used for the data range */ //this.niceNum=new function( range, round) { //this.niceNum=function( range, round) { function niceNum(range, round) { this.exponent; /** exponent of range */ this.fraction; /** fractional part of range */ this.niceFraction; /** nice, rounded fraction */ //this.exponent = Math.floor(Math.log10(range)); this.exponent = Math.floor(log10(range)); this.fraction = range / Math.pow(10, this.exponent); if (type) { if (round) { if (this.fraction < 2) this.niceFraction = 1.5; //this.niceFraction = 1; else if (this.fraction < 4) this.niceFraction = 3; else if (this.fraction < 7) this.niceFraction = 6; else this.niceFraction = 9; } else { if (this.fraction <= 2) this.niceFraction = 1.5; //this.niceFraction = 1; else if (this.fraction <= 4) this.niceFraction = 3; else if (this.fraction <= 7) this.niceFraction = 6; else this.niceFraction = 9; } } else { if (round) { if (this.fraction < 1.5) this.niceFraction = 1; else if (this.fraction < 3) this.niceFraction = 2; else if (this.fraction < 7) this.niceFraction = 5; else this.niceFraction = 10; } else { if (this.fraction <= 1) this.niceFraction = 1; else if (this.fraction <= 2) this.niceFraction = 2; else if (this.fraction <= 5) this.niceFraction = 5; else this.niceFraction = 10; } } return this.niceFraction * Math.pow(10, this.exponent); } ; /** * Calculate and update values for tick spacing and nice * minimum and maximum data points on the axis. */ function calculate() { self.range = niceNum(self.maxPoint - self.minPoint, false); self.tickSpacing = niceNum(self.range / (self.maxTicks - 1), true); self.niceMin = Math.floor(self.minPoint / self.tickSpacing) * self.tickSpacing; self.niceMax = Math.ceil(self.maxPoint / self.tickSpacing) * self.tickSpacing; if (type) { if (self.niceMin < 0) self.niceMin = 0; if (self.niceMax > 180) self.niceMax = 180; } } ; /** * Sets the minimum and maximum data points for the axis. * * @param minPoint the minimum data point on the axis * @param maxPoint the maximum data point on the axis */ this.setMinMaxPoints = function (minPoint, maxPoint) { this.minPoint = minPoint; this.maxPoint = maxPoint; calculate(); }; /** * Sets maximum number of tick marks we're comfortable with * * @param maxTicks the maximum number of tick marks for the axis */ this.setMaxTicks = function (maxTicks) { this.maxTicks = maxTicks; calculate(); }; } //------------------------------------------------------------------------------ /** * Creates data object for drawing on Chart * * @param nPointsP the number of data points * @param nColumnsP the number of array columns (2 or 4); if nColumnsP=2, errors are not drawn * @param aaP the name of data array * @param colorP the color of symbol interior and/or line * @param symbolP the symbol type; if symbolP=0, symbols are not drawn; symbolP=1,2...9 correspond to different symbol types: 1 - circle,2 - square, 3 - diamond, 4 - star, 5 - triangle up, 6 - triangle down, 7 - triangle left, 8 - triangle right, 9 - pentagon * @param symbolSizeP the size (diameter) of symbol * @param lineP the thickness of line; if lineP=0, line is not drawn * @param errorLineWidthP the thickness of error bars * @param legendStrP the legend string shown on the right * @param isDataLogScaleP if true, data is plotted in logarithmic scale */ function ChartData(nPointsP, nColumnsP, aaP, colorP, symbolP, symbolSizeP, lineP, errorLineWidthP, legendStrP, isDataLogScaleP) { this.nPoints = nPointsP; this.nColumns = nColumnsP; //this.aa = aaP; this.aa; this.color = colorP; this.symbol = symbolP; this.symbolSize = symbolSizeP; this.line = lineP; this.errorLineWidth = errorLineWidthP; this.aaLog = createArray(nPointsP, nColumnsP); this.aaLin = createArray(nPointsP, nColumnsP); this.isLogScaleAvailable = true; this.legendStr = legendStrP; this.isDataLogScale = isDataLogScaleP; this.isMinMax = true; //this.aaLog = aaP; //this.aaLin = aaP; for (i = 0; i < nPointsP; i++) { for (j = 0; j < nColumnsP; j++) { this.aaLin[i][j] = aaP[i][j]; //alert(this.aaLin[i][j]); } } if (this.isDataLogScale) { for (i = 0; i < nPointsP; i++) { if (this.aaLin[i][1] > 0) this.aaLog[i][1] = Math.log(this.aaLin[i][1]) / ln10; else { this.isLogScaleAvailable = false; console.log("Logarithmic scale is not available!"); return; } this.aaLog[i][0] = this.aaLin[i][0]; // error bars check if (nColumnsP > 2) { if (this.aaLin[i][1] - this.aaLin[i][3] > 0) { this.aaLog[i][2] = Math.log(this.aaLin[i][1] + this.aaLin[i][2]) / ln10 - Math.log(this.aaLin[i][1]) / ln10; this.aaLog[i][3] = Math.log(this.aaLin[i][1]) / ln10 - Math.log(this.aaLin[i][1] - this.aaLin[i][3]) / ln10; } else { /* this.isLogScaleAvailable = false; alert("Logarithmic scale is not available!"); return; */ this.aaLog[i][2] = Math.log(this.aaLin[i][1] + this.aaLin[i][2]) / ln10 - Math.log(this.aaLin[i][1]) / ln10; this.aaLog[i][3] =Number.NaN; } } } } } //------------------------------------------------------------------------------ /** * Creates chart object for drawing data * * @param canvasName the name of canvas * @param tickLabelFontP the font of tick labels * @param tickLabelColorP the color of tick labels * @param axisLabelFontP the font of axis labels * @param axisLabelColorP the color of axis labels * @param xAxisLabelP the X-axis label string * @param yAxisLabelP the Y-axis label string * @param lineWidthP the thickness of axis lines * @param drawGridP if true, gridlines are drawn * @param gridColorP the color of gridlines * @param bgColorP the color of background * @param majorTickLengthP the length of major ticks; the length of minor ticks is majorTickLengthP/2 * @param isLogScaleP if true, Y-axis is plotted in logarithmic scale * @param isTopP if true, Y-axis label is shown on top * @param isRightP if true, the legend is shown */ function Chart(canvasName, tickLabelFontP, tickLabelColorP, axisLabelFontP, axisLabelColorP, xAxisLabelP, yAxisLabelP, lineWidthP, drawGridP, gridColorP, bgColorP, majorTickLengthP, isLogScaleP, isTopP, isRightP) { var chartThis = this; var canvas = document.getElementById(canvasName); var context = canvas.getContext('2d'); this.arrayOfData = new Array(); this.tickLabelFont = tickLabelFontP; this.getTickLabelFont = function () { return tickLabelFont; }; this.setTickLabelFont = function (newVal) { this.tickLabelFont = newVal; }; this.tickLabelColor = tickLabelColorP; this.getTickLabelColor = function () { return tickLabelColor; }; this.setTickLabelColor = function (newVal) { this.tickLabelColor = newVal; }; this.axisLabelFont = axisLabelFontP; this.getAxisLabelFont = function () { return axisLabelFont; }; this.setAxisLabelFont = function (newVal) { this.axisLabelFont = newVal; }; this.axisLabelColor = axisLabelColorP; this.getAxisLabelColor = function () { return axisLabelColor; }; this.setAxisLabelColor = function (newVal) { this.axisLabelColor = newVal; }; this.xAxisLabel = xAxisLabelP; this.getXAxisLabel = function () { return xAxisLabel; }; this.setXAxisLabel = function (newVal) { this.xAxisLabel = newVal; }; this.yAxisLabel = yAxisLabelP; this.getYAxisLabel = function () { return yAxisLabel; }; this.setYAxisLabel = function (newVal) { this.yAxisLabel = newVal; }; this.lineWidth = lineWidthP; this.getLineWidth = function () { return lineWidth; }; this.setLineWidth = function (newVal) { this.lineWidth = newVal; }; this.drawGrid = drawGridP; this.getDrawGrid = function () { return drawGrid; }; this.setDrawGrid = function (newVal) { this.drawGrid = newVal; }; this.showGridLines = function () { this.drawGrid = true; this.draw(); }; this.hideGridLines = function () { this.drawGrid = false; this.draw(); }; this.gridColor = gridColorP; this.getGridColor = function () { return gridColor; }; this.setGridColor = function (newVal) { this.gridColor = newVal; }; this.bgColor = bgColorP; this.getBgColor = function () { return bgColor; }; this.setBgColor = function (newVal) { this.bgColor = newVal; }; this.majorTickLength = majorTickLengthP; this.getMajorTickLength = function () { return majorTickLength; }; this.setMajorTickLength = function (newVal) { this.majorTickLength = newVal; }; this.isLogScale = isLogScaleP; this.getIsLogScale = function () { return this.isLogScale; }; this.setIsLogScale = function (newVal) { this.isLogScale = newVal; }; this.showLogScale = function () { this.isLogScale = true; this.draw(); }; this.showLinearScale = function () { this.isLogScale = false; this.draw(); }; this.isTop = isTopP; this.getIsTop = function () { return isTop; }; this.setIsTop = function (newVal) { this.isTop = newVal; }; this.isRight = isRightP; this.getIsRight = function () { return isRight; }; this.setIsRight = function (newVal) { this.isRight = newVal; }; this.xAxisType = false; this.setXAxisType = function (newVal) { this.xAxisType = newVal; }; this.isLegendOnTop = true; this.getIsLegendOnTop = function () { return isLegendOnTop; }; this.setIsLegendOnTop = function (newVal) { this.isLegendOnTop = newVal; }; this.isLegendVisible = true; this.showLegend = function () { this.isLegendVisible = true; this.draw(); }; this.hideLegend = function () { this.isLegendVisible = false; this.draw(); }; this.zoomX1; this.zoomY1; this.canvas0; this.canvas3; this.context0; this.startZoom = function (x1, y1) { zoomX1 = x1; zoomY1 = y1; canvas0 = document.createElement('canvas'); canvas0.width = canvas.width; canvas0.height = canvas.height; context0 = canvas0.getContext('2d'); context0.drawImage(canvas, 0, 0); }; var canvas2 = document.createElement('canvas'); canvas2.width = canvas.width; canvas2.height = canvas.height; var context2 = canvas2.getContext('2d'); var canvas3 = document.createElement('canvas'); canvas3.width = canvas.width; canvas3.height = canvas.height; var context3 = canvas3.getContext('2d'); this.continueZoom = function (x2, y2) { context2.clearRect(0, 0, canvas.width, canvas.height); context3.clearRect(0, 0, canvas.width, canvas.height); context3.beginPath(); context3.rect(zoomX1, zoomY1, -(zoomX1 - x2), -(zoomY1 - y2)); context3.lineWidth = 2; context3.strokeStyle = 'black'; context3.stroke(); context2.drawImage(canvas0, 0, 0); context2.drawImage(canvas3, 0, 0); context.drawImage(canvas2, 0, 0); }; this.xMinZ; this.xMaxZ; this.yMinZ; this.yMaxZ; this.endZoom = function (x1, y1) { if (Math.abs(zoomX1 - x1) < 10 && Math.abs(zoomY1 - y1) < 10) { context.drawImage(canvas0, 0, 0); return; } this.xMinZ = this.xmin; this.xMaxZ = this.xmax; this.yMinZ = this.ymin; this.yMaxZ = this.ymax; //alert("endzoom "+this.xmin); X1 = this.fXscale * (zoomX1 - this.fLeft) + this.xmin; Y1 = this.fYscale * (this.fHeight + this.fTop - zoomY1) + this.ymin; X2 = this.fXscale * (x1 - this.fLeft) + this.xmin; Y2 = this.fYscale * (this.fHeight + this.fTop - y1) + this.ymin; if (this.xAxisType && X1 <= 0) X1 = 0; if (this.xAxisType && X2 <= 0) X2 = 0; if (this.xAxisType && X1 > 180) X1 = 180; if (this.xAxisType && X2 > 180) X2 = 180; this.setXYLimits(Math.min(X1, X2), Math.max(X1, X2), Math.min(Y1, Y2), Math.max(Y1, Y2)); this.draw(); }; this.isFirstRun = true; this.restoreInitialScale = function () { //alert("restore initial"+this.xMin0); this.setXYLimits(this.xMin0, this.xMax0, this.yMin0, this.yMax0); this.areXYLimitsSet = false; this.draw(); }; this.restorePreviousScale = function () { //alert("restore previous"+this.xMinZ); this.setXYLimits(this.xMinZ, this.xMaxZ, this.yMinZ, this.yMaxZ); //alert("restore previous"+this.xmin); this.areXYLimitsSet = true; this.draw(); }; var xmin, xmax, ymin, ymax; //this.xmin; this.xmax; this.ymin; this.ymax; var niceXmin, niceXmax, niceYmin, niceYmax; var xtickSpacing, ytickSpacing; var ymaxSet; this.areXYNLimitsSet = false; this.areXNLimitsSet = false; this.areYNLimitsSet = false; this.areXYLimitsSet = false; this.areXLimitsSet = false; this.areYLimitsSet = false; this.isYmaxSet = false; this.nXTicks; this.nYTicks; this.setdrawGrid = function (drawGridP) { this.drawGrid = drawGridP; } //------------------------------------------------------------------------------ this.drawSymbol = function (fillStyleColor, strokeStyleColor, errorLineWidth, centerX, centerY, symbolSize, symbolType) { context.fillStyle = fillStyleColor; context.strokeStyle = strokeStyleColor; context.lineWidth = errorLineWidth; switch (symbolType) { //circle case 1: { context.beginPath(); context.arc(centerX, centerY, symbolSize, 0, 2 * Math.PI); context.closePath(); context.stroke(); break; } //square case 2: { context.beginPath(); context.rect(centerX - symbolSize, centerY - symbolSize, 2 * symbolSize, 2 * symbolSize); context.closePath(); context.stroke(); break; } //diamond case 3: { context.beginPath(); context.moveTo(centerX - symbolSize, centerY); context.lineTo(centerX, centerY - symbolSize); context.lineTo(centerX + symbolSize, centerY); context.lineTo(centerX, centerY + symbolSize); context.closePath(); context.stroke(); break; } //star case 4: { drawStar(centerX, centerY, 5, symbolSize, symbolSize / 2, context); break; } //triangle up case 5: { context.beginPath(); context.moveTo(centerX, centerY - 1.5 * symbolSize); context.lineTo(centerX + symbolSize, centerY + 0.5 * symbolSize); context.lineTo(centerX - symbolSize, centerY + 0.5 * symbolSize); context.closePath(); context.stroke(); break; } //triangle down case 6: { context.beginPath(); context.moveTo(centerX, centerY + 1.5 * symbolSize); context.lineTo(centerX + symbolSize, centerY - 0.5 * symbolSize); context.lineTo(centerX - symbolSize, centerY - 0.5 * symbolSize); context.closePath(); context.stroke(); break; } //triangle left case 7: { context.save(); context.translate(centerX, centerY); context.rotate(Math.PI / 2); context.beginPath(); context.moveTo(0, 1.5 * symbolSize); context.lineTo(symbolSize, -0.5 * symbolSize); context.lineTo(-symbolSize, -0.5 * symbolSize); context.closePath(); context.stroke(); context.restore(); break; } //triangle right case 8: { context.save(); context.translate(centerX, centerY); context.rotate(-Math.PI / 2); context.beginPath(); context.moveTo(0, 1.5 * symbolSize); context.lineTo(symbolSize, -0.5 * symbolSize); context.lineTo(-symbolSize, -0.5 * symbolSize); context.closePath(); context.stroke(); context.restore(); break; } //pentagon case 9: { polygon(context, centerX, centerY, symbolSize, 5, -Math.PI / 2, false); break; } //default default: { break; } } //fill symbols context.fill(); }; //------------------------------------------------------------------------------ this.draw = function () { for (j = 0; j < this.arrayOfData.length; j++) { if (this.isLogScale) this.arrayOfData[j].aa = this.arrayOfData[j].aaLog; else this.arrayOfData[j].aa = this.arrayOfData[j].aaLin; } if (this.areXYLimitsSet === false && this.areXYNLimitsSet === false) { if (this.areXLimitsSet === false && this.areXNLimitsSet === false) { this.xmin = Number.POSITIVE_INFINITY; this.xmax = Number.NEGATIVE_INFINITY; for (j = 0; j < this.arrayOfData.length; j++) { if (this.arrayOfData[j].isMinMax === false) continue; for (i = 0; i < this.arrayOfData[j].nPoints; i++) { if (this.arrayOfData[j].aa[i][0] < this.xmin) this.xmin = this.arrayOfData[j].aa[i][0]; if (this.arrayOfData[j].aa[i][0] > this.xmax) this.xmax = this.arrayOfData[j].aa[i][0]; } } if (this.xmin === this.xmax) { if (this.xmin === 0) xnumScale = new NiceScale(-1, 1, this.xAxisType); else if (this.xmin > 0) xnumScale = new NiceScale(0, 2 * this.xmax, this.xAxisType); else xnumScale = new NiceScale(2 * this.xmax, 0, this.xAxisType); xMin = xnumScale.niceMin; xMax = xnumScale.niceMax; xtickSpacing = xnumScale.tickSpacing; this.setXNLimits(xMin, xMax, Math.round((xMax - xMin) / xtickSpacing)); } else { xnumScale = new NiceScale(this.xmin, this.xmax, this.xAxisType); xMin = xnumScale.niceMin; xMax = xnumScale.niceMax; xtickSpacing = xnumScale.tickSpacing; this.setXNLimits(xMin, xMax, Math.round((xMax - xMin) / xtickSpacing)); } } if (this.areYLimitsSet === false && this.areYNLimitsSet === false) { this.ymin = Number.POSITIVE_INFINITY; this.ymax = Number.NEGATIVE_INFINITY; for (j = 0; j < this.arrayOfData.length; j++) { if (this.arrayOfData[j].isMinMax === false) continue; for (i = 0; i < this.arrayOfData[j].nPoints; i++) { if(isFinite(this.arrayOfData[j].aa[i][3])) { y = 1. * this.arrayOfData[j].aa[i][1] - ((this.arrayOfData[j].nColumns > 2) ? this.arrayOfData[j].aa[i][3] : 0.0); } else { y = 1. * this.arrayOfData[j].aa[i][1] - ((this.arrayOfData[j].nColumns > 2) ? 0.0 : 0.0); } if (y < this.ymin) this.ymin = y; y = 1. * this.arrayOfData[j].aa[i][1] + ((this.arrayOfData[j].nColumns > 2) ? this.arrayOfData[j].aa[i][2] : 0.0); if (y > this.ymax) this.ymax = y; } } if (this.ymin === this.ymax) { if (this.isLogScale === false) { if (this.ymin === 0) ynumScale = new NiceScale(-1, 1, 0); else if (this.ymin > 0) ynumScale = new NiceScale(0, 2 * this.ymax, 0); else ynumScale = new NiceScale(2 * this.ymax, 0, 0); yMin = ynumScale.niceMin; yMax = ynumScale.niceMax; ytickSpacing = ynumScale.tickSpacing; this.setYNLimits(yMin, yMax, Math.round((yMax - yMin) / ytickSpacing)); } else { this.ymin = Math.floor(this.ymin); this.ymax = Math.ceil(this.ymax); if (this.ymin === this.ymax) { this.ymin = this.ymin - 1; this.ymax = this.ymax + 1; } this.setYNLimits(this.ymin, this.ymax, (this.ymax - this.ymin)); } } else { if (this.isLogScale === false) { ynumScale = new NiceScale(this.ymin, this.ymax, 0); yMin = ynumScale.niceMin; yMax = ynumScale.niceMax; ytickSpacing = ynumScale.tickSpacing; this.setYNLimits(yMin, yMax, (yMax - yMin) / ytickSpacing); } else { this.ymin = Math.floor(this.ymin); this.ymax = Math.ceil(this.ymax); this.setYNLimits(this.ymin, this.ymax, (this.ymax - this.ymin)); } } } } if (this.areXYLimitsSet === true || this.areXLimitsSet === true) { xnumScale = new NiceScale(this.xmin, this.xmax, this.xAxisType); xMin = this.xmin; xMax = this.xmax; xtickSpacing = xnumScale.tickSpacing; // this.setXNLimits(xMin, xMax, ((xMax - xMin) / calcStepSize((xMax - xMin), 6))); this.setXNLimits(xMin, xMax, ((xMax - xMin) / xtickSpacing)); this.niceXmin = xnumScale.niceMin; this.niceXmax = xnumScale.niceMax; this.xtickSpacing = xtickSpacing; } if (this.areXYLimitsSet === true || this.areYLimitsSet === true) { ynumScale = new NiceScale(this.ymin, this.ymax, 0); yMin = this.ymin; yMax = this.ymax; ytickSpacing = ynumScale.tickSpacing; //this.setYNLimits(yMin, yMax, ((yMax - yMin) / calcStepSize((yMax - yMin), 6))); this.setYNLimits(yMin, yMax, ((yMax - yMin) / ytickSpacing)); this.niceYmin = ynumScale.niceMin; this.niceYmax = ynumScale.niceMax; if (this.isLogScale === false) this.ytickSpacing = ytickSpacing; else this.ytickSpacing = 1; //this.ytickSpacing = ytickSpacing; } if (this.isYmaxSet === true && this.ymax > this.ymaxSet && this.ymaxSet > this.ymin) this.ymax = this.ymaxSet; //------------------------------------------------------------------------------ var h = canvas.height;//important!! var w = canvas.width;//important!! context.beginPath(); context.fillStyle = this.bgColor; context.fillRect(1, 1, w - 2, h - 2); var top = 20, left = 120, bottom = 80, right = 20; var maxStrWidth = 0; this.legendWidth = 0; if (this.isTop) top = 3 * this.majorTickLength + 0.25 * this.majorTickLength + parseInt(this.axisLabelFont); else top = 2 * this.majorTickLength; if (this.isRight && this.isLegendVisible) { context.font = this.tickLabelFont; for (j = 0; j < this.arrayOfData.length; j++) { if (this.arrayOfData[j].legendStr.length !== 0) { if (maxStrWidth < context.measureText(this.arrayOfData[j].legendStr).width) maxStrWidth = context.measureText(this.arrayOfData[j].legendStr).width; } } //right = 4 * this.majorTickLength + 12 + maxStrWidth + 2 * this.arrayOfData[0].symbolSize + 12; right = 4 * this.majorTickLength + maxStrWidth + 40; } else right = 2 * this.majorTickLength; right = 2 * this.majorTickLength; this.legendWidth = 2 * this.majorTickLength + maxStrWidth + 40; //---------------------------------------- //temporary workaround if (this.xmax === 180) right = 3 * this.majorTickLength; //---------------------------------------- bottom = parseInt(this.tickLabelFont) + parseInt(this.axisLabelFont) + 3 * this.majorTickLength; context.font = this.tickLabelFont; var maxWidth = Number.NEGATIVE_INFINITY; // for (i = 0; i <= this.nYTicks; i++) // { for (i = 0; this.niceXmin + i * this.xtickSpacing <= this.xmax; i++) { if (this.niceXmin + i * this.xtickSpacing >= this.xmin) {//new var width; if (this.isLogScale) { //------------------------------- var str1 = '10'; var metrics1 = context.measureText(str1); var width1 = metrics1.width; //------------------------------- var fontSize1 = parseInt(context.font); var fontSize2 = Math.round(2 * fontSize1 / 3); var fontSizeDiff = fontSize1 - fontSize2; var strF = context.font.split(' ', 2); context.font = fontSize2.toString() + 'px ' + strF[1]; //------------------------------- var yy = Math.round(this.ymin + i * Yheight / this.nYTicks); var str2 = yy.toString(); var metrics2 = context.measureText(str2); var width2 = metrics2.width; width = width1 + width2; } else { //var metrics = context.measureText(this.ymin + i * Yheight / this.nYTicks); var metrics = context.measureText(round2(this.niceYmin + i * this.ytickSpacing, this.ytickSpacing)); width = metrics.width; } if (width > maxWidth) maxWidth = width; }//new } if (this.isTop) left = maxWidth + 1 * this.majorTickLength + 0.25 * this.majorTickLength; else left = maxWidth + 3 * this.majorTickLength + 0.25 * this.majorTickLength + parseInt(this.axisLabelFont); var width = w - left - right, height = h - top - bottom; width = Math.round(width); height = Math.round(height); this.fWidth = width; this.fHeight = height; this.fTop = top; this.fLeft = left; //------------------------------------------------------------------------------ var Xwidth = this.xmax - this.xmin, Yheight = this.ymax - this.ymin, Xscale = Xwidth / width, Yscale = Yheight / height; this.fXscale = Xscale; this.fYscale = Yscale; //------------------------------------------------------------------------------ if (this.drawGrid) { //vertictal grid lines for (i = 0; this.niceXmin + i * this.xtickSpacing <= this.xmax; i++) { if (this.niceXmin + i * this.xtickSpacing >= this.xmin) { x1 = left + (i * this.xtickSpacing - (this.xmin - this.niceXmin)) / Xscale; drawVerticalDashedLine(x1, top + height, top, 4, context, this.gridColor, this.lineWidth); } } //horizontal grid lines for (i = 0; this.niceYmin + i * this.ytickSpacing <= this.ymax; i++) { if (this.niceYmin + i * this.ytickSpacing >= this.ymin) { y1 = top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale; drawHorizontalDashedLine(left, left + width, y1, 4, context, this.gridColor, this.lineWidth); } } } //------------------------------------------------------------------------------ for (j = 0; j < this.arrayOfData.length; j++) { context.fillStyle = this.arrayOfData[j].color; context.strokeStyle = this.arrayOfData[j].color; for (i = 0; i < this.arrayOfData[j].nPoints; i++) { //draw line if (this.arrayOfData[j].line > 0) { if (i < this.arrayOfData[j].nPoints - 1) { x1 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin) / Yscale; x2 = left + (this.arrayOfData[j].aa[i + 1][0] - this.xmin) / Xscale; y2 = height + top - (this.arrayOfData[j].aa[i + 1][1] - this.ymin) / Yscale; drawLine(x1, y1, x2, y2, context, this.arrayOfData[j].color, this.arrayOfData[j].line); } } //draw symbols if (this.arrayOfData[j].symbol > 0) { //draw plus errors context.strokeStyle = "black"; //if (this.arrayOfData[j].nColumns === 4) if (this.arrayOfData[j].nColumns >= 4) { x1 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin) / Yscale; x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; y2 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin + this.arrayOfData[j].aa[i][2]) / Yscale; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); x1 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale - this.arrayOfData[j].symbolSize; y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin + this.arrayOfData[j].aa[i][2]) / Yscale; x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale + this.arrayOfData[j].symbolSize; y2 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin + this.arrayOfData[j].aa[i][2]) / Yscale; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); //draw minus errors if(isFinite(this.arrayOfData[j].aa[i][3])) { x1 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin) / Yscale; x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; y2 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); x1 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale - this.arrayOfData[j].symbolSize; y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale; x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale + this.arrayOfData[j].symbolSize; y2 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); } else { x1 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin) / Yscale; x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; //y2 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale; y2 = height + top; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); x1 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale - this.arrayOfData[j].symbolSize; //y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale; //y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale - this.arrayOfData[j].symbolSize; //y1 = height + top - 2*this.arrayOfData[j].symbolSize; y1 = height + top - 1.5*this.arrayOfData[j].symbolSize; //x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale + this.arrayOfData[j].symbolSize; x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; //y2 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale; y2 = height + top; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); x1 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale + this.arrayOfData[j].symbolSize; //y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale; //y1 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale - this.arrayOfData[j].symbolSize; //y1 = height + top - 2*this.arrayOfData[j].symbolSize; y1 = height + top - 1.5*this.arrayOfData[j].symbolSize; //x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale + this.arrayOfData[j].symbolSize; x2 = left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale; //y2 = height + top - (this.arrayOfData[j].aa[i][1] - this.ymin - this.arrayOfData[j].aa[i][3]) / Yscale; y2 = height + top; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); } } //draw symbols this.drawSymbol(this.arrayOfData[j].color, "black", this.arrayOfData[j].errorLineWidth, left + (this.arrayOfData[j].aa[i][0] - this.xmin) / Xscale, height + top - (this.arrayOfData[j].aa[i][1] - this.ymin) / Yscale, this.arrayOfData[j].symbolSize, this.arrayOfData[j].symbol); } } } //------------------------------------------------------------------------------ //this ensures lines do not go out of axis limits context.fillStyle = this.bgColor; context.beginPath(); context.fillRect(1, 1, w - 2, top - 1); context.beginPath(); context.fillRect(1, h - bottom + 1, w - 2, bottom - 2); context.beginPath(); context.fillRect(1, 1, left - 2, h - 2); context.beginPath(); context.fillRect(w - right, 1, right - 1, h - 2); context.beginPath();//here!!! context.lineWidth = this.lineWidth; context.rect(0.5, 0.5, w - 1, h - 1); context.stroke(); context.strokeStyle = "black"; context.rect(Math.floor(left) + 0.5, Math.floor(top) + 0.5, width, height); context.stroke(); //------------------------------------------------------------------------------ for (i = 0; this.niceXmin + i * this.xtickSpacing <= this.xmax; i++) { if (this.niceXmin + i * this.xtickSpacing >= this.xmin) { //horizontal bottom major ticks x1 = left + (i * this.xtickSpacing - (this.xmin - this.niceXmin)) / Xscale; y1 = top + height; x2 = x1; y2 = top + height + this.majorTickLength; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); //horizontal top major ticks y1 = top; y2 = top - this.majorTickLength; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); //horizontal bottom major tick labels context.textAlign = "center"; context.textBaseline = "top"; context.font = this.tickLabelFont; context.fillStyle = this.tickLabelColor; //context.fillText(this.niceXmin + i * this.xtickSpacing, x1, top + height + this.majorTickLength); //context.fillText(round1(this.niceXmin + i * this.xtickSpacing), x1, top + height + this.majorTickLength); //context.fillText(round2(this.niceXmin + i * this.xtickSpacing, this.xtickSpacing), x1, top + height + this.majorTickLength); context.fillText(round2(this.niceXmin + i * this.xtickSpacing, this.xtickSpacing / 2.), x1, top + height + this.majorTickLength); } if (this.niceXmin + i * this.xtickSpacing + 0.5 * this.xtickSpacing >= this.xmin && this.niceXmin + i * this.xtickSpacing + 0.5 * this.xtickSpacing <= this.xmax) { //horizontal bottom minor ticks x1 = left + (i * this.xtickSpacing + 0.5 * this.xtickSpacing - (this.xmin - this.niceXmin)) / Xscale; y1 = top + height; x2 = x1; y2 = top + height + this.majorTickLength / 2; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); //horizontal top minor ticks y1 = top; y2 = top - this.majorTickLength / 2; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); } } //------------------------------------------------------------------------------ for (i = 0; this.niceYmin + i * this.ytickSpacing <= this.ymax; i++) { if (this.niceYmin + i * this.ytickSpacing >= this.ymin) { //vertical right major ticks x1 = left + width; y1 = top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale; x2 = left + width + this.majorTickLength; y2 = y1; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); //vertical left major ticks x1 = left; x2 = left - this.majorTickLength; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); //vertical left major tick labels context.textAlign = "right"; context.textBaseline = "middle"; context.font = this.tickLabelFont; context.fillStyle = this.tickLabelColor; if (this.isLogScale) { //------------------------------- context.textAlign = "right"; context.textBaseline = "middle"; context.fillStyle = 'black'; //------------------------------- var str1 = '10'; var metrics1 = context.measureText(str1); var width1 = metrics1.width; //------------------------------- context.textAlign = "left"; context.textBaseline = "middle"; context.fillStyle = 'black'; var fontSize1 = parseInt(context.font); var fontSize2 = Math.round(2 * fontSize1 / 3); var fontSizeDiff = fontSize1 - fontSize2; var strF = context.font.split(' ', 2); context.font = fontSize2.toString() + 'px ' + strF[1]; //------------------------------- //var yy = Math.round(this.ymin + i * Yheight / this.nYTicks); var yy = Math.round(i * this.ytickSpacing + this.niceYmin); var str2 = yy.toString(); var metrics2 = context.measureText(str2); var width2 = metrics2.width; //------------------------------- context.fillText(str2, left - this.majorTickLength - 0.25 * this.majorTickLength - width2, top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale - fontSizeDiff); //------------------------------- context.textAlign = "right"; context.textBaseline = "middle"; context.font = this.tickLabelFont; context.fillStyle = this.tickLabelColor; context.fillText(str1, left - this.majorTickLength - 0.25 * this.majorTickLength - width2, top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale); } else { //context.fillText(this.niceYmin + i * this.ytickSpacing, left - this.majorTickLength - 0.25 * this.majorTickLength, top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale); //context.fillText(round1(this.niceYmin + i * this.ytickSpacing), left - this.majorTickLength - 0.25 * this.majorTickLength, top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale); //context.fillText(round2(this.niceYmin + i * this.ytickSpacing, this.ytickSpacing), left - this.majorTickLength - 0.25 * this.majorTickLength, top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale); context.fillText(round2(this.niceYmin + i * this.ytickSpacing, this.ytickSpacing / 2), left - this.majorTickLength - 0.25 * this.majorTickLength, top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale); } } //minor ticks if (this.isLogScale) { for (j = 2; j < 10; j++) { if (this.niceYmin + i * this.ytickSpacing + this.ytickSpacing * Math.log(j) / ln10 >= this.ymin && this.niceYmin + i * this.ytickSpacing + this.ytickSpacing * Math.log(j) / ln10 <= this.ymax) { //vertical right minor ticks x1 = left + width; y1 = top + height - (i * this.ytickSpacing - (this.ymin - this.niceYmin) + this.ytickSpacing * Math.log(j) / ln10) / Yscale; x2 = left + width + this.majorTickLength / 2; y2 = y1; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); //vertical left minor ticks x1 = left; x2 = left - this.majorTickLength / 2; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); } } } else { if (this.niceYmin + i * this.ytickSpacing + 0.5 * this.ytickSpacing >= this.ymin && this.niceYmin + i * this.ytickSpacing + 0.5 * this.ytickSpacing <= this.ymax) { //vertical right minor ticks x1 = left + width; y1 = top + height - (i * this.ytickSpacing + 0.5 * this.ytickSpacing - (this.ymin - this.niceYmin)) / Yscale; x2 = left + width + this.majorTickLength / 2; y2 = y1; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); //vertical left minor ticks x1 = left; x2 = left - this.majorTickLength / 2; drawLine(x1, y1, x2, y2, context, "black", this.lineWidth); } } } //------------------------------------------------------------------------------ //set Y-axis label if (this.isTop) { context.textAlign = "left"; context.textBaseline = "bottom"; context.font = this.axisLabelFont; context.fillStyle = this.axisLabelColor; context.fillText(this.yAxisLabel, left, top - 2 * this.majorTickLength); } else { context.save(); context.translate(left - 2 * this.majorTickLength - 0.25 * this.majorTickLength - maxWidth, top + 0.5 * height); context.rotate(-Math.PI / 2); context.textAlign = "center"; context.textBaseline = "bottom"; context.font = this.axisLabelFont; context.fillStyle = this.axisLabelColor; context.fillText(this.yAxisLabel, 0, 0); context.restore(); } //------------------------------------------------------------------------------ //set X-axis label context.textAlign = "center"; context.textBaseline = "bottom"; context.font = this.axisLabelFont; context.fillStyle = this.axisLabelColor; context.fillText(this.xAxisLabel, left + 0.5 * width, top + height + bottom - this.majorTickLength); //------------------------------------------------------------------------------ //legend if (this.isRight && this.isLegendVisible) { var nLegengStr = 0; for (j = 0; j < this.arrayOfData.length; j++) { if (this.arrayOfData[j].legendStr.length !== 0) nLegengStr++; } if (nLegengStr > 0) { context.rect(0.5 + left + width - this.legendWidth - 2 * this.majorTickLength, this.isLegendOnTop ? 0.5 + top + this.majorTickLength : 0.5 + top - this.majorTickLength + height - (2 * this.majorTickLength + this.majorTickLength * (nLegengStr - 1) + parseInt(this.tickLabelFont) * (nLegengStr)), this.legendWidth + this.majorTickLength - 0.5, 0.5 + 2 * this.majorTickLength + this.majorTickLength * (nLegengStr - 1) + parseInt(this.tickLabelFont) * (nLegengStr)); context.strokeStyle = 'black'; context.stroke(); context.fillStyle = this.bgColor; context.fill(); var jjj=0; for (j = 0; j < this.arrayOfData.length; j++) { if (this.arrayOfData[j].legendStr.length !== 0) { context.fillStyle = this.arrayOfData[j].color; context.strokeStyle = this.arrayOfData[j].color; //-------------------------------------------- //x1 = left + width + 2 * this.majorTickLength; x1 = left + width - this.legendWidth - this.majorTickLength; //y1 = top + this.majorTickLength + this.majorTickLength * j + parseInt(this.tickLabelFont) * j; this.isLegendOnTop ? y1 = top + 3 * this.majorTickLength + this.majorTickLength * jjj + parseInt(this.tickLabelFont) * jjj : y1 = top + 3 * this.majorTickLength + this.majorTickLength * jjj + parseInt(this.tickLabelFont) * jjj + height - 4 * this.majorTickLength - this.majorTickLength * (nLegengStr - 1) - parseInt(this.tickLabelFont) * (nLegengStr); x2 = x1 + 40; //y2 = top + this.majorTickLength + this.majorTickLength * j + parseInt(this.tickLabelFont) * j; y2 = y1; if (this.arrayOfData[j].line > 0) drawLine(x1, y1, x2, y2, context, this.arrayOfData[j].color, this.arrayOfData[j].line); if (this.arrayOfData[j].symbol > 0) this.drawSymbol(this.arrayOfData[j].color, "black", this.arrayOfData[j].errorLineWidth, x1 + 40 / 2, y2, this.arrayOfData[j].symbolSize, this.arrayOfData[j].symbol); context.textAlign = "left"; context.textBaseline = "middle"; context.font = this.tickLabelFont; context.fillStyle = this.tickLabelColor; context.fillText(this.arrayOfData[j].legendStr, x2 + this.majorTickLength, y2); jjj++; //-------------------------------------------- } } } } //reset limits to enable redraw with different parameters this.areXYNLimitsSet = false; this.areXNLimitsSet = false; this.areYNLimitsSet = false; this.areXYLimitsSet = false; this.areXLimitsSet = false; this.areYLimitsSet = false; if (this.isFirstRun) { this.xMin0 = this.xmin; this.xMax0 = this.xmax; this.yMin0 = this.ymin; this.yMax0 = this.ymax; this.xMinZ = this.xmin; this.xMaxZ = this.xmax; this.yMinZ = this.ymin; this.yMaxZ = this.ymax; this.isFirstRun = false; } }; //------------------------------------------------------------------------------ //set xMin,xMax,yMin,yMax this.setXYNLimits = function (xMinP, xMaxP, nXTicksP, yMinP, yMaxP, nYTicksP) { this.xmin = xMinP; this.xmax = xMaxP; this.ymin = yMinP; this.ymax = yMaxP; this.nXTicks = nXTicksP; this.nYTicks = nYTicksP; this.areXYNLimitsSet = true; this.niceXmin = this.xmin; this.niceXmax = this.xmax; this.xtickSpacing = ((xMaxP - xMinP) / nXTicksP); this.niceYmin = this.ymin; this.niceYmax = this.ymax; if (this.isLogScale === false) this.ytickSpacing = ((yMaxP - yMinP) / nYTicksP); else this.ytickSpacing = 1; }; //------------------------------------------------------------------------------ this.setXNLimits = function (xMinP, xMaxP, nXTicksP) { this.xmin = xMinP; this.xmax = xMaxP; this.nXTicks = nXTicksP; this.areXNLimitsSet = true; this.niceXmin = this.xmin; this.niceXmax = this.xmax; this.xtickSpacing = ((xMaxP - xMinP) / nXTicksP); }; //------------------------------------------------------------------------------ this.setYNLimits = function (yMinP, yMaxP, nYTicksP) { this.ymin = yMinP; this.ymax = yMaxP; this.nYTicks = nYTicksP; this.areYNLimitsSet = true; this.niceYmin = this.ymin; this.niceYmax = this.ymax; if (this.isLogScale === false) this.ytickSpacing = ((yMaxP - yMinP) / nYTicksP); else this.ytickSpacing = 1; }; //------------------------------------------------------------------------------ this.setXYLimits = function (xMinP, xMaxP, yMinP, yMaxP) { this.xmin = xMinP; this.xmax = xMaxP; this.ymin = yMinP; this.ymax = yMaxP; this.areXYLimitsSet = true; /* xmin = xMinP; xmax = xMaxP; ymin = yMinP; ymax = yMaxP; areXYLimitsSet = true; */ }; //------------------------------------------------------------------------------ this.setXLimits = function (xMinP, xMaxP) { this.xmin = xMinP; this.xmax = xMaxP; this.areXLimitsSet = true; }; //------------------------------------------------------------------------------ this.setYLimits = function (yMinP, yMaxP) { this.ymin = yMinP; this.ymax = yMaxP; this.areYLimitsSet = true; }; //------------------------------------------------------------------------------ this.setYmax = function (yMaxP) { this.ymaxSet = yMaxP; this.isYmaxSet = true; }; //------------------------------------------------------------------------------ //add new data this.addData = function (ChartData) { this.arrayOfData.push(ChartData); }; //------------------------------------------------------------------------------ this.deleteAllData = function () { while (this.arrayOfData.length > 0) this.arrayOfData.pop(); }; //------------------------------------------------------------------------------ this.replaceData = function (num, dat) { this.arrayOfData[num] = dat; }; //------------------------------------------------------------------------------ this.getVisibleData = function (sig_p, sig_m, separator, num_digX, isScientificX, num_digY, isScientificY) { sig_p = typeof sig_p !== 'undefined' ? sig_p : true; sig_m = typeof sig_m !== 'undefined' ? sig_m : true; separator = typeof separator !== 'undefined' ? separator : "\t"; num_digX = typeof num_digX !== 'undefined' ? num_digX : 4; isScientificX = typeof isScientificX !== 'undefined' ? isScientificX : false; num_digY = typeof num_digY !== 'undefined' ? num_digY : 4; isScientificY = typeof isScientificY !== 'undefined' ? isScientificY : false; var result = ""; for (j = 0; j < this.arrayOfData.length; j++) { if ((this.arrayOfData[j].line > 0) || (this.arrayOfData[j].symbol > 0)) { if (this.arrayOfData[j].legendStr.length > 0) result += this.arrayOfData[j].legendStr + "\n"; for (i = 0; i < this.arrayOfData[j].nPoints; i++) { if ((this.arrayOfData[j].nColumns < 4) && ((sig_p === true) || (sig_m === true))) { console.log("No errors in data!"); break; } result += formatFloat(this.arrayOfData[j].aaLin[i][0], num_digX, isScientificX) + separator + formatFloat(this.arrayOfData[j].aaLin[i][1], num_digY, isScientificY); if ((sig_p === true) || (sig_m === true)) result += separator; else { result += "\n"; continue; } if (sig_p === true) result += formatFloat(this.arrayOfData[j].aaLin[i][2], num_digY, isScientificY); if (sig_m === true) result += separator; else { result += "\n"; continue; } result += formatFloat(this.arrayOfData[j].aaLin[i][3], num_digY, isScientificY) + "\n"; } } } return result; }; //------------------------------------------------------------------------------ // this.getAllData = function (sig_p, sig_m, separator, num_dig, isScientific) this.getAllData = function (sig_p, sig_m, separator, num_digX, isScientificX, num_digY, isScientificY) { sig_p = typeof sig_p !== 'undefined' ? sig_p : true; sig_m = typeof sig_m !== 'undefined' ? sig_m : true; separator = typeof separator !== 'undefined' ? separator : "\t"; num_digX = typeof num_digX !== 'undefined' ? num_digX : 4; isScientificX = typeof isScientificX !== 'undefined' ? isScientificX : false; num_digY = typeof num_digY !== 'undefined' ? num_digY : 4; isScientificY = typeof isScientificY !== 'undefined' ? isScientificY : false; var result = ""; for (j = 0; j < this.arrayOfData.length; j++) { //if ( (this.arrayOfData[j].line > 0) || (this.arrayOfData[j].symbol > 0 ) ) { if (this.arrayOfData[j].legendStr.length > 0) result += this.arrayOfData[j].legendStr + "\n"; for (i = 0; i < this.arrayOfData[j].nPoints; i++) { if ((this.arrayOfData[j].nColumns < 4) && ((sig_p === true) || (sig_m === true))) { console.log("No errors in data!"); break; } result += formatFloat(1.0*this.arrayOfData[j].aaLin[i][0], num_digX, isScientificX) + separator + formatFloat(1.0*this.arrayOfData[j].aaLin[i][1], num_digY, isScientificY); /* result += 1.0*this.arrayOfData[j].aaLin[i][0] + separator + 1.0*this.arrayOfData[j].aaLin[i][1]; */ if ((sig_p === true) || (sig_m === true)) result += separator; else { result += "\n"; continue; } if (sig_p === true) result += formatFloat(1.0*this.arrayOfData[j].aaLin[i][2], num_digY, isScientificY); // result += 1.0*this.arrayOfData[j].aaLin[i][2]; if (sig_m === true) result += separator; else { result += "\n"; continue; } //result += formatFloat(1.0*this.arrayOfData[j].aaLin[i][3], num_digY, isScientificY) + "\n"; result += formatFloat(1.0*this.arrayOfData[j].aaLin[i][3], num_digY, isScientificY); //result += 1.0*this.arrayOfData[j].aaLin[i][3]; if(this.arrayOfData[j].nColumns > 4) { result += separator; result += this.arrayOfData[j].aaLin[i][4]; //result += this.arrayOfData[j].aa[i][4]; } result += "\n"; } } } return result; }; //------------------------------------------------------------------------------ this.getSingleData = function (j, sig_p, sig_m, separator, num_digX, isScientificX, num_digY, isScientificY) { j = typeof j !== 'undefined' ? j : 4; sig_p = typeof sig_p !== 'undefined' ? sig_p : true; sig_m = typeof sig_m !== 'undefined' ? sig_m : true; separator = typeof separator !== 'undefined' ? separator : "\t"; num_digX = typeof num_digX !== 'undefined' ? num_digX : 4; isScientificX = typeof isScientificX !== 'undefined' ? isScientificX : false; num_digY = typeof num_digY !== 'undefined' ? num_digY : 4; isScientificY = typeof isScientificY !== 'undefined' ? isScientificY : false; var result = ""; //for (j = 0; j < this.arrayOfData.length; j++) { //if ( (this.arrayOfData[j].line > 0) || (this.arrayOfData[j].symbol > 0 ) ) { if (this.arrayOfData[j].legendStr.length > 0) result += this.arrayOfData[j].legendStr + "\n"; for (i = 0; i < this.arrayOfData[j].nPoints; i++) { if ((this.arrayOfData[j].nColumns < 4) && ((sig_p === true) || (sig_m === true))) { console.log("No errors in data!"); break; } result += formatFloat(this.arrayOfData[j].aaLin[i][0], num_digX, isScientificX) + separator + formatFloat(this.arrayOfData[j].aaLin[i][1], num_digY, isScientificY); if ((sig_p === true) || (sig_m === true)) result += separator; else { result += "\n"; continue; } if (sig_p === true) result += formatFloat(this.arrayOfData[j].aaLin[i][2], num_digY, isScientificY); if (sig_m === true) result += separator; else { result += "\n"; continue; } result += formatFloat(this.arrayOfData[j].aaLin[i][3], num_digY, isScientificY) + "\n"; } } } return result; }; //------------------------------------------------------------------------------ //set canvas this.setCanvas = function (canvasName) { this.canvas = document.getElementById(canvasName); }; //------------------------------------------------------------------------------ }; //------------------------------------------------------------------------------