From: etimberg Date: Fri, 14 Oct 2016 00:43:11 +0000 (-0400) Subject: Bar chart performance improvements X-Git-Tag: v2.4.0~1^2~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3365ba6d29e579e99db61dd65390e39536a0800d;p=thirdparty%2FChart.js.git Bar chart performance improvements --- diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index f828eb79e..e9a85aabd 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -69,31 +69,29 @@ module.exports = function(Chart) { var custom = rectangle.custom || {}; var dataset = me.getDataset(); - helpers.extend(rectangle, { - // Utility - _xScale: xScale, - _yScale: yScale, - _datasetIndex: me.index, - _index: index, - - // Desired view properties - _model: { - x: me.calculateBarX(index, me.index), - y: reset ? scaleBase : me.calculateBarY(index, me.index), - - // Tooltip - label: me.chart.data.labels[index], - datasetLabel: dataset.label, - - // Appearance - base: reset ? scaleBase : me.calculateBarBase(me.index, index), - width: me.calculateBarWidth(index), - backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), - borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped, - borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), - borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) - } - }); + rectangle._xScale = xScale; + rectangle._yScale = yScale; + rectangle._datasetIndex = me.index; + rectangle._index = index; + + var ruler = me.getRuler(index); + rectangle._model = { + x: me.calculateBarX(index, me.index, ruler), + y: reset ? scaleBase : me.calculateBarY(index, me.index), + + // Tooltip + label: me.chart.data.labels[index], + datasetLabel: dataset.label, + + // Appearance + base: reset ? scaleBase : me.calculateBarBase(me.index, index), + width: me.calculateBarWidth(ruler), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), + borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped, + borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), + borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) + }; + rectangle.pivot(); }, @@ -160,12 +158,11 @@ module.exports = function(Chart) { }; }, - calculateBarWidth: function(index) { + calculateBarWidth: function(ruler) { var xScale = this.getScaleForId(this.getMeta().xAxisID); if (xScale.options.barThickness) { return xScale.options.barThickness; } - var ruler = this.getRuler(index); return xScale.options.stacked ? ruler.categoryWidth : ruler.barWidth; }, @@ -184,13 +181,11 @@ module.exports = function(Chart) { return barIndex; }, - calculateBarX: function(index, datasetIndex) { + calculateBarX: function(index, datasetIndex, ruler) { var me = this; var meta = me.getMeta(); var xScale = me.getScaleForId(meta.xAxisID); var barIndex = me.getBarIndex(datasetIndex); - - var ruler = me.getRuler(index); var leftTick = xScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo); leftTick -= me.chart.isCombo ? (ruler.tickWidth / 2) : 0; @@ -242,12 +237,16 @@ module.exports = function(Chart) { draw: function(ease) { var me = this; var easingDecimal = ease || 1; - helpers.each(me.getMeta().data, function(rectangle, index) { - var d = me.getDataset().data[index]; + var metaData = me.getMeta().data; + var dataset = me.getDataset(); + var i, len; + + for (i = 0, len = metaData.length; i < len; ++i) { + var d = dataset.data[i]; if (d !== null && d !== undefined && !isNaN(d)) { - rectangle.transition(easingDecimal).draw(); + metaData[i].transition(easingDecimal).draw(); } - }, me); + } }, setHoverStyle: function(rectangle) { @@ -342,88 +341,84 @@ module.exports = function(Chart) { var dataset = me.getDataset(); var rectangleElementOptions = me.chart.options.elements.rectangle; - helpers.extend(rectangle, { - // Utility - _xScale: xScale, - _yScale: yScale, - _datasetIndex: me.index, - _index: index, - - // Desired view properties - _model: { - x: reset ? scaleBase : me.calculateBarX(index, me.index), - y: me.calculateBarY(index, me.index), - - // Tooltip - label: me.chart.data.labels[index], - datasetLabel: dataset.label, - - // Appearance - base: reset ? scaleBase : me.calculateBarBase(me.index, index), - height: me.calculateBarHeight(index), - backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), - borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped, - borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), - borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) - }, + rectangle._xScale = xScale; + rectangle._yScale = yScale; + rectangle._datasetIndex = me.index; + rectangle._index = index; - draw: function() { - var ctx = this._chart.ctx; - var vm = this._view; - - var halfHeight = vm.height / 2, - topY = vm.y - halfHeight, - bottomY = vm.y + halfHeight, - right = vm.base - (vm.base - vm.x), - halfStroke = vm.borderWidth / 2; - - // Canvas doesn't allow us to stroke inside the width so we can - // adjust the sizes to fit if we're setting a stroke on the line - if (vm.borderWidth) { - topY += halfStroke; - bottomY -= halfStroke; - right += halfStroke; - } + var ruler = me.getRuler(index); + rectangle._model = { + x: reset ? scaleBase : me.calculateBarX(index, me.index), + y: me.calculateBarY(index, me.index, ruler), + + // Tooltip + label: me.chart.data.labels[index], + datasetLabel: dataset.label, + + // Appearance + base: reset ? scaleBase : me.calculateBarBase(me.index, index), + height: me.calculateBarHeight(ruler), + backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor), + borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped, + borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor), + borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth) + }; + rectangle.draw = function() { + var ctx = this._chart.ctx; + var vm = this._view; + + var halfHeight = vm.height / 2, + topY = vm.y - halfHeight, + bottomY = vm.y + halfHeight, + right = vm.base - (vm.base - vm.x), + halfStroke = vm.borderWidth / 2; + + // Canvas doesn't allow us to stroke inside the width so we can + // adjust the sizes to fit if we're setting a stroke on the line + if (vm.borderWidth) { + topY += halfStroke; + bottomY -= halfStroke; + right += halfStroke; + } - ctx.beginPath(); - - ctx.fillStyle = vm.backgroundColor; - ctx.strokeStyle = vm.borderColor; - ctx.lineWidth = vm.borderWidth; - - // Corner points, from bottom-left to bottom-right clockwise - // | 1 2 | - // | 0 3 | - var corners = [ - [vm.base, bottomY], - [vm.base, topY], - [right, topY], - [right, bottomY] - ]; - - // Find first (starting) corner with fallback to 'bottom' - var borders = ['bottom', 'left', 'top', 'right']; - var startCorner = borders.indexOf(vm.borderSkipped, 0); - if (startCorner === -1) { - startCorner = 0; - } + ctx.beginPath(); + + ctx.fillStyle = vm.backgroundColor; + ctx.strokeStyle = vm.borderColor; + ctx.lineWidth = vm.borderWidth; + + // Corner points, from bottom-left to bottom-right clockwise + // | 1 2 | + // | 0 3 | + var corners = [ + [vm.base, bottomY], + [vm.base, topY], + [right, topY], + [right, bottomY] + ]; + + // Find first (starting) corner with fallback to 'bottom' + var borders = ['bottom', 'left', 'top', 'right']; + var startCorner = borders.indexOf(vm.borderSkipped, 0); + if (startCorner === -1) { + startCorner = 0; + } - function cornerAt(cornerIndex) { - return corners[(startCorner + cornerIndex) % 4]; - } + function cornerAt(cornerIndex) { + return corners[(startCorner + cornerIndex) % 4]; + } - // Draw rectangle from 'startCorner' - ctx.moveTo.apply(ctx, cornerAt(0)); - for (var i = 1; i < 4; i++) { - ctx.lineTo.apply(ctx, cornerAt(i)); - } + // Draw rectangle from 'startCorner' + ctx.moveTo.apply(ctx, cornerAt(0)); + for (var i = 1; i < 4; i++) { + ctx.lineTo.apply(ctx, cornerAt(i)); + } - ctx.fill(); - if (vm.borderWidth) { - ctx.stroke(); - } + ctx.fill(); + if (vm.borderWidth) { + ctx.stroke(); } - }); + }; rectangle.pivot(); }, @@ -490,13 +485,12 @@ module.exports = function(Chart) { }; }, - calculateBarHeight: function(index) { + calculateBarHeight: function(ruler) { var me = this; var yScale = me.getScaleForId(me.getMeta().yAxisID); if (yScale.options.barThickness) { return yScale.options.barThickness; } - var ruler = me.getRuler(index); return yScale.options.stacked ? ruler.categoryHeight : ruler.barHeight; }, @@ -533,13 +527,11 @@ module.exports = function(Chart) { return xScale.getPixelForValue(value); }, - calculateBarY: function(index, datasetIndex) { + calculateBarY: function(index, datasetIndex, ruler) { var me = this; var meta = me.getMeta(); var yScale = me.getScaleForId(meta.yAxisID); var barIndex = me.getBarIndex(datasetIndex); - - var ruler = me.getRuler(index); var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo); topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0; diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index 2faff1b6e..2e218dfe9 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -210,9 +210,11 @@ module.exports = function(Chart) { draw: function(ease) { var easingDecimal = ease || 1; - helpers.each(this.getMeta().data, function(element) { - element.transition(easingDecimal).draw(); - }); + var i, len; + var metaData = this.getMeta().data; + for (i = 0, len = metaData.length; i < len; ++i) { + metaData[i].transition(easingDecimal).draw(); + } }, removeHoverStyle: function(element, elementOpts) { diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 890e04c42..e2d5f56bc 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -167,13 +167,8 @@ module.exports = function(Chart) { convertTicksToLabels: function() { var me = this; // Convert ticks to strings - me.ticks = me.ticks.map(function(numericalTick, index, ticks) { - if (me.options.ticks.userCallback) { - return me.options.ticks.userCallback(numericalTick, index, ticks); - } - return me.options.ticks.callback(numericalTick, index, ticks); - }, - me); + var tickOpts = me.options.ticks; + me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback); }, afterTickToLabelConversion: function() { helpers.callCallback(this.options.afterTickToLabelConversion, [this]); diff --git a/src/elements/element.rectangle.js b/src/elements/element.rectangle.js index 3f4ea10f9..427916791 100644 --- a/src/elements/element.rectangle.js +++ b/src/elements/element.rectangle.js @@ -95,9 +95,12 @@ module.exports = function(Chart) { } // Draw rectangle from 'startCorner' - ctx.moveTo.apply(ctx, cornerAt(0)); + var corner = cornerAt(0); + ctx.moveTo(corner[0], corner[1]); + for (var i = 1; i < 4; i++) { - ctx.lineTo.apply(ctx, cornerAt(i)); + corner = cornerAt(i); + ctx.lineTo(corner[0], corner[1]); } ctx.fill();