1
+ // Test the placement of Axis Referencing Objects (AROs)
2
+
1
3
var Plotly = require ( '../lib/index' ) ;
2
4
var d3 = require ( 'd3' ) ;
3
5
var createGraphDiv = require ( '../test/jasmine/assets/create_graph_div' ) ;
@@ -7,6 +9,7 @@ var getSVGElemScreenBBox = require('../test/jasmine/assets/get_svg_elem_screen_b
7
9
var Lib = require ( '../src/lib' ) ;
8
10
var Axes = require ( '../src/plots/cartesian/axes' ) ;
9
11
var axisIds = require ( '../src/plots/cartesian/axis_ids' ) ;
12
+ var testImage = 'https://images.plot.ly/language-icons/api-home/js-logo.png' ;
10
13
11
14
// NOTE: this tolerance is in pixels
12
15
var EQUALITY_TOLERANCE = 1e-2 ;
@@ -18,17 +21,76 @@ var it = function(s,f) {
18
21
f ( function ( ) { console . log ( s + ' is done.' ) ; } ) ;
19
22
}
20
23
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 ;
31
92
}
93
+ return aro ;
32
94
}
33
95
34
96
// axid is e.g., 'x', 'y2' etc.
@@ -45,37 +107,37 @@ function logAxisIfAxType(layoutIn,layoutOut,axid,axtype) {
45
107
46
108
// axref can be xref or yref
47
109
// 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 ] ) ;
50
112
var axletter = axref [ 0 ] ;
51
113
var ret ;
52
114
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 ] ) ;
55
117
} 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 ] ) ;
58
120
} else if ( reftype === 'paper' ) {
59
121
var axis = axref [ 0 ] ;
60
- ret = pixelCalc . mapPaperToPixel ( layout , axis , shape [ c ] ) ;
122
+ ret = pixelCalc . mapPaperToPixel ( layout , axis , aro [ c ] ) ;
61
123
}
62
124
return ret ;
63
125
}
64
126
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
66
128
// bounding box
67
- function shapeToBBox ( layout , shape ) {
129
+ function aroToBBox ( layout , aro ) {
68
130
var bbox = { } ;
69
131
var x1 ;
70
132
var y1 ;
71
133
// 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' ) ;
74
136
// 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
76
138
// 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' ) ;
79
141
bbox . width = x1 - bbox . x ;
80
142
bbox . height = y1 - bbox . y ;
81
143
return bbox ;
@@ -92,85 +154,104 @@ function compareBBoxes(a,b) {
92
154
true ) ;
93
155
}
94
156
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
96
158
// 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 ;
100
162
} ) . 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 ) ;
104
166
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 ) ;
107
169
}
108
170
return ret ;
109
171
}
110
172
111
173
// some made-up values for testing
112
- var shapePositionsX = [
174
+ var aroPositionsX = [
113
175
{
114
- // shapes referring to data
176
+ // aros referring to data
115
177
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
118
181
} ,
119
182
{
120
- // shapes referring to domains
183
+ // aros referring to domains
121
184
ref : 'domain' ,
122
185
value : [ 0.2 , 0.75 ] ,
186
+ size : 0.3
123
187
} ,
124
188
{
125
- // shapes referring to paper
189
+ // aros referring to paper
126
190
ref : 'paper' ,
127
- value : [ 0.25 , 0.8 ]
128
- }
191
+ value : [ 0.25 , 0.8 ] ,
192
+ size : 0.35
193
+ } ,
129
194
] ;
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 = [
131
202
{
132
- // shapes referring to data
203
+ // aros referring to data
133
204
ref : 'range' ,
134
205
// two values for rects
135
206
value : [ 1 , 2 ]
136
207
} ,
137
208
{
138
- // shapes referring to domains
209
+ // aros referring to domains
139
210
ref : 'domain' ,
140
211
value : [ 0.25 , 0.7 ] ,
141
212
} ,
142
213
{
143
- // shapes referring to paper
214
+ // aros referring to paper
144
215
ref : 'paper' ,
145
216
value : [ 0.2 , 0.85 ]
146
217
}
147
218
] ;
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' ] ;
148
227
var axisTypes = [ 'linear' , 'log' ] ;
149
228
// Test on 'x', 'y', 'x2', 'y2' axes
150
229
// TODO the 'paper' position references are tested twice when once would
151
230
// suffice.
152
231
var axNum = [ '' , '2' ] ;
153
232
// only test line and rect for now
154
- var shapeType = [ 'line' , 'rect' ] ;
233
+ var aroType = [ 'line' , 'rect' ] ;
155
234
// 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 ) {
158
239
var xAxNum = combo [ 0 ] ;
159
240
var xaxisType = combo [ 1 ] ;
160
- var xshapePos = combo [ 2 ] ;
241
+ var xaroPos = combo [ 2 ] ;
161
242
var yAxNum = combo [ 3 ] ;
162
243
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
166
247
+ ' for x' + xAxNum + ' of type '
167
248
+ xaxisType
168
249
+ ' with a value referencing '
169
- + xshapePos . ref
250
+ + xaroPos . ref
170
251
+ ' and for y' + yAxNum + ' of type '
171
252
+ yaxisType
172
253
+ ' with a value referencing '
173
- + yshapePos . ref ,
254
+ + yaroPos . ref ,
174
255
function ( done ) {
175
256
var gd = createGraphDiv ( ) ;
176
257
var mock = Lib . extendDeep ( { } ,
@@ -179,32 +260,32 @@ var testDomRefShapeCombo = function(combo) {
179
260
console . log ( combo ) ;
180
261
}
181
262
Plotly . newPlot ( gd , mock )
182
- var shape = {
183
- type : shapeType ,
184
- line : { color : shapeColor }
263
+ var aro = {
264
+ type : aroType ,
265
+ line : { color : aroColor }
185
266
} ;
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 ] } ;
189
270
// change to log axes if need be
190
271
logAxisIfAxType ( gd . layout , layout , 'x' + xAxNum , xaxisType ) ;
191
272
logAxisIfAxType ( gd . layout , layout , 'y' + yAxNum , yaxisType ) ;
192
273
Plotly . relayout ( gd , layout ) ;
193
- console . log ( checkShapePosition ( gd , shape ) ) ;
274
+ console . log ( checkAROPosition ( gd , aro ) ) ;
194
275
destroyGraphDiv ( ) ;
195
276
} ) ;
196
277
}
197
278
198
- // Test correct shape positions
199
- function test_correct_shape_positions ( ) {
279
+ // Test correct aro positions
280
+ function test_correct_aro_positions ( ) {
200
281
var iterable = require ( 'extra-iterable' ) ;
201
282
// for both x and y axes
202
283
var testCombos = [ ...iterable . cartesianProduct ( [
203
- axNum , axisTypes , shapePositionsX , axNum , axisTypes , shapePositionsY , shapeType
284
+ axNum , axisTypes , aroPositionsX , axNum , axisTypes , aroPositionsY , aroType
204
285
] ) ] ;
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
206
287
// placed properly
207
- testCombos . forEach ( testDomRefShapeCombo ) ;
288
+ testCombos . forEach ( testDomRefAROCombo ) ;
208
289
}
209
290
210
- test_correct_shape_positions ( ) ;
291
+ test_correct_aro_positions ( ) ;
0 commit comments