From 09bcac9b5c699c75909b77dc40dc40b5a3af1030 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Thu, 5 May 2016 20:00:11 -0400 Subject: [PATCH 01/12] Reduce element.point size --- src/elements/element.point.js | 90 +++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/src/elements/element.point.js b/src/elements/element.point.js index 93f59be1fd7..c92c0ad48cc 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -61,80 +61,86 @@ module.exports = function(Chart) { var radius = vm.radius; var xOffset, - yOffset; + yOffset, + beginPath = "beginPath", + moveTo = "moveTo", + lineTo = "lineTo", + closePath = "closePath", + fillRect = "fillRect", + strokeRect = "strokeRect"; switch (pointStyle) { // Default includes circle default: - ctx.beginPath(); + ctx[beginPath](); ctx.arc(x, y, radius, 0, Math.PI * 2); - ctx.closePath(); + ctx[closePath](); ctx.fill(); break; case 'triangle': - ctx.beginPath(); + ctx[beginPath](); var edgeLength = 3 * radius / Math.sqrt(3); var height = edgeLength * Math.sqrt(3) / 2; - ctx.moveTo(x - edgeLength / 2, y + height / 3); - ctx.lineTo(x + edgeLength / 2, y + height / 3); - ctx.lineTo(x, y - 2 * height / 3); - ctx.closePath(); + ctx[moveTo](x - edgeLength / 2, y + height / 3); + ctx[lineTo](x + edgeLength / 2, y + height / 3); + ctx[lineTo](x, y - 2 * height / 3); + ctx[closePath](); ctx.fill(); break; case 'rect': - ctx.fillRect(x - 1 / Math.SQRT2 * radius, y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); - ctx.strokeRect(x - 1 / Math.SQRT2 * radius, y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx[fillRect](x - 1 / Math.SQRT2 * radius, y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx[strokeRect](x - 1 / Math.SQRT2 * radius, y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); break; case 'rectRot': ctx.translate(x, y); ctx.rotate(Math.PI / 4); - ctx.fillRect(-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); - ctx.strokeRect(-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx[fillRect](-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx[strokeRect](-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); ctx.setTransform(1, 0, 0, 1, 0, 0); break; case 'cross': - ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y - radius); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); + ctx[beginPath](); + ctx[moveTo](x, y + radius); + ctx[lineTo](x, y - radius); + ctx[moveTo](x - radius, y); + ctx[lineTo](x + radius, y); + ctx[closePath](); break; case 'crossRot': - ctx.beginPath(); + ctx[beginPath](); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x - xOffset, y + yOffset); - ctx.lineTo(x + xOffset, y - yOffset); - ctx.closePath(); + ctx[moveTo](x - xOffset, y - yOffset); + ctx[lineTo](x + xOffset, y + yOffset); + ctx[moveTo](x - xOffset, y + yOffset); + ctx[lineTo](x + xOffset, y - yOffset); + ctx[closePath](); break; case 'star': - ctx.beginPath(); - ctx.moveTo(x, y + radius); - ctx.lineTo(x, y - radius); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); + ctx[beginPath](); + ctx[moveTo](x, y + radius); + ctx[lineTo](x, y - radius); + ctx[moveTo](x - radius, y); + ctx[lineTo](x + radius, y); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; - ctx.moveTo(x - xOffset, y - yOffset); - ctx.lineTo(x + xOffset, y + yOffset); - ctx.moveTo(x - xOffset, y + yOffset); - ctx.lineTo(x + xOffset, y - yOffset); - ctx.closePath(); + ctx[moveTo](x - xOffset, y - yOffset); + ctx[lineTo](x + xOffset, y + yOffset); + ctx[moveTo](x - xOffset, y + yOffset); + ctx[lineTo](x + xOffset, y - yOffset); + ctx[closePath](); break; case 'line': - ctx.beginPath(); - ctx.moveTo(x - radius, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); + ctx[beginPath](); + ctx[moveTo](x - radius, y); + ctx[lineTo](x + radius, y); + ctx[closePath](); break; case 'dash': - ctx.beginPath(); - ctx.moveTo(x, y); - ctx.lineTo(x + radius, y); - ctx.closePath(); + ctx[beginPath](); + ctx[moveTo](x, y); + ctx[lineTo](x + radius, y); + ctx[closePath](); break; } From 655163a7f5167306e4cc686f4afd2d6e06b7480e Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Thu, 5 May 2016 20:47:33 -0400 Subject: [PATCH 02/12] Doughnut controller size reductions --- src/controllers/controller.doughnut.js | 141 +++++++++++++------------ src/core/core.datasetController.js | 26 ++++- 2 files changed, 99 insertions(+), 68 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 7170ecccf7e..2ec30ee3579 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -2,9 +2,10 @@ module.exports = function(Chart) { - var helpers = Chart.helpers; + var helpers = Chart.helpers, + defaults = Chart.defaults; - Chart.defaults.doughnut = { + defaults.doughnut = { animation: { //Boolean - Whether we animate the rotation of the Doughnut animateRotate: true, @@ -98,21 +99,21 @@ module.exports = function(Chart) { } }; - Chart.defaults.pie = helpers.clone(Chart.defaults.doughnut); - helpers.extend(Chart.defaults.pie, { + defaults.pie = helpers.clone(defaults.doughnut); + helpers.extend(defaults.pie, { cutoutPercentage: 0 }); Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({ - linkScales: function() { - // no scales for doughnut - }, + // no scales for doughnut + linkScales: helpers.noop, addElements: function() { - var meta = this.getMeta(); + var meta = this.getMeta(), + data = meta.data; helpers.each(this.getDataset().data, function(value, index) { - meta.data[index] = meta.data[index] || new Chart.elements.Arc({ + data[index] = data[index] || new Chart.elements.Arc({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index @@ -125,10 +126,11 @@ module.exports = function(Chart) { _chart: this.chart.chart, _datasetIndex: this.index, _index: index - }); + }), + ds = this.getDataset(); - if (colorForNewElement && helpers.isArray(this.getDataset().backgroundColor)) { - this.getDataset().backgroundColor.splice(index, 0, colorForNewElement); + if (colorForNewElement && helpers.isArray(ds.backgroundColor)) { + ds.backgroundColor.splice(index, 0, colorForNewElement); } // Add to the points array and reset it @@ -150,23 +152,33 @@ module.exports = function(Chart) { }, update: function update(reset) { - var availableWidth = this.chart.chartArea.right - this.chart.chartArea.left - this.chart.options.elements.arc.borderWidth; - var availableHeight = this.chart.chartArea.bottom - this.chart.chartArea.top - this.chart.options.elements.arc.borderWidth; - var minSize = Math.min(availableWidth, availableHeight); - var offset = {x: 0, y: 0}; + var chart = this.chart, + chartArea = chart.chartArea, + opts = chart.options, + arcOpts = opts.elements.arc, + availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth, + availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth, + minSize = Math.min(availableWidth, availableHeight), + offset = { + x: 0, + y: 0 + }, + meta = this.getMeta(), + cutoutPercentage = opts.cutoutPercentage, + circumference = opts.circumference; // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc - if (this.chart.options.circumference < Math.PI * 2.0) { - var startAngle = this.chart.options.rotation % (Math.PI * 2.0); + if (circumference < Math.PI * 2.0) { + var startAngle = opts.rotation % (Math.PI * 2.0); startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0); - var endAngle = startAngle + this.chart.options.circumference; + var endAngle = startAngle + circumference; var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)}; var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)}; var contains0 = (startAngle <= 0 && 0 <= endAngle) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle); var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle); var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle); var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle); - var cutout = this.chart.options.cutoutPercentage / 100.0; + var cutout = cutoutPercentage / 100.0; var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))}; var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))}; var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5}; @@ -174,66 +186,77 @@ module.exports = function(Chart) { offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5}; } - this.chart.outerRadius = Math.max(minSize / 2, 0); - this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0); - this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.getVisibleDatasetCount(); - this.chart.offsetX = offset.x * this.chart.outerRadius; - this.chart.offsetY = offset.y * this.chart.outerRadius; + chart.outerRadius = Math.max(minSize / 2, 0); + chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 1, 0); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); + chart.offsetX = offset.x * chart.outerRadius; + chart.offsetY = offset.y * chart.outerRadius; - this.getMeta().total = this.calculateTotal(); + meta.total = this.calculateTotal(); - this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.getRingIndex(this.index)); - this.innerRadius = this.outerRadius - this.chart.radiusLength; + this.outerRadius = chart.outerRadius - (chart.radiusLength * this.getRingIndex(this.index)); + this.innerRadius = this.outerRadius - chart.radiusLength; - helpers.each(this.getMeta().data, function(arc, index) { + helpers.each(meta.data, function(arc, index) { this.updateElement(arc, index, reset); }, this); }, updateElement: function(arc, index, reset) { - var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2; - var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2; - var startAngle = this.chart.options.rotation; // non reset case handled later - var endAngle = this.chart.options.rotation; // non reset case handled later - var circumference = reset && this.chart.options.animation.animateRotate ? 0 : arc.hidden? 0 : this.calculateCircumference(this.getDataset().data[index]) * (this.chart.options.circumference / (2.0 * Math.PI)); - var innerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.innerRadius; - var outerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.outerRadius; + var chart = this.chart, + chartArea = chart.chartArea, + opts = chart.options, + animationOpts = opts.animation, + arcOpts = opts.elements.arc, + centerX = (chartArea.left + chartArea.right) / 2, + centerY = (chartArea.top + chartArea.bottom) / 2, + startAngle = opts.rotation, // non reset case handled later + endAngle = opts.rotation, // non reset case handled later + dataset = this.getDataset(), + circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : this.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)), + innerRadius = reset && animationOpts.animateScale ? 0 : this.innerRadius, + outerRadius = reset && animationOpts.animateScale ? 0 : this.outerRadius, + custom = arc.custom, + valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault, + backgroundColor = "backgroundColor", + hoverBackgroundColor = "hoverBackgroundColor", + borderWidth = "borderWidth", + borderColor = "borderColor"; helpers.extend(arc, { // Utility - _chart: this.chart.chart, + _chart: chart.chart, _datasetIndex: this.index, _index: index, // Desired view properties _model: { - x: centerX + this.chart.offsetX, - y: centerY + this.chart.offsetY, + x: centerX + chart.offsetX, + y: centerY + chart.offsetY, startAngle: startAngle, endAngle: endAngle, circumference: circumference, outerRadius: outerRadius, innerRadius: innerRadius, - - backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), - hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor), - borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), - borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), - - label: helpers.getValueAtIndexOrDefault(this.getDataset().label, index, this.chart.data.labels[index]) + label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index]) } }); - // Set correct angles if not resetting - if (!reset || !this.chart.options.animation.animateRotate) { + var model = arc._model; + model[backgroundColor] = custom && custom[backgroundColor] ? custom[backgroundColor] : valueAtIndexOrDefault(dataset[backgroundColor], index, arcOpts[backgroundColor]); + model[hoverBackgroundColor] = custom && custom[hoverBackgroundColor] ? custom[hoverBackgroundColor] : valueAtIndexOrDefault(dataset[hoverBackgroundColor], index, arcOpts[hoverBackgroundColor]); + model[borderWidth] = custom && custom[borderWidth] ? custom[borderWidth] : valueAtIndexOrDefault(dataset[borderWidth], index, arcOpts[borderWidth]); + model[borderColor] = custom && custom[borderColor] ? custom[borderColor] : valueAtIndexOrDefault(dataset[borderColor], index, arcOpts[borderColor]); + // Set correct angles if not resetting + if (!reset || !animationOpts.animateRotate) { if (index === 0) { - arc._model.startAngle = this.chart.options.rotation; + model.startAngle = opts.rotation; } else { - arc._model.startAngle = this.getMeta().data[index - 1]._model.endAngle; + model.startAngle = this.getMeta().data[index - 1]._model.endAngle; } - arc._model.endAngle = arc._model.startAngle + arc._model.circumference; + model.endAngle = model.startAngle + model.circumference; } arc.pivot(); @@ -246,22 +269,8 @@ module.exports = function(Chart) { }); }, - setHoverStyle: function(arc) { - var dataset = this.chart.data.datasets[arc._datasetIndex]; - var index = arc._index; - - arc._model.backgroundColor = arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(arc._model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); - arc._model.borderColor = arc.custom && arc.custom.hoverBorderColor ? arc.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(arc._model.borderColor).saturate(0.5).darken(0.1).rgbString()); - arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, arc._model.borderWidth); - }, - removeHoverStyle: function(arc) { - var dataset = this.chart.data.datasets[arc._datasetIndex]; - var index = arc._index; - - arc._model.backgroundColor = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor); - arc._model.borderColor = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor); - arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth); + Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); }, calculateTotal: function() { diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index dad49e234a5..a2ed16704ee 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -72,8 +72,30 @@ module.exports = function(Chart) { addElements: noop, addElementAndReset: noop, draw: noop, - removeHoverStyle: noop, - setHoverStyle: noop, + removeHoverStyle: function(element, elementOpts) { + var dataset = this.chart.data.datasets[element._datasetIndex], + index = element._index, + custom = element.custom, + valueOrDefault = helpers.getValueAtIndexOrDefault, + color = helpers.color, + model = element._model; + + model.backgroundColor = custom && custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor); + model.borderColor = custom && custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor); + model.borderWidth = custom && custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth); + }, + setHoverStyle: function(element) { + var dataset = this.chart.data.datasets[element._datasetIndex], + index = element._index, + custom = element.custom, + valueOrDefault = helpers.getValueAtIndexOrDefault, + color = helpers.color, + model = element._model; + + model.backgroundColor = custom && custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, color(model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); + model.borderColor = custom && custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, color(model.borderColor).saturate(0.5).darken(0.1).rgbString()); + model.borderWidth = custom && custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth); + }, update: noop }); From 1b6ffd623c02b23206dfba22665209dbce5332ce Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Thu, 5 May 2016 21:01:48 -0400 Subject: [PATCH 03/12] Core.Title reductions --- src/core/core.title.js | 44 +++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/core/core.title.js b/src/core/core.title.js index 91bfc74f037..0982986ca49 100644 --- a/src/core/core.title.js +++ b/src/core/core.title.js @@ -104,24 +104,27 @@ module.exports = function(Chart) { beforeFit: noop, fit: function() { - var ctx = this.ctx, + var _this = this, + ctx = _this.ctx, valueOrDefault = helpers.getValueOrDefault, - opts = this.options, + opts = _this.options, globalDefaults = Chart.defaults.global, display = opts.display, fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize), - minSize = this.minSize; + minSize = _this.minSize, + width = "width", + height = "height"; - if (this.isHorizontal()) { - minSize.width = this.maxWidth; // fill all the width - minSize.height = display ? fontSize + (opts.padding * 2) : 0; + if (_this.isHorizontal()) { + minSize[width] = _this.maxWidth; // fill all the width + minSize[height] = display ? fontSize + (opts.padding * 2) : 0; } else { - minSize.width = display ? fontSize + (opts.padding * 2) : 0; - minSize.height = this.maxHeight; // fill all the height + minSize[width] = display ? fontSize + (opts.padding * 2) : 0; + minSize[height] = _this.maxHeight; // fill all the height } - this.width = minSize.width; - this.height = minSize.height; + _this[width] = minSize[width]; + _this[height] = minSize[height]; }, afterFit: noop, @@ -134,9 +137,10 @@ module.exports = function(Chart) { // Actualy draw the title block on the canvas draw: function() { - var ctx = this.ctx, + var _this = this, + ctx = _this.ctx, valueOrDefault = helpers.getValueOrDefault, - opts = this.options, + opts = _this.options, globalDefaults = Chart.defaults.global; if (opts.display) { @@ -146,18 +150,22 @@ module.exports = function(Chart) { titleFont = helpers.fontString(fontSize, fontStyle, fontFamily), rotation = 0, titleX, - titleY; + titleY, + top = _this.top, + left = _this.left, + bottom = _this.bottom, + right = _this.right; ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour ctx.font = titleFont; // Horizontal - if (this.isHorizontal()) { - titleX = this.left + ((this.right - this.left) / 2); // midpoint of the width - titleY = this.top + ((this.bottom - this.top) / 2); // midpoint of the height + if (_this.isHorizontal()) { + titleX = left + ((right - left) / 2); // midpoint of the width + titleY = top + ((bottom - top) / 2); // midpoint of the height } else { - titleX = opts.position === 'left' ? this.left + (fontSize / 2) : this.right - (fontSize / 2); - titleY = this.top + ((this.bottom - this.top) / 2); + titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2); + titleY = top + ((bottom - top) / 2); rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5); } From 72c791f35263291d9e3e0c336f9d983a26bb046c Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 7 May 2016 17:00:00 -0400 Subject: [PATCH 04/12] Revert "Reduce element.point size" This reverts commit 09bcac9b5c699c75909b77dc40dc40b5a3af1030. --- src/elements/element.point.js | 90 ++++++++++++++++------------------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/src/elements/element.point.js b/src/elements/element.point.js index c92c0ad48cc..93f59be1fd7 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -61,86 +61,80 @@ module.exports = function(Chart) { var radius = vm.radius; var xOffset, - yOffset, - beginPath = "beginPath", - moveTo = "moveTo", - lineTo = "lineTo", - closePath = "closePath", - fillRect = "fillRect", - strokeRect = "strokeRect"; + yOffset; switch (pointStyle) { // Default includes circle default: - ctx[beginPath](); + ctx.beginPath(); ctx.arc(x, y, radius, 0, Math.PI * 2); - ctx[closePath](); + ctx.closePath(); ctx.fill(); break; case 'triangle': - ctx[beginPath](); + ctx.beginPath(); var edgeLength = 3 * radius / Math.sqrt(3); var height = edgeLength * Math.sqrt(3) / 2; - ctx[moveTo](x - edgeLength / 2, y + height / 3); - ctx[lineTo](x + edgeLength / 2, y + height / 3); - ctx[lineTo](x, y - 2 * height / 3); - ctx[closePath](); + ctx.moveTo(x - edgeLength / 2, y + height / 3); + ctx.lineTo(x + edgeLength / 2, y + height / 3); + ctx.lineTo(x, y - 2 * height / 3); + ctx.closePath(); ctx.fill(); break; case 'rect': - ctx[fillRect](x - 1 / Math.SQRT2 * radius, y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); - ctx[strokeRect](x - 1 / Math.SQRT2 * radius, y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx.fillRect(x - 1 / Math.SQRT2 * radius, y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx.strokeRect(x - 1 / Math.SQRT2 * radius, y - 1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); break; case 'rectRot': ctx.translate(x, y); ctx.rotate(Math.PI / 4); - ctx[fillRect](-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); - ctx[strokeRect](-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx.fillRect(-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); + ctx.strokeRect(-1 / Math.SQRT2 * radius, -1 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius, 2 / Math.SQRT2 * radius); ctx.setTransform(1, 0, 0, 1, 0, 0); break; case 'cross': - ctx[beginPath](); - ctx[moveTo](x, y + radius); - ctx[lineTo](x, y - radius); - ctx[moveTo](x - radius, y); - ctx[lineTo](x + radius, y); - ctx[closePath](); + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y - radius); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); break; case 'crossRot': - ctx[beginPath](); + ctx.beginPath(); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; - ctx[moveTo](x - xOffset, y - yOffset); - ctx[lineTo](x + xOffset, y + yOffset); - ctx[moveTo](x - xOffset, y + yOffset); - ctx[lineTo](x + xOffset, y - yOffset); - ctx[closePath](); + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x - xOffset, y + yOffset); + ctx.lineTo(x + xOffset, y - yOffset); + ctx.closePath(); break; case 'star': - ctx[beginPath](); - ctx[moveTo](x, y + radius); - ctx[lineTo](x, y - radius); - ctx[moveTo](x - radius, y); - ctx[lineTo](x + radius, y); + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y - radius); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); xOffset = Math.cos(Math.PI / 4) * radius; yOffset = Math.sin(Math.PI / 4) * radius; - ctx[moveTo](x - xOffset, y - yOffset); - ctx[lineTo](x + xOffset, y + yOffset); - ctx[moveTo](x - xOffset, y + yOffset); - ctx[lineTo](x + xOffset, y - yOffset); - ctx[closePath](); + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x - xOffset, y + yOffset); + ctx.lineTo(x + xOffset, y - yOffset); + ctx.closePath(); break; case 'line': - ctx[beginPath](); - ctx[moveTo](x - radius, y); - ctx[lineTo](x + radius, y); - ctx[closePath](); + ctx.beginPath(); + ctx.moveTo(x - radius, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); break; case 'dash': - ctx[beginPath](); - ctx[moveTo](x, y); - ctx[lineTo](x + radius, y); - ctx[closePath](); + ctx.beginPath(); + ctx.moveTo(x, y); + ctx.lineTo(x + radius, y); + ctx.closePath(); break; } From 5141c90c7bf4d449244aa7476eeb7eb396e0d603 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 7 May 2016 17:04:34 -0400 Subject: [PATCH 05/12] Revert unnecessary changes --- src/controllers/controller.doughnut.js | 14 +++++--------- src/core/core.title.js | 16 +++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 2ec30ee3579..ba21c450697 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -217,11 +217,7 @@ module.exports = function(Chart) { innerRadius = reset && animationOpts.animateScale ? 0 : this.innerRadius, outerRadius = reset && animationOpts.animateScale ? 0 : this.outerRadius, custom = arc.custom, - valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault, - backgroundColor = "backgroundColor", - hoverBackgroundColor = "hoverBackgroundColor", - borderWidth = "borderWidth", - borderColor = "borderColor"; + valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; helpers.extend(arc, { // Utility @@ -243,10 +239,10 @@ module.exports = function(Chart) { }); var model = arc._model; - model[backgroundColor] = custom && custom[backgroundColor] ? custom[backgroundColor] : valueAtIndexOrDefault(dataset[backgroundColor], index, arcOpts[backgroundColor]); - model[hoverBackgroundColor] = custom && custom[hoverBackgroundColor] ? custom[hoverBackgroundColor] : valueAtIndexOrDefault(dataset[hoverBackgroundColor], index, arcOpts[hoverBackgroundColor]); - model[borderWidth] = custom && custom[borderWidth] ? custom[borderWidth] : valueAtIndexOrDefault(dataset[borderWidth], index, arcOpts[borderWidth]); - model[borderColor] = custom && custom[borderColor] ? custom[borderColor] : valueAtIndexOrDefault(dataset[borderColor], index, arcOpts[borderColor]); + model.backgroundColor = custom && custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(dataset.backgroundColor, index, arcOpts.backgroundColor); + model.hoverBackgroundColor = custom && custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueAtIndexOrDefault(dataset.hoverBackgroundColor, index, arcOpts.hoverBackgroundColor); + model.borderWidth = custom && custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(dataset.borderWidth, index, arcOpts.borderWidth); + model.borderColor = custom && custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(dataset.borderColor, index, arcOpts.borderColor); // Set correct angles if not resetting if (!reset || !animationOpts.animateRotate) { diff --git a/src/core/core.title.js b/src/core/core.title.js index 0982986ca49..b6d82c07ed1 100644 --- a/src/core/core.title.js +++ b/src/core/core.title.js @@ -111,20 +111,18 @@ module.exports = function(Chart) { globalDefaults = Chart.defaults.global, display = opts.display, fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize), - minSize = _this.minSize, - width = "width", - height = "height"; + minSize = _this.minSize; if (_this.isHorizontal()) { - minSize[width] = _this.maxWidth; // fill all the width - minSize[height] = display ? fontSize + (opts.padding * 2) : 0; + minSize.width = _this.maxWidth; // fill all the width + minSize.height = display ? fontSize + (opts.padding * 2) : 0; } else { - minSize[width] = display ? fontSize + (opts.padding * 2) : 0; - minSize[height] = _this.maxHeight; // fill all the height + minSize.width = display ? fontSize + (opts.padding * 2) : 0; + minSize.height = _this.maxHeight; // fill all the height } - _this[width] = minSize[width]; - _this[height] = minSize[height]; + _this.width = minSize.width; + _this.height = minSize.height; }, afterFit: noop, From cf5c75ea9e9e6f8a1193ebc79c2000f608aa3e83 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 7 May 2016 17:09:17 -0400 Subject: [PATCH 06/12] get a little more from the point element --- src/elements/element.point.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/elements/element.point.js b/src/elements/element.point.js index 93f59be1fd7..306a643c533 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -3,14 +3,15 @@ module.exports = function(Chart) { var helpers = Chart.helpers, - globalOpts = Chart.defaults.global; + globalOpts = Chart.defaults.global, + defaultColor = globalOpts.defaultColor; globalOpts.elements.point = { radius: 3, pointStyle: 'circle', - backgroundColor: globalOpts.defaultColor, + backgroundColor: defaultColor, borderWidth: 1, - borderColor: globalOpts.defaultColor, + borderColor: defaultColor, // Hover hitRadius: 1, hoverRadius: 4, @@ -53,10 +54,10 @@ module.exports = function(Chart) { if (!isNaN(vm.radius) && vm.radius > 0) { - ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor; - ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, Chart.defaults.global.elements.point.borderWidth); + ctx.strokeStyle = vm.borderColor || defaultColor; + ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth); - ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor; + ctx.fillStyle = vm.backgroundColor || defaultColor; var radius = vm.radius; From 9d832cc39df0ecea80fd9b0ca9f6e19b393d2489 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 7 May 2016 19:47:40 -0400 Subject: [PATCH 07/12] More donut improvements --- src/controllers/controller.doughnut.js | 75 +++++++++++++++----------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index ba21c450697..e22abda2aa0 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -20,11 +20,15 @@ module.exports = function(Chart) { var text = []; text.push('
    '); - if (chart.data.datasets.length) { - for (var i = 0; i < chart.data.datasets[0].data.length; ++i) { - text.push('
  • '); - if (chart.data.labels[i]) { - text.push(chart.data.labels[i]); + var data = chart.data; + var datasets = data.datasets; + var labels = data.labels; + + if (datasets.length) { + for (var i = 0; i < datasets[0].data.length; ++i) { + text.push('
  • '); + if (labels[i]) { + text.push(labels[i]); } text.push('
  • '); } @@ -42,9 +46,12 @@ module.exports = function(Chart) { var meta = chart.getDatasetMeta(0); var ds = data.datasets[0]; var arc = meta.data[i]; - var fill = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(ds.backgroundColor, i, this.chart.options.elements.arc.backgroundColor); - var stroke = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(ds.borderColor, i, this.chart.options.elements.arc.borderColor); - var bw = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(ds.borderWidth, i, this.chart.options.elements.arc.borderWidth); + var custom = arc.custom; + var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; + var arcOpts = chart.options.elements.arc; + var fill = custom && custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); + var stroke = custom && custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); + var bw = custom && custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); return { text: label, @@ -56,7 +63,7 @@ module.exports = function(Chart) { // Extra data used for toggling the correct item index: i }; - }, this); + }); } else { return []; } @@ -110,32 +117,34 @@ module.exports = function(Chart) { linkScales: helpers.noop, addElements: function() { + var _this = this; var meta = this.getMeta(), data = meta.data; - helpers.each(this.getDataset().data, function(value, index) { + helpers.each(_this.getDataset().data, function(value, index) { data[index] = data[index] || new Chart.elements.Arc({ - _chart: this.chart.chart, - _datasetIndex: this.index, + _chart: _this.chart.chart, + _datasetIndex: _this.index, _index: index }); - }, this); + }); }, addElementAndReset: function(index, colorForNewElement) { + var _this = this; var arc = new Chart.elements.Arc({ - _chart: this.chart.chart, - _datasetIndex: this.index, + _chart: _this.chart.chart, + _datasetIndex: _this.index, _index: index }), - ds = this.getDataset(); + ds = _this.getDataset(); if (colorForNewElement && helpers.isArray(ds.backgroundColor)) { ds.backgroundColor.splice(index, 0, colorForNewElement); } // Add to the points array and reset it - this.getMeta().data.splice(index, 0, arc); - this.updateElement(arc, index, true); + _this.getMeta().data.splice(index, 0, arc); + _this.updateElement(arc, index, true); }, // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly @@ -152,7 +161,8 @@ module.exports = function(Chart) { }, update: function update(reset) { - var chart = this.chart, + var _this = this; + var chart = _this.chart, chartArea = chart.chartArea, opts = chart.options, arcOpts = opts.elements.arc, @@ -163,7 +173,7 @@ module.exports = function(Chart) { x: 0, y: 0 }, - meta = this.getMeta(), + meta = _this.getMeta(), cutoutPercentage = opts.cutoutPercentage, circumference = opts.circumference; @@ -192,18 +202,19 @@ module.exports = function(Chart) { chart.offsetX = offset.x * chart.outerRadius; chart.offsetY = offset.y * chart.outerRadius; - meta.total = this.calculateTotal(); + meta.total = _this.calculateTotal(); - this.outerRadius = chart.outerRadius - (chart.radiusLength * this.getRingIndex(this.index)); - this.innerRadius = this.outerRadius - chart.radiusLength; + _this.outerRadius = chart.outerRadius - (chart.radiusLength * _this.getRingIndex(_this.index)); + _this.innerRadius = _this.outerRadius - chart.radiusLength; helpers.each(meta.data, function(arc, index) { - this.updateElement(arc, index, reset); - }, this); + _this.updateElement(arc, index, reset); + }); }, updateElement: function(arc, index, reset) { - var chart = this.chart, + var _this = this; + var chart = _this.chart, chartArea = chart.chartArea, opts = chart.options, animationOpts = opts.animation, @@ -212,17 +223,17 @@ module.exports = function(Chart) { centerY = (chartArea.top + chartArea.bottom) / 2, startAngle = opts.rotation, // non reset case handled later endAngle = opts.rotation, // non reset case handled later - dataset = this.getDataset(), - circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : this.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)), - innerRadius = reset && animationOpts.animateScale ? 0 : this.innerRadius, - outerRadius = reset && animationOpts.animateScale ? 0 : this.outerRadius, + dataset = _this.getDataset(), + circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : _this.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)), + innerRadius = reset && animationOpts.animateScale ? 0 : _this.innerRadius, + outerRadius = reset && animationOpts.animateScale ? 0 : _this.outerRadius, custom = arc.custom, valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; helpers.extend(arc, { // Utility _chart: chart.chart, - _datasetIndex: this.index, + _datasetIndex: _this.index, _index: index, // Desired view properties @@ -249,7 +260,7 @@ module.exports = function(Chart) { if (index === 0) { model.startAngle = opts.rotation; } else { - model.startAngle = this.getMeta().data[index - 1]._model.endAngle; + model.startAngle = _this.getMeta().data[index - 1]._model.endAngle; } model.endAngle = model.startAngle + model.circumference; From 166801055e95f283ac33ad1ea6e03e58e2f9d30f Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 7 May 2016 21:04:39 -0400 Subject: [PATCH 08/12] Improvements to polar area controller. Moved common draw code up to core dataset controller --- src/controllers/controller.doughnut.js | 7 -- src/controllers/controller.polarArea.js | 141 ++++++++++++------------ src/core/core.datasetController.js | 7 +- 3 files changed, 79 insertions(+), 76 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index e22abda2aa0..8a68a68cf80 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -269,13 +269,6 @@ module.exports = function(Chart) { arc.pivot(); }, - draw: function(ease) { - var easingDecimal = ease || 1; - helpers.each(this.getMeta().data, function(arc, index) { - arc.transition(easingDecimal).draw(); - }); - }, - removeHoverStyle: function(arc) { Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); }, diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index 0b64c9248eb..eb0f5c598ca 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -22,11 +22,15 @@ module.exports = function(Chart) { var text = []; text.push('
      '); - if (chart.data.datasets.length) { - for (var i = 0; i < chart.data.datasets[0].data.length; ++i) { - text.push('
    • '); - if (chart.data.labels[i]) { - text.push(chart.data.labels[i]); + var data = chart.data; + var datasets = data.datasets; + var labels = data.labels; + + if (datasets.length) { + for (var i = 0; i < datasets[0].data.length; ++i) { + text.push('
    • '); + if (labels[i]) { + text.push(labels[i]); } text.push('
    • '); } @@ -44,9 +48,12 @@ module.exports = function(Chart) { var meta = chart.getDatasetMeta(0); var ds = data.datasets[0]; var arc = meta.data[i]; - var fill = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(ds.backgroundColor, i, this.chart.options.elements.arc.backgroundColor); - var stroke = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(ds.borderColor, i, this.chart.options.elements.arc.borderColor); - var bw = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(ds.borderWidth, i, this.chart.options.elements.arc.borderWidth); + var custom = arc.custom; + var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; + var arcOpts = chart.options.elements.arc; + var fill = custom && custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); + var stroke = custom && custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); + var bw = custom && custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); return { text: label, @@ -58,7 +65,7 @@ module.exports = function(Chart) { // Extra data used for toggling the correct item index: i }; - }, this); + }); } else { return []; } @@ -98,61 +105,80 @@ module.exports = function(Chart) { }, addElements: function() { + var _this = this; var meta = this.getMeta(); - helpers.each(this.getDataset().data, function(value, index) { + helpers.each(_this.getDataset().data, function(value, index) { meta.data[index] = meta.data[index] || new Chart.elements.Arc({ - _chart: this.chart.chart, - _datasetIndex: this.index, + _chart: _this.chart.chart, + _datasetIndex: _this.index, _index: index }); - }, this); + }); }, addElementAndReset: function(index) { + var _this = this; var arc = new Chart.elements.Arc({ - _chart: this.chart.chart, - _datasetIndex: this.index, + _chart: _this.chart.chart, + _datasetIndex: _this.index, _index: index }); // Add to the points array and reset it - this.getMeta().data.splice(index, 0, arc); - this.updateElement(arc, index, true); + _this.getMeta().data.splice(index, 0, arc); + _this.updateElement(arc, index, true); }, update: function update(reset) { + var _this = this; + var chart = _this.chart; + var chartArea = chart.chartArea; var meta = this.getMeta(); - var minSize = Math.min(this.chart.chartArea.right - this.chart.chartArea.left, this.chart.chartArea.bottom - this.chart.chartArea.top); - this.chart.outerRadius = Math.max((minSize - this.chart.options.elements.arc.borderWidth / 2) / 2, 0); - this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0); - this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.getVisibleDatasetCount(); + var opts = chart.options; + var arcOpts = opts.elements.arc; + var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0); + chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); - this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.index); - this.innerRadius = this.outerRadius - this.chart.radiusLength; + _this.outerRadius = chart.outerRadius - (chart.radiusLength * _this.index); + _this.innerRadius = _this.outerRadius - chart.radiusLength; - meta.count = this.countVisibleElements(); + meta.count = _this.countVisibleElements(); helpers.each(meta.data, function(arc, index) { - this.updateElement(arc, index, reset); - }, this); + _this.updateElement(arc, index, reset); + }); }, updateElement: function(arc, index, reset) { - var circumference = this.calculateCircumference(this.getDataset().data[index]); - var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2; - var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2; + var _this = this; + var chart = _this.chart; + var chartArea = chart.chartArea; + var dataset = _this.getDataset(); + var opts = chart.options; + var animationOpts = opts.animation; + var arcOpts = opts.elements.arc; + var custom = arc.custom; + var scale = chart.scale; + var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault; + var labels = chart.data.labels; + + var circumference = _this.calculateCircumference(dataset.data[index]); + var centerX = (chartArea.left + chartArea.right) / 2; + var centerY = (chartArea.top + chartArea.bottom) / 2; // If there is NaN data before us, we need to calculate the starting angle correctly. // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data var visibleCount = 0; - var meta = this.getMeta(); + var meta = _this.getMeta(); for (var i = 0; i < index; ++i) { - if (!isNaN(this.getDataset().data[i]) && !meta.data[i].hidden) { + if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) { ++visibleCount; } } - var distance = arc.hidden? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]); + var distance = arc.hidden? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); var startAngle = (-0.5 * Math.PI) + (circumference * visibleCount); var endAngle = startAngle + (arc.hidden? 0 : circumference); @@ -160,23 +186,23 @@ module.exports = function(Chart) { x: centerX, y: centerY, innerRadius: 0, - outerRadius: this.chart.options.animation.animateScale ? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]), - startAngle: this.chart.options.animation.animateRotate ? Math.PI * -0.5 : startAngle, - endAngle: this.chart.options.animation.animateRotate ? Math.PI * -0.5 : endAngle, + outerRadius: animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]), + startAngle: animationOpts.animateRotate ? Math.PI * -0.5 : startAngle, + endAngle: animationOpts.animateRotate ? Math.PI * -0.5 : endAngle, - backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), - borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), - borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), + backgroundColor: custom && custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(dataset.backgroundColor, index, arcOpts.backgroundColor), + borderWidth: custom && custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(dataset.borderWidth, index, arcOpts.borderWidth), + borderColor: custom && custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(dataset.borderColor, index, arcOpts.borderColor), - label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index]) + label: getValueAtIndexOrDefault(labels, index, labels[index]) }; helpers.extend(arc, { // Utility - _chart: this.chart.chart, - _datasetIndex: this.index, + _chart: chart.chart, + _datasetIndex: _this.index, _index: index, - _scale: this.chart.scale, + _scale: scale, // Desired view properties _model: reset ? resetModel : { @@ -187,40 +213,19 @@ module.exports = function(Chart) { startAngle: startAngle, endAngle: endAngle, - backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), - borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), - borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), + backgroundColor: custom && custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(dataset.backgroundColor, index, arcOpts.backgroundColor), + borderWidth: custom && custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(dataset.borderWidth, index, arcOpts.borderWidth), + borderColor: custom && custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(dataset.borderColor, index, arcOpts.borderColor), - label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index]) + label: getValueAtIndexOrDefault(labels, index, labels[index]) } }); arc.pivot(); }, - draw: function(ease) { - var easingDecimal = ease || 1; - helpers.each(this.getMeta().data, function(arc, index) { - arc.transition(easingDecimal).draw(); - }); - }, - - setHoverStyle: function(arc) { - var dataset = this.chart.data.datasets[arc._datasetIndex]; - var index = arc._index; - - arc._model.backgroundColor = arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(arc._model.backgroundColor).saturate(0.5).darken(0.1).rgbString()); - arc._model.borderColor = arc.custom && arc.custom.hoverBorderColor ? arc.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(arc._model.borderColor).saturate(0.5).darken(0.1).rgbString()); - arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, arc._model.borderWidth); - }, - removeHoverStyle: function(arc) { - var dataset = this.chart.data.datasets[arc._datasetIndex]; - var index = arc._index; - - arc._model.backgroundColor = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor); - arc._model.borderColor = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor); - arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth); + Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); }, countVisibleElements: function() { diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index a2ed16704ee..e483e3f3ea2 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -71,7 +71,12 @@ module.exports = function(Chart) { // Controllers should implement the following addElements: noop, addElementAndReset: noop, - draw: noop, + draw: function(ease) { + var easingDecimal = ease || 1; + helpers.each(this.getMeta().data, function(element, index) { + element.transition(easingDecimal).draw(); + }); + }, removeHoverStyle: function(element, elementOpts) { var dataset = this.chart.data.datasets[element._datasetIndex], index = element._index, From 33d10374bbc99ff18f318134c6d6b1a1e562120c Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 7 May 2016 21:37:24 -0400 Subject: [PATCH 09/12] Minor improvement to polar area controller --- src/controllers/controller.polarArea.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index eb0f5c598ca..2308be89b7b 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -100,15 +100,14 @@ module.exports = function(Chart) { }; Chart.controllers.polarArea = Chart.DatasetController.extend({ - linkScales: function() { - // no scales for doughnut - }, + linkScales: helpers.noop, addElements: function() { var _this = this; var meta = this.getMeta(); + var data = meta.data; helpers.each(_this.getDataset().data, function(value, index) { - meta.data[index] = meta.data[index] || new Chart.elements.Arc({ + data[index] = data[index] || new Chart.elements.Arc({ _chart: _this.chart.chart, _datasetIndex: _this.index, _index: index From 4ef5d942e682d50078c31431b6888c0e998cf9ec Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 8 May 2016 07:55:29 -0400 Subject: [PATCH 10/12] Linear scale improvements --- src/scales/scale.linear.js | 47 ++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/scales/scale.linear.js b/src/scales/scale.linear.js index 90fcab9fec8..15db914ba62 100644 --- a/src/scales/scale.linear.js +++ b/src/scales/scale.linear.js @@ -228,41 +228,44 @@ module.exports = function(Chart) { return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); }, convertTicksToLabels: function() { - this.ticksAsNumbers = this.ticks.slice(); - this.zeroLineIndex = this.ticks.indexOf(0); + var _this = this; + _this.ticksAsNumbers = _this.ticks.slice(); + _this.zeroLineIndex = _this.ticks.indexOf(0); - Chart.Scale.prototype.convertTicksToLabels.call(this); + Chart.Scale.prototype.convertTicksToLabels.call(_this); }, // Utils getPixelForValue: function(value, index, datasetIndex, includeOffset) { // This must be called after fit has been run so that // this.left, this.top, this.right, and this.bottom have been defined - var rightValue = +this.getRightValue(value); + var _this = this; + var paddingLeft = _this.paddingLeft; + var paddingBottom = _this.paddingBottom; + var start = _this.start; + + var rightValue = +_this.getRightValue(value); var pixel; - var range = this.end - this.start; + var innerDimension; + var range = _this.end - start; - if (this.isHorizontal()) { - var innerWidth = this.width - (this.paddingLeft + this.paddingRight); - pixel = this.left + (innerWidth / range * (rightValue - this.start)); - return Math.round(pixel + this.paddingLeft); + if (_this.isHorizontal()) { + innerDimension = _this.width - (paddingLeft + _this.paddingRight); + pixel = _this.left + (innerDimension / range * (rightValue - start)); + return Math.round(pixel + paddingLeft); } else { - var innerHeight = this.height - (this.paddingTop + this.paddingBottom); - pixel = (this.bottom - this.paddingBottom) - (innerHeight / range * (rightValue - this.start)); + innerDimension = _this.height - (_this.paddingTop + paddingBottom); + pixel = (_this.bottom - paddingBottom) - (innerDimension / range * (rightValue - start)); return Math.round(pixel); } }, getValueForPixel: function(pixel) { - var offset; - - if (this.isHorizontal()) { - var innerWidth = this.width - (this.paddingLeft + this.paddingRight); - offset = (pixel - this.left - this.paddingLeft) / innerWidth; - } else { - var innerHeight = this.height - (this.paddingTop + this.paddingBottom); - offset = (this.bottom - this.paddingBottom - pixel) / innerHeight; - } - - return this.start + ((this.end - this.start) * offset); + var _this = this; + var isHorizontal = _this.isHorizontal(); + var paddingLeft = _this.paddingLeft; + var paddingBottom = _this.paddingBottom; + var innerDimension = isHorizontal ? _this.width - (paddingLeft + _this.paddingRight) : _this.height - (_this.paddingTop + paddingBottom); + var offset = (isHorizontal ? pixel - _this.left - paddingLeft : _this.bottom - paddingBottom - pixel) / innerDimension; + return _this.start + ((_this.end - _this.start) * offset); }, getPixelForTick: function(index, includeOffset) { return this.getPixelForValue(this.ticksAsNumbers[index], null, null, includeOffset); From e86a13dcef6fe50b8171b89f6404256ef27cde3c Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 8 May 2016 08:32:48 -0400 Subject: [PATCH 11/12] More linear scale work --- src/scales/scale.linear.js | 152 ++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 68 deletions(-) diff --git a/src/scales/scale.linear.js b/src/scales/scale.linear.js index 2b53125ee09..f6363d44c0d 100644 --- a/src/scales/scale.linear.js +++ b/src/scales/scale.linear.js @@ -37,17 +37,29 @@ module.exports = function(Chart) { var LinearScale = Chart.Scale.extend({ determineDataLimits: function() { + var _this = this; + var opts = _this.options; + var tickOpts = opts.ticks; + var chart = _this.chart; + var data = chart.data; + var datasets = data.datasets; + var isHorizontal = _this.isHorizontal(); + + function IDMatches(meta) { + return isHorizontal ? meta.xAxisID === _this.id : meta.yAxisID === _this.id; + } + // First Calculate the range - this.min = null; - this.max = null; + _this.min = null; + _this.max = null; - if (this.options.stacked) { + if (opts.stacked) { var valuesPerType = {}; var hasPositiveValues = false; var hasNegativeValues = false; - helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { - var meta = this.chart.getDatasetMeta(datasetIndex); + helpers.each(datasets, function(dataset, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); if (valuesPerType[meta.type] === undefined) { valuesPerType[meta.type] = { positiveValues: [], @@ -59,9 +71,9 @@ module.exports = function(Chart) { var positiveValues = valuesPerType[meta.type].positiveValues; var negativeValues = valuesPerType[meta.type].negativeValues; - if (this.chart.isDatasetVisible(datasetIndex) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) { + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { helpers.each(dataset.data, function(rawValue, index) { - var value = +this.getRightValue(rawValue); + var value = +_this.getRightValue(rawValue); if (isNaN(value) || meta.data[index].hidden) { return; } @@ -69,7 +81,7 @@ module.exports = function(Chart) { positiveValues[index] = positiveValues[index] || 0; negativeValues[index] = negativeValues[index] || 0; - if (this.options.relativePoints) { + if (opts.relativePoints) { positiveValues[index] = 100; } else { if (value < 0) { @@ -80,84 +92,88 @@ module.exports = function(Chart) { positiveValues[index] += value; } } - }, this); + }); } - }, this); + }); helpers.each(valuesPerType, function(valuesForType) { var values = valuesForType.positiveValues.concat(valuesForType.negativeValues); var minVal = helpers.min(values); var maxVal = helpers.max(values); - this.min = this.min === null ? minVal : Math.min(this.min, minVal); - this.max = this.max === null ? maxVal : Math.max(this.max, maxVal); - }, this); + _this.min = _this.min === null ? minVal : Math.min(_this.min, minVal); + _this.max = _this.max === null ? maxVal : Math.max(_this.max, maxVal); + }); } else { - helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { - var meta = this.chart.getDatasetMeta(datasetIndex); - if (this.chart.isDatasetVisible(datasetIndex) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) { + helpers.each(datasets, function(dataset, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { helpers.each(dataset.data, function(rawValue, index) { - var value = +this.getRightValue(rawValue); + var value = +_this.getRightValue(rawValue); if (isNaN(value) || meta.data[index].hidden) { return; } - if (this.min === null) { - this.min = value; - } else if (value < this.min) { - this.min = value; + if (_this.min === null) { + _this.min = value; + } else if (value < _this.min) { + _this.min = value; } - if (this.max === null) { - this.max = value; - } else if (value > this.max) { - this.max = value; + if (_this.max === null) { + _this.max = value; + } else if (value > _this.max) { + _this.max = value; } - }, this); + }); } - }, this); + }); } // If we are forcing it to begin at 0, but 0 will already be rendered on the chart, // do nothing since that would make the chart weird. If the user really wants a weird chart // axis, they can manually override it - if (this.options.ticks.beginAtZero) { - var minSign = helpers.sign(this.min); - var maxSign = helpers.sign(this.max); + if (tickOpts.beginAtZero) { + var minSign = helpers.sign(_this.min); + var maxSign = helpers.sign(_this.max); if (minSign < 0 && maxSign < 0) { // move the top up to 0 - this.max = 0; + _this.max = 0; } else if (minSign > 0 && maxSign > 0) { // move the botttom down to 0 - this.min = 0; + _this.min = 0; } } - if (this.options.ticks.min !== undefined) { - this.min = this.options.ticks.min; - } else if (this.options.ticks.suggestedMin !== undefined) { - this.min = Math.min(this.min, this.options.ticks.suggestedMin); + if (tickOpts.min !== undefined) { + _this.min = tickOpts.min; + } else if (tickOpts.suggestedMin !== undefined) { + _this.min = Math.min(_this.min, tickOpts.suggestedMin); } - if (this.options.ticks.max !== undefined) { - this.max = this.options.ticks.max; - } else if (this.options.ticks.suggestedMax !== undefined) { - this.max = Math.max(this.max, this.options.ticks.suggestedMax); + if (tickOpts.max !== undefined) { + _this.max = tickOpts.max; + } else if (tickOpts.suggestedMax !== undefined) { + _this.max = Math.max(_this.max, tickOpts.suggestedMax); } - if (this.min === this.max) { - this.max++; + if (_this.min === _this.max) { + _this.max++; - if (!this.options.ticks.beginAtZero) { - this.min--; + if (!tickOpts.beginAtZero) { + _this.min--; } } }, buildTicks: function() { + var _this = this; + var opts = _this.options; + var tickOpts = opts.ticks; + var getValueOrDefault = helpers.getValueOrDefault; + var isHorizontal = _this.isHorizontal(); - // Then calulate the ticks - this.ticks = []; + var ticks = _this.ticks = []; // Figure out what the max number of ticks we can support it is based on the size of // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 @@ -166,12 +182,12 @@ module.exports = function(Chart) { var maxTicks; - if (this.isHorizontal()) { - maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.width / 50)); + if (isHorizontal) { + maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(_this.width / 50)); } else { // The factor of 2 used to scale the font size has been experimentally determined. - var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize); - maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.height / (2 * tickFontSize))); + var tickFontSize = getValueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize); + maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(_this.height / (2 * tickFontSize))); } // Make sure we always have at least 2 ticks @@ -182,15 +198,15 @@ module.exports = function(Chart) { // for details. var spacing; - var fixedStepSizeSet = (this.options.ticks.fixedStepSize && this.options.ticks.fixedStepSize > 0) || (this.options.ticks.stepSize && this.options.ticks.stepSize > 0); + var fixedStepSizeSet = (tickOpts.fixedStepSize && tickOpts.fixedStepSize > 0) || (tickOpts.stepSize && tickOpts.stepSize > 0); if (fixedStepSizeSet) { - spacing = helpers.getValueOrDefault(this.options.ticks.fixedStepSize, this.options.ticks.stepSize); + spacing = getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize); } else { - var niceRange = helpers.niceNum(this.max - this.min, false); + var niceRange = helpers.niceNum(_this.max - _this.min, false); spacing = helpers.niceNum(niceRange / (maxTicks - 1), true); } - var niceMin = Math.floor(this.min / spacing) * spacing; - var niceMax = Math.ceil(this.max / spacing) * spacing; + var niceMin = Math.floor(_this.min / spacing) * spacing; + var niceMax = Math.ceil(_this.max / spacing) * spacing; var numSpaces = (niceMax - niceMin) / spacing; // If very close to our rounded value, use it. @@ -201,30 +217,30 @@ module.exports = function(Chart) { } // Put the values into the ticks array - this.ticks.push(this.options.ticks.min !== undefined ? this.options.ticks.min : niceMin); + ticks.push(tickOpts.min !== undefined ? tickOpts.min : niceMin); for (var j = 1; j < numSpaces; ++j) { - this.ticks.push(niceMin + (j * spacing)); + ticks.push(niceMin + (j * spacing)); } - this.ticks.push(this.options.ticks.max !== undefined ? this.options.ticks.max : niceMax); + ticks.push(tickOpts.max !== undefined ? tickOpts.max : niceMax); - if (this.options.position === "left" || this.options.position === "right") { + if (!isHorizontal) { // We are in a vertical orientation. The top value is the highest. So reverse the array - this.ticks.reverse(); + ticks.reverse(); } // At this point, we need to update our max and min given the tick values since we have expanded the // range of the scale - this.max = helpers.max(this.ticks); - this.min = helpers.min(this.ticks); + _this.max = helpers.max(ticks); + _this.min = helpers.min(ticks); - if (this.options.ticks.reverse) { - this.ticks.reverse(); + if (tickOpts.reverse) { + ticks.reverse(); - this.start = this.max; - this.end = this.min; + _this.start = _this.max; + _this.end = _this.min; } else { - this.start = this.min; - this.end = this.max; + _this.start = _this.min; + _this.end = _this.max; } }, getLabelForIndex: function(index, datasetIndex) { From ee383ef4a68abc23353108204bf89409f4b8208d Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 8 May 2016 09:24:45 -0400 Subject: [PATCH 12/12] Logarithmic scale improvements --- src/scales/scale.logarithmic.js | 162 ++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 69 deletions(-) diff --git a/src/scales/scale.logarithmic.js b/src/scales/scale.logarithmic.js index 408318f922e..4cdc0ac3644 100644 --- a/src/scales/scale.logarithmic.js +++ b/src/scales/scale.logarithmic.js @@ -10,7 +10,7 @@ module.exports = function(Chart) { // label settings ticks: { callback: function(value, index, arr) { - var remain = value / (Math.pow(10, Math.floor(Chart.helpers.log10(value)))); + var remain = value / (Math.pow(10, Math.floor(helpers.log10(value)))); if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === arr.length - 1) { return value.toExponential(); @@ -23,99 +23,116 @@ module.exports = function(Chart) { var LogarithmicScale = Chart.Scale.extend({ determineDataLimits: function() { + var _this = this; + var opts = _this.options; + var tickOpts = opts.ticks; + var chart = _this.chart; + var data = chart.data; + var datasets = data.datasets; + var getValueOrDefault = helpers.getValueOrDefault; + var isHorizontal = _this.isHorizontal(); + function IDMatches(meta) { + return isHorizontal ? meta.xAxisID === _this.id : meta.yAxisID === _this.id; + } + // Calculate Range - this.min = null; - this.max = null; + _this.min = null; + _this.max = null; - if (this.options.stacked) { + if (opts.stacked) { var valuesPerType = {}; - helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { - var meta = this.chart.getDatasetMeta(datasetIndex); - if (this.chart.isDatasetVisible(datasetIndex) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) { + helpers.each(datasets, function(dataset, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { if (valuesPerType[meta.type] === undefined) { valuesPerType[meta.type] = []; } helpers.each(dataset.data, function(rawValue, index) { var values = valuesPerType[meta.type]; - var value = +this.getRightValue(rawValue); + var value = +_this.getRightValue(rawValue); if (isNaN(value) || meta.data[index].hidden) { return; } values[index] = values[index] || 0; - if (this.options.relativePoints) { + if (opts.relativePoints) { values[index] = 100; } else { // Don't need to split positive and negative since the log scale can't handle a 0 crossing values[index] += value; } - }, this); + }); } - }, this); + }); helpers.each(valuesPerType, function(valuesForType) { var minVal = helpers.min(valuesForType); var maxVal = helpers.max(valuesForType); - this.min = this.min === null ? minVal : Math.min(this.min, minVal); - this.max = this.max === null ? maxVal : Math.max(this.max, maxVal); - }, this); + _this.min = _this.min === null ? minVal : Math.min(_this.min, minVal); + _this.max = _this.max === null ? maxVal : Math.max(_this.max, maxVal); + }); } else { - helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { - var meta = this.chart.getDatasetMeta(datasetIndex); - if (this.chart.isDatasetVisible(datasetIndex) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) { + helpers.each(datasets, function(dataset, datasetIndex) { + var meta = chart.getDatasetMeta(datasetIndex); + if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { helpers.each(dataset.data, function(rawValue, index) { - var value = +this.getRightValue(rawValue); + var value = +_this.getRightValue(rawValue); if (isNaN(value) || meta.data[index].hidden) { return; } - if (this.min === null) { - this.min = value; - } else if (value < this.min) { - this.min = value; + if (_this.min === null) { + _this.min = value; + } else if (value < _this.min) { + _this.min = value; } - if (this.max === null) { - this.max = value; - } else if (value > this.max) { - this.max = value; + if (_this.max === null) { + _this.max = value; + } else if (value > _this.max) { + _this.max = value; } - }, this); + }); } - }, this); + }); } - this.min = this.options.ticks.min !== undefined ? this.options.ticks.min : this.min; - this.max = this.options.ticks.max !== undefined ? this.options.ticks.max : this.max; + _this.min = getValueOrDefault(tickOpts.min, _this.min); + _this.max = getValueOrDefault(tickOpts.max, _this.max); - if (this.min === this.max) { - if (this.min !== 0 && this.min !== null) { - this.min = Math.pow(10, Math.floor(helpers.log10(this.min)) - 1); - this.max = Math.pow(10, Math.floor(helpers.log10(this.max)) + 1); + if (_this.min === _this.max) { + if (_this.min !== 0 && _this.min !== null) { + _this.min = Math.pow(10, Math.floor(helpers.log10(_this.min)) - 1); + _this.max = Math.pow(10, Math.floor(helpers.log10(_this.max)) + 1); } else { - this.min = 1; - this.max = 10; + _this.min = 1; + _this.max = 10; } } }, buildTicks: function() { + var _this = this; + var opts = _this.options; + var tickOpts = opts.ticks; + var getValueOrDefault = helpers.getValueOrDefault; + // Reset the ticks array. Later on, we will draw a grid line at these positions // The array simply contains the numerical value of the spots where ticks will be - this.ticks = []; + var ticks = _this.ticks = []; // Figure out what the max number of ticks we can support it is based on the size of // the axis area. For now, we say that the minimum tick spacing in pixels must be 50 // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on // the graph - var tickVal = this.options.ticks.min !== undefined ? this.options.ticks.min : Math.pow(10, Math.floor(helpers.log10(this.min))); + var tickVal = getValueOrDefault(tickOpts.min, Math.pow(10, Math.floor(helpers.log10(_this.min)))); - while (tickVal < this.max) { - this.ticks.push(tickVal); + while (tickVal < _this.max) { + ticks.push(tickVal); var exp = Math.floor(helpers.log10(tickVal)); var significand = Math.floor(tickVal / Math.pow(10, exp)) + 1; @@ -128,27 +145,27 @@ module.exports = function(Chart) { tickVal = significand * Math.pow(10, exp); } - var lastTick = this.options.ticks.max !== undefined ? this.options.ticks.max : tickVal; - this.ticks.push(lastTick); + var lastTick = getValueOrDefault(tickOpts.max, tickVal); + ticks.push(lastTick); - if (this.options.position === "left" || this.options.position === "right") { + if (!_this.isHorizontal()) { // We are in a vertical orientation. The top value is the highest. So reverse the array - this.ticks.reverse(); + ticks.reverse(); } // At this point, we need to update our max and min given the tick values since we have expanded the // range of the scale - this.max = helpers.max(this.ticks); - this.min = helpers.min(this.ticks); + _this.max = helpers.max(ticks); + _this.min = helpers.min(ticks); - if (this.options.ticks.reverse) { - this.ticks.reverse(); + if (tickOpts.reverse) { + ticks.reverse(); - this.start = this.max; - this.end = this.min; + _this.start = _this.max; + _this.end = _this.min; } else { - this.start = this.min; - this.end = this.max; + _this.start = _this.min; + _this.end = _this.max; } }, convertTicksToLabels: function() { @@ -164,48 +181,55 @@ module.exports = function(Chart) { return this.getPixelForValue(this.tickValues[index], null, null, includeOffset); }, getPixelForValue: function(value, index, datasetIndex, includeOffset) { + var _this = this; + var innerDimension; var pixel; - var newVal = +this.getRightValue(value) -; var range = helpers.log10(this.end) - helpers.log10(this.start); + var start = _this.start; + var newVal = +_this.getRightValue(value); + var range = helpers.log10(_this.end) - helpers.log10(start); + var paddingTop = _this.paddingTop; + var paddingBottom = _this.paddingBottom; + var paddingLeft = _this.paddingLeft; - if (this.isHorizontal()) { + if (_this.isHorizontal()) { if (newVal === 0) { - pixel = this.left + this.paddingLeft; + pixel = _this.left + paddingLeft; } else { - var innerWidth = this.width - (this.paddingLeft + this.paddingRight); - pixel = this.left + (innerWidth / range * (helpers.log10(newVal) - helpers.log10(this.start))); - pixel += this.paddingLeft; + innerDimension = _this.width - (paddingLeft + _this.paddingRight); + pixel = _this.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start))); + pixel += paddingLeft; } } else { // Bottom - top since pixels increase downard on a screen if (newVal === 0) { - pixel = this.top + this.paddingTop; + pixel = _this.top + paddingTop; } else { - var innerHeight = this.height - (this.paddingTop + this.paddingBottom); - pixel = (this.bottom - this.paddingBottom) - (innerHeight / range * (helpers.log10(newVal) - helpers.log10(this.start))); + innerDimension = _this.height - (paddingTop + paddingBottom); + pixel = (_this.bottom - paddingBottom) - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start))); } } return pixel; }, getValueForPixel: function(pixel) { + var _this = this; var offset; - var range = helpers.log10(this.end) - helpers.log10(this.start); + var range = helpers.log10(_this.end) - helpers.log10(_this.start); var value; + var innerDimension; - if (this.isHorizontal()) { - var innerWidth = this.width - (this.paddingLeft + this.paddingRight); - value = this.start * Math.pow(10, (pixel - this.left - this.paddingLeft) * range / innerWidth); + if (_this.isHorizontal()) { + innerDimension = _this.width - (_this.paddingLeft + _this.paddingRight); + value = _this.start * Math.pow(10, (pixel - _this.left - _this.paddingLeft) * range / innerDimension); } else { - var innerHeight = this.height - (this.paddingTop + this.paddingBottom); - value = Math.pow(10, (this.bottom - this.paddingBottom - pixel) * range / innerHeight) / this.start; + innerDimension = _this.height - (_this.paddingTop + _this.paddingBottom); + value = Math.pow(10, (_this.bottom - _this.paddingBottom - pixel) * range / innerDimension) / _this.start; } return value; } - }); Chart.scaleService.registerScaleType("logarithmic", LogarithmicScale, defaultConfig);