Skip to content

Commit e9cfe04

Browse files
committed
add axis breaks default logic
1 parent 4f6ea7e commit e9cfe04

File tree

2 files changed

+176
-0
lines changed

2 files changed

+176
-0
lines changed

src/plots/cartesian/axis_defaults.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
var Registry = require('../../registry');
1212
var Lib = require('../../lib');
1313

14+
var handleArrayContainerDefaults = require('../array_container_defaults');
15+
1416
var layoutAttributes = require('./layout_attributes');
1517
var handleTickValueDefaults = require('./tick_value_defaults');
1618
var handleTickMarkDefaults = require('./tick_mark_defaults');
@@ -19,6 +21,8 @@ var handleCategoryOrderDefaults = require('./category_order_defaults');
1921
var handleLineGridDefaults = require('./line_grid_defaults');
2022
var setConvert = require('./set_convert');
2123

24+
var ONEDAY = require('../../constants/numerical').ONEDAY;
25+
2226
/**
2327
* options: object containing:
2428
*
@@ -117,5 +121,68 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
117121
}
118122
}
119123

124+
// TODO
125+
// - does this make sense for 'log', 'category' and 'multicategory' axis types ??
126+
127+
var breaks = containerIn.breaks;
128+
if(Array.isArray(breaks) && breaks.length) {
129+
handleArrayContainerDefaults(containerIn, containerOut, {
130+
name: 'breaks',
131+
inclusionAttr: 'enabled',
132+
handleItemDefaults: breaksDefaults
133+
});
134+
setConvert(containerOut, layoutOut);
135+
}
136+
120137
return containerOut;
121138
};
139+
140+
function breaksDefaults(itemIn, itemOut, containerOut) {
141+
function coerce(attr, dflt) {
142+
return Lib.coerce(itemIn, itemOut, layoutAttributes.breaks, attr, dflt);
143+
}
144+
145+
var enabled = coerce('enabled');
146+
147+
if(enabled) {
148+
var isDateAxis = containerOut.type === 'date';
149+
150+
var bnds = coerce('bounds');
151+
152+
if(bnds && bnds.length >= 2) {
153+
if(bnds.length > 2) {
154+
itemOut.bounds = itemOut.bounds.slice(0, 2);
155+
}
156+
157+
if(containerOut.autorange === false) {
158+
var rng = containerOut.range;
159+
160+
// if bounds are bigger than the (set) range, disable break
161+
if(rng[0] < rng[1]) {
162+
if(bnds[0] < rng[0] && bnds[1] > rng[1]) {
163+
itemOut.enabled = false;
164+
return;
165+
}
166+
} else if(bnds[0] > rng[0] && bnds[1] < rng[1]) {
167+
itemOut.enabled = false;
168+
return;
169+
}
170+
}
171+
172+
if(isDateAxis) {
173+
coerce('pattern');
174+
}
175+
} else {
176+
var values = coerce('values');
177+
178+
if(values && values.length) {
179+
coerce('dvalue', isDateAxis ? ONEDAY : 1);
180+
} else {
181+
itemOut.enabled = false;
182+
return;
183+
}
184+
}
185+
186+
coerce('operation');
187+
}
188+
}

test/jasmine/tests/axes_test.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,115 @@ describe('Test axes', function() {
10171017
expect(layoutOut.yaxis.range).withContext('yaxis range').toEqual([0, 4]);
10181018
expect(layoutOut.yaxis2.range).withContext('yaxis2 range').toEqual([0, 4]);
10191019
});
1020+
1021+
it('should coerce *breaks* container only when it is a non-empty array', function() {
1022+
layoutIn = {
1023+
xaxis: {breaks: [{bounds: [0, 1]}]},
1024+
xaxis2: {breaks: []},
1025+
xaxis3: {breaks: false},
1026+
xaxis4: {}
1027+
};
1028+
layoutOut._subplots.xaxis.push('x2', 'x3', 'x4');
1029+
supplyLayoutDefaults(layoutIn, layoutOut, fullData);
1030+
1031+
expect(Array.isArray(layoutOut.xaxis.breaks) && layoutOut.xaxis.breaks.length)
1032+
.toBe(1, 'xaxis.breaks is array of length 1');
1033+
expect(layoutOut.xaxis2.breaks).toBeUndefined();
1034+
expect(layoutOut.xaxis3.breaks).toBeUndefined();
1035+
expect(layoutOut.xaxis4.breaks).toBeUndefined();
1036+
});
1037+
1038+
it('should set *breaks* to *enabled:false* when *bounds* have less than 2 items', function() {
1039+
layoutIn = {
1040+
xaxis: {breaks: [{bounds: [0]}]},
1041+
xaxis2: {breaks: [{bounds: [0], values: [1]}]},
1042+
xaxis3: {breaks: [{bounds: [0], values: {}}]},
1043+
xaxis4: {breaks: [{bounds: [0, 1, 2]}]}
1044+
};
1045+
layoutOut._subplots.xaxis.push('x2', 'x3', 'x4');
1046+
supplyLayoutDefaults(layoutIn, layoutOut, fullData);
1047+
1048+
expect(layoutOut.xaxis.breaks[0].enabled).toBe(false, 'invalid *bounds*');
1049+
expect(layoutOut.xaxis2.breaks[0].enabled).toBe(true, 'invalid *bounds*, valid *values*');
1050+
expect(layoutOut.xaxis3.breaks[0].enabled).toBe(false, 'invalid *bounds*, invalid *values*');
1051+
expect(layoutOut.xaxis4.breaks[0].enabled && layoutOut.xaxis4.breaks[0].bounds)
1052+
.withContext('valid *bounds*, sliced to length=2').toEqual([0, 1]);
1053+
});
1054+
1055+
it('if *breaks* *bounds* are bigger than the set *range*, disable break', function() {
1056+
layoutIn = {
1057+
xaxis: {range: [0, 4], breaks: [{bounds: [1, 2]}]},
1058+
xaxis2: {range: [1, 2], breaks: [{bounds: [0, 4]}]},
1059+
xaxis3: {range: [4, 0], breaks: [{bounds: [2, 1]}]},
1060+
xaxis4: {range: [2, 1], breaks: [{bounds: [4, 0]}]}
1061+
};
1062+
layoutOut._subplots.xaxis.push('x2', 'x3', 'x4');
1063+
supplyLayoutDefaults(layoutIn, layoutOut, fullData);
1064+
1065+
expect(layoutOut.xaxis.breaks[0].enabled).toBe(true, '*bounds* within set range');
1066+
expect(layoutOut.xaxis2.breaks[0].enabled).toBe(false, '*bounds* bigger than set range');
1067+
expect(layoutOut.xaxis3.breaks[0].enabled).toBe(true, '*bounds* within set range (reversed)');
1068+
expect(layoutOut.xaxis4.breaks[0].enabled).toBe(false, '*bounds* bigger than set range (reversed)');
1069+
});
1070+
1071+
it('should coerce *breaks* *bounds* over *values*/*dvalue* if both are present', function() {
1072+
layoutIn = {
1073+
xaxis: {breaks: [{bounds: [0, 1]}]},
1074+
xaxis2: {breaks: [{values: [0, 2, 4], dvalue: 2}]},
1075+
xaxis3: {breaks: [{bounds: [0, 1], values: [0, 2, 4], dvalue: 2}]},
1076+
xaxis4: {breaks: [{bounds: false, values: [0, 2, 4], dvalue: 2}]},
1077+
};
1078+
layoutOut._subplots.xaxis.push('x2', 'x3', 'x4');
1079+
supplyLayoutDefaults(layoutIn, layoutOut, fullData);
1080+
1081+
var xaBreak = layoutOut.xaxis.breaks[0];
1082+
expect(xaBreak.bounds).withContext('valid *bounds*').toEqual([0, 1]);
1083+
expect(xaBreak.values).toBe(undefined, 'not coerced');
1084+
expect(xaBreak.dvalue).toBe(undefined, 'not coerced');
1085+
1086+
xaBreak = layoutOut.xaxis2.breaks[0];
1087+
expect(xaBreak.bounds).toBe(undefined, 'not set, not coerced');
1088+
expect(xaBreak.values).withContext('valid *values*').toEqual([0, 2, 4]);
1089+
expect(xaBreak.dvalue).toBe(2, 'valid *dvalue*');
1090+
1091+
xaBreak = layoutOut.xaxis3.breaks[0];
1092+
expect(xaBreak.bounds).withContext('set to valid, coerced').toEqual([0, 1]);
1093+
expect(xaBreak.values).toBe(undefined, 'not coerced');
1094+
expect(xaBreak.dvalue).toBe(undefined, 'not coerced');
1095+
1096+
xaBreak = layoutOut.xaxis4.breaks[0];
1097+
expect(xaBreak.bounds).toBe(undefined, 'set but invalid, not coerced');
1098+
expect(xaBreak.values).withContext('valid *values*').toEqual([0, 2, 4]);
1099+
expect(xaBreak.dvalue).toBe(2, 'valid *dvalue*');
1100+
});
1101+
1102+
it('should only coerce breaks *pattern* on date axes with *bounds*', function() {
1103+
layoutIn = {
1104+
xaxis: {type: 'linear', breaks: [{bounds: [0, 1], pattern: 'not-gonna-work'}]},
1105+
xaxis2: {type: 'date', breaks: [{bounds: ['2020-01-04', '2020-01-05']}]},
1106+
xaxis3: {type: 'date', breaks: [{bounds: [6, 0], pattern: '%w'}]},
1107+
xaxis4: {type: 'date', breaks: [{values: ['2020-01-04', '2020-01-05'], pattern: 'NOP'}]},
1108+
};
1109+
layoutOut._subplots.xaxis.push('x2', 'x3', 'x4');
1110+
supplyLayoutDefaults(layoutIn, layoutOut, fullData);
1111+
1112+
expect(layoutOut.xaxis.breaks[0].pattern).toBe(undefined, 'not coerced, on linear axis');
1113+
expect(layoutOut.xaxis2.breaks[0].pattern).toBe('', 'coerced to dflt value');
1114+
expect(layoutOut.xaxis3.breaks[0].pattern).toBe('%w', 'coerced');
1115+
expect(layoutOut.xaxis4.breaks[0].pattern).toBe(undefined, 'not coerce, using *values*');
1116+
});
1117+
1118+
it('should only coerce *dvalue* with correct smart dflt', function() {
1119+
layoutIn = {
1120+
xaxis: {type: 'linear', breaks: [{values: [1]}]},
1121+
xaxis2: {type: 'date', breaks: [{values: ['2020-01-04']}]},
1122+
};
1123+
layoutOut._subplots.xaxis.push('x2');
1124+
supplyLayoutDefaults(layoutIn, layoutOut, fullData);
1125+
1126+
expect(layoutOut.xaxis.breaks[0].dvalue).toBe(1, 'type:linear dflt');
1127+
expect(layoutOut.xaxis2.breaks[0].dvalue).toBe(24 * 60 * 60 * 1000, 'type:date dflt');
1128+
});
10201129
});
10211130

10221131
describe('constraints relayout', function() {

0 commit comments

Comments
 (0)