@@ -24,7 +24,7 @@ import Scale, { ScaleGetTicksOpt, ScaleSettingDefault } from './Scale';
2424import * as helper from './helper' ;
2525import { ScaleTick , ParsedAxisBreakList , ScaleDataValue , NullUndefined } from '../util/types' ;
2626import { getScaleBreakHelper } from './break' ;
27- import { assert } from 'zrender/src/core/util' ;
27+ import { assert , retrieve2 } from 'zrender/src/core/util' ;
2828
2929class IntervalScale < SETTING extends ScaleSettingDefault = ScaleSettingDefault > extends Scale < SETTING > {
3030
@@ -34,13 +34,30 @@ class IntervalScale<SETTING extends ScaleSettingDefault = ScaleSettingDefault> e
3434 // Step is calculated in adjustExtent.
3535 protected _interval : number = 0 ;
3636 protected _intervalPrecision : number = 2 ;
37- // `_intervalCount` effectively specifies the number of "nice segment". This is for special cases,
38- // such as `alignTo: true` and min max are fixed. In this case, `_interval` may be specified with
39- // a "not-nice" value and needs to be rounded with `_intervalPrecision` for better appearance. Then
40- // merely accumulating `_interval` may generate incorrect number of ticks. So `_intervalCount` is
41- // required to specify the expected tick number.
37+ protected _extentPrecision : number [ ] = [ ] ;
38+ /**
39+ * `_intervalCount` effectively specifies the number of "nice segments". This is for special cases,
40+ * such as `alignTicks: true` and min max are fixed. In this case, `_interval` may be specified with
41+ * a "not-nice" value and needs to be rounded with `_intervalPrecision` for better appearance. Then
42+ * merely accumulating `_interval` may generate incorrect number of ticks due to cumulative errors.
43+ * So `_intervalCount` is required to specify the expected nice ticks number.
44+ * Should ensure `_intervalCount >= -1`,
45+ * where `-1` means no nice tick (e.g., `_extent: [5.2, 5.8], _interval: 1`),
46+ * and `0` means only one nice tick (e.g., `_extent: [5, 5.8], _interval: 1`).
47+ * @see setInterval
48+ */
4249 private _intervalCount : number | NullUndefined = undefined ;
43- // Should ensure: `_extent[0] <= _niceExtent[0] && _niceExtent[1] <= _extent[1]`
50+ /**
51+ * Should ensure:
52+ * `_extent[0] <= _niceExtent[0] && _niceExtent[1] <= _extent[1]`
53+ * But NOTICE:
54+ * `_niceExtent[0] - _niceExtent[1] <= _interval`, rather than always `< 0`,
55+ * because `_niceExtent` is typically calculated by
56+ * `[ Math.ceil(_extent[0] / _interval) * _interval, Math.floor(_extent[1] / _interval) * _interval ]`.
57+ * e.g., `_extent: [5.2, 5.8]` with interval `1` will get `_niceExtent: [6, 5]`.
58+ * e.g., `_extent: [5, 5.8]` with interval `1` will get `_niceExtent: [5, 5]`.
59+ * @see setInterval
60+ */
4461 protected _niceExtent : [ number , number ] ;
4562
4663
@@ -90,53 +107,43 @@ class IntervalScale<SETTING extends ScaleSettingDefault = ScaleSettingDefault> e
90107 /**
91108 * @final override is DISALLOWED.
92109 */
93- setInterval ( { interval, intervalCount, intervalPrecision, niceExtent} : {
110+ setInterval ( { interval, intervalCount, intervalPrecision, extentPrecision , niceExtent} : {
94111 interval ?: number | NullUndefined ;
112+ // See comments of `_intervalCount`.
95113 intervalCount ?: number | NullUndefined ;
96114 intervalPrecision ?: number | NullUndefined ;
115+ extentPrecision ?: number [ ] | NullUndefined ;
97116 niceExtent ?: number [ ] ;
98117 } ) : void {
99- const intervalCountSpecified = intervalCount != null ;
118+ const extent = this . _extent ;
119+
100120 if ( __DEV__ ) {
101121 assert ( interval != null ) ;
102- if ( intervalCountSpecified ) {
122+ if ( intervalCount != null ) {
103123 assert (
104- intervalCount > 0
124+ intervalCount >= - 1
105125 && intervalPrecision != null
106126 // Do not support intervalCount on axis break currently.
107127 && ! this . hasBreaks ( )
108128 ) ;
109129 }
110- }
111-
112- const extent = this . _extent ;
113- if ( __DEV__ ) {
114130 if ( niceExtent != null ) {
115- assert (
116- isFinite ( niceExtent [ 0 ] ) && isFinite ( niceExtent [ 1 ] )
117- && extent [ 0 ] <= niceExtent [ 0 ] && niceExtent [ 1 ] <= extent [ 1 ]
118- ) ;
131+ assert ( isFinite ( niceExtent [ 0 ] ) && isFinite ( niceExtent [ 1 ] ) ) ;
132+ assert ( extent [ 0 ] <= niceExtent [ 0 ] && niceExtent [ 1 ] <= extent [ 1 ] ) ;
133+ assert ( round ( niceExtent [ 0 ] - niceExtent [ 1 ] , getPrecision ( interval ) ) <= interval ) ;
119134 }
120135 }
121- niceExtent = this . _niceExtent = niceExtent != null
122- ? niceExtent . slice ( ) as [ number , number ]
136+
137+ // Set or clear
138+ this . _niceExtent =
139+ niceExtent != null ? niceExtent . slice ( ) as [ number , number ]
123140 // Dropped the auto calculated niceExtent and use user-set extent.
124141 // We assume users want to set both interval and extent to get a better result.
125142 : extent . slice ( ) as [ number , number ] ;
126-
127143 this . _interval = interval ;
128-
129- if ( ! intervalCountSpecified ) {
130- // This is for cases of "nice" interval.
131- this . _intervalCount = undefined ; // Clear
132- this . _intervalPrecision = helper . getIntervalPrecision ( interval ) ;
133- }
134- else {
135- // This is for cases of "not-nice" interval, typically min max are fixed and
136- // axis alignment is required.
137- this . _intervalCount = intervalCount ;
138- this . _intervalPrecision = intervalPrecision ;
139- }
144+ this . _intervalCount = intervalCount ;
145+ this . _intervalPrecision = retrieve2 ( intervalPrecision , helper . getIntervalPrecision ( interval ) ) ;
146+ this . _extentPrecision = extentPrecision || [ ] ;
140147 }
141148
142149 /**
@@ -191,13 +198,17 @@ class IntervalScale<SETTING extends ScaleSettingDefault = ScaleSettingDefault> e
191198 ;
192199 niceTickIdx ++
193200 ) {
201+ // Consider case `_extent: [5.2, 5.8], _niceExtent: [6, 5], interval: 1`,
202+ // `_intervalCount` makes sense iff `-1`.
203+ // Consider case `_extent: [5, 5.8], _niceExtent: [5, 5], interval: 1`,
204+ // `_intervalCount` makes sense iff `0`.
194205 if ( intervalCount == null ) {
195- if ( tick > niceTickExtent [ 1 ] ) {
206+ if ( tick > niceTickExtent [ 1 ] || ! isFinite ( tick ) || ! isFinite ( niceTickExtent [ 1 ] ) ) {
196207 break ;
197208 }
198209 }
199210 else {
200- if ( niceTickIdx > intervalCount ) { // ticks number should be `intervalCount + 1`
211+ if ( niceTickIdx > intervalCount ) { // nice ticks number should be `intervalCount + 1`
201212 break ;
202213 }
203214 // Consider cumulative error, especially caused by rounding, the last nice
@@ -398,12 +409,13 @@ class IntervalScale<SETTING extends ScaleSettingDefault = ScaleSettingDefault> e
398409 calcNiceExtent ( opt : {
399410 splitNumber : number , // By default 5.
400411 // Do not modify the original extent[0]/extent[1] except for an invalid extent.
401- fixMin ?: boolean ,
402- fixMax ?: boolean ,
412+ fixMinMax ?: boolean [ ] , // [fixMin, fixMax]
403413 minInterval ?: number ,
404414 maxInterval ?: number
405415 } ) : void {
406- let extent = helper . intervalScaleEnsureValidExtent ( this . _extent , opt ) ;
416+ const fixMinMax = opt . fixMinMax || [ ] ;
417+
418+ let extent = helper . intervalScaleEnsureValidExtent ( this . _extent , fixMinMax ) ;
407419
408420 this . _innerSetExtent ( extent [ 0 ] , extent [ 1 ] ) ;
409421 extent = this . _extent . slice ( ) as [ number , number ] ;
@@ -412,10 +424,10 @@ class IntervalScale<SETTING extends ScaleSettingDefault = ScaleSettingDefault> e
412424 const interval = this . _interval ;
413425 const intervalPrecition = this . _intervalPrecision ;
414426
415- if ( ! opt . fixMin ) {
427+ if ( ! fixMinMax [ 0 ] ) {
416428 extent [ 0 ] = round ( mathFloor ( extent [ 0 ] / interval ) * interval , intervalPrecition ) ;
417429 }
418- if ( ! opt . fixMax ) {
430+ if ( ! fixMinMax [ 1 ] ) {
419431 extent [ 1 ] = round ( mathCeil ( extent [ 1 ] / interval ) * interval , intervalPrecition ) ;
420432 }
421433 this . _innerSetExtent ( extent [ 0 ] , extent [ 1 ] ) ;
0 commit comments