diff --git a/src/coord/axisCommonTypes.ts b/src/coord/axisCommonTypes.ts index eee3ab74e3..ffcbc6cce8 100644 --- a/src/coord/axisCommonTypes.ts +++ b/src/coord/axisCommonTypes.ts @@ -163,6 +163,20 @@ export interface NumericAxisBaseOptionCommon extends AxisBaseOptionCommon { * Will be ignored if interval is set. */ alignTicks?: boolean + + /** + * Data min value to be included in axis extent calculation. + * The final min value will be the minimum of this value and the data min. + * Only works for value axis. + */ + dataMin?: ScaleDataValue; + + /** + * Data max value to be included in axis extent calculation. + * The final max value will be the maximum of this value and the data max. + * Only works for value axis. + */ + dataMax?: ScaleDataValue; } export interface CategoryAxisBaseOption extends AxisBaseOptionCommon { diff --git a/src/coord/scaleRawExtentInfo.ts b/src/coord/scaleRawExtentInfo.ts index 78c29cc0cf..389b98c3b1 100644 --- a/src/coord/scaleRawExtentInfo.ts +++ b/src/coord/scaleRawExtentInfo.ts @@ -21,7 +21,7 @@ import { assert, isArray, eqNaN, isFunction } from 'zrender/src/core/util'; import Scale from '../scale/Scale'; import { AxisBaseModel } from './AxisBaseModel'; import { parsePercent } from 'zrender/src/contain/text'; -import { AxisBaseOption, CategoryAxisBaseOption } from './axisCommonTypes'; +import { AxisBaseOption, CategoryAxisBaseOption, NumericAxisBaseOptionCommon } from './axisCommonTypes'; import { ScaleDataValue } from '../util/types'; @@ -69,6 +69,9 @@ export class ScaleRawExtentInfo { // Make that the `rawExtentInfo` can not be modified any more. readonly frozen: boolean; + // custom dataMin/dataMax + private _dataMinNum: number; + private _dataMaxNum: number; constructor( scale: Scale, @@ -98,6 +101,19 @@ export class ScaleRawExtentInfo { const isOrdinal = this._isOrdinal = scale.type === 'ordinal'; this._needCrossZero = scale.type === 'interval' && model.getNeedCrossZero && model.getNeedCrossZero(); + if (scale.type === 'interval' || scale.type === 'log' || scale.type === 'time') { + // Process custom dataMin/dataMax + const dataMinRaw = (model as AxisBaseModel).get('dataMin', true); + if (dataMinRaw != null) { + this._dataMinNum = parseAxisModelMinMax(scale, dataMinRaw); + } + + const dataMaxRaw = (model as AxisBaseModel).get('dataMax', true); + if (dataMaxRaw != null) { + this._dataMaxNum = parseAxisModelMinMax(scale, dataMaxRaw); + } + } + let axisMinValue = model.get('min', true); if (axisMinValue == null) { axisMinValue = model.get('startValue', true); @@ -173,8 +189,20 @@ export class ScaleRawExtentInfo { // (3) If no data, it should be ensured that `scale.setBlank` is set. const isOrdinal = this._isOrdinal; - const dataMin = this._dataMin; - const dataMax = this._dataMax; + let dataMin = this._dataMin; + let dataMax = this._dataMax; + + // Include custom dataMin/dataMax in calculation + // If dataMin is set and less than current data minimum, update the minimum value + if (this._dataMinNum != null && isFinite(dataMin) && this._dataMinNum < dataMin) { + dataMin = this._dataMinNum; + } + + // If dataMax is set and greater than current data maximum, update the maximum value + if (this._dataMaxNum != null && isFinite(dataMax) && this._dataMaxNum > dataMax) { + dataMax = this._dataMaxNum; + } + const axisDataLen = this._axisDataLen; const boundaryGapInner = this._boundaryGapInner; diff --git a/test/axis-data-min-max.html b/test/axis-data-min-max.html new file mode 100644 index 0000000000..e0d510aa11 --- /dev/null +++ b/test/axis-data-min-max.html @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+ + + + +