Skip to content

Commit b67657f

Browse files
committed
redefine what 'r' means for category axes & add cleanPos axis method
- DO NOT convert category position value to indices (the old 'r') in Axes.coercePosition - as this relied on ax._categories which isn't defined during Plots.supplyDefaults. - modify `type: 'category'` conversions functions accordingly (a bit hacky) - update annotation/click.js to reflect change in 'r' definition - use ax.cleanPos to clean position value per axis type in coercePosition
1 parent 48b8131 commit b67657f

File tree

6 files changed

+63
-69
lines changed

6 files changed

+63
-69
lines changed

src/components/annotations/click.js

+14-5
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,22 @@ function getToggleSets(gd, hoverData) {
8383
explicitOffSet = [],
8484
hoverLen = (hoverData || []).length;
8585

86-
var i, j, anni, showMode, pointj, toggleType;
86+
var i, j, anni, showMode, pointj, xa, ya, toggleType;
8787

8888
for(i = 0; i < annotations.length; i++) {
8989
anni = annotations[i];
9090
showMode = anni.clicktoshow;
91+
9192
if(showMode) {
9293
for(j = 0; j < hoverLen; j++) {
9394
pointj = hoverData[j];
94-
if(pointj.xaxis._id === anni.xref &&
95-
pointj.yaxis._id === anni.yref &&
96-
pointj.xaxis.d2r(pointj.x) === anni._xclick &&
97-
pointj.yaxis.d2r(pointj.y) === anni._yclick
95+
xa = pointj.xaxis;
96+
ya = pointj.yaxis;
97+
98+
if(xa._id === anni.xref &&
99+
ya._id === anni.yref &&
100+
xa.d2r(pointj.x) === clickData2r(anni._xclick, xa) &&
101+
ya.d2r(pointj.y) === clickData2r(anni._yclick, ya)
98102
) {
99103
// match! toggle this annotation
100104
// regardless of its clicktoshow mode
@@ -121,3 +125,8 @@ function getToggleSets(gd, hoverData) {
121125

122126
return {on: onSet, off: offSet, explicitOff: explicitOffSet};
123127
}
128+
129+
// to handle log axes until v2
130+
function clickData2r(d, ax) {
131+
return ax.type === 'log' ? ax.l2r(d) : ax.d2r(d);
132+
}

src/lib/index.js

+12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
'use strict';
1111

1212
var d3 = require('d3');
13+
var isNumeric = require('fast-isnumeric');
14+
15+
var numConstants = require('../constants/numerical');
16+
var FP_SAFE = numConstants.FP_SAFE;
17+
var BADNUM = numConstants.BADNUM;
1318

1419
var lib = module.exports = {};
1520

@@ -87,6 +92,13 @@ lib.pushUnique = require('./push_unique');
8792

8893
lib.cleanNumber = require('./clean_number');
8994

95+
lib.num = function num(v) {
96+
if(!isNumeric(v)) return BADNUM;
97+
v = Number(v);
98+
if(v < -FP_SAFE || v > FP_SAFE) return BADNUM;
99+
return isNumeric(v) ? Number(v) : BADNUM;
100+
};
101+
90102
lib.noop = require('./noop');
91103
lib.identity = require('./identity');
92104

src/plots/cartesian/axes.js

+8-22
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ var ONEDAY = constants.ONEDAY;
2727
var ONEHOUR = constants.ONEHOUR;
2828
var ONEMIN = constants.ONEMIN;
2929
var ONESEC = constants.ONESEC;
30-
var BADNUM = constants.BADNUM;
3130

3231
var axes = module.exports = {};
3332

@@ -100,33 +99,20 @@ axes.coerceRef = function(containerIn, containerOut, gd, attr, dflt, extraOption
10099
* - for other types: coerce them to numbers
101100
*/
102101
axes.coercePosition = function(containerOut, gd, coerce, axRef, attr, dflt) {
103-
var pos,
104-
newPos;
102+
var ax, pos;
105103

106104
if(axRef === 'paper' || axRef === 'pixel') {
105+
ax = { cleanPos: Lib.num };
107106
pos = coerce(attr, dflt);
108-
}
109-
else {
110-
var ax = axes.getFromId(gd, axRef);
111-
107+
} else {
108+
ax = axes.getFromId(gd, axRef);
112109
dflt = ax.fraction2r(dflt);
113110
pos = coerce(attr, dflt);
114-
115-
if(ax.type === 'category') {
116-
// if position is given as a category name, convert it to a number
117-
if(typeof pos === 'string' && (ax._categories || []).length) {
118-
newPos = ax._categories.indexOf(pos);
119-
containerOut[attr] = (newPos === -1) ? dflt : newPos;
120-
return;
121-
}
122-
}
123-
else if(ax.type === 'date') {
124-
containerOut[attr] = Lib.cleanDate(pos, BADNUM, ax.calendar);
125-
return;
126-
}
127111
}
128-
// finally make sure we have a number (unless date type already returned a string)
129-
containerOut[attr] = isNumeric(pos) ? Number(pos) : dflt;
112+
113+
containerOut[attr] = ax.cleanPos(pos);
114+
};
115+
130116
};
131117

132118
axes.getDataToCoordFunc = function(gd, trace, target, targetArray) {

src/plots/cartesian/set_convert.js

+21-16
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var Lib = require('../../lib');
1616
var cleanNumber = Lib.cleanNumber;
1717
var ms2DateTime = Lib.ms2DateTime;
1818
var dateTime2ms = Lib.dateTime2ms;
19+
var num = Lib.num;
1920

2021
var numConstants = require('../../constants/numerical');
2122
var FP_SAFE = numConstants.FP_SAFE;
@@ -28,13 +29,6 @@ function fromLog(v) {
2829
return Math.pow(10, v);
2930
}
3031

31-
function num(v) {
32-
if(!isNumeric(v)) return BADNUM;
33-
v = Number(v);
34-
if(v < -FP_SAFE || v > FP_SAFE) return BADNUM;
35-
return isNumeric(v) ? Number(v) : BADNUM;
36-
}
37-
3832
/**
3933
* Define the conversion functions for an axis data is used in 5 ways:
4034
*
@@ -152,7 +146,7 @@ module.exports = function setConvert(ax, fullLayout) {
152146
if(index !== undefined) return index;
153147
}
154148

155-
if(typeof v === 'number') { return v; }
149+
if(isNumeric(v)) return +v;
156150
}
157151

158152
function l2p(v) {
@@ -186,6 +180,8 @@ module.exports = function setConvert(ax, fullLayout) {
186180

187181
ax.d2p = ax.r2p = function(v) { return ax.l2p(cleanNumber(v)); };
188182
ax.p2d = ax.p2r = p2l;
183+
184+
ax.cleanPos = num;
189185
}
190186
else if(ax.type === 'log') {
191187
// d and c are data vals, r and l are logged (but d and r need cleaning)
@@ -203,6 +199,8 @@ module.exports = function setConvert(ax, fullLayout) {
203199

204200
ax.r2p = function(v) { return ax.l2p(cleanNumber(v)); };
205201
ax.p2r = p2l;
202+
203+
ax.cleanPos = num;
206204
}
207205
else if(ax.type === 'date') {
208206
// r and d are date strings, l and c are ms
@@ -222,24 +220,31 @@ module.exports = function setConvert(ax, fullLayout) {
222220

223221
ax.d2p = ax.r2p = function(v, _, calendar) { return ax.l2p(dt2ms(v, 0, calendar)); };
224222
ax.p2d = ax.p2r = function(px, r, calendar) { return ms2dt(p2l(px), r, calendar); };
223+
224+
ax.cleanPos = function(v) { return Lib.cleanDate(v, BADNUM, ax.calendar); };
225225
}
226226
else if(ax.type === 'category') {
227-
// d is categories; r, c, and l are indices
228-
// TODO: should r accept category names too?
229-
// ie r2c and r2l would be getCategoryIndex (and r2p would change)
227+
// d is categories (string)
228+
// c and l are indices (numbers)
229+
// r is categories or numbers
230230

231-
ax.d2r = ax.d2c = ax.d2l = setCategoryIndex;
231+
ax.d2c = ax.d2l = setCategoryIndex;
232232
ax.r2d = ax.c2d = ax.l2d = getCategoryName;
233233

234-
// special d2l variant that won't add categories
235-
ax.d2l_noadd = getCategoryIndex;
234+
ax.d2r = ax.d2l_noadd = getCategoryIndex;
236235

237-
ax.r2l = ax.l2r = ax.r2c = ax.c2r = num;
236+
ax.l2r = ax.r2c = ax.c2r = num;
237+
ax.r2l = getCategoryIndex;
238238

239239
ax.d2p = function(v) { return ax.l2p(getCategoryIndex(v)); };
240240
ax.p2d = function(px) { return getCategoryName(p2l(px)); };
241-
ax.r2p = ax.l2p;
241+
ax.r2p = ax.d2p;
242242
ax.p2r = p2l;
243+
244+
ax.cleanPos = function(v) {
245+
if(typeof v === 'string' && v !== '') return v;
246+
return num(v);
247+
};
243248
}
244249

245250
// find the range value at the specified (linear) fraction of the axis

src/traces/heatmap/calc.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,15 @@ module.exports = function calc(gd, trace) {
5757
z = binned.z;
5858
}
5959
else {
60-
if(hasColumns(trace)) convertColumnData(trace, xa, ya, 'x', 'y', ['z']);
60+
if(hasColumns(trace)) {
61+
convertColumnData(trace, xa, ya, 'x', 'y', ['z']);
62+
x = trace.x;
63+
y = trace.y;
64+
} else {
65+
x = trace.x ? xa.makeCalcdata(trace, 'x') : [];
66+
y = trace.y ? ya.makeCalcdata(trace, 'y') : [];
67+
}
6168

62-
x = trace.x ? xa.makeCalcdata(trace, 'x') : [];
63-
y = trace.y ? ya.makeCalcdata(trace, 'y') : [];
6469
x0 = trace.x0 || 0;
6570
dx = trace.dx || 1;
6671
y0 = trace.y0 || 0;

test/jasmine/tests/annotations_test.js

-23
Original file line numberDiff line numberDiff line change
@@ -98,39 +98,16 @@ describe('Test annotations', function() {
9898
expect(layoutOut.annotations[0].ax).toEqual('2004-07-01');
9999
});
100100

101-
it('should convert ax/ay category coordinates to linear coords', function() {
102101
var layoutIn = {
103102
annotations: [{
104-
showarrow: true,
105-
axref: 'x',
106-
ayref: 'y',
107-
x: 'c',
108-
ax: 1,
109-
y: 'A',
110-
ay: 3
111103
}]
112104
};
113105

114106
var layoutOut = {
115-
xaxis: {
116-
type: 'category',
117-
_categories: ['a', 'b', 'c'],
118-
range: [-0.5, 2.5] },
119-
yaxis: {
120-
type: 'category',
121-
_categories: ['A', 'B', 'C'],
122-
range: [-0.5, 3]
123-
}
124107
};
125-
Axes.setConvert(layoutOut.xaxis);
126-
Axes.setConvert(layoutOut.yaxis);
127108

128109
_supply(layoutIn, layoutOut);
129110

130-
expect(layoutOut.annotations[0].x).toEqual(2);
131-
expect(layoutOut.annotations[0].ax).toEqual(1);
132-
expect(layoutOut.annotations[0].y).toEqual(0);
133-
expect(layoutOut.annotations[0].ay).toEqual(3);
134111
});
135112
});
136113
});

0 commit comments

Comments
 (0)