From a102a271b9f78593a6b62b92c3976c0dec26f83e Mon Sep 17 00:00:00 2001 From: Adam Butler Date: Tue, 16 Dec 2014 21:06:00 +0000 Subject: [PATCH] Update to 1.0.1-beta.4 --- lib/chart-js-rails/version.rb | 2 +- vendor/assets/javascripts/Chart.js | 319 ++++++++++++++++++----------- 2 files changed, 198 insertions(+), 123 deletions(-) diff --git a/lib/chart-js-rails/version.rb b/lib/chart-js-rails/version.rb index c409946..9503fc6 100644 --- a/lib/chart-js-rails/version.rb +++ b/lib/chart-js-rails/version.rb @@ -1,5 +1,5 @@ module ChartJs module Rails - VERSION = "0.0.7" + VERSION = "1.0.1-beta.4" end end diff --git a/vendor/assets/javascripts/Chart.js b/vendor/assets/javascripts/Chart.js index 15b53b7..6a9492e 100644 --- a/vendor/assets/javascripts/Chart.js +++ b/vendor/assets/javascripts/Chart.js @@ -1,6 +1,7 @@ /*! * Chart.js * http://chartjs.org/ + * Version: 1.0.1-beta.4 * * Copyright 2014 Nick Downie * Released under the MIT license @@ -91,6 +92,9 @@ // Boolean - whether or not the chart should be responsive and resize when the browser does. responsive: false, + // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container + maintainAspectRatio: true, + // Boolean - Determines whether to draw tooltips on the canvas or not - attaches events to touchmove & mousemove showTooltips: true, @@ -213,6 +217,41 @@ return -1; } }, + where = helpers.where = function(collection, filterCallback){ + var filtered = []; + + helpers.each(collection, function(item){ + if (filterCallback(item)){ + filtered.push(item); + } + }); + + return filtered; + }, + findNextWhere = helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex){ + // Default to start of the array + if (!startIndex){ + startIndex = -1; + } + for (var i = startIndex + 1; i < arrayToSearch.length; i++) { + var currentItem = arrayToSearch[i]; + if (filterCallback(currentItem)){ + return currentItem; + } + }; + }, + findPreviousWhere = helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex){ + // Default to end of the array + if (!startIndex){ + startIndex = arrayToSearch.length; + } + for (var i = startIndex - 1; i >= 0; i--) { + var currentItem = arrayToSearch[i]; + if (filterCallback(currentItem)){ + return currentItem; + } + }; + }, inherits = helpers.inherits = function(extensions){ //Basic javascript inheritance based on the model created in Backbone.js var parent = this; @@ -241,7 +280,7 @@ //Method for warning of errors if (window.console && typeof window.console.warn == "function") console.warn(str); }, - amd = helpers.amd = (typeof root.define == 'function' && root.define.amd), + amd = helpers.amd = (typeof define == 'function' && define.amd), //-- Math methods isNumber = helpers.isNumber = function(n){ return !isNaN(parseFloat(n)) && isFinite(n); @@ -402,6 +441,11 @@ //Templating methods //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/ template = helpers.template = function(templateString, valuesObject){ + // If templateString is function rather than string-template - call the function for valuesObject + if(templateString instanceof Function){ + return templateString(valuesObject); + } + var cache = {}; function tmpl(str, data){ // Figure out if we're getting a template, or if we need to @@ -693,16 +737,22 @@ removeEvent(chartInstance.chart.canvas, eventName, handler); }); }, - getMaximumSize = helpers.getMaximumSize = function(domNode){ + getMaximumWidth = helpers.getMaximumWidth = function(domNode){ var container = domNode.parentNode; // TODO = check cross browser stuff with this. return container.clientWidth; }, + getMaximumHeight = helpers.getMaximumHeight = function(domNode){ + var container = domNode.parentNode; + // TODO = check cross browser stuff with this. + return container.clientHeight; + }, + getMaximumSize = helpers.getMaximumSize = helpers.getMaximumWidth, // legacy support retinaScale = helpers.retinaScale = function(chart){ var ctx = chart.ctx, width = chart.canvas.width, height = chart.canvas.height; - //console.log(width + " x " + height); + if (window.devicePixelRatio) { ctx.canvas.style.width = width + "px"; ctx.canvas.style.height = height + "px"; @@ -776,8 +826,8 @@ resize : function(callback){ this.stop(); var canvas = this.chart.canvas, - newWidth = getMaximumSize(this.chart.canvas), - newHeight = newWidth / this.chart.aspectRatio; + newWidth = getMaximumWidth(this.chart.canvas), + newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : getMaximumHeight(this.chart.canvas); canvas.width = this.chart.width = newWidth; canvas.height = this.chart.height = newHeight; @@ -873,7 +923,7 @@ yMin; helpers.each(this.datasets, function(dataset){ dataCollection = dataset.points || dataset.bars || dataset.segments; - if (dataCollection[dataIndex]){ + if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){ Elements.push(dataCollection[dataIndex]); } }); @@ -1037,6 +1087,9 @@ x : this.x, y : this.y }; + }, + hasValue: function(){ + return isNumber(this.value); } }); @@ -1083,6 +1136,7 @@ // ctx.fill(); // ctx.moveTo(this.controlPoints.inner.x,this.controlPoints.inner.y); + // ctx.lineTo(this.x, this.y); // ctx.lineTo(this.controlPoints.outer.x,this.controlPoints.outer.y); // ctx.stroke(); @@ -1887,6 +1941,7 @@ }; }).call(this); + (function(){ "use strict"; @@ -1993,18 +2048,16 @@ this.datasets.push(datasetObject); helpers.each(dataset.data,function(dataPoint,index){ - if (helpers.isNumber(dataPoint)){ - //Add a new point for each piece of data, passing any required data to draw. - datasetObject.bars.push(new this.BarClass({ - value : dataPoint, - label : data.labels[index], - datasetLabel: dataset.label, - strokeColor : dataset.strokeColor, - fillColor : dataset.fillColor, - highlightFill : dataset.highlightFill || dataset.fillColor, - highlightStroke : dataset.highlightStroke || dataset.strokeColor - })); - } + //Add a new point for each piece of data, passing any required data to draw. + datasetObject.bars.push(new this.BarClass({ + value : dataPoint, + label : data.labels[index], + datasetLabel: dataset.label, + strokeColor : dataset.strokeColor, + fillColor : dataset.fillColor, + highlightFill : dataset.highlightFill || dataset.fillColor, + highlightStroke : dataset.highlightStroke || dataset.strokeColor + })); },this); },this); @@ -2119,19 +2172,17 @@ addData : function(valuesArray,label){ //Map the values array for each of the datasets helpers.each(valuesArray,function(value,datasetIndex){ - if (helpers.isNumber(value)){ - //Add a new point for each piece of data, passing any required data to draw. - this.datasets[datasetIndex].bars.push(new this.BarClass({ - value : value, - label : label, - x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1), - y: this.scale.endPoint, - width : this.scale.calculateBarWidth(this.datasets.length), - base : this.scale.endPoint, - strokeColor : this.datasets[datasetIndex].strokeColor, - fillColor : this.datasets[datasetIndex].fillColor - })); - } + //Add a new point for each piece of data, passing any required data to draw. + this.datasets[datasetIndex].bars.push(new this.BarClass({ + value : value, + label : label, + x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1), + y: this.scale.endPoint, + width : this.scale.calculateBarWidth(this.datasets.length), + base : this.scale.endPoint, + strokeColor : this.datasets[datasetIndex].strokeColor, + fillColor : this.datasets[datasetIndex].fillColor + })); },this); this.scale.addXLabel(label); @@ -2168,13 +2219,15 @@ //Draw all the bars for each dataset helpers.each(this.datasets,function(dataset,datasetIndex){ helpers.each(dataset.bars,function(bar,index){ - bar.base = this.scale.endPoint; - //Transition then draw - bar.transition({ - x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index), - y : this.scale.calculateY(bar.value), - width : this.scale.calculateBarWidth(this.datasets.length) - }, easingDecimal).draw(); + if (bar.hasValue()){ + bar.base = this.scale.endPoint; + //Transition then draw + bar.transition({ + x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index), + y : this.scale.calculateY(bar.value), + width : this.scale.calculateBarWidth(this.datasets.length) + }, easingDecimal).draw(); + } },this); },this); @@ -2467,19 +2520,16 @@ helpers.each(dataset.data,function(dataPoint,index){ - //Best way to do this? or in draw sequence...? - if (helpers.isNumber(dataPoint)){ //Add a new point for each piece of data, passing any required data to draw. - datasetObject.points.push(new this.PointClass({ - value : dataPoint, - label : data.labels[index], - datasetLabel: dataset.label, - strokeColor : dataset.pointStrokeColor, - fillColor : dataset.pointColor, - highlightFill : dataset.pointHighlightFill || dataset.pointColor, - highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor - })); - } + datasetObject.points.push(new this.PointClass({ + value : dataPoint, + label : data.labels[index], + datasetLabel: dataset.label, + strokeColor : dataset.pointStrokeColor, + fillColor : dataset.pointColor, + highlightFill : dataset.pointHighlightFill || dataset.pointColor, + highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor + })); },this); this.buildScale(data.labels); @@ -2586,17 +2636,15 @@ //Map the values array for each of the datasets helpers.each(valuesArray,function(value,datasetIndex){ - if (helpers.isNumber(value)){ - //Add a new point for each piece of data, passing any required data to draw. - this.datasets[datasetIndex].points.push(new this.PointClass({ - value : value, - label : label, - x: this.scale.calculateX(this.scale.valuesCount+1), - y: this.scale.endPoint, - strokeColor : this.datasets[datasetIndex].pointStrokeColor, - fillColor : this.datasets[datasetIndex].pointColor - })); - } + //Add a new point for each piece of data, passing any required data to draw. + this.datasets[datasetIndex].points.push(new this.PointClass({ + value : value, + label : label, + x: this.scale.calculateX(this.scale.valuesCount+1), + y: this.scale.endPoint, + strokeColor : this.datasets[datasetIndex].pointStrokeColor, + fillColor : this.datasets[datasetIndex].pointColor + })); },this); this.scale.addXLabel(label); @@ -2624,37 +2672,64 @@ var ctx = this.chart.ctx; + // Some helper methods for getting the next/prev points + var hasValue = function(item){ + return item.value !== null; + }, + nextPoint = function(point, collection, index){ + return helpers.findNextWhere(collection, hasValue, index) || point; + }, + previousPoint = function(point, collection, index){ + return helpers.findPreviousWhere(collection, hasValue, index) || point; + }; + this.scale.draw(easingDecimal); helpers.each(this.datasets,function(dataset){ + var pointsWithValues = helpers.where(dataset.points, hasValue); //Transition each point first so that the line and point drawing isn't out of sync //We can use this extra loop to calculate the control points of this dataset also in this loop - helpers.each(dataset.points,function(point,index){ - point.transition({ - y : this.scale.calculateY(point.value), - x : this.scale.calculateX(index) - }, easingDecimal); - + helpers.each(dataset.points, function(point, index){ + if (point.hasValue()){ + point.transition({ + y : this.scale.calculateY(point.value), + x : this.scale.calculateX(index) + }, easingDecimal); + } },this); // Control points need to be calculated in a seperate loop, because we need to know the current x/y of the point // This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed if (this.options.bezierCurve){ - helpers.each(dataset.points,function(point,index){ - //If we're at the start or end, we don't have a previous/next point - //By setting the tension to 0 here, the curve will transition to straight at the end - if (index === 0){ - point.controlPoints = helpers.splineCurve(point,point,dataset.points[index+1],0); + helpers.each(pointsWithValues, function(point, index){ + var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0; + point.controlPoints = helpers.splineCurve( + previousPoint(point, pointsWithValues, index), + point, + nextPoint(point, pointsWithValues, index), + tension + ); + + // Prevent the bezier going outside of the bounds of the graph + + // Cap puter bezier handles to the upper/lower scale bounds + if (point.controlPoints.outer.y > this.scale.endPoint){ + point.controlPoints.outer.y = this.scale.endPoint; } - else if (index >= dataset.points.length-1){ - point.controlPoints = helpers.splineCurve(dataset.points[index-1],point,point,0); + else if (point.controlPoints.outer.y < this.scale.startPoint){ + point.controlPoints.outer.y = this.scale.startPoint; } - else{ - point.controlPoints = helpers.splineCurve(dataset.points[index-1],point,dataset.points[index+1],this.options.bezierCurveTension); + + // Cap inner bezier handles to the upper/lower scale bounds + if (point.controlPoints.inner.y > this.scale.endPoint){ + point.controlPoints.inner.y = this.scale.endPoint; + } + else if (point.controlPoints.inner.y < this.scale.startPoint){ + point.controlPoints.inner.y = this.scale.startPoint; } },this); } @@ -2664,12 +2739,18 @@ ctx.lineWidth = this.options.datasetStrokeWidth; ctx.strokeStyle = dataset.strokeColor; ctx.beginPath(); - helpers.each(dataset.points,function(point,index){ - if (index>0){ + + helpers.each(pointsWithValues, function(point, index){ + if (index === 0){ + ctx.moveTo(point.x, point.y); + } + else{ if(this.options.bezierCurve){ + var previous = previousPoint(point, pointsWithValues, index); + ctx.bezierCurveTo( - dataset.points[index-1].controlPoints.outer.x, - dataset.points[index-1].controlPoints.outer.y, + previous.controlPoints.outer.x, + previous.controlPoints.outer.y, point.controlPoints.inner.x, point.controlPoints.inner.y, point.x, @@ -2679,19 +2760,15 @@ else{ ctx.lineTo(point.x,point.y); } - } - else{ - ctx.moveTo(point.x,point.y); - } - },this); - ctx.stroke(); + }, this); + ctx.stroke(); - if (this.options.datasetFill){ + if (this.options.datasetFill && pointsWithValues.length > 0){ //Round off the line by going to the base of the chart, back to the start, then fill. - ctx.lineTo(dataset.points[dataset.points.length-1].x, this.scale.endPoint); - ctx.lineTo(this.scale.calculateX(0), this.scale.endPoint); + ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint); + ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint); ctx.fillStyle = dataset.fillColor; ctx.closePath(); ctx.fill(); @@ -2700,10 +2777,9 @@ //Now draw the points over the line //A little inefficient double looping, but better than the line //lagging behind the point positions - helpers.each(dataset.points,function(point){ + helpers.each(pointsWithValues,function(point){ point.draw(); }); - },this); } }); @@ -3071,25 +3147,22 @@ this.datasets.push(datasetObject); helpers.each(dataset.data,function(dataPoint,index){ - //Best way to do this? or in draw sequence...? - if (helpers.isNumber(dataPoint)){ //Add a new point for each piece of data, passing any required data to draw. - var pointPosition; - if (!this.scale.animation){ - pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint)); - } - datasetObject.points.push(new this.PointClass({ - value : dataPoint, - label : data.labels[index], - datasetLabel: dataset.label, - x: (this.options.animation) ? this.scale.xCenter : pointPosition.x, - y: (this.options.animation) ? this.scale.yCenter : pointPosition.y, - strokeColor : dataset.pointStrokeColor, - fillColor : dataset.pointColor, - highlightFill : dataset.pointHighlightFill || dataset.pointColor, - highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor - })); + var pointPosition; + if (!this.scale.animation){ + pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint)); } + datasetObject.points.push(new this.PointClass({ + value : dataPoint, + label : data.labels[index], + datasetLabel: dataset.label, + x: (this.options.animation) ? this.scale.xCenter : pointPosition.x, + y: (this.options.animation) ? this.scale.yCenter : pointPosition.y, + strokeColor : dataset.pointStrokeColor, + fillColor : dataset.pointColor, + highlightFill : dataset.pointHighlightFill || dataset.pointColor, + highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor + })); },this); },this); @@ -3204,17 +3277,15 @@ //Map the values array for each of the datasets this.scale.valuesCount++; helpers.each(valuesArray,function(value,datasetIndex){ - if (helpers.isNumber(value)){ - var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value)); - this.datasets[datasetIndex].points.push(new this.PointClass({ - value : value, - label : label, - x: pointPosition.x, - y: pointPosition.y, - strokeColor : this.datasets[datasetIndex].pointStrokeColor, - fillColor : this.datasets[datasetIndex].pointColor - })); - } + var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value)); + this.datasets[datasetIndex].points.push(new this.PointClass({ + value : value, + label : label, + x: pointPosition.x, + y: pointPosition.y, + strokeColor : this.datasets[datasetIndex].pointStrokeColor, + fillColor : this.datasets[datasetIndex].pointColor + })); },this); this.scale.labels.push(label); @@ -3261,7 +3332,9 @@ //Transition each point first so that the line and point drawing isn't out of sync helpers.each(dataset.points,function(point,index){ - point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal); + if (point.hasValue()){ + point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal); + } },this); @@ -3288,7 +3361,9 @@ //A little inefficient double looping, but better than the line //lagging behind the point positions helpers.each(dataset.points,function(point){ - point.draw(); + if (point.hasValue()){ + point.draw(); + } }); },this); @@ -3301,4 +3376,4 @@ -}).call(this); \ No newline at end of file +}).call(this);