@@ -16,10 +16,10 @@ var Lib = require('../../lib');
16
16
var Color = require ( '../../components/color' ) ;
17
17
var Drawing = require ( '../../components/drawing' ) ;
18
18
var Plots = require ( '../plots' ) ;
19
+ var Axes = require ( '../../plots/cartesian/axes' ) ;
19
20
var setConvertCartesian = require ( '../cartesian/set_convert' ) ;
20
21
var setConvertPolar = require ( './set_convert' ) ;
21
22
var doAutoRange = require ( '../cartesian/autorange' ) . doAutoRange ;
22
- var doTicksSingle = require ( '../cartesian/axes' ) . doTicksSingle ;
23
23
var dragBox = require ( '../cartesian/dragbox' ) ;
24
24
var dragElement = require ( '../../components/dragelement' ) ;
25
25
var Fx = require ( '../../components/fx' ) ;
@@ -65,7 +65,7 @@ function Polar(gd, id) {
65
65
. attr ( 'class' , id ) ;
66
66
67
67
// unfortunately, we have to keep track of some axis tick settings
68
- // so that we don't have to call doTicksSingle with its special redraw flag
68
+ // as polar subplots do not implement the 'ticks' editType
69
69
this . radialTickLayout = null ;
70
70
this . angularTickLayout = null ;
71
71
}
@@ -141,11 +141,9 @@ proto.updateLayers = function(fullLayout, polarLayout) {
141
141
break ;
142
142
case 'radial-grid' :
143
143
sel . style ( 'fill' , 'none' ) ;
144
- sel . append ( 'g' ) . classed ( 'x' , 1 ) ;
145
144
break ;
146
145
case 'angular-grid' :
147
146
sel . style ( 'fill' , 'none' ) ;
148
- sel . append ( 'g' ) . classed ( 'angularaxis' , 1 ) ;
149
147
break ;
150
148
case 'radial-line' :
151
149
sel . append ( 'line' ) . style ( 'fill' , 'none' ) ;
@@ -167,14 +165,15 @@ proto.updateLayers = function(fullLayout, polarLayout) {
167
165
*
168
166
* - this.radialAxis
169
167
* extends polarLayout.radialaxis, adds mocked 'domain' and
170
- * few other keys in order to reuse Cartesian doAutoRange and doTicksSingle,
168
+ * few other keys in order to reuse Cartesian doAutoRange and the Axes
169
+ * drawing routines.
171
170
* used for calcdata -> geometric conversions (aka c2g) during the plot step
172
171
* + setGeometry setups ax.c2g for given ax.range
173
172
* + setScale setups ax._m,ax._b for given ax.range
174
173
*
175
174
* - this.angularAxis
176
175
* extends polarLayout.angularaxis, adds mocked 'range' and 'domain' and
177
- * a few other keys in order to reuse Cartesian doTicksSingle,
176
+ * a few other keys in order to reuse the Axes drawing routines.
178
177
* used for calcdata -> geometric conversions (aka c2g) during the plot step
179
178
* + setGeometry setups ax.c2g given ax.rotation, ax.direction & ax._categories,
180
179
* and mocks ax.range
@@ -247,8 +246,6 @@ proto.updateLayout = function(fullLayout, polarLayout) {
247
246
var cyy = _this . cyy = cy - yOffset2 ;
248
247
249
248
_this . radialAxis = _this . mockAxis ( fullLayout , polarLayout , radialLayout , {
250
- _axislayer : layers [ 'radial-axis' ] ,
251
- _gridlayer : layers [ 'radial-grid' ] ,
252
249
// make this an 'x' axis to make positioning (especially rotation) easier
253
250
_id : 'x' ,
254
251
// convert to 'x' axis equivalent
@@ -261,8 +258,6 @@ proto.updateLayout = function(fullLayout, polarLayout) {
261
258
} ) ;
262
259
263
260
_this . angularAxis = _this . mockAxis ( fullLayout , polarLayout , angularLayout , {
264
- _axislayer : layers [ 'angular-axis' ] ,
265
- _gridlayer : layers [ 'angular-grid' ] ,
266
261
side : 'right' ,
267
262
// to get auto nticks right
268
263
domain : [ 0 , Math . PI ] ,
@@ -311,12 +306,7 @@ proto.mockAxis = function(fullLayout, polarLayout, axLayout, opts) {
311
306
var commonOpts = {
312
307
// to get _boundingBox computation right when showticklabels is false
313
308
anchor : 'free' ,
314
- position : 0 ,
315
- _pos : 0 ,
316
- // dummy truthy value to make doTicksSingle draw the grid
317
- _counteraxis : true ,
318
- // don't use automargins routine for labels
319
- automargin : false
309
+ position : 0
320
310
} ;
321
311
322
312
var ax = Lib . extendFlat ( commonOpts , axLayout , opts ) ;
@@ -392,18 +382,18 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) {
392
382
// rotate auto tick labels by 180 if in quadrant II and III to make them
393
383
// readable from left-to-right
394
384
//
395
- // TODO try moving deeper in doTicksSingle for better results?
385
+ // TODO try moving deeper in Axes.drawLabels for better results?
396
386
if ( ax . tickangle === 'auto' && ( a0 > 90 && a0 <= 270 ) ) {
397
387
ax . tickangle = 180 ;
398
388
}
399
389
400
390
// easier to set rotate angle with custom translate function
401
- ax . _transfn = function ( d ) {
391
+ var transFn = function ( d ) {
402
392
return 'translate(' + ( ax . l2p ( d . x ) + innerRadius ) + ',0)' ;
403
393
} ;
404
394
405
395
// set special grid path function
406
- ax . _gridpath = function ( d ) {
396
+ var gridPathFn = function ( d ) {
407
397
return _this . pathArc ( ax . r2p ( d . x ) + innerRadius ) ;
408
398
} ;
409
399
@@ -415,14 +405,50 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) {
415
405
416
406
if ( hasRoomForIt ) {
417
407
ax . setScale ( ) ;
418
- doTicksSingle ( gd , ax , true ) ;
408
+
409
+ var vals = Axes . calcTicks ( ax ) ;
410
+ var valsClipped = Axes . clipEnds ( ax , vals ) ;
411
+ var labelFns = Axes . makeLabelFns ( ax , 0 ) ;
412
+
413
+ var sideOpposite = { x : 'top' , y : 'right' } [ ax . _id ] ;
414
+ var tickSign = [ - 1 , 1 , ax . side === sideOpposite ? 1 : - 1 ] ;
415
+ if ( ( ax . ticks !== 'inside' ) === ( ax . _id === 'x' ) ) {
416
+ tickSign = tickSign . map ( function ( v ) { return - v ; } ) ;
417
+ }
418
+
419
+ Axes . drawTicks ( gd , ax , {
420
+ // TODO right? No need to clip here ever?
421
+ vals : vals ,
422
+ layer : layers [ 'radial-axis' ] ,
423
+ path : Axes . makeTickPath ( ax , 0 , tickSign [ 2 ] ) ,
424
+ transFn : transFn
425
+ } ) ;
426
+
427
+ Axes . drawGrid ( gd , ax , {
428
+ vals : valsClipped ,
429
+ layer : layers [ 'radial-grid' ] ,
430
+ path : gridPathFn ,
431
+ transFn : transFn
432
+ } ) ;
433
+
434
+ Axes . drawLabels ( gd , ax , {
435
+ vals : vals ,
436
+ layer : layers [ 'radial-axis' ] ,
437
+ shift : 0 ,
438
+ transFn : transFn ,
439
+ labelXFn : labelFns . labelXFn ,
440
+ labelYFn : labelFns . labelYFn ,
441
+ labelAnchorFn : labelFns . labelAnchorFn ,
442
+ skipTitle : true
443
+ } ) ;
419
444
}
420
445
421
446
// stash 'actual' radial axis angle for drag handlers (in degrees)
422
447
var angle = _this . radialAxisAngle = _this . vangles ?
423
448
rad2deg ( snapToVertexAngle ( deg2rad ( radialLayout . angle ) , _this . vangles ) ) :
424
449
radialLayout . angle ;
425
450
451
+ // TODO no more "draw-and-then-tweak" !!!
426
452
var trans = strTranslate ( cx , cy ) + strRotate ( - angle ) ;
427
453
428
454
updateElement (
@@ -431,6 +457,7 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) {
431
457
{ transform : trans }
432
458
) ;
433
459
460
+ // TODO !!
434
461
// move all grid paths to about circle center,
435
462
// undo individual grid lines translations
436
463
updateElement (
@@ -514,16 +541,8 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) {
514
541
ax . dtick = rad2deg ( ax . dtick ) ;
515
542
}
516
543
517
- // Use tickval filter for category axes instead of tweaking
518
- // the range w.r.t sector, so that sectors that cross 360 can
519
- // show all their ticks.
520
- if ( ax . type === 'category' ) {
521
- ax . _tickFilter = function ( d ) {
522
- return Lib . isAngleInsideSector ( t2g ( d ) , _this . sectorInRad ) ;
523
- } ;
524
- }
525
-
526
- ax . _transfn = function ( d ) {
544
+ // TODO break up into two functions!
545
+ var transFn = function ( d ) {
527
546
var sel = d3 . select ( this ) ;
528
547
var hasElement = sel && sel . node ( ) ;
529
548
@@ -541,17 +560,18 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) {
541
560
return out ;
542
561
} ;
543
562
544
- ax . _gridpath = function ( d ) {
563
+ var gridPathFn = function ( d ) {
545
564
var rad = t2g ( d ) ;
546
565
var cosRad = Math . cos ( rad ) ;
547
566
var sinRad = Math . sin ( rad ) ;
548
567
return 'M' + [ cx + innerRadius * cosRad , cy - innerRadius * sinRad ] +
549
568
'L' + [ cx + radius * cosRad , cy - radius * sinRad ] ;
550
569
} ;
551
570
571
+ Axes . makeLabelFns ( ax , 0 ) ;
552
572
var offset4fontsize = ( angularLayout . ticks !== 'outside' ? 0.7 : 0.5 ) ;
553
573
554
- ax . _labelx = function ( d ) {
574
+ var labelXFn = function ( d ) {
555
575
var rad = t2g ( d ) ;
556
576
var labelStandoff = ax . _labelStandoff ;
557
577
var pad = ax . _pad ;
@@ -564,7 +584,7 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) {
564
584
return offset4tx + offset4tick ;
565
585
} ;
566
586
567
- ax . _labely = function ( d ) {
587
+ var labelYFn = function ( d ) {
568
588
var rad = t2g ( d ) ;
569
589
var labelStandoff = ax . _labelStandoff ;
570
590
var labelShift = ax . _labelShift ;
@@ -576,7 +596,8 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) {
576
596
return offset4tx + offset4tick ;
577
597
} ;
578
598
579
- ax . _labelanchor = function ( angle , d ) {
599
+ // TODO maybe switch angle, d ordering ??
600
+ var labelAnchorFn = function ( angle , d ) {
580
601
var rad = t2g ( d ) ;
581
602
return signSin ( rad ) === 0 ?
582
603
( signCos ( rad ) > 0 ? 'start' : 'end' ) :
@@ -590,13 +611,57 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) {
590
611
}
591
612
592
613
ax . setScale ( ) ;
593
- doTicksSingle ( gd , ax , true ) ;
614
+
615
+ var vals = Axes . calcTicks ( ax ) ;
616
+ // Use tickval filter for category axes instead of tweaking
617
+ // the range w.r.t sector, so that sectors that cross 360 can
618
+ // show all their ticks.
619
+ var tickVals = ax . type === 'category' ?
620
+ vals . filter ( function ( d ) { return Lib . isAngleInsideSector ( t2g ( d ) , _this . sectorInRad ) ; } ) :
621
+ vals ;
622
+
623
+ if ( ax . visible ) {
624
+ // TODO dry!!
625
+ var sideOpposite = 'right' ;
626
+ var tickSign = [ - 1 , 1 , ax . side === sideOpposite ? 1 : - 1 ] ;
627
+ if ( ( ax . ticks !== 'inside' ) === false ) {
628
+ tickSign = tickSign . map ( function ( v ) { return - v ; } ) ;
629
+ }
630
+
631
+ var pad = tickSign [ 2 ] * ( ax . linewidth || 1 ) / 2 ;
632
+ var len = tickSign [ 2 ] * ax . ticklen ;
633
+
634
+ Axes . drawTicks ( gd , ax , {
635
+ vals : tickVals ,
636
+ layer : layers [ 'angular-axis' ] ,
637
+ path : 'M' + pad + ',0h' + len ,
638
+ transFn : transFn
639
+ } ) ;
640
+
641
+ Axes . drawGrid ( gd , ax , {
642
+ vals : tickVals ,
643
+ layer : layers [ 'angular-grid' ] ,
644
+ path : gridPathFn ,
645
+ transFn : transFn
646
+ } ) ;
647
+
648
+ Axes . drawLabels ( gd , ax , {
649
+ vals : tickVals ,
650
+ layer : layers [ 'angular-axis' ] ,
651
+ shift : 0 ,
652
+ transFn : transFn ,
653
+ labelXFn : labelXFn ,
654
+ labelYFn : labelYFn ,
655
+ labelAnchorFn : labelAnchorFn ,
656
+ skipTitle : true
657
+ } ) ;
658
+ }
594
659
595
660
// angle of polygon vertices in geometric radians (null means circles)
596
661
// TODO what to do when ax.period > ax._categories ??
597
662
var vangles ;
598
663
if ( polarLayout . gridshape === 'linear' ) {
599
- vangles = ax . _vals . map ( t2g ) ;
664
+ vangles = vals . map ( t2g ) ;
600
665
601
666
// ax._vals should be always ordered, make them
602
667
// always turn counterclockwise for convenience here
@@ -1044,29 +1109,25 @@ proto.updateRadialDrag = function(fullLayout, polarLayout, rngIndex) {
1044
1109
return ;
1045
1110
}
1046
1111
1112
+ var fullLayoutNow = gd . _fullLayout ;
1113
+ var polarLayoutNow = fullLayoutNow [ _this . id ] ;
1114
+
1047
1115
// update radial range -> update c2g -> update _m,_b
1048
1116
radialAxis . range [ rngIndex ] = rprime ;
1049
1117
radialAxis . _rl [ rngIndex ] = rprime ;
1050
- radialAxis . setGeometry ( ) ;
1051
- radialAxis . setScale ( ) ;
1118
+ _this . updateRadialAxis ( fullLayoutNow , polarLayoutNow ) ;
1052
1119
1053
1120
_this . xaxis . setRange ( ) ;
1054
1121
_this . xaxis . setScale ( ) ;
1055
1122
_this . yaxis . setRange ( ) ;
1056
1123
_this . yaxis . setScale ( ) ;
1057
1124
1058
- doTicksSingle ( gd , radialAxis , true ) ;
1059
- layers [ 'radial-grid' ]
1060
- . attr ( 'transform' , strTranslate ( cx , cy ) )
1061
- . selectAll ( 'path' ) . attr ( 'transform' , null ) ;
1062
-
1063
1125
var hasRegl = false ;
1064
1126
1065
1127
for ( var traceType in _this . traceHash ) {
1066
1128
var moduleCalcData = _this . traceHash [ traceType ] ;
1067
1129
var moduleCalcDataVisible = Lib . filterVisible ( moduleCalcData ) ;
1068
1130
var _module = moduleCalcData [ 0 ] [ 0 ] . trace . _module ;
1069
- var polarLayoutNow = gd . _fullLayout [ _this . id ] ;
1070
1131
_module . plot ( gd , _this , moduleCalcDataVisible , polarLayoutNow ) ;
1071
1132
if ( Registry . traceIs ( traceType , 'gl' ) && moduleCalcDataVisible . length ) hasRegl = true ;
1072
1133
}
@@ -1140,6 +1201,7 @@ proto.updateAngularDrag = function(fullLayout) {
1140
1201
function moveFn ( dx , dy ) {
1141
1202
var fullLayoutNow = _this . gd . _fullLayout ;
1142
1203
var polarLayoutNow = fullLayoutNow [ _this . id ] ;
1204
+
1143
1205
var x1 = x0 + dx ;
1144
1206
var y1 = y0 + dy ;
1145
1207
var a1 = xy2a ( x1 , y1 ) ;
@@ -1158,7 +1220,6 @@ proto.updateAngularDrag = function(fullLayout) {
1158
1220
1159
1221
layers . bg . attr ( 'transform' , trans ) ;
1160
1222
layers [ 'radial-grid' ] . attr ( 'transform' , trans ) ;
1161
- layers [ 'angular-line' ] . select ( 'path' ) . attr ( 'transform' , trans ) ;
1162
1223
layers [ 'radial-axis' ] . attr ( 'transform' , trans2 ) ;
1163
1224
layers [ 'radial-line' ] . select ( 'line' ) . attr ( 'transform' , trans2 ) ;
1164
1225
_this . updateRadialAxisTitle ( fullLayoutNow , polarLayoutNow , rrot1 ) ;
@@ -1184,10 +1245,7 @@ proto.updateAngularDrag = function(fullLayout) {
1184
1245
1185
1246
// update rotation -> range -> _m,_b
1186
1247
angularAxis . rotation = Lib . modHalf ( rot1 , 360 ) ;
1187
- angularAxis . setGeometry ( ) ;
1188
- angularAxis . setScale ( ) ;
1189
-
1190
- doTicksSingle ( gd , angularAxis , true ) ;
1248
+ _this . updateAngularAxis ( fullLayoutNow , polarLayoutNow ) ;
1191
1249
1192
1250
if ( _this . _hasClipOnAxisFalse && ! Lib . isFullCircle ( _this . sectorInRad ) ) {
1193
1251
scatterTraces . call ( Drawing . hideOutsideRangePoints , _this ) ;
0 commit comments