Skip to content

Commit e12dcb4

Browse files
Starting to generalize the domain reference tests
So we can use the same code for shapes, annotations and images. Found a way to test the correct annotation size without having to know how the arrow is shortened to deal with the box around the text.
1 parent c328243 commit e12dcb4

File tree

3 files changed

+273
-109
lines changed

3 files changed

+273
-109
lines changed

test/domain_ref_shapes_test.js

Lines changed: 148 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Test the placement of Axis Referencing Objects (AROs)
2+
13
var Plotly = require('../lib/index');
24
var d3 = require('d3');
35
var createGraphDiv = require('../test/jasmine/assets/create_graph_div');
@@ -7,6 +9,7 @@ var getSVGElemScreenBBox = require('../test/jasmine/assets/get_svg_elem_screen_b
79
var Lib = require('../src/lib');
810
var Axes = require('../src/plots/cartesian/axes');
911
var axisIds = require('../src/plots/cartesian/axis_ids');
12+
var testImage = 'https://images.plot.ly/language-icons/api-home/js-logo.png';
1013

1114
// NOTE: this tolerance is in pixels
1215
var EQUALITY_TOLERANCE = 1e-2;
@@ -18,17 +21,76 @@ var it = function(s,f) {
1821
f(function() { console.log(s + ' is done.'); });
1922
}
2023

21-
// acts on an Object representing a shape which could be a line or a rect
22-
function shapeFromShapePos(shape,axletter,axnum,shapepos) {
23-
shape[axletter+'0'] = shapepos.value[0];
24-
shape[axletter+'1'] = shapepos.value[1];
25-
if (shapepos.ref === 'range') {
26-
shape[axletter+'ref'] = axletter + axnum;
27-
} else if (shapepos.ref === 'domain') {
28-
shape[axletter+'ref'] = axletter + axnum + ' domain';
29-
} else if (shapepos.ref === 'paper') {
30-
shape[axletter+'ref'] = 'paper';
24+
// acts on an Object representing a aro which could be a line or a rect
25+
// DEPRECATED
26+
function aroFromAROPos(aro,axletter,axnum,aropos) {
27+
aro[axletter+'0'] = aropos.value[0];
28+
aro[axletter+'1'] = aropos.value[1];
29+
if (aropos.ref === 'range') {
30+
aro[axletter+'ref'] = axletter + axnum;
31+
} else if (aropos.ref === 'domain') {
32+
aro[axletter+'ref'] = axletter + axnum + ' domain';
33+
} else if (aropos.ref === 'paper') {
34+
aro[axletter+'ref'] = 'paper';
35+
}
36+
}
37+
38+
// set common parameters of an ARO
39+
// {aro} is the object whose parameters to set
40+
// {axletter} is the axis, x or y
41+
// {axnum} is the axis number
42+
// {value} is the value of the first coordinate (e.g., x0 if axletter is x)
43+
// {ref} is ['range'|'domain'|'paper']
44+
function aroSetCommonParams(aro,axletter,axnum,value,ref) {
45+
aro[axletter+'0'] = value;
46+
if (ref === 'range') {
47+
aro[axletter+'ref'] = axletter + axnum;
48+
} else if (aropos.ref === 'domain') {
49+
aro[axletter+'ref'] = axletter + axnum + ' domain';
50+
} else if (aropos.ref === 'paper') {
51+
aro[axletter+'ref'] = 'paper';
52+
}
53+
}
54+
55+
// shape, annotation and image all take x0, y0, xref, yref, color parameters
56+
// arotype can be 'shape', 'annotation', or 'image'
57+
// shapes take type=[line|rect], x1, y1
58+
// annotations take ax, ay, axref, ayref, (text is just set to "A" and xanchor
59+
// and yanchor are always set to left because these are text attributes which we
60+
// don't test)
61+
// images take xsize, ysize, xanchor, yanchor (sizing is set to stretch for simplicity
62+
// in computing the bounding box and source is something predetermined)
63+
function aroFromParams(arotype,x0,y0,xreftype,yreftype,xaxnum,yaxnum,color,opts) {
64+
var aro = {};
65+
// fill with common values
66+
aroSetCommonParams(aro,'x',xaxnum,x0,xreftype);
67+
aroSetCommonParams(aro,'y',yaxnum,y0,yreftype);
68+
switch (arotype) {
69+
case 'shape':
70+
aro.x1 = opts.x1;
71+
aro.y1 = opts.y1;
72+
aro.type = opts.type;
73+
aro.line = {color: color};
74+
case 'annotation':
75+
aro.text = "A";
76+
aro.ax = opts.ax;
77+
aro.ay = opts.ay;
78+
aro.axref = opts.axref;
79+
aro.ayref = opts.ayref;
80+
aro.showarrow = true;
81+
aro.arrowhead = 0;
82+
aro.arrowcolor = color;
83+
case 'image':
84+
aro.sizex = opts.sizex;
85+
aro.sizey = opts.sizey;
86+
aro.xanchor = opts.xanchor;
87+
aro.yanchor = opts.yanchor;
88+
aro.sizing = "stretch";
89+
aro.source = testImage;
90+
default:
91+
throw "Bad arotype: " + arotype;
3192
}
93+
return aro;
3294
}
3395

3496
// axid is e.g., 'x', 'y2' etc.
@@ -45,37 +107,37 @@ function logAxisIfAxType(layoutIn,layoutOut,axid,axtype) {
45107

46108
// axref can be xref or yref
47109
// c can be x0, x1, y0, y1
48-
function mapShapeCoordToPixel(layout,axref,shape,c) {
49-
var reftype = Axes.getRefType(shape[axref]);
110+
function mapAROCoordToPixel(layout,axref,aro,c) {
111+
var reftype = Axes.getRefType(aro[axref]);
50112
var axletter = axref[0];
51113
var ret;
52114
if (reftype === 'range') {
53-
var axis = axisIds.id2name(shape[axref]);
54-
ret = pixelCalc.mapRangeToPixel(layout, axis, shape[c]);
115+
var axis = axisIds.id2name(aro[axref]);
116+
ret = pixelCalc.mapRangeToPixel(layout, axis, aro[c]);
55117
} else if (reftype === 'domain') {
56-
var axis = axisIds.id2name(shape[axref]);
57-
ret = pixelCalc.mapDomainToPixel(layout, axis, shape[c]);
118+
var axis = axisIds.id2name(aro[axref]);
119+
ret = pixelCalc.mapDomainToPixel(layout, axis, aro[c]);
58120
} else if (reftype === 'paper') {
59121
var axis = axref[0];
60-
ret = pixelCalc.mapPaperToPixel(layout, axis, shape[c]);
122+
ret = pixelCalc.mapPaperToPixel(layout, axis, aro[c]);
61123
}
62124
return ret;
63125
}
64126

65-
// compute the bounding box of the shape so that it can be compared with the SVG
127+
// compute the bounding box of the aro so that it can be compared with the SVG
66128
// bounding box
67-
function shapeToBBox(layout,shape) {
129+
function aroToBBox(layout,aro) {
68130
var bbox = {};
69131
var x1;
70132
var y1;
71133
// map x coordinates
72-
bbox.x = mapShapeCoordToPixel(layout,'xref',shape,'x0');
73-
x1 = mapShapeCoordToPixel(layout,'xref',shape,'x1');
134+
bbox.x = mapAROCoordToPixel(layout,'xref',aro,'x0');
135+
x1 = mapAROCoordToPixel(layout,'xref',aro,'x1');
74136
// SVG bounding boxes have x,y referring to top left corner, but here we are
75-
// specifying shapes where y0 refers to the bottom left corner like
137+
// specifying aros where y0 refers to the bottom left corner like
76138
// Plotly.js, so we swap y0 and y1
77-
bbox.y = mapShapeCoordToPixel(layout,'yref',shape,'y1');
78-
y1 = mapShapeCoordToPixel(layout,'yref',shape,'y0');
139+
bbox.y = mapAROCoordToPixel(layout,'yref',aro,'y1');
140+
y1 = mapAROCoordToPixel(layout,'yref',aro,'y0');
79141
bbox.width = x1 - bbox.x;
80142
bbox.height = y1 - bbox.y;
81143
return bbox;
@@ -92,85 +154,104 @@ function compareBBoxes(a,b) {
92154
true);
93155
}
94156

95-
// gets the SVG bounding box of the shape and checks it against what mapToPixel
157+
// gets the SVG bounding box of the aro and checks it against what mapToPixel
96158
// gives
97-
function checkShapePosition(gd,shape) {
98-
var shapePath = d3.selectAll('path').filter(function () {
99-
return this.style.stroke === shape.line.color;
159+
function checkAROPosition(gd,aro) {
160+
var aroPath = d3.selectAll('path').filter(function () {
161+
return this.style.stroke === aro.line.color;
100162
}).node();
101-
var shapePathBBox = getSVGElemScreenBBox(shapePath);
102-
var shapeBBox = shapeToBBox(gd.layout,shape);
103-
var ret = compareBBoxes(shapeBBox,shapePathBBox);
163+
var aroPathBBox = getSVGElemScreenBBox(aroPath);
164+
var aroBBox = aroToBBox(gd.layout,aro);
165+
var ret = compareBBoxes(aroBBox,aroPathBBox);
104166
if (DEBUG) {
105-
console.log('SVG BBox',shapePathBBox);
106-
console.log('shape BBox',shapeBBox);
167+
console.log('SVG BBox',aroPathBBox);
168+
console.log('aro BBox',aroBBox);
107169
}
108170
return ret;
109171
}
110172

111173
// some made-up values for testing
112-
var shapePositionsX = [
174+
var aroPositionsX = [
113175
{
114-
// shapes referring to data
176+
// aros referring to data
115177
ref: 'range',
116-
// two values for rects
117-
value: [2,3]
178+
value: [2,3],
179+
// for objects that need a size (i.e., images)
180+
size: 1.5
118181
},
119182
{
120-
// shapes referring to domains
183+
// aros referring to domains
121184
ref: 'domain',
122185
value: [0.2,0.75],
186+
size: 0.3
123187
},
124188
{
125-
// shapes referring to paper
189+
// aros referring to paper
126190
ref: 'paper',
127-
value: [0.25, 0.8]
128-
}
191+
value: [0.25, 0.8],
192+
size: 0.35
193+
},
129194
];
130-
var shapePositionsY = [
195+
var aroRelPixelSizeX [
196+
// this means specify the offset with the second value in aroPositions{X,Y}
197+
{ ref: 'nopixel' },
198+
// with this you can specify the arrow in pixels
199+
{ ref: 'pixel', value: 100 }
200+
];
201+
var aroPositionsY = [
131202
{
132-
// shapes referring to data
203+
// aros referring to data
133204
ref: 'range',
134205
// two values for rects
135206
value: [1,2]
136207
},
137208
{
138-
// shapes referring to domains
209+
// aros referring to domains
139210
ref: 'domain',
140211
value: [0.25,0.7],
141212
},
142213
{
143-
// shapes referring to paper
214+
// aros referring to paper
144215
ref: 'paper',
145216
value: [0.2, 0.85]
146217
}
147218
];
219+
var aroRelPixelSizeY [
220+
// this means specify the offset with the second value in aroPositions{X,Y}
221+
{ ref: 'nopixel' },
222+
// with this you can specify the arrow in pixels
223+
{ ref: 'pixel', value: 200 }
224+
];
225+
226+
var aroTypes = ['shape', 'annotation', 'image'];
148227
var axisTypes = [ 'linear', 'log' ];
149228
// Test on 'x', 'y', 'x2', 'y2' axes
150229
// TODO the 'paper' position references are tested twice when once would
151230
// suffice.
152231
var axNum = ['','2'];
153232
// only test line and rect for now
154-
var shapeType = ['line','rect'];
233+
var aroType = ['line','rect'];
155234
// this color chosen so it can easily be found with d3
156-
var shapeColor = 'rgb(50, 100, 150)';
157-
var testDomRefShapeCombo = function(combo) {
235+
// NOTE: for images color cannot be set but it will be the only image in the
236+
// plot so you can use d3.select('g image').node()
237+
var aroColor = 'rgb(50, 100, 150)';
238+
var testDomRefAROCombo = function(combo) {
158239
var xAxNum = combo[0];
159240
var xaxisType = combo[1];
160-
var xshapePos = combo[2];
241+
var xaroPos = combo[2];
161242
var yAxNum = combo[3];
162243
var yaxisType = combo[4];
163-
var yshapePos = combo[5];
164-
var shapeType = combo[6];
165-
it('should draw a ' + shapeType
244+
var yaroPos = combo[5];
245+
var aroType = combo[6];
246+
it('should draw a ' + aroType
166247
+ ' for x' + xAxNum + ' of type '
167248
+ xaxisType
168249
+ ' with a value referencing '
169-
+ xshapePos.ref
250+
+ xaroPos.ref
170251
+ ' and for y' + yAxNum + ' of type '
171252
+ yaxisType
172253
+ ' with a value referencing '
173-
+ yshapePos.ref,
254+
+ yaroPos.ref,
174255
function (done) {
175256
var gd = createGraphDiv();
176257
var mock = Lib.extendDeep({},
@@ -179,32 +260,32 @@ var testDomRefShapeCombo = function(combo) {
179260
console.log(combo);
180261
}
181262
Plotly.newPlot(gd, mock)
182-
var shape = {
183-
type: shapeType,
184-
line: { color: shapeColor }
263+
var aro = {
264+
type: aroType,
265+
line: { color: aroColor }
185266
};
186-
shapeFromShapePos(shape,'x',xAxNum,xshapePos);
187-
shapeFromShapePos(shape,'y',yAxNum,yshapePos);
188-
var layout = {shapes: [shape]};
267+
aroFromAROPos(aro,'x',xAxNum,xaroPos);
268+
aroFromAROPos(aro,'y',yAxNum,yaroPos);
269+
var layout = {shapes: [aro]};
189270
// change to log axes if need be
190271
logAxisIfAxType(gd.layout,layout,'x'+xAxNum,xaxisType);
191272
logAxisIfAxType(gd.layout,layout,'y'+yAxNum,yaxisType);
192273
Plotly.relayout(gd,layout);
193-
console.log(checkShapePosition(gd,shape));
274+
console.log(checkAROPosition(gd,aro));
194275
destroyGraphDiv();
195276
});
196277
}
197278

198-
// Test correct shape positions
199-
function test_correct_shape_positions () {
279+
// Test correct aro positions
280+
function test_correct_aro_positions () {
200281
var iterable = require('extra-iterable');
201282
// for both x and y axes
202283
var testCombos = [...iterable.cartesianProduct([
203-
axNum,axisTypes,shapePositionsX,axNum,axisTypes,shapePositionsY,shapeType
284+
axNum,axisTypes,aroPositionsX,axNum,axisTypes,aroPositionsY,aroType
204285
])];
205-
// map all the combinations to a shape definition and check this shape is
286+
// map all the combinations to a aro definition and check this aro is
206287
// placed properly
207-
testCombos.forEach(testDomRefShapeCombo);
288+
testCombos.forEach(testDomRefAROCombo);
208289
}
209290

210-
test_correct_shape_positions();
291+
test_correct_aro_positions();

test/domain_ref_test.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,13 @@
66
</head>
77
<body>
88
<script src="domain_ref_test-min.js"></script>
9+
<script>
10+
function findPathWithColor(c) {
11+
var aroPath = d3.selectAll('path').filter(function () {
12+
return this.style.stroke === c;
13+
}).node();
14+
return aroPath;
15+
}
16+
</script>
917
</body>
1018
</html>

0 commit comments

Comments
 (0)