Deprecate configMerge and scaleMerge helpers (#6022)

These methods shouldn't have been public since they are specific to the chart controller internal logic. Note that this scale custom merging will be removed in v3.
This commit is contained in:
Simon Brunel 2019-01-29 17:52:21 +01:00 committed by GitHub
parent 17f6fd2340
commit 0697d0de90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 242 additions and 225 deletions

View File

@ -35,16 +35,80 @@ defaults._set('global', {
responsiveAnimationDuration: 0
});
/**
* Recursively merge the given config objects representing the `scales` option
* by incorporating scale defaults in `xAxes` and `yAxes` array items, then
* returns a deep copy of the result, thus doesn't alter inputs.
*/
function mergeScaleConfig(/* config objects ... */) {
return helpers.merge({}, [].slice.call(arguments), {
merger: function(key, target, source, options) {
if (key === 'xAxes' || key === 'yAxes') {
var slen = source[key].length;
var i, type, scale;
if (!target[key]) {
target[key] = [];
}
for (i = 0; i < slen; ++i) {
scale = source[key][i];
type = valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear');
if (i >= target[key].length) {
target[key].push({});
}
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], [scaleService.getScaleDefaults(type), scale]);
} else {
// scales type are the same
helpers.merge(target[key][i], scale);
}
}
} else {
helpers._merger(key, target, source, options);
}
}
});
}
/**
* Recursively merge the given config objects as the root options by handling
* default scale options for the `scales` and `scale` properties, then returns
* a deep copy of the result, thus doesn't alter inputs.
*/
function mergeConfig(/* config objects ... */) {
return helpers.merge({}, [].slice.call(arguments), {
merger: function(key, target, source, options) {
var tval = target[key] || {};
var sval = source[key];
if (key === 'scales') {
// scale config merging is complex. Add our own function here for that
target[key] = mergeScaleConfig(tval, sval);
} else if (key === 'scale') {
// used in polar area & radar charts since there is only one scale
target[key] = helpers.merge(tval, [scaleService.getScaleDefaults(sval.type), sval]);
} else {
helpers._merger(key, target, source, options);
}
}
});
}
function initConfig(config) {
config = config || {};
// Do NOT use configMerge() for the data object because this method merges arrays
// Do NOT use mergeConfig for the data object because this method merges arrays
// and so would change references to labels and datasets, preventing data updates.
var data = config.data = config.data || {};
data.datasets = data.datasets || [];
data.labels = data.labels || [];
config.options = helpers.configMerge(
config.options = mergeConfig(
defaults.global,
defaults[config.type],
config.options || {});
@ -59,7 +123,7 @@ function updateConfig(chart) {
layouts.removeBox(chart, scale);
});
newOptions = helpers.configMerge(
newOptions = mergeConfig(
defaults.global,
defaults[chart.config.type],
newOptions);
@ -981,3 +1045,21 @@ Chart.Controller = Chart;
* @private
*/
Chart.types = {};
/**
* Provided for backward compatibility, not available anymore.
* @namespace Chart.helpers.configMerge
* @deprecated since version 2.8.0
* @todo remove at version 3
* @private
*/
helpers.configMerge = mergeConfig;
/**
* Provided for backward compatibility, not available anymore.
* @namespace Chart.helpers.scaleMerge
* @deprecated since version 2.8.0
* @todo remove at version 3
* @private
*/
helpers.scaleMerge = mergeScaleConfig;

View File

@ -5,66 +5,11 @@
var color = require('chartjs-color');
var defaults = require('./core.defaults');
var helpers = require('../helpers/index');
var scaleService = require('../core/core.scaleService');
module.exports = function() {
// -- Basic js utility methods
helpers.configMerge = function(/* objects ... */) {
return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
merger: function(key, target, source, options) {
var tval = target[key] || {};
var sval = source[key];
if (key === 'scales') {
// scale config merging is complex. Add our own function here for that
target[key] = helpers.scaleMerge(tval, sval);
} else if (key === 'scale') {
// used in polar area & radar charts since there is only one scale
target[key] = helpers.merge(tval, [scaleService.getScaleDefaults(sval.type), sval]);
} else {
helpers._merger(key, target, source, options);
}
}
});
};
helpers.scaleMerge = function(/* objects ... */) {
return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
merger: function(key, target, source, options) {
if (key === 'xAxes' || key === 'yAxes') {
var slen = source[key].length;
var i, type, scale;
if (!target[key]) {
target[key] = [];
}
for (i = 0; i < slen; ++i) {
scale = source[key][i];
type = helpers.valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear');
if (i >= target[key].length) {
target[key].push({});
}
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], [scaleService.getScaleDefaults(type), scale]);
} else {
// scales type are the same
helpers.merge(target[key][i], scale);
}
}
} else {
helpers._merger(key, target, source, options);
}
}
});
};
helpers.where = function(collection, filterCallback) {
if (helpers.isArray(collection) && Array.prototype.filter) {
return collection.filter(filterCallback);

View File

@ -192,7 +192,7 @@ var helpers = {
/**
* The default merger when Chart.helpers.merge is called without merger option.
* Note(SB): this method is also used by configMerge and scaleMerge as fallback.
* Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
* @private
*/
_merger: function(key, target, source, options) {

View File

@ -159,6 +159,150 @@ describe('Chart', function() {
});
});
describe('when merging scale options', function() {
beforeEach(function() {
Chart.helpers.merge(Chart.defaults.scale, {
_jasmineCheckA: 'a0',
_jasmineCheckB: 'b0',
_jasmineCheckC: 'c0'
});
Chart.helpers.merge(Chart.scaleService.defaults.logarithmic, {
_jasmineCheckB: 'b1',
_jasmineCheckC: 'c1',
});
});
afterEach(function() {
delete Chart.defaults.scale._jasmineCheckA;
delete Chart.defaults.scale._jasmineCheckB;
delete Chart.defaults.scale._jasmineCheckC;
delete Chart.scaleService.defaults.logarithmic._jasmineCheckB;
delete Chart.scaleService.defaults.logarithmic._jasmineCheckC;
});
it('should default to "category" for x scales and "linear" for y scales', function() {
var chart = acquireChart({
type: 'line',
options: {
scales: {
xAxes: [
{id: 'foo0'},
{id: 'foo1'}
],
yAxes: [
{id: 'bar0'},
{id: 'bar1'}
]
}
}
});
expect(chart.scales.foo0.type).toBe('category');
expect(chart.scales.foo1.type).toBe('category');
expect(chart.scales.bar0.type).toBe('linear');
expect(chart.scales.bar1.type).toBe('linear');
});
it('should correctly apply defaults on central scale', function() {
var chart = acquireChart({
type: 'line',
options: {
scale: {
id: 'foo',
type: 'logarithmic',
_jasmineCheckC: 'c2',
_jasmineCheckD: 'd2'
}
}
});
// let's check a few values from the user options and defaults
expect(chart.scales.foo.type).toBe('logarithmic');
expect(chart.scales.foo.options).toBe(chart.options.scale);
expect(chart.scales.foo.options).toEqual(
jasmine.objectContaining({
_jasmineCheckA: 'a0',
_jasmineCheckB: 'b1',
_jasmineCheckC: 'c2',
_jasmineCheckD: 'd2'
}));
});
it('should correctly apply defaults on xy scales', function() {
var chart = acquireChart({
type: 'line',
options: {
scales: {
xAxes: [{
id: 'foo',
type: 'logarithmic',
_jasmineCheckC: 'c2',
_jasmineCheckD: 'd2'
}],
yAxes: [{
id: 'bar',
type: 'time',
_jasmineCheckC: 'c2',
_jasmineCheckE: 'e2'
}]
}
}
});
expect(chart.scales.foo.type).toBe('logarithmic');
expect(chart.scales.foo.options).toBe(chart.options.scales.xAxes[0]);
expect(chart.scales.foo.options).toEqual(
jasmine.objectContaining({
_jasmineCheckA: 'a0',
_jasmineCheckB: 'b1',
_jasmineCheckC: 'c2',
_jasmineCheckD: 'd2'
}));
expect(chart.scales.bar.type).toBe('time');
expect(chart.scales.bar.options).toBe(chart.options.scales.yAxes[0]);
expect(chart.scales.bar.options).toEqual(
jasmine.objectContaining({
_jasmineCheckA: 'a0',
_jasmineCheckB: 'b0',
_jasmineCheckC: 'c2',
_jasmineCheckE: 'e2'
}));
});
it('should not alter defaults when merging config', function() {
var chart = acquireChart({
type: 'line',
options: {
_jasmineCheck: 42,
scales: {
xAxes: [{
id: 'foo',
type: 'linear',
_jasmineCheck: 42,
}],
yAxes: [{
id: 'bar',
type: 'category',
_jasmineCheck: 42,
}]
}
}
});
expect(chart.options._jasmineCheck).toBeDefined();
expect(chart.scales.foo.options._jasmineCheck).toBeDefined();
expect(chart.scales.bar.options._jasmineCheck).toBeDefined();
expect(Chart.defaults.line._jasmineCheck).not.toBeDefined();
expect(Chart.defaults.global._jasmineCheck).not.toBeDefined();
expect(Chart.scaleService.defaults.linear._jasmineCheck).not.toBeDefined();
expect(Chart.scaleService.defaults.category._jasmineCheck).not.toBeDefined();
});
});
describe('config.options.responsive: false', function() {
it('should not inject the resizer element', function() {
var chart = acquireChart({

View File

@ -6,172 +6,6 @@ describe('Core helper tests', function() {
helpers = window.Chart.helpers;
});
it('should merge a normal config without scales', function() {
var baseConfig = {
valueProp: 5,
arrayProp: [1, 2, 3, 4, 5, 6],
objectProp: {
prop1: 'abc',
prop2: 56
}
};
var toMerge = {
valueProp2: null,
arrayProp: ['a', 'c'],
objectProp: {
prop1: 'c',
prop3: 'prop3'
}
};
var merged = helpers.configMerge(baseConfig, toMerge);
expect(merged).toEqual({
valueProp: 5,
valueProp2: null,
arrayProp: ['a', 'c'],
objectProp: {
prop1: 'c',
prop2: 56,
prop3: 'prop3'
}
});
});
it('should merge scale configs', function() {
var baseConfig = {
scales: {
prop1: {
abc: 123,
def: '456'
},
prop2: 777,
yAxes: [{
type: 'linear',
}, {
type: 'log'
}]
}
};
var toMerge = {
scales: {
prop1: {
def: 'bbb',
ghi: 78
},
prop2: null,
yAxes: [{
type: 'linear',
axisProp: 456
}, {
// pulls in linear default config since axis type changes
type: 'linear',
position: 'right'
}, {
// Pulls in linear default config since axis not in base
type: 'linear'
}]
}
};
var merged = helpers.configMerge(baseConfig, toMerge);
expect(merged).toEqual({
scales: {
prop1: {
abc: 123,
def: 'bbb',
ghi: 78
},
prop2: null,
yAxes: [{
type: 'linear',
axisProp: 456
}, {
display: true,
gridLines: {
color: 'rgba(0, 0, 0, 0.1)',
drawBorder: true,
drawOnChartArea: true,
drawTicks: true, // draw ticks extending towards the label
tickMarkLength: 10,
lineWidth: 1,
offsetGridLines: false,
display: true,
zeroLineColor: 'rgba(0,0,0,0.25)',
zeroLineWidth: 1,
zeroLineBorderDash: [],
zeroLineBorderDashOffset: 0.0,
borderDash: [],
borderDashOffset: 0.0
},
position: 'right',
offset: false,
scaleLabel: Chart.defaults.scale.scaleLabel,
ticks: {
beginAtZero: false,
minRotation: 0,
maxRotation: 50,
mirror: false,
padding: 0,
reverse: false,
display: true,
callback: merged.scales.yAxes[1].ticks.callback, // make it nicer, then check explicitly below
autoSkip: true,
autoSkipPadding: 0,
labelOffset: 0,
minor: {},
major: {},
},
type: 'linear'
}, {
display: true,
gridLines: {
color: 'rgba(0, 0, 0, 0.1)',
drawBorder: true,
drawOnChartArea: true,
drawTicks: true, // draw ticks extending towards the label,
tickMarkLength: 10,
lineWidth: 1,
offsetGridLines: false,
display: true,
zeroLineColor: 'rgba(0,0,0,0.25)',
zeroLineWidth: 1,
zeroLineBorderDash: [],
zeroLineBorderDashOffset: 0.0,
borderDash: [],
borderDashOffset: 0.0
},
position: 'left',
offset: false,
scaleLabel: Chart.defaults.scale.scaleLabel,
ticks: {
beginAtZero: false,
minRotation: 0,
maxRotation: 50,
mirror: false,
padding: 0,
reverse: false,
display: true,
callback: merged.scales.yAxes[2].ticks.callback, // make it nicer, then check explicitly below
autoSkip: true,
autoSkipPadding: 0,
labelOffset: 0,
minor: {},
major: {},
},
type: 'linear'
}]
}
});
// Are these actually functions
expect(merged.scales.yAxes[1].ticks.callback).toEqual(jasmine.any(Function));
expect(merged.scales.yAxes[2].ticks.callback).toEqual(jasmine.any(Function));
});
it('should filter an array', function() {
var data = [-10, 0, 6, 0, 7];
var callback = function(item) {

View File

@ -42,6 +42,18 @@ describe('Deprecations', function() {
expect(Chart.types).toEqual({});
});
});
describe('Chart.helpers.configMerge', function() {
it('should be defined as a function', function() {
expect(typeof Chart.helpers.configMerge).toBe('function');
});
});
describe('Chart.helpers.scaleMerge', function() {
it('should be defined as a function', function() {
expect(typeof Chart.helpers.scaleMerge).toBe('function');
});
});
});
describe('Version 2.7.3', function() {