Skip to content

Commit ab20fae

Browse files
committed
pull out tick0/dtick validation logic for reuse
1 parent e066bb9 commit ab20fae

File tree

2 files changed

+93
-44
lines changed

2 files changed

+93
-44
lines changed

src/plots/cartesian/clean_ticks.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* Copyright 2012-2018, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var isNumeric = require('fast-isnumeric');
13+
var Lib = require('../../lib');
14+
var ONEDAY = require('../../constants/numerical').ONEDAY;
15+
16+
/**
17+
* Return a validated dtick value for this axis
18+
*
19+
* @param {any} dtick: the candidate dtick. valid values are numbers and strings,
20+
* and further constrained depending on the axis type.
21+
* @param {string} axType: the axis type
22+
*/
23+
exports.dtick = function(dtick, axType) {
24+
var isLog = axType === 'log';
25+
var isDate = axType === 'date';
26+
var isCat = axType === 'category';
27+
var dtickDflt = isDate ? ONEDAY : 1;
28+
29+
if(!dtick) return dtickDflt;
30+
31+
if(isNumeric(dtick)) {
32+
dtick = Number(dtick);
33+
if(dtick <= 0) return dtickDflt;
34+
if(isCat) {
35+
// category dtick must be positive integers
36+
return Math.max(1, Math.round(dtick));
37+
}
38+
if(isDate) {
39+
// date dtick must be at least 0.1ms (our current precision)
40+
return Math.max(0.1, dtick);
41+
}
42+
return dtick;
43+
}
44+
45+
if(typeof dtick !== 'string' || !(isDate || isLog)) {
46+
return dtickDflt;
47+
}
48+
49+
var prefix = dtick.charAt(0);
50+
var dtickNum = dtick.substr(1);
51+
dtickNum = isNumeric(dtickNum) ? Number(dtickNum) : 0;
52+
53+
if((dtickNum <= 0) || !(
54+
// "M<n>" gives ticks every (integer) n months
55+
(isDate && prefix === 'M' && dtickNum === Math.round(dtickNum)) ||
56+
// "L<f>" gives ticks linearly spaced in data (not in position) every (float) f
57+
(isLog && prefix === 'L') ||
58+
// "D1" gives powers of 10 with all small digits between, "D2" gives only 2 and 5
59+
(isLog && prefix === 'D' && (dtickNum === 1 || dtickNum === 2))
60+
)) {
61+
return dtickDflt;
62+
}
63+
64+
return dtick;
65+
};
66+
67+
/**
68+
* Return a validated tick0 for this axis
69+
*
70+
* @param {any} tick0: the candidate tick0. Valid values are numbers and strings,
71+
* further constrained depending on the axis type
72+
* @param {string} axType: the axis type
73+
* @param {string} calendar: for date axes, the calendar to validate/convert with
74+
* @param {any} dtick: an already valid dtick. Only used for D1 and D2 log dticks,
75+
* which do not support tick0 at all.
76+
*/
77+
exports.tick0 = function(tick0, axType, calendar, dtick) {
78+
if(axType === 'date') {
79+
return Lib.cleanDate(tick0, Lib.dateTick0(calendar));
80+
}
81+
if(dtick === 'D1' || dtick === 'D2') {
82+
// D1 and D2 modes ignore tick0 entirely
83+
return undefined;
84+
}
85+
// Aside from date axes, tick0 must be numeric
86+
return isNumeric(tick0) ? Number(tick0) : 0;
87+
};

src/plots/cartesian/tick_value_defaults.js

Lines changed: 6 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@
99

1010
'use strict';
1111

12-
var isNumeric = require('fast-isnumeric');
13-
var Lib = require('../../lib');
14-
var ONEDAY = require('../../constants/numerical').ONEDAY;
12+
var cleanTicks = require('./clean_ticks');
1513

1614

1715
module.exports = function handleTickValueDefaults(containerIn, containerOut, coerce, axType) {
@@ -33,47 +31,11 @@ module.exports = function handleTickValueDefaults(containerIn, containerOut, coe
3331
else if(tickmode === 'linear') {
3432
// dtick is usually a positive number, but there are some
3533
// special strings available for log or date axes
36-
// default is 1 day for dates, otherwise 1
37-
var dtickDflt = (axType === 'date') ? ONEDAY : 1;
38-
var dtick = coerce('dtick', dtickDflt);
39-
if(isNumeric(dtick)) {
40-
containerOut.dtick = (dtick > 0) ? Number(dtick) : dtickDflt;
41-
}
42-
else if(typeof dtick !== 'string') {
43-
containerOut.dtick = dtickDflt;
44-
}
45-
else {
46-
// date and log special cases are all one character plus a number
47-
var prefix = dtick.charAt(0),
48-
dtickNum = dtick.substr(1);
49-
50-
dtickNum = isNumeric(dtickNum) ? Number(dtickNum) : 0;
51-
if((dtickNum <= 0) || !(
52-
// "M<n>" gives ticks every (integer) n months
53-
(axType === 'date' && prefix === 'M' && dtickNum === Math.round(dtickNum)) ||
54-
// "L<f>" gives ticks linearly spaced in data (not in position) every (float) f
55-
(axType === 'log' && prefix === 'L') ||
56-
// "D1" gives powers of 10 with all small digits between, "D2" gives only 2 and 5
57-
(axType === 'log' && prefix === 'D' && (dtickNum === 1 || dtickNum === 2))
58-
)) {
59-
containerOut.dtick = dtickDflt;
60-
}
61-
}
62-
63-
// tick0 can have different valType for different axis types, so
64-
// validate that now. Also for dates, change milliseconds to date strings
65-
var tick0Dflt = (axType === 'date') ? Lib.dateTick0(containerOut.calendar) : 0;
66-
var tick0 = coerce('tick0', tick0Dflt);
67-
if(axType === 'date') {
68-
containerOut.tick0 = Lib.cleanDate(tick0, tick0Dflt);
69-
}
70-
// Aside from date axes, dtick must be numeric; D1 and D2 modes ignore tick0 entirely
71-
else if(isNumeric(tick0) && dtick !== 'D1' && dtick !== 'D2') {
72-
containerOut.tick0 = Number(tick0);
73-
}
74-
else {
75-
containerOut.tick0 = tick0Dflt;
76-
}
34+
// tick0 also has special logic
35+
var dtick = containerOut.dtick = cleanTicks.dtick(
36+
containerIn.dtick, axType);
37+
containerOut.tick0 = cleanTicks.tick0(
38+
containerIn.tick0, axType, containerOut.calendar, dtick);
7739
}
7840
else {
7941
var tickvals = coerce('tickvals');

0 commit comments

Comments
 (0)