From b17c452425194137bd9358d42c7a40990ee9efe1 Mon Sep 17 00:00:00 2001 From: Simon Brunel Date: Sun, 16 Jul 2017 19:38:19 +0200 Subject: [PATCH] Make `Chart.defaults/Ticks/Interaction` importable (#4512) Default options can now be accessed by importing `core/core.defaults`. The returned object acts as a singleton and is populated when importing classes that expose their own default values (meaning that importing only `code.defaults` results in an empty object). Also make `Chart.Ticks` and `Chart.Interaction` importable since existing defaults rely on these values. Add the `defaults._set` method that make easier declaring new defaults by merging given values with existing ones for a specific scope (`global`, `scale`, `bar`, etc). --- src/chart.js | 6 +- src/charts/Chart.Scatter.js | 40 -- src/controllers/controller.bar.js | 153 +++---- src/controllers/controller.bubble.js | 66 +-- src/controllers/controller.doughnut.js | 212 +++++---- src/controllers/controller.line.js | 41 +- src/controllers/controller.polarArea.js | 188 ++++---- src/controllers/controller.radar.js | 23 +- src/controllers/controller.scatter.js | 42 ++ src/core/core.animation.js | 11 +- src/core/core.controller.js | 16 +- src/core/core.defaults.js | 12 + src/core/core.helpers.js | 8 +- src/core/core.interaction.js | 555 ++++++++++++------------ src/core/core.js | 87 ++-- src/core/core.plugin.js | 10 +- src/core/core.scale.js | 102 ++--- src/core/core.scaleService.js | 13 +- src/core/core.ticks.js | 357 ++++++++------- src/core/core.tooltip.js | 29 +- src/elements/element.arc.js | 19 +- src/elements/element.line.js | 33 +- src/elements/element.point.js | 34 +- src/elements/element.rectangle.js | 22 +- src/plugins/plugin.filler.js | 24 +- src/plugins/plugin.legend.js | 37 +- src/plugins/plugin.title.js | 32 +- src/scales/scale.linear.js | 6 +- src/scales/scale.linearbase.js | 3 +- src/scales/scale.logarithmic.js | 5 +- src/scales/scale.radialLinear.js | 6 +- src/scales/scale.time.js | 3 +- 32 files changed, 1126 insertions(+), 1069 deletions(-) create mode 100644 src/controllers/controller.scatter.js create mode 100644 src/core/core.defaults.js diff --git a/src/chart.js b/src/chart.js index 9580c2387b5..146cfbaa8d3 100644 --- a/src/chart.js +++ b/src/chart.js @@ -8,7 +8,10 @@ Chart.helpers = require('./helpers/index'); // @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests! require('./core/core.helpers')(Chart); +Chart.defaults = require('./core/core.defaults'); +Chart.Interaction = require('./core/core.interaction'); Chart.platform = require('./platforms/platform'); +Chart.Ticks = require('./core/core.ticks'); require('./core/core.element')(Chart); require('./core/core.plugin')(Chart); @@ -17,9 +20,7 @@ require('./core/core.controller')(Chart); require('./core/core.datasetController')(Chart); require('./core/core.layoutService')(Chart); require('./core/core.scaleService')(Chart); -require('./core/core.ticks')(Chart); require('./core/core.scale')(Chart); -require('./core/core.interaction')(Chart); require('./core/core.tooltip')(Chart); require('./elements/element.arc')(Chart); @@ -42,6 +43,7 @@ require('./controllers/controller.doughnut')(Chart); require('./controllers/controller.line')(Chart); require('./controllers/controller.polarArea')(Chart); require('./controllers/controller.radar')(Chart); +require('./controllers/controller.scatter')(Chart); require('./charts/Chart.Bar')(Chart); require('./charts/Chart.Bubble')(Chart); diff --git a/src/charts/Chart.Scatter.js b/src/charts/Chart.Scatter.js index 7b7e67d435e..9006e571293 100644 --- a/src/charts/Chart.Scatter.js +++ b/src/charts/Chart.Scatter.js @@ -1,48 +1,8 @@ 'use strict'; module.exports = function(Chart) { - - var defaultConfig = { - hover: { - mode: 'single' - }, - - scales: { - xAxes: [{ - type: 'linear', // scatter should not use a category axis - position: 'bottom', - id: 'x-axis-1' // need an ID so datasets can reference the scale - }], - yAxes: [{ - type: 'linear', - position: 'left', - id: 'y-axis-1' - }] - }, - showLines: false, - - tooltips: { - callbacks: { - title: function() { - // Title doesn't make sense for scatter since we format the data as a point - return ''; - }, - label: function(tooltipItem) { - return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')'; - } - } - } - }; - - // Register the default config for this type - Chart.defaults.scatter = defaultConfig; - - // Scatter charts use line controllers - Chart.controllers.scatter = Chart.controllers.line; - Chart.Scatter = function(context, config) { config.type = 'scatter'; return new Chart(context, config); }; - }; diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 93d285323c3..97a077e66d5 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -1,32 +1,91 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { +defaults._set('bar', { + hover: { + mode: 'label' + }, - Chart.defaults.bar = { - hover: { - mode: 'label' - }, + scales: { + xAxes: [{ + type: 'category', - scales: { - xAxes: [{ - type: 'category', + // Specific to Bar Controller + categoryPercentage: 0.8, + barPercentage: 0.9, - // Specific to Bar Controller - categoryPercentage: 0.8, - barPercentage: 0.9, + // grid line settings + gridLines: { + offsetGridLines: true + } + }], + + yAxes: [{ + type: 'linear' + }] + } +}); + +defaults._set('horizontalBar', { + hover: { + mode: 'label' + }, + + scales: { + xAxes: [{ + type: 'linear', + position: 'bottom' + }], + + yAxes: [{ + position: 'left', + type: 'category', + + // Specific to Horizontal Bar Controller + categoryPercentage: 0.8, + barPercentage: 0.9, + + // grid line settings + gridLines: { + offsetGridLines: true + } + }] + }, - // grid line settings - gridLines: { - offsetGridLines: true + elements: { + rectangle: { + borderSkipped: 'left' + } + }, + + tooltips: { + callbacks: { + title: function(item, data) { + // Pick first xLabel for now + var title = ''; + + if (item.length > 0) { + if (item[0].yLabel) { + title = item[0].yLabel; + } else if (data.labels.length > 0 && item[0].index < data.labels.length) { + title = data.labels[item[0].index]; + } } - }], - yAxes: [{ - type: 'linear' - }] + + return title; + }, + + label: function(item, data) { + var datasetLabel = data.datasets[item.datasetIndex].label || ''; + return datasetLabel + ': ' + item.xLabel; + } } - }; + } +}); + +module.exports = function(Chart) { Chart.controllers.bar = Chart.DatasetController.extend({ @@ -309,62 +368,6 @@ module.exports = function(Chart) { } }); - - // including horizontalBar in the bar file, instead of a file of its own - // it extends bar (like pie extends doughnut) - Chart.defaults.horizontalBar = { - hover: { - mode: 'label' - }, - - scales: { - xAxes: [{ - type: 'linear', - position: 'bottom' - }], - yAxes: [{ - position: 'left', - type: 'category', - - // Specific to Horizontal Bar Controller - categoryPercentage: 0.8, - barPercentage: 0.9, - - // grid line settings - gridLines: { - offsetGridLines: true - } - }] - }, - elements: { - rectangle: { - borderSkipped: 'left' - } - }, - tooltips: { - callbacks: { - title: function(tooltipItems, data) { - // Pick first xLabel for now - var title = ''; - - if (tooltipItems.length > 0) { - if (tooltipItems[0].yLabel) { - title = tooltipItems[0].yLabel; - } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) { - title = data.labels[tooltipItems[0].index]; - } - } - - return title; - }, - label: function(tooltipItem, data) { - var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || ''; - return datasetLabel + ': ' + tooltipItem.xLabel; - } - } - } - }; - Chart.controllers.horizontalBar = Chart.controllers.bar.extend({ /** * @private diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index b91b15f1277..6d410114ec2 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -1,41 +1,43 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - Chart.defaults.bubble = { - hover: { - mode: 'single' - }, - - scales: { - xAxes: [{ - type: 'linear', // bubble should probably use a linear scale by default - position: 'bottom', - id: 'x-axis-0' // need an ID so datasets can reference the scale - }], - yAxes: [{ - type: 'linear', - position: 'left', - id: 'y-axis-0' - }] - }, - - tooltips: { - callbacks: { - title: function() { - // Title doesn't make sense for scatter since we format the data as a point - return ''; - }, - label: function(tooltipItem, data) { - var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || ''; - var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; - return datasetLabel + ': (' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ', ' + dataPoint.r + ')'; - } +defaults._set('bubble', { + hover: { + mode: 'single' + }, + + scales: { + xAxes: [{ + type: 'linear', // bubble should probably use a linear scale by default + position: 'bottom', + id: 'x-axis-0' // need an ID so datasets can reference the scale + }], + yAxes: [{ + type: 'linear', + position: 'left', + id: 'y-axis-0' + }] + }, + + tooltips: { + callbacks: { + title: function() { + // Title doesn't make sense for scatter since we format the data as a point + return ''; + }, + label: function(item, data) { + var datasetLabel = data.datasets[item.datasetIndex].label || ''; + var dataPoint = data.datasets[item.datasetIndex].data[item.index]; + return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')'; } } - }; + } +}); + + +module.exports = function(Chart) { Chart.controllers.bubble = Chart.DatasetController.extend({ diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index c87c59bbcb0..ffbf22a66cc 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -1,130 +1,128 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - var defaults = Chart.defaults; - - defaults.doughnut = { - animation: { - // Boolean - Whether we animate the rotation of the Doughnut - animateRotate: true, - // Boolean - Whether we animate scaling the Doughnut from the centre - animateScale: false - }, - hover: { - mode: 'single' - }, - legendCallback: function(chart) { - var text = []; - text.push(''); + return text.join(''); + }, + legend: { + labels: { + generateLabels: function(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i]; + var custom = arc && arc.custom || {}; + var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; + var arcOpts = chart.options.elements.arc; + var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); + var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); + var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); + + return { + text: label, + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, + + // Extra data used for toggling the correct item + index: i + }; + }); } - }, + return []; + } + }, - onClick: function(e, legendItem) { - var index = legendItem.index; - var chart = this.chart; - var i, ilen, meta; - - for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { - meta = chart.getDatasetMeta(i); - // toggle visibility of index if exists - if (meta.data[index]) { - meta.data[index].hidden = !meta.data[index].hidden; - } - } + onClick: function(e, legendItem) { + var index = legendItem.index; + var chart = this.chart; + var i, ilen, meta; - chart.update(); + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + // toggle visibility of index if exists + if (meta.data[index]) { + meta.data[index].hidden = !meta.data[index].hidden; + } } - }, - // The percentage of the chart that we cut out of the middle. - cutoutPercentage: 50, + chart.update(); + } + }, - // The rotation of the chart, where the first data arc begins. - rotation: Math.PI * -0.5, + // The percentage of the chart that we cut out of the middle. + cutoutPercentage: 50, - // The total circumference of the chart. - circumference: Math.PI * 2.0, + // The rotation of the chart, where the first data arc begins. + rotation: Math.PI * -0.5, - // Need to override these to give a nice default - tooltips: { - callbacks: { - title: function() { - return ''; - }, - label: function(tooltipItem, data) { - var dataLabel = data.labels[tooltipItem.index]; - var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; - - if (helpers.isArray(dataLabel)) { - // show value on first line of multiline label - // need to clone because we are changing the value - dataLabel = dataLabel.slice(); - dataLabel[0] += value; - } else { - dataLabel += value; - } - - return dataLabel; + // The total circumference of the chart. + circumference: Math.PI * 2.0, + + // Need to override these to give a nice default + tooltips: { + callbacks: { + title: function() { + return ''; + }, + label: function(tooltipItem, data) { + var dataLabel = data.labels[tooltipItem.index]; + var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index]; + + if (helpers.isArray(dataLabel)) { + // show value on first line of multiline label + // need to clone because we are changing the value + dataLabel = dataLabel.slice(); + dataLabel[0] += value; + } else { + dataLabel += value; } + + return dataLabel; } } - }; + } +}); - defaults.pie = helpers.clone(defaults.doughnut); - helpers.extend(defaults.pie, { - cutoutPercentage: 0 - }); +defaults._set('pie', helpers.clone(defaults.doughnut)); +defaults._set('pie', { + cutoutPercentage: 0 +}); +module.exports = function(Chart) { Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({ diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index c31e73f23d4..d841ada64dc 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -1,28 +1,29 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - Chart.defaults.line = { - showLines: true, - spanGaps: false, - - hover: { - mode: 'label' - }, +defaults._set('line', { + showLines: true, + spanGaps: false, + + hover: { + mode: 'label' + }, + + scales: { + xAxes: [{ + type: 'category', + id: 'x-axis-0' + }], + yAxes: [{ + type: 'linear', + id: 'y-axis-0' + }] + } +}); - scales: { - xAxes: [{ - type: 'category', - id: 'x-axis-0' - }], - yAxes: [{ - type: 'linear', - id: 'y-axis-0' - }] - } - }; +module.exports = function(Chart) { function lineEnabled(dataset, options) { return helpers.valueOrDefault(dataset.showLine, options.showLines); diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index bf2cd6b41bf..c0ac2993e38 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -1,113 +1,113 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - Chart.defaults.polarArea = { - - scale: { - type: 'radialLinear', - angleLines: { - display: false - }, - gridLines: { - circular: true - }, - pointLabels: { - display: false - }, - ticks: { - beginAtZero: true - } +defaults._set('polarArea', { + scale: { + type: 'radialLinear', + angleLines: { + display: false }, - - // Boolean - Whether to animate the rotation of the chart - animation: { - animateRotate: true, - animateScale: true + gridLines: { + circular: true }, - - startAngle: -0.5 * Math.PI, - legendCallback: function(chart) { - var text = []; - text.push(''); + return text.join(''); + }, + legend: { + labels: { + generateLabels: function(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i]; + var custom = arc.custom || {}; + var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; + var arcOpts = chart.options.elements.arc; + var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); + var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); + var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); + + return { + text: label, + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, + + // Extra data used for toggling the correct item + index: i + }; + }); } - }, - - onClick: function(e, legendItem) { - var index = legendItem.index; - var chart = this.chart; - var i, ilen, meta; + return []; + } + }, - for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { - meta = chart.getDatasetMeta(i); - meta.data[index].hidden = !meta.data[index].hidden; - } + onClick: function(e, legendItem) { + var index = legendItem.index; + var chart = this.chart; + var i, ilen, meta; - chart.update(); + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + meta.data[index].hidden = !meta.data[index].hidden; } - }, - // Need to override these to give a nice default - tooltips: { - callbacks: { - title: function() { - return ''; - }, - label: function(tooltipItem, data) { - return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel; - } + chart.update(); + } + }, + + // Need to override these to give a nice default + tooltips: { + callbacks: { + title: function() { + return ''; + }, + label: function(item, data) { + return data.labels[item.index] + ': ' + item.yLabel; } } - }; + } +}); + +module.exports = function(Chart) { Chart.controllers.polarArea = Chart.DatasetController.extend({ diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index 24c83b46318..b3bccdca970 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -1,19 +1,20 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - Chart.defaults.radar = { - scale: { - type: 'radialLinear' - }, - elements: { - line: { - tension: 0 // no bezier in radar - } +defaults._set('radar', { + scale: { + type: 'radialLinear' + }, + elements: { + line: { + tension: 0 // no bezier in radar } - }; + } +}); + +module.exports = function(Chart) { Chart.controllers.radar = Chart.DatasetController.extend({ diff --git a/src/controllers/controller.scatter.js b/src/controllers/controller.scatter.js new file mode 100644 index 00000000000..b2e2cf1f7e1 --- /dev/null +++ b/src/controllers/controller.scatter.js @@ -0,0 +1,42 @@ +'use strict'; + +var defaults = require('../core/core.defaults'); + +defaults._set('scatter', { + hover: { + mode: 'single' + }, + + scales: { + xAxes: [{ + id: 'x-axis-1', // need an ID so datasets can reference the scale + type: 'linear', // scatter should not use a category axis + position: 'bottom' + }], + yAxes: [{ + id: 'y-axis-1', + type: 'linear', + position: 'left' + }] + }, + + showLines: false, + + tooltips: { + callbacks: { + title: function() { + return ''; // doesn't make sense for scatter since data are formatted as a point + }, + label: function(item) { + return '(' + item.xLabel + ', ' + item.yLabel + ')'; + } + } + } +}); + +module.exports = function(Chart) { + + // Scatter charts use line controllers + Chart.controllers.scatter = Chart.controllers.line; + +}; diff --git a/src/core/core.animation.js b/src/core/core.animation.js index 40208916a66..bbd44cde18e 100644 --- a/src/core/core.animation.js +++ b/src/core/core.animation.js @@ -1,16 +1,19 @@ /* global window: false */ 'use strict'; +var defaults = require('./core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - Chart.defaults.global.animation = { +defaults._set('global', { + animation: { duration: 1000, easing: 'easeOutQuart', onProgress: helpers.noop, onComplete: helpers.noop - }; + } +}); + +module.exports = function(Chart) { Chart.Animation = Chart.Element.extend({ chart: null, // the animation associated chart instance diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 4a86d70d2fb..2033c542549 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -1,6 +1,8 @@ 'use strict'; +var defaults = require('./core.defaults'); var helpers = require('../helpers/index'); +var Interaction = require('./core.interaction'); var platform = require('../platforms/platform'); module.exports = function(Chart) { @@ -29,8 +31,8 @@ module.exports = function(Chart) { data.labels = data.labels || []; config.options = helpers.configMerge( - Chart.defaults.global, - Chart.defaults[config.type], + defaults.global, + defaults[config.type], config.options || {}); return config; @@ -601,19 +603,19 @@ module.exports = function(Chart) { // Get the single element that was clicked on // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw getElementAtEvent: function(e) { - return Chart.Interaction.modes.single(this, e); + return Interaction.modes.single(this, e); }, getElementsAtEvent: function(e) { - return Chart.Interaction.modes.label(this, e, {intersect: true}); + return Interaction.modes.label(this, e, {intersect: true}); }, getElementsAtXAxis: function(e) { - return Chart.Interaction.modes['x-axis'](this, e, {intersect: true}); + return Interaction.modes['x-axis'](this, e, {intersect: true}); }, getElementsAtEventForMode: function(e, mode, options) { - var method = Chart.Interaction.modes[mode]; + var method = Interaction.modes[mode]; if (typeof method === 'function') { return method(this, e, options); } @@ -622,7 +624,7 @@ module.exports = function(Chart) { }, getDatasetAtEvent: function(e) { - return Chart.Interaction.modes.dataset(this, e, {intersect: true}); + return Interaction.modes.dataset(this, e, {intersect: true}); }, getDatasetMeta: function(datasetIndex) { diff --git a/src/core/core.defaults.js b/src/core/core.defaults.js new file mode 100644 index 00000000000..29bb040d4f0 --- /dev/null +++ b/src/core/core.defaults.js @@ -0,0 +1,12 @@ +'use strict'; + +var helpers = require('../helpers/index'); + +module.exports = { + /** + * @private + */ + _set: function(scope, values) { + return helpers.merge(this[scope] || (this[scope] = {}), values); + } +}; diff --git a/src/core/core.helpers.js b/src/core/core.helpers.js index 8896e232aad..90e116d2cee 100644 --- a/src/core/core.helpers.js +++ b/src/core/core.helpers.js @@ -3,6 +3,7 @@ 'use strict'; var color = require('chartjs-color'); +var defaults = require('./core.defaults'); var helpers = require('../helpers/index'); module.exports = function(Chart) { @@ -43,7 +44,7 @@ module.exports = function(Chart) { merger: function(key, target, source, options) { if (key === 'xAxes' || key === 'yAxes') { var slen = source[key].length; - var i, type, scale, defaults; + var i, type, scale; if (!target[key]) { target[key] = []; @@ -52,7 +53,6 @@ module.exports = function(Chart) { for (i = 0; i < slen; ++i) { scale = source[key][i]; type = helpers.valueOrDefault(scale.type, key === 'xAxes'? 'category' : 'linear'); - defaults = Chart.scaleService.getScaleDefaults(type); if (i >= target[key].length) { target[key].push({}); @@ -61,7 +61,7 @@ module.exports = function(Chart) { if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) { // new/untyped scale or type changed: let's apply the new defaults // then merge source scale to correctly overwrite the defaults. - helpers.merge(target[key][i], [defaults, scale]); + helpers.merge(target[key][i], [Chart.scaleService.getScaleDefaults(type), scale]); } else { // scales type are the same helpers.merge(target[key][i], scale); @@ -612,7 +612,7 @@ module.exports = function(Chart) { function(value) { /* global CanvasGradient */ if (value instanceof CanvasGradient) { - value = Chart.defaults.global.defaultColor; + value = defaults.global.defaultColor; } return color(value); diff --git a/src/core/core.interaction.js b/src/core/core.interaction.js index 6e35bd950e8..793468d43fb 100644 --- a/src/core/core.interaction.js +++ b/src/core/core.interaction.js @@ -2,316 +2,313 @@ var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - /** - * Helper function to get relative position for an event - * @param {Event|IEvent} event - The event to get the position for - * @param {Chart} chart - The chart - * @returns {Point} the event position - */ - function getRelativePosition(e, chart) { - if (e.native) { - return { - x: e.x, - y: e.y - }; - } - - return helpers.getRelativePosition(e, chart); +/** + * Helper function to get relative position for an event + * @param {Event|IEvent} event - The event to get the position for + * @param {Chart} chart - The chart + * @returns {Point} the event position + */ +function getRelativePosition(e, chart) { + if (e.native) { + return { + x: e.x, + y: e.y + }; } - /** - * Helper function to traverse all of the visible elements in the chart - * @param chart {chart} the chart - * @param handler {Function} the callback to execute for each visible item - */ - function parseVisibleItems(chart, handler) { - var datasets = chart.data.datasets; - var meta, i, j, ilen, jlen; - - for (i = 0, ilen = datasets.length; i < ilen; ++i) { - if (!chart.isDatasetVisible(i)) { - continue; - } + return helpers.getRelativePosition(e, chart); +} + +/** + * Helper function to traverse all of the visible elements in the chart + * @param chart {chart} the chart + * @param handler {Function} the callback to execute for each visible item + */ +function parseVisibleItems(chart, handler) { + var datasets = chart.data.datasets; + var meta, i, j, ilen, jlen; + + for (i = 0, ilen = datasets.length; i < ilen; ++i) { + if (!chart.isDatasetVisible(i)) { + continue; + } - meta = chart.getDatasetMeta(i); - for (j = 0, jlen = meta.data.length; j < jlen; ++j) { - var element = meta.data[j]; - if (!element._view.skip) { - handler(element); - } + meta = chart.getDatasetMeta(i); + for (j = 0, jlen = meta.data.length; j < jlen; ++j) { + var element = meta.data[j]; + if (!element._view.skip) { + handler(element); } } } - - /** - * Helper function to get the items that intersect the event position - * @param items {ChartElement[]} elements to filter - * @param position {Point} the point to be nearest to - * @return {ChartElement[]} the nearest items - */ - function getIntersectItems(chart, position) { - var elements = []; - - parseVisibleItems(chart, function(element) { - if (element.inRange(position.x, position.y)) { - elements.push(element); - } - }); - - return elements; +} + +/** + * Helper function to get the items that intersect the event position + * @param items {ChartElement[]} elements to filter + * @param position {Point} the point to be nearest to + * @return {ChartElement[]} the nearest items + */ +function getIntersectItems(chart, position) { + var elements = []; + + parseVisibleItems(chart, function(element) { + if (element.inRange(position.x, position.y)) { + elements.push(element); + } + }); + + return elements; +} + +/** + * Helper function to get the items nearest to the event position considering all visible items in teh chart + * @param chart {Chart} the chart to look at elements from + * @param position {Point} the point to be nearest to + * @param intersect {Boolean} if true, only consider items that intersect the position + * @param distanceMetric {Function} Optional function to provide the distance between + * @return {ChartElement[]} the nearest items + */ +function getNearestItems(chart, position, intersect, distanceMetric) { + var minDistance = Number.POSITIVE_INFINITY; + var nearestItems = []; + + if (!distanceMetric) { + distanceMetric = helpers.distanceBetweenPoints; } - /** - * Helper function to get the items nearest to the event position considering all visible items in teh chart - * @param chart {Chart} the chart to look at elements from - * @param position {Point} the point to be nearest to - * @param intersect {Boolean} if true, only consider items that intersect the position - * @param distanceMetric {Function} Optional function to provide the distance between - * @return {ChartElement[]} the nearest items - */ - function getNearestItems(chart, position, intersect, distanceMetric) { - var minDistance = Number.POSITIVE_INFINITY; - var nearestItems = []; - - if (!distanceMetric) { - distanceMetric = helpers.distanceBetweenPoints; + parseVisibleItems(chart, function(element) { + if (intersect && !element.inRange(position.x, position.y)) { + return; } - parseVisibleItems(chart, function(element) { - if (intersect && !element.inRange(position.x, position.y)) { - return; - } + var center = element.getCenterPoint(); + var distance = distanceMetric(position, center); - var center = element.getCenterPoint(); - var distance = distanceMetric(position, center); + if (distance < minDistance) { + nearestItems = [element]; + minDistance = distance; + } else if (distance === minDistance) { + // Can have multiple items at the same distance in which case we sort by size + nearestItems.push(element); + } + }); - if (distance < minDistance) { - nearestItems = [element]; - minDistance = distance; - } else if (distance === minDistance) { - // Can have multiple items at the same distance in which case we sort by size - nearestItems.push(element); - } - }); + return nearestItems; +} - return nearestItems; +function indexMode(chart, e, options) { + var position = getRelativePosition(e, chart); + var distanceMetric = function(pt1, pt2) { + return Math.abs(pt1.x - pt2.x); + }; + var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); + var elements = []; + + if (!items.length) { + return []; } - function indexMode(chart, e, options) { - var position = getRelativePosition(e, chart); - var distanceMetric = function(pt1, pt2) { - return Math.abs(pt1.x - pt2.x); - }; - var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric); - var elements = []; + chart.data.datasets.forEach(function(dataset, datasetIndex) { + if (chart.isDatasetVisible(datasetIndex)) { + var meta = chart.getDatasetMeta(datasetIndex), + element = meta.data[items[0]._index]; - if (!items.length) { - return []; + // don't count items that are skipped (null data) + if (element && !element._view.skip) { + elements.push(element); + } } - - chart.data.datasets.forEach(function(dataset, datasetIndex) { - if (chart.isDatasetVisible(datasetIndex)) { - var meta = chart.getDatasetMeta(datasetIndex), - element = meta.data[items[0]._index]; - - // don't count items that are skipped (null data) - if (element && !element._view.skip) { + }); + + return elements; +} + +/** + * @interface IInteractionOptions + */ +/** + * If true, only consider items that intersect the point + * @name IInterfaceOptions#boolean + * @type Boolean + */ + +/** + * Contains interaction related functions + * @namespace Chart.Interaction + */ +module.exports = { + // Helper function for different modes + modes: { + single: function(chart, e) { + var position = getRelativePosition(e, chart); + var elements = []; + + parseVisibleItems(chart, function(element) { + if (element.inRange(position.x, position.y)) { elements.push(element); + return elements; } + }); + + return elements.slice(0, 1); + }, + + /** + * @function Chart.Interaction.modes.label + * @deprecated since version 2.4.0 + * @todo remove at version 3 + * @private + */ + label: indexMode, + + /** + * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something + * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item + * @function Chart.Interaction.modes.index + * @since v2.4.0 + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use during interaction + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + index: indexMode, + + /** + * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something + * If the options.intersect is false, we find the nearest item and return the items in that dataset + * @function Chart.Interaction.modes.dataset + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use during interaction + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + dataset: function(chart, e, options) { + var position = getRelativePosition(e, chart); + var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false); + + if (items.length > 0) { + items = chart.getDatasetMeta(items[0]._datasetIndex).data; } - }); - return elements; - } - - /** - * @interface IInteractionOptions - */ - /** - * If true, only consider items that intersect the point - * @name IInterfaceOptions#boolean - * @type Boolean - */ - - /** - * Contains interaction related functions - * @namespace Chart.Interaction - */ - Chart.Interaction = { - // Helper function for different modes - modes: { - single: function(chart, e) { - var position = getRelativePosition(e, chart); - var elements = []; - - parseVisibleItems(chart, function(element) { - if (element.inRange(position.x, position.y)) { - elements.push(element); - return elements; + return items; + }, + + /** + * @function Chart.Interaction.modes.x-axis + * @deprecated since version 2.4.0. Use index mode and intersect == true + * @todo remove at version 3 + * @private + */ + 'x-axis': function(chart, e) { + return indexMode(chart, e, true); + }, + + /** + * Point mode returns all elements that hit test based on the event position + * of the event + * @function Chart.Interaction.modes.intersect + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + point: function(chart, e) { + var position = getRelativePosition(e, chart); + return getIntersectItems(chart, position); + }, + + /** + * nearest mode returns the element closest to the point + * @function Chart.Interaction.modes.intersect + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + nearest: function(chart, e, options) { + var position = getRelativePosition(e, chart); + var nearestItems = getNearestItems(chart, position, options.intersect); + + // We have multiple items at the same distance from the event. Now sort by smallest + if (nearestItems.length > 1) { + nearestItems.sort(function(a, b) { + var sizeA = a.getArea(); + var sizeB = b.getArea(); + var ret = sizeA - sizeB; + + if (ret === 0) { + // if equal sort by dataset index + ret = a._datasetIndex - b._datasetIndex; } + + return ret; }); + } - return elements.slice(0, 1); - }, - - /** - * @function Chart.Interaction.modes.label - * @deprecated since version 2.4.0 - * @todo remove at version 3 - * @private - */ - label: indexMode, - - /** - * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something - * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item - * @function Chart.Interaction.modes.index - * @since v2.4.0 - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use during interaction - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - index: indexMode, - - /** - * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something - * If the options.intersect is false, we find the nearest item and return the items in that dataset - * @function Chart.Interaction.modes.dataset - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use during interaction - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - dataset: function(chart, e, options) { - var position = getRelativePosition(e, chart); - var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false); - - if (items.length > 0) { - items = chart.getDatasetMeta(items[0]._datasetIndex).data; + // Return only 1 item + return nearestItems.slice(0, 1); + }, + + /** + * x mode returns the elements that hit-test at the current x coordinate + * @function Chart.Interaction.modes.x + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + x: function(chart, e, options) { + var position = getRelativePosition(e, chart); + var items = []; + var intersectsItem = false; + + parseVisibleItems(chart, function(element) { + if (element.inXRange(position.x)) { + items.push(element); } - return items; - }, - - /** - * @function Chart.Interaction.modes.x-axis - * @deprecated since version 2.4.0. Use index mode and intersect == true - * @todo remove at version 3 - * @private - */ - 'x-axis': function(chart, e) { - return indexMode(chart, e, true); - }, - - /** - * Point mode returns all elements that hit test based on the event position - * of the event - * @function Chart.Interaction.modes.intersect - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - point: function(chart, e) { - var position = getRelativePosition(e, chart); - return getIntersectItems(chart, position); - }, - - /** - * nearest mode returns the element closest to the point - * @function Chart.Interaction.modes.intersect - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - nearest: function(chart, e, options) { - var position = getRelativePosition(e, chart); - var nearestItems = getNearestItems(chart, position, options.intersect); - - // We have multiple items at the same distance from the event. Now sort by smallest - if (nearestItems.length > 1) { - nearestItems.sort(function(a, b) { - var sizeA = a.getArea(); - var sizeB = b.getArea(); - var ret = sizeA - sizeB; - - if (ret === 0) { - // if equal sort by dataset index - ret = a._datasetIndex - b._datasetIndex; - } - - return ret; - }); + if (element.inRange(position.x, position.y)) { + intersectsItem = true; } + }); - // Return only 1 item - return nearestItems.slice(0, 1); - }, - - /** - * x mode returns the elements that hit-test at the current x coordinate - * @function Chart.Interaction.modes.x - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - x: function(chart, e, options) { - var position = getRelativePosition(e, chart); - var items = []; - var intersectsItem = false; - - parseVisibleItems(chart, function(element) { - if (element.inXRange(position.x)) { - items.push(element); - } - - if (element.inRange(position.x, position.y)) { - intersectsItem = true; - } - }); - - // If we want to trigger on an intersect and we don't have any items - // that intersect the position, return nothing - if (options.intersect && !intersectsItem) { - items = []; + // If we want to trigger on an intersect and we don't have any items + // that intersect the position, return nothing + if (options.intersect && !intersectsItem) { + items = []; + } + return items; + }, + + /** + * y mode returns the elements that hit-test at the current y coordinate + * @function Chart.Interaction.modes.y + * @param chart {chart} the chart we are returning items from + * @param e {Event} the event we are find things at + * @param options {IInteractionOptions} options to use + * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned + */ + y: function(chart, e, options) { + var position = getRelativePosition(e, chart); + var items = []; + var intersectsItem = false; + + parseVisibleItems(chart, function(element) { + if (element.inYRange(position.y)) { + items.push(element); } - return items; - }, - - /** - * y mode returns the elements that hit-test at the current y coordinate - * @function Chart.Interaction.modes.y - * @param chart {chart} the chart we are returning items from - * @param e {Event} the event we are find things at - * @param options {IInteractionOptions} options to use - * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned - */ - y: function(chart, e, options) { - var position = getRelativePosition(e, chart); - var items = []; - var intersectsItem = false; - - parseVisibleItems(chart, function(element) { - if (element.inYRange(position.y)) { - items.push(element); - } - if (element.inRange(position.x, position.y)) { - intersectsItem = true; - } - }); - - // If we want to trigger on an intersect and we don't have any items - // that intersect the position, return nothing - if (options.intersect && !intersectsItem) { - items = []; + if (element.inRange(position.x, position.y)) { + intersectsItem = true; } - return items; + }); + + // If we want to trigger on an intersect and we don't have any items + // that intersect the position, return nothing + if (options.intersect && !intersectsItem) { + items = []; } + return items; } - }; + } }; diff --git a/src/core/core.js b/src/core/core.js index afb51c71d65..906b897c699 100644 --- a/src/core/core.js +++ b/src/core/core.js @@ -1,5 +1,40 @@ 'use strict'; +var defaults = require('./core.defaults'); + +defaults._set('global', { + responsive: true, + responsiveAnimationDuration: 0, + maintainAspectRatio: true, + events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'], + hover: { + onHover: null, + mode: 'nearest', + intersect: true, + animationDuration: 400 + }, + onClick: null, + defaultColor: 'rgba(0,0,0,0.1)', + defaultFontColor: '#666', + defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + defaultFontSize: 12, + defaultFontStyle: 'normal', + showLines: true, + + // Element defaults defined in element extensions + elements: {}, + + // Layout options such as padding + layout: { + padding: { + top: 0, + right: 0, + bottom: 0, + left: 0 + } + } +}); + module.exports = function() { // Occupy the global variable of Chart, and create a simple base class @@ -8,58 +43,6 @@ module.exports = function() { return this; }; - // Globally expose the defaults to allow for user updating/changing - Chart.defaults = { - global: { - responsive: true, - responsiveAnimationDuration: 0, - maintainAspectRatio: true, - events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'], - hover: { - onHover: null, - mode: 'nearest', - intersect: true, - animationDuration: 400 - }, - onClick: null, - defaultColor: 'rgba(0,0,0,0.1)', - defaultFontColor: '#666', - defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - defaultFontSize: 12, - defaultFontStyle: 'normal', - showLines: true, - - // Element defaults defined in element extensions - elements: {}, - - // Layout options such as padding - layout: { - padding: { - top: 0, - right: 0, - bottom: 0, - left: 0 - } - }, - - // Legend callback string - legendCallback: function(chart) { - var text = []; - text.push(''); - - return text.join(''); - } - } - }; - Chart.Chart = Chart; return Chart; diff --git a/src/core/core.plugin.js b/src/core/core.plugin.js index 92761158033..2c472ce0da4 100644 --- a/src/core/core.plugin.js +++ b/src/core/core.plugin.js @@ -1,10 +1,13 @@ 'use strict'; +var defaults = require('./core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { +defaults._set('global', { + plugins: {} +}); - Chart.defaults.global.plugins = {}; +module.exports = function(Chart) { /** * The plugin service singleton @@ -128,7 +131,6 @@ module.exports = function(Chart) { var plugins = []; var descriptors = []; var config = (chart && chart.config) || {}; - var defaults = Chart.defaults.global.plugins; var options = (config.options && config.options.plugins) || {}; this._plugins.concat(config.plugins || []).forEach(function(plugin) { @@ -144,7 +146,7 @@ module.exports = function(Chart) { } if (opts === true) { - opts = helpers.clone(defaults[id]); + opts = helpers.clone(defaults.global.plugins[id]); } plugins.push(plugin); diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 38d1d10ac5a..9626c3f0e6c 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -1,58 +1,60 @@ 'use strict'; +var defaults = require('./core.defaults'); var helpers = require('../helpers/index'); +var Ticks = require('./core.ticks'); -module.exports = function(Chart) { +defaults._set('scale', { + display: true, + position: 'left', - Chart.defaults.scale = { + // grid line settings + gridLines: { display: true, - position: 'left', - - // grid line settings - gridLines: { - display: true, - color: 'rgba(0, 0, 0, 0.1)', - lineWidth: 1, - drawBorder: true, - drawOnChartArea: true, - drawTicks: true, - tickMarkLength: 10, - zeroLineWidth: 1, - zeroLineColor: 'rgba(0,0,0,0.25)', - zeroLineBorderDash: [], - zeroLineBorderDashOffset: 0.0, - offsetGridLines: false, - borderDash: [], - borderDashOffset: 0.0 - }, - - // scale label - scaleLabel: { - // actual label - labelString: '', - - // display property - display: false, - }, + color: 'rgba(0, 0, 0, 0.1)', + lineWidth: 1, + drawBorder: true, + drawOnChartArea: true, + drawTicks: true, + tickMarkLength: 10, + zeroLineWidth: 1, + zeroLineColor: 'rgba(0,0,0,0.25)', + zeroLineBorderDash: [], + zeroLineBorderDashOffset: 0.0, + offsetGridLines: false, + borderDash: [], + borderDashOffset: 0.0 + }, + + // scale label + scaleLabel: { + // actual label + labelString: '', + + // display property + display: false, + }, + + // label settings + ticks: { + beginAtZero: false, + minRotation: 0, + maxRotation: 50, + mirror: false, + padding: 0, + reverse: false, + display: true, + autoSkip: true, + autoSkipPadding: 0, + labelOffset: 0, + // We pass through arrays to be rendered as multiline labels, we convert Others to strings here. + callback: Ticks.formatters.values, + minor: {}, + major: {} + } +}); - // label settings - ticks: { - beginAtZero: false, - minRotation: 0, - maxRotation: 50, - mirror: false, - padding: 0, - reverse: false, - display: true, - autoSkip: true, - autoSkipPadding: 0, - labelOffset: 0, - // We pass through arrays to be rendered as multiline labels, we convert Others to strings here. - callback: Chart.Ticks.formatters.values, - minor: {}, - major: {} - } - }; +module.exports = function(Chart) { function computeTextSize(context, tick, font) { return helpers.isArray(tick) ? @@ -62,7 +64,7 @@ module.exports = function(Chart) { function parseFontOptions(options) { var valueOrDefault = helpers.valueOrDefault; - var globalDefaults = Chart.defaults.global; + var globalDefaults = defaults.global; var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize); var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle); var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily); @@ -511,7 +513,7 @@ module.exports = function(Chart) { } var context = me.ctx; - var globalDefaults = Chart.defaults.global; + var globalDefaults = defaults.global; var optionTicks = options.ticks.minor; var optionMajorTicks = options.ticks.major || optionTicks; var gridLines = options.gridLines; diff --git a/src/core/core.scaleService.js b/src/core/core.scaleService.js index e903b701b08..23cabe610d2 100644 --- a/src/core/core.scaleService.js +++ b/src/core/core.scaleService.js @@ -1,5 +1,6 @@ 'use strict'; +var defaults = require('./core.defaults'); var helpers = require('../helpers/index'); module.exports = function(Chart) { @@ -13,21 +14,21 @@ module.exports = function(Chart) { // Scale config defaults defaults: {}, - registerScaleType: function(type, scaleConstructor, defaults) { + registerScaleType: function(type, scaleConstructor, scaleDefaults) { this.constructors[type] = scaleConstructor; - this.defaults[type] = helpers.clone(defaults); + this.defaults[type] = helpers.clone(scaleDefaults); }, getScaleConstructor: function(type) { return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined; }, getScaleDefaults: function(type) { // Return the scale defaults merged with the global settings so that we always use the latest ones - return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [Chart.defaults.scale, this.defaults[type]]) : {}; + return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [defaults.scale, this.defaults[type]]) : {}; }, updateScaleDefaults: function(type, additions) { - var defaults = this.defaults; - if (defaults.hasOwnProperty(type)) { - defaults[type] = helpers.extend(defaults[type], additions); + var me = this; + if (me.defaults.hasOwnProperty(type)) { + me.defaults[type] = helpers.extend(me.defaults[type], additions); } }, addScalesToLayout: function(chart) { diff --git a/src/core/core.ticks.js b/src/core/core.ticks.js index a3b721164ba..11f44142c47 100644 --- a/src/core/core.ticks.js +++ b/src/core/core.ticks.js @@ -2,209 +2,206 @@ var helpers = require('../helpers/index'); -module.exports = function(Chart) { - +/** + * Namespace to hold static tick generation functions + * @namespace Chart.Ticks + */ +module.exports = { /** - * Namespace to hold static tick generation functions - * @namespace Chart.Ticks + * Namespace to hold generators for different types of ticks + * @namespace Chart.Ticks.generators */ - Chart.Ticks = { + generators: { /** - * Namespace to hold generators for different types of ticks - * @namespace Chart.Ticks.generators + * Interface for the options provided to the numeric tick generator + * @interface INumericTickGenerationOptions + */ + /** + * The maximum number of ticks to display + * @name INumericTickGenerationOptions#maxTicks + * @type Number + */ + /** + * The distance between each tick. + * @name INumericTickGenerationOptions#stepSize + * @type Number + * @optional + */ + /** + * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum + * @name INumericTickGenerationOptions#min + * @type Number + * @optional + */ + /** + * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum + * @name INumericTickGenerationOptions#max + * @type Number + * @optional */ - generators: { - /** - * Interface for the options provided to the numeric tick generator - * @interface INumericTickGenerationOptions - */ - /** - * The maximum number of ticks to display - * @name INumericTickGenerationOptions#maxTicks - * @type Number - */ - /** - * The distance between each tick. - * @name INumericTickGenerationOptions#stepSize - * @type Number - * @optional - */ - /** - * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum - * @name INumericTickGenerationOptions#min - * @type Number - * @optional - */ - /** - * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum - * @name INumericTickGenerationOptions#max - * @type Number - * @optional - */ - - /** - * Generate a set of linear ticks - * @method Chart.Ticks.generators.linear - * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks - * @param dataRange {IRange} the range of the data - * @returns {Array} array of tick values - */ - linear: function(generationOptions, dataRange) { - var ticks = []; - // To get a "nice" value for the tick spacing, we will use the appropriately named - // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks - // for details. - - var spacing; - if (generationOptions.stepSize && generationOptions.stepSize > 0) { - spacing = generationOptions.stepSize; - } else { - var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false); - spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true); - } - var niceMin = Math.floor(dataRange.min / spacing) * spacing; - var niceMax = Math.ceil(dataRange.max / spacing) * spacing; - - // If min, max and stepSize is set and they make an evenly spaced scale use it. - if (generationOptions.min && generationOptions.max && generationOptions.stepSize) { - // If very close to our whole number, use it. - if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) { - niceMin = generationOptions.min; - niceMax = generationOptions.max; - } - } - var numSpaces = (niceMax - niceMin) / spacing; - // If very close to our rounded value, use it. - if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { - numSpaces = Math.round(numSpaces); - } else { - numSpaces = Math.ceil(numSpaces); + /** + * Generate a set of linear ticks + * @method Chart.Ticks.generators.linear + * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks + * @param dataRange {IRange} the range of the data + * @returns {Array} array of tick values + */ + linear: function(generationOptions, dataRange) { + var ticks = []; + // To get a "nice" value for the tick spacing, we will use the appropriately named + // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks + // for details. + + var spacing; + if (generationOptions.stepSize && generationOptions.stepSize > 0) { + spacing = generationOptions.stepSize; + } else { + var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false); + spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true); + } + var niceMin = Math.floor(dataRange.min / spacing) * spacing; + var niceMax = Math.ceil(dataRange.max / spacing) * spacing; + + // If min, max and stepSize is set and they make an evenly spaced scale use it. + if (generationOptions.min && generationOptions.max && generationOptions.stepSize) { + // If very close to our whole number, use it. + if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) { + niceMin = generationOptions.min; + niceMax = generationOptions.max; } + } - // Put the values into the ticks array - ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin); - for (var j = 1; j < numSpaces; ++j) { - ticks.push(niceMin + (j * spacing)); - } - ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax); - - return ticks; - }, - - /** - * Generate a set of logarithmic ticks - * @method Chart.Ticks.generators.logarithmic - * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks - * @param dataRange {IRange} the range of the data - * @returns {Array} array of tick values - */ - logarithmic: function(generationOptions, dataRange) { - var ticks = []; - var valueOrDefault = helpers.valueOrDefault; - - // 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 = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min)))); - - var endExp = Math.floor(helpers.log10(dataRange.max)); - var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); - var exp; - var significand; - - if (tickVal === 0) { - exp = Math.floor(helpers.log10(dataRange.minNotZero)); - significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp)); - - ticks.push(tickVal); - tickVal = significand * Math.pow(10, exp); - } else { - exp = Math.floor(helpers.log10(tickVal)); - significand = Math.floor(tickVal / Math.pow(10, exp)); - } + var numSpaces = (niceMax - niceMin) / spacing; + // If very close to our rounded value, use it. + if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { + numSpaces = Math.round(numSpaces); + } else { + numSpaces = Math.ceil(numSpaces); + } + + // Put the values into the ticks array + ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin); + for (var j = 1; j < numSpaces; ++j) { + ticks.push(niceMin + (j * spacing)); + } + ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax); + + return ticks; + }, - do { - ticks.push(tickVal); + /** + * Generate a set of logarithmic ticks + * @method Chart.Ticks.generators.logarithmic + * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks + * @param dataRange {IRange} the range of the data + * @returns {Array} array of tick values + */ + logarithmic: function(generationOptions, dataRange) { + var ticks = []; + var valueOrDefault = helpers.valueOrDefault; + + // 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 = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min)))); + + var endExp = Math.floor(helpers.log10(dataRange.max)); + var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); + var exp; + var significand; + + if (tickVal === 0) { + exp = Math.floor(helpers.log10(dataRange.minNotZero)); + significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp)); + + ticks.push(tickVal); + tickVal = significand * Math.pow(10, exp); + } else { + exp = Math.floor(helpers.log10(tickVal)); + significand = Math.floor(tickVal / Math.pow(10, exp)); + } - ++significand; - if (significand === 10) { - significand = 1; - ++exp; - } + do { + ticks.push(tickVal); - tickVal = significand * Math.pow(10, exp); - } while (exp < endExp || (exp === endExp && significand < endSignificand)); + ++significand; + if (significand === 10) { + significand = 1; + ++exp; + } - var lastTick = valueOrDefault(generationOptions.max, tickVal); - ticks.push(lastTick); + tickVal = significand * Math.pow(10, exp); + } while (exp < endExp || (exp === endExp && significand < endSignificand)); - return ticks; - }, + var lastTick = valueOrDefault(generationOptions.max, tickVal); + ticks.push(lastTick); - time: helpers.time.generateTicks + return ticks; }, + time: helpers.time.generateTicks + }, + + /** + * Namespace to hold formatters for different types of ticks + * @namespace Chart.Ticks.formatters + */ + formatters: { /** - * Namespace to hold formatters for different types of ticks - * @namespace Chart.Ticks.formatters + * Formatter for value labels + * @method Chart.Ticks.formatters.values + * @param value the value to display + * @return {String|Array} the label to display */ - formatters: { - /** - * Formatter for value labels - * @method Chart.Ticks.formatters.values - * @param value the value to display - * @return {String|Array} the label to display - */ - values: function(value) { - return helpers.isArray(value) ? value : '' + value; - }, - - /** - * Formatter for linear numeric ticks - * @method Chart.Ticks.formatters.linear - * @param tickValue {Number} the value to be formatted - * @param index {Number} the position of the tickValue parameter in the ticks array - * @param ticks {Array} the list of ticks being converted - * @return {String} string representation of the tickValue parameter - */ - linear: function(tickValue, index, ticks) { - // If we have lots of ticks, don't use the ones - var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0]; - - // If we have a number like 2.5 as the delta, figure out how many decimal places we need - if (Math.abs(delta) > 1) { - if (tickValue !== Math.floor(tickValue)) { - // not an integer - delta = tickValue - Math.floor(tickValue); - } + values: function(value) { + return helpers.isArray(value) ? value : '' + value; + }, + + /** + * Formatter for linear numeric ticks + * @method Chart.Ticks.formatters.linear + * @param tickValue {Number} the value to be formatted + * @param index {Number} the position of the tickValue parameter in the ticks array + * @param ticks {Array} the list of ticks being converted + * @return {String} string representation of the tickValue parameter + */ + linear: function(tickValue, index, ticks) { + // If we have lots of ticks, don't use the ones + var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0]; + + // If we have a number like 2.5 as the delta, figure out how many decimal places we need + if (Math.abs(delta) > 1) { + if (tickValue !== Math.floor(tickValue)) { + // not an integer + delta = tickValue - Math.floor(tickValue); } + } - var logDelta = helpers.log10(Math.abs(delta)); - var tickString = ''; + var logDelta = helpers.log10(Math.abs(delta)); + var tickString = ''; - if (tickValue !== 0) { - var numDecimal = -1 * Math.floor(logDelta); - numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places - tickString = tickValue.toFixed(numDecimal); - } else { - tickString = '0'; // never show decimal places for 0 - } + if (tickValue !== 0) { + var numDecimal = -1 * Math.floor(logDelta); + numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places + tickString = tickValue.toFixed(numDecimal); + } else { + tickString = '0'; // never show decimal places for 0 + } - return tickString; - }, + return tickString; + }, - logarithmic: function(tickValue, index, ticks) { - var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue)))); + logarithmic: function(tickValue, index, ticks) { + var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue)))); - if (tickValue === 0) { - return '0'; - } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) { - return tickValue.toExponential(); - } - return ''; + if (tickValue === 0) { + return '0'; + } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) { + return tickValue.toExponential(); } + return ''; } - }; + } }; diff --git a/src/core/core.tooltip.js b/src/core/core.tooltip.js index 6794320511f..a1ded8e3b6b 100644 --- a/src/core/core.tooltip.js +++ b/src/core/core.tooltip.js @@ -1,18 +1,10 @@ 'use strict'; +var defaults = require('./core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - /** - * Helper method to merge the opacity into a color - */ - function mergeOpacity(colorString, opacity) { - var color = helpers.color(colorString); - return color.alpha(opacity * color.alpha()).rgbaString(); - } - - Chart.defaults.global.tooltips = { +defaults._set('global', { + tooltips: { enabled: true, custom: null, mode: 'nearest', @@ -100,7 +92,18 @@ module.exports = function(Chart) { footer: helpers.noop, afterFooter: helpers.noop } - }; + } +}); + +module.exports = function(Chart) { + + /** + * Helper method to merge the opacity into a color + */ + function mergeOpacity(colorString, opacity) { + var color = helpers.color(colorString); + return color.alpha(opacity * color.alpha()).rgbaString(); + } // Helper to push or concat based on if the 2nd parameter is an array or not function pushOrConcat(base, toPush) { @@ -140,7 +143,7 @@ module.exports = function(Chart) { * @param tooltipOpts {Object} the tooltip options */ function getBaseModel(tooltipOpts) { - var globalDefaults = Chart.defaults.global; + var globalDefaults = defaults.global; var valueOrDefault = helpers.valueOrDefault; return { diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index 8604dfaea26..101302cf8aa 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -1,16 +1,19 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - var globalOpts = Chart.defaults.global; +defaults._set('global', { + elements: { + arc: { + backgroundColor: defaults.global.defaultColor, + borderColor: '#fff', + borderWidth: 2 + } + } +}); - globalOpts.elements.arc = { - backgroundColor: globalOpts.defaultColor, - borderColor: '#fff', - borderWidth: 2 - }; +module.exports = function(Chart) { Chart.elements.Arc = Chart.Element.extend({ inLabelRange: function(mouseX) { diff --git a/src/elements/element.line.js b/src/elements/element.line.js index 5a21fafb20b..f2bfcf67dc9 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -1,23 +1,28 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { +var globalDefaults = defaults.global; - var globalDefaults = Chart.defaults.global; +defaults._set('global', { + elements: { + line: { + tension: 0.4, + backgroundColor: globalDefaults.defaultColor, + borderWidth: 3, + borderColor: globalDefaults.defaultColor, + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: 'miter', + capBezierPoints: true, + fill: true, // do we fill in the area between the line and its base axis + } + } +}); - Chart.defaults.global.elements.line = { - tension: 0.4, - backgroundColor: globalDefaults.defaultColor, - borderWidth: 3, - borderColor: globalDefaults.defaultColor, - borderCapStyle: 'butt', - borderDash: [], - borderDashOffset: 0.0, - borderJoinStyle: 'miter', - capBezierPoints: true, - fill: true, // do we fill in the area between the line and its base axis - }; +module.exports = function(Chart) { Chart.elements.Line = Chart.Element.extend({ draw: function() { diff --git a/src/elements/element.point.js b/src/elements/element.point.js index c09329b1737..0b5d12d1286 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -1,23 +1,27 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { +var defaultColor = defaults.global.defaultColor; - var globalOpts = Chart.defaults.global, - defaultColor = globalOpts.defaultColor; +defaults._set('global', { + elements: { + point: { + radius: 3, + pointStyle: 'circle', + backgroundColor: defaultColor, + borderColor: defaultColor, + borderWidth: 1, + // Hover + hitRadius: 1, + hoverRadius: 4, + hoverBorderWidth: 1 + } + } +}); - globalOpts.elements.point = { - radius: 3, - pointStyle: 'circle', - backgroundColor: defaultColor, - borderWidth: 1, - borderColor: defaultColor, - // Hover - hitRadius: 1, - hoverRadius: 4, - hoverBorderWidth: 1 - }; +module.exports = function(Chart) { function xRange(mouseX) { var vm = this._view; @@ -74,7 +78,7 @@ module.exports = function(Chart) { } ctx.strokeStyle = vm.borderColor || defaultColor; - ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth); + ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth); ctx.fillStyle = vm.backgroundColor || defaultColor; // Cliping for Points. diff --git a/src/elements/element.rectangle.js b/src/elements/element.rectangle.js index c3b81976140..00f017e66e4 100644 --- a/src/elements/element.rectangle.js +++ b/src/elements/element.rectangle.js @@ -1,15 +1,19 @@ 'use strict'; -module.exports = function(Chart) { - - var globalOpts = Chart.defaults.global; +var defaults = require('../core/core.defaults'); + +defaults._set('global', { + elements: { + rectangle: { + backgroundColor: defaults.global.defaultColor, + borderColor: defaults.global.defaultColor, + borderSkipped: 'bottom', + borderWidth: 0 + } + } +}); - globalOpts.elements.rectangle = { - backgroundColor: globalOpts.defaultColor, - borderWidth: 0, - borderColor: globalOpts.defaultColor, - borderSkipped: 'bottom' - }; +module.exports = function(Chart) { function isVertical(bar) { return bar._view.width !== undefined; diff --git a/src/plugins/plugin.filler.js b/src/plugins/plugin.filler.js index 4f49064f084..51aed7669cf 100644 --- a/src/plugins/plugin.filler.js +++ b/src/plugins/plugin.filler.js @@ -1,18 +1,24 @@ +/** + * Plugin based on discussion from the following Chart.js issues: + * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569 + * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897 + */ + 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); +defaults._set('global', { + plugins: { + filler: { + propagate: true + } + } +}); + module.exports = function(Chart) { - /** - * Plugin based on discussion from the following Chart.js issues: - * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569 - * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897 - */ - Chart.defaults.global.plugins.filler = { - propagate: true - }; - var defaults = Chart.defaults; var mappers = { dataset: function(source) { var index = source.fill; diff --git a/src/plugins/plugin.legend.js b/src/plugins/plugin.legend.js index 3eb0f57dfcb..1a32c079857 100644 --- a/src/plugins/plugin.legend.js +++ b/src/plugins/plugin.legend.js @@ -1,13 +1,10 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - var layout = Chart.layoutService; - var noop = helpers.noop; - - Chart.defaults.global.legend = { +defaults._set('global', { + legend: { display: true, position: 'top', fullWidth: true, @@ -64,7 +61,27 @@ module.exports = function(Chart) { }, this) : []; } } - }; + }, + + legendCallback: function(chart) { + var text = []; + text.push('
    '); + for (var i = 0; i < chart.data.datasets.length; i++) { + text.push('
  • '); + if (chart.data.datasets[i].label) { + text.push(chart.data.datasets[i].label); + } + text.push('
  • '); + } + text.push('
'); + return text.join(''); + } +}); + +module.exports = function(Chart) { + + var layout = Chart.layoutService; + var noop = helpers.noop; /** * Helper function to get the box width based on the usePointStyle option @@ -192,7 +209,7 @@ module.exports = function(Chart) { var ctx = me.ctx; - var globalDefault = Chart.defaults.global, + var globalDefault = defaults.global, valueOrDefault = helpers.valueOrDefault, fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize), fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle), @@ -304,7 +321,7 @@ module.exports = function(Chart) { var me = this; var opts = me.options; var labelOpts = opts.labels; - var globalDefault = Chart.defaults.global, + var globalDefault = defaults.global, lineDefault = globalDefault.elements.line, legendWidth = me.width, lineWidths = me.lineWidths; @@ -525,7 +542,7 @@ module.exports = function(Chart) { var legend = chart.legend; if (legendOpts) { - helpers.mergeIf(legendOpts, Chart.defaults.global.legend); + helpers.mergeIf(legendOpts, defaults.global.legend); if (legend) { layout.configure(chart, legend, legendOpts); diff --git a/src/plugins/plugin.title.js b/src/plugins/plugin.title.js index 42ad1b0d3db..30f8813d92a 100644 --- a/src/plugins/plugin.title.js +++ b/src/plugins/plugin.title.js @@ -1,23 +1,24 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); -module.exports = function(Chart) { - - var layout = Chart.layoutService; - var noop = helpers.noop; - - Chart.defaults.global.title = { +defaults._set('global', { + title: { display: false, - position: 'top', - fullWidth: true, - weight: 2000, // by default greater than legend (1000) to be above fontStyle: 'bold', + fullWidth: true, padding: 10, + position: 'top', + text: '', + weight: 2000 // by default greater than legend (1000) to be above + } +}); - // actual title - text: '' - }; +module.exports = function(Chart) { + + var layout = Chart.layoutService; + var noop = helpers.noop; Chart.Title = Chart.Element.extend({ initialize: function(config) { @@ -109,9 +110,8 @@ module.exports = function(Chart) { var me = this, valueOrDefault = helpers.valueOrDefault, opts = me.options, - globalDefaults = Chart.defaults.global, display = opts.display, - fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize), + fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize), minSize = me.minSize, lineCount = helpers.isArray(opts.text) ? opts.text.length : 1, lineHeight = valueOrDefault(opts.lineHeight, fontSize), @@ -143,7 +143,7 @@ module.exports = function(Chart) { ctx = me.ctx, valueOrDefault = helpers.valueOrDefault, opts = me.options, - globalDefaults = Chart.defaults.global; + globalDefaults = defaults.global; if (opts.display) { var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize), @@ -225,7 +225,7 @@ module.exports = function(Chart) { var titleBlock = chart.titleBlock; if (titleOpts) { - helpers.mergeIf(titleOpts, Chart.defaults.global.title); + helpers.mergeIf(titleOpts, defaults.global.title); if (titleBlock) { layout.configure(chart, titleBlock, titleOpts); diff --git a/src/scales/scale.linear.js b/src/scales/scale.linear.js index 34223c28383..94ebd12a5a0 100644 --- a/src/scales/scale.linear.js +++ b/src/scales/scale.linear.js @@ -1,13 +1,15 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); +var Ticks = require('../core/core.ticks'); module.exports = function(Chart) { var defaultConfig = { position: 'left', ticks: { - callback: Chart.Ticks.formatters.linear + callback: Ticks.formatters.linear } }; @@ -139,7 +141,7 @@ module.exports = function(Chart) { maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50)); } else { // The factor of 2 used to scale the font size has been experimentally determined. - var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize); + var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize); maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize))); } diff --git a/src/scales/scale.linearbase.js b/src/scales/scale.linearbase.js index 33bc22517bf..cf75b31663d 100644 --- a/src/scales/scale.linearbase.js +++ b/src/scales/scale.linearbase.js @@ -1,6 +1,7 @@ 'use strict'; var helpers = require('../helpers/index'); +var Ticks = require('../core/core.ticks'); module.exports = function(Chart) { @@ -94,7 +95,7 @@ module.exports = function(Chart) { max: tickOpts.max, stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize) }; - var ticks = me.ticks = Chart.Ticks.generators.linear(numericGeneratorOptions, me); + var ticks = me.ticks = Ticks.generators.linear(numericGeneratorOptions, me); me.handleDirectionalChanges(); diff --git a/src/scales/scale.logarithmic.js b/src/scales/scale.logarithmic.js index a5c5fa918a2..a6a0606ade1 100644 --- a/src/scales/scale.logarithmic.js +++ b/src/scales/scale.logarithmic.js @@ -1,6 +1,7 @@ 'use strict'; var helpers = require('../helpers/index'); +var Ticks = require('../core/core.ticks'); module.exports = function(Chart) { @@ -9,7 +10,7 @@ module.exports = function(Chart) { // label settings ticks: { - callback: Chart.Ticks.formatters.logarithmic + callback: Ticks.formatters.logarithmic } }; @@ -142,7 +143,7 @@ module.exports = function(Chart) { min: tickOpts.min, max: tickOpts.max }; - var ticks = me.ticks = Chart.Ticks.generators.logarithmic(generationOptions, me); + var ticks = me.ticks = Ticks.generators.logarithmic(generationOptions, me); if (!me.isHorizontal()) { // We are in a vertical orientation. The top value is the highest. So reverse the array diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 93036c691e5..f1194fd82ae 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -1,10 +1,12 @@ 'use strict'; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); +var Ticks = require('../core/core.ticks'); module.exports = function(Chart) { - var globalDefaults = Chart.defaults.global; + var globalDefaults = defaults.global; var defaultConfig = { display: true, @@ -37,7 +39,7 @@ module.exports = function(Chart) { // Number - The backdrop padding to the side of the label in pixels backdropPaddingX: 2, - callback: Chart.Ticks.formatters.linear + callback: Ticks.formatters.linear }, pointLabels: { diff --git a/src/scales/scale.time.js b/src/scales/scale.time.js index fab5ccd6416..41d022a7938 100644 --- a/src/scales/scale.time.js +++ b/src/scales/scale.time.js @@ -4,6 +4,7 @@ var moment = require('moment'); moment = typeof(moment) === 'function' ? moment : window.moment; +var defaults = require('../core/core.defaults'); var helpers = require('../helpers/index'); module.exports = function(Chart) { @@ -274,7 +275,7 @@ module.exports = function(Chart) { var tickLabelWidth = me.ctx.measureText(label).width; var cosRotation = Math.cos(helpers.toRadians(ticks.maxRotation)); var sinRotation = Math.sin(helpers.toRadians(ticks.maxRotation)); - var tickFontSize = helpers.valueOrDefault(ticks.fontSize, Chart.defaults.global.defaultFontSize); + var tickFontSize = helpers.valueOrDefault(ticks.fontSize, defaults.global.defaultFontSize); return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation); }, getLabelCapacity: function(exampleTime) {