You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2021/12/28 13:48:36 UTC
[echarts] branch axis-align created (now cc0ebd2)
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a change to branch axis-align
in repository https://gitbox.apache.org/repos/asf/echarts.git.
at cc0ebd2 feat(axis): add alignTicks
This branch includes the following new commits:
new cc0ebd2 feat(axis): add alignTicks
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org
[echarts] 01/01: feat(axis): add alignTicks
Posted by sh...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
shenyi pushed a commit to branch axis-align
in repository https://gitbox.apache.org/repos/asf/echarts.git
commit cc0ebd2845781021cb05287fded7c94b26174619
Author: pissang <bm...@gmail.com>
AuthorDate: Tue Dec 28 21:47:14 2021 +0800
feat(axis): add alignTicks
---
src/component/axis/CartesianAxisView.ts | 4 +-
src/component/timeline/SliderTimelineView.ts | 2 +-
src/coord/axisCommonTypes.ts | 10 +-
src/coord/axisHelper.ts | 17 +-
src/coord/cartesian/Grid.ts | 82 +-
src/coord/radar/Radar.ts | 72 +-
src/scale/Interval.ts | 10 +-
src/scale/Log.ts | 9 +-
src/scale/Ordinal.ts | 4 +-
src/scale/Scale.ts | 6 +-
src/scale/Time.ts | 9 +-
src/scale/helper.ts | 114 +++
src/util/number.ts | 14 +
test/auto-align.html | 1270 ++++++++++++++++++++++++++
test/axis-align-ticks-random.html | 186 ++++
15 files changed, 1694 insertions(+), 115 deletions(-)
diff --git a/src/component/axis/CartesianAxisView.ts b/src/component/axis/CartesianAxisView.ts
index 2000574..e040398 100644
--- a/src/component/axis/CartesianAxisView.ts
+++ b/src/component/axis/CartesianAxisView.ts
@@ -28,6 +28,7 @@ import ExtensionAPI from '../../core/ExtensionAPI';
import CartesianAxisModel from '../../coord/cartesian/AxisModel';
import GridModel from '../../coord/cartesian/GridModel';
import { Payload } from '../../util/types';
+import { isIntervalOrLogScale } from '../../scale/helper';
const axisBuilderAttrs = [
'axisLine', 'axisTickLabel', 'axisName'
@@ -69,8 +70,7 @@ class CartesianAxisView extends AxisView {
handleAutoShown(elementType) {
const cartesians = gridModel.coordinateSystem.getCartesians();
for (let i = 0; i < cartesians.length; i++) {
- const otherAxisType = cartesians[i].getOtherAxis(axisModel.axis).type;
- if (otherAxisType === 'value' || otherAxisType === 'log') {
+ if (isIntervalOrLogScale(cartesians[i].getOtherAxis(axisModel.axis).scale)) {
// Still show axis tick or axisLine if other axis is value / log
return true;
}
diff --git a/src/component/timeline/SliderTimelineView.ts b/src/component/timeline/SliderTimelineView.ts
index b49bc95..32eb7d6 100644
--- a/src/component/timeline/SliderTimelineView.ts
+++ b/src/component/timeline/SliderTimelineView.ts
@@ -351,7 +351,7 @@ class SliderTimelineView extends TimelineView {
const dataExtent = data.getDataExtent('value');
scale.setExtent(dataExtent[0], dataExtent[1]);
- scale.niceTicks();
+ scale.calcNiceTicks();
const axis = new TimelineAxis('value', scale, layoutInfo.axisExtent as [number, number], axisType);
axis.model = timelineModel;
diff --git a/src/coord/axisCommonTypes.ts b/src/coord/axisCommonTypes.ts
index fac7d7c..e3241cb 100644
--- a/src/coord/axisCommonTypes.ts
+++ b/src/coord/axisCommonTypes.ts
@@ -81,7 +81,7 @@ export interface AxisBaseOptionCommon extends ComponentOption,
}
-interface NumericAxisBaseOptionCommon extends AxisBaseOptionCommon {
+export interface NumericAxisBaseOptionCommon extends AxisBaseOptionCommon {
/*
* The gap at both ends of the axis.
* [GAP, GAP], where
@@ -105,6 +105,14 @@ interface NumericAxisBaseOptionCommon extends AxisBaseOptionCommon {
* Specify max interval when auto calculate tick interval.
*/
maxInterval?: number;
+
+ /**
+ * If align ticks to the first axis that is not use alignTicks
+ * If all axes has alignTicks: true. The first one will be applied.
+ *
+ * Will be ignored if interval is set.
+ */
+ alignTicks?: boolean
}
export interface CategoryAxisBaseOption extends AxisBaseOptionCommon {
diff --git a/src/coord/axisHelper.ts b/src/coord/axisHelper.ts
index 53a60b6..e8bf8a6 100644
--- a/src/coord/axisHelper.ts
+++ b/src/coord/axisHelper.ts
@@ -149,7 +149,10 @@ function adjustScaleForOverflow(
// Precondition of calling this method:
// The scale extent has been initailized using series data extent via
// `scale.setExtent` or `scale.unionExtentFromData`;
-export function niceScaleExtent(scale: Scale, inModel: AxisBaseModel) {
+export function niceScaleExtent(
+ scale: Scale,
+ inModel: AxisBaseModel
+) {
const model = inModel as AxisBaseModel<LogAxisBaseOption>;
const extentInfo = getScaleExtent(scale, model);
const extent = extentInfo.extent;
@@ -160,15 +163,16 @@ export function niceScaleExtent(scale: Scale, inModel: AxisBaseModel) {
}
const scaleType = scale.type;
+ const interval = model.get('interval');
+ const isIntervalOrTime = scaleType === 'interval' || scaleType === 'time';
+
scale.setExtent(extent[0], extent[1]);
- scale.niceExtent({
+ scale.calcNiceExtent({
splitNumber: splitNumber,
fixMin: extentInfo.fixMin,
fixMax: extentInfo.fixMax,
- minInterval: (scaleType === 'interval' || scaleType === 'time')
- ? model.get('minInterval') : null,
- maxInterval: (scaleType === 'interval' || scaleType === 'time')
- ? model.get('maxInterval') : null
+ minInterval: isIntervalOrTime ? model.get('minInterval') : null,
+ maxInterval: isIntervalOrTime ? model.get('maxInterval') : null
});
// If some one specified the min, max. And the default calculated interval
@@ -176,7 +180,6 @@ export function niceScaleExtent(scale: Scale, inModel: AxisBaseModel) {
// in angle axis with angle 0 - 360. Interval calculated in interval scale is hard
// to be 60.
// FIXME
- const interval = model.get('interval');
if (interval != null) {
(scale as IntervalScale).setInterval && (scale as IntervalScale).setInterval(interval);
}
diff --git a/src/coord/cartesian/Grid.ts b/src/coord/cartesian/Grid.ts
index aba0b73..d9c6de6 100644
--- a/src/coord/cartesian/Grid.ts
+++ b/src/coord/cartesian/Grid.ts
@@ -23,7 +23,7 @@
* TODO Default cartesian
*/
-import {isObject, each, indexOf, retrieve3} from 'zrender/src/core/util';
+import {isObject, each, indexOf, retrieve3, map, keys} from 'zrender/src/core/util';
import {getLayoutRect, LayoutRect} from '../../util/layout';
import {
createScaleByModel,
@@ -47,14 +47,20 @@ import { ScaleDataValue } from '../../util/types';
import SeriesData from '../../data/SeriesData';
import OrdinalScale from '../../scale/Ordinal';
import { isCartesian2DSeries, findAxisModels } from './cartesianAxisHelper';
-import { CategoryAxisBaseOption } from '../axisCommonTypes';
+import { CategoryAxisBaseOption, NumericAxisBaseOptionCommon } from '../axisCommonTypes';
import { AxisBaseModel } from '../AxisBaseModel';
+import { alignScaleTicks, isIntervalOrLogScale } from '../../scale/helper';
+import IntervalScale from '../../scale/Interval';
+import LogScale from '../../scale/Log';
type Cartesian2DDimensionName = 'x' | 'y';
type FinderAxisIndex = {xAxisIndex?: number, yAxisIndex?: number};
-type AxesMap = {x: Axis2D[], y: Axis2D[]};
+type AxesMap = {
+ x: Axis2D[],
+ y: Axis2D[]
+};
class Grid implements CoordinateSystemMaster {
@@ -92,12 +98,55 @@ class Grid implements CoordinateSystemMaster {
this._updateScale(ecModel, this.model);
- each(axesMap.x, function (xAxis) {
- niceScaleExtent(xAxis.scale, xAxis.model);
- });
- each(axesMap.y, function (yAxis) {
- niceScaleExtent(yAxis.scale, yAxis.model);
- });
+ function updateAxisTicks(axes: Record<number, Axis2D>) {
+ let alignTo: Axis2D;
+ // Axis is added in order of axisIndex.
+ const axesIndices = keys(axes);
+ const len = axesIndices.length;
+ if (!len) {
+ return;
+ }
+ const axisNeedsAlign: Axis2D[] = [];
+ // Process once and calculate the ticks for those don't use alignTicks.
+ for (let i = len - 1; i >= 0; i--) {
+ const idx = +axesIndices[i]; // Convert to number.
+ const axis = axes[idx];
+ const model = axis.model as AxisBaseModel<NumericAxisBaseOptionCommon>;
+ const scale = axis.scale;
+ if (// Only value and log axis without interval support alignTicks.
+ isIntervalOrLogScale(scale)
+ && model.get('alignTicks')
+ && model.get('interval') == null
+ ) {
+ axisNeedsAlign.push(axis);
+ }
+ else {
+ niceScaleExtent(scale, model);
+ if (isIntervalOrLogScale(scale)) { // Can only align to interval or log axis.
+ alignTo = axis;
+ }
+ }
+ };
+ // All axes has set alignTicks. Pick the first one.
+ // PENDING. Should we find the axis that both set interval, min, max and align to this one?
+ if (axisNeedsAlign.length) {
+ if (!alignTo) {
+ alignTo = axisNeedsAlign.pop();
+ niceScaleExtent(alignTo.scale, alignTo.model);
+ }
+
+ each(axisNeedsAlign, axis => {
+ alignScaleTicks(
+ axis.scale as IntervalScale | LogScale,
+ axis.model,
+ alignTo.scale as IntervalScale | LogScale
+ );
+ });
+ }
+ }
+
+ updateAxisTicks(axesMap.x);
+ updateAxisTicks(axesMap.y);
// Key: axisDim_axisIndex, value: boolean, whether onZero target.
const onZeroRecords = {} as Dictionary<boolean>;
@@ -177,15 +226,6 @@ class Grid implements CoordinateSystemMaster {
const axesMapOnDim = this._axesMap[dim];
if (axesMapOnDim != null) {
return axesMapOnDim[axisIndex || 0];
- // if (axisIndex == null) {
- // Find first axis
- // for (let name in axesMapOnDim) {
- // if (axesMapOnDim.hasOwnProperty(name)) {
- // return axesMapOnDim[name];
- // }
- // }
- // }
- // return axesMapOnDim[axisIndex];
}
}
@@ -445,10 +485,8 @@ class Grid implements CoordinateSystemMaster {
const xAxis = cartesian.getAxis('x');
const yAxis = cartesian.getAxis('y');
- if (data.type === 'list') {
- unionExtent(data, xAxis);
- unionExtent(data, yAxis);
- }
+ unionExtent(data, xAxis);
+ unionExtent(data, yAxis);
}
}, this);
diff --git a/src/coord/radar/Radar.ts b/src/coord/radar/Radar.ts
index b98c3af..f80ec8e 100644
--- a/src/coord/radar/Radar.ts
+++ b/src/coord/radar/Radar.ts
@@ -34,6 +34,7 @@ import { ScaleDataValue } from '../../util/types';
import { ParsedModelFinder } from '../../util/model';
import { parseAxisModelMinMax } from '../scaleRawExtentInfo';
import { map, each } from 'zrender/src/core/util';
+import { alignScaleTicks } from '../../scale/helper';
class Radar implements CoordinateSystem, CoordinateSystemMaster {
@@ -172,71 +173,16 @@ class Radar implements CoordinateSystem, CoordinateSystemMaster {
}, this);
const splitNumber = radarModel.get('splitNumber');
-
- function increaseInterval(interval: number) {
- const exp10 = Math.pow(10, Math.floor(Math.log(interval) / Math.LN10));
- // Increase interval
- let f = interval / exp10;
- if (f === 2) {
- f = 5;
- }
- else { // f is 2 or 5
- f *= 2;
- }
- return f * exp10;
- }
+ const dummyScale = new IntervalScale();
+ dummyScale.setExtent(0, splitNumber);
+ dummyScale.setInterval(1);
// Force all the axis fixing the maxSplitNumber.
each(indicatorAxes, function (indicatorAxis, idx) {
- const rawExtent = getScaleExtent(indicatorAxis.scale, indicatorAxis.model).extent;
- niceScaleExtent(indicatorAxis.scale, indicatorAxis.model);
-
- const axisModel = indicatorAxis.model;
- const scale = indicatorAxis.scale as IntervalScale;
- const fixedMin = parseAxisModelMinMax(scale, axisModel.get('min', true) as ScaleDataValue);
- const fixedMax = parseAxisModelMinMax(scale, axisModel.get('max', true) as ScaleDataValue);
- let interval = scale.getInterval();
-
- if (fixedMin != null && fixedMax != null) {
- // User set min, max, divide to get new interval
- scale.setExtent(+fixedMin, +fixedMax);
- scale.setInterval(
- (fixedMax - fixedMin) / splitNumber
- );
- }
- else if (fixedMin != null) {
- let max;
- // User set min, expand extent on the other side
- do {
- max = fixedMin + interval * splitNumber;
- scale.setExtent(+fixedMin, max);
- // Interval must been set after extent
- // FIXME
- scale.setInterval(interval);
-
- interval = increaseInterval(interval);
- } while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1]));
- }
- else if (fixedMax != null) {
- let min;
- // User set min, expand extent on the other side
- do {
- min = fixedMax - interval * splitNumber;
- scale.setExtent(min, +fixedMax);
- scale.setInterval(interval);
- interval = increaseInterval(interval);
- } while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0]));
- }
- else {
- const nicedSplitNumber = scale.getTicks().length - 1;
- if (nicedSplitNumber > splitNumber) {
- interval = increaseInterval(interval);
- }
- // TODO
- const max = Math.ceil(rawExtent[1] / interval) * interval;
- const min = numberUtil.round(max - interval * splitNumber);
- scale.setExtent(min, max);
- scale.setInterval(interval);
- }
+ alignScaleTicks(
+ indicatorAxis.scale as IntervalScale,
+ indicatorAxis.model,
+ dummyScale
+ );
});
}
diff --git a/src/scale/Interval.ts b/src/scale/Interval.ts
index a1102fe..1f4a7f9 100644
--- a/src/scale/Interval.ts
+++ b/src/scale/Interval.ts
@@ -215,7 +215,7 @@ class IntervalScale<SETTING extends Dictionary<unknown> = Dictionary<unknown>> e
/**
* @param splitNumber By default `5`.
*/
- niceTicks(splitNumber?: number, minInterval?: number, maxInterval?: number): void {
+ calcNiceTicks(splitNumber?: number, minInterval?: number, maxInterval?: number): void {
splitNumber = splitNumber || 5;
const extent = this._extent;
let span = extent[1] - extent[0];
@@ -238,7 +238,7 @@ class IntervalScale<SETTING extends Dictionary<unknown> = Dictionary<unknown>> e
this._niceExtent = result.niceTickExtent;
}
- niceExtent(opt: {
+ calcNiceExtent(opt: {
splitNumber: number, // By default 5.
fixMin?: boolean,
fixMax?: boolean,
@@ -275,8 +275,7 @@ class IntervalScale<SETTING extends Dictionary<unknown> = Dictionary<unknown>> e
extent[1] = 1;
}
- this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
-
+ this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
// let extent = this._extent;
const interval = this._interval;
@@ -288,6 +287,9 @@ class IntervalScale<SETTING extends Dictionary<unknown> = Dictionary<unknown>> e
}
}
+ setNiceExtent(min: number, max: number) {
+ this._niceExtent = [min, max];
+ }
}
Scale.registerClass(IntervalScale);
diff --git a/src/scale/Log.ts b/src/scale/Log.ts
index f8c3258..41586e8 100644
--- a/src/scale/Log.ts
+++ b/src/scale/Log.ts
@@ -59,7 +59,7 @@ class LogScale extends Scale {
/**
* @param Whether expand the ticks to niced extent.
*/
- getTicks(expandToNicedExtent: boolean): ScaleTick[] {
+ getTicks(expandToNicedExtent?: boolean): ScaleTick[] {
const originalScale = this._originalScale;
const extent = this._extent;
const originalExtent = originalScale.getExtent();
@@ -128,7 +128,7 @@ class LogScale extends Scale {
* Update interval and extent of intervals for nice ticks
* @param approxTickNum default 10 Given approx tick number
*/
- niceTicks(approxTickNum: number): void {
+ calcNiceTicks(approxTickNum: number): void {
approxTickNum = approxTickNum || 10;
const extent = this._extent;
const span = extent[1] - extent[0];
@@ -158,14 +158,14 @@ class LogScale extends Scale {
this._niceExtent = niceExtent;
}
- niceExtent(opt: {
+ calcNiceExtent(opt: {
splitNumber: number, // By default 5.
fixMin?: boolean,
fixMax?: boolean,
minInterval?: number,
maxInterval?: number
}): void {
- intervalScaleProto.niceExtent.call(this, opt);
+ intervalScaleProto.calcNiceExtent.call(this, opt);
this._fixMin = opt.fixMin;
this._fixMax = opt.fixMax;
@@ -198,7 +198,6 @@ const proto = LogScale.prototype;
proto.getMinorTicks = intervalScaleProto.getMinorTicks;
proto.getLabel = intervalScaleProto.getLabel;
-
function fixRoundingError(val: number, originalVal: number): number {
return roundingErrorFix(val, numberUtil.getPrecision(originalVal));
}
diff --git a/src/scale/Ordinal.ts b/src/scale/Ordinal.ts
index 01139da..13ee2b1 100644
--- a/src/scale/Ordinal.ts
+++ b/src/scale/Ordinal.ts
@@ -280,9 +280,9 @@ class OrdinalScale extends Scale<OrdinalScaleSetting> {
return this._ordinalMeta;
}
- niceTicks() {}
+ calcNiceTicks() {}
- niceExtent() {}
+ calcNiceExtent() {}
}
diff --git a/src/scale/Scale.ts b/src/scale/Scale.ts
index afae3f4..143f4c9 100644
--- a/src/scale/Scale.ts
+++ b/src/scale/Scale.ts
@@ -149,14 +149,14 @@ abstract class Scale<SETTING extends Dictionary<unknown> = Dictionary<unknown>>
* @param minInterval Optional.
* @param maxInterval Optional.
*/
- abstract niceTicks(
+ abstract calcNiceTicks(
// FIXME:TS make them in a "opt", the same with `niceExtent`?
splitNumber?: number,
minInterval?: number,
maxInterval?: number
): void;
- abstract niceExtent(
+ abstract calcNiceExtent(
opt?: {
splitNumber?: number,
fixMin?: boolean,
@@ -171,7 +171,7 @@ abstract class Scale<SETTING extends Dictionary<unknown> = Dictionary<unknown>>
*/
abstract getLabel(tick: ScaleTick): string;
- abstract getTicks(expandToNicedExtent?: boolean): ScaleTick[];
+ abstract getTicks(): ScaleTick[];
abstract getMinorTicks(splitNumber: number): number[][];
diff --git a/src/scale/Time.ts b/src/scale/Time.ts
index d9e1b94..b64567b 100644
--- a/src/scale/Time.ts
+++ b/src/scale/Time.ts
@@ -144,9 +144,8 @@ class TimeScale extends IntervalScale<TimeScaleSetting> {
/**
* @override
- * @param expandToNicedExtent Whether expand the ticks to niced extent.
*/
- getTicks(expandToNicedExtent?: boolean): TimeScaleTick[] {
+ getTicks(): TimeScaleTick[] {
const interval = this._interval;
const extent = this._extent;
@@ -180,7 +179,7 @@ class TimeScale extends IntervalScale<TimeScaleSetting> {
return ticks;
}
- niceExtent(
+ calcNiceExtent(
opt?: {
splitNumber?: number,
fixMin?: boolean,
@@ -203,10 +202,10 @@ class TimeScale extends IntervalScale<TimeScaleSetting> {
extent[0] = extent[1] - ONE_DAY;
}
- this.niceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
+ this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
}
- niceTicks(approxTickNum: number, minInterval: number, maxInterval: number): void {
+ calcNiceTicks(approxTickNum: number, minInterval: number, maxInterval: number): void {
approxTickNum = approxTickNum || 10;
const extent = this._extent;
diff --git a/src/scale/helper.ts b/src/scale/helper.ts
index 4965dc2..ff8923d 100644
--- a/src/scale/helper.ts
+++ b/src/scale/helper.ts
@@ -17,15 +17,29 @@
* under the License.
*/
+import { NumericAxisBaseOptionCommon } from '../coord/axisCommonTypes';
import * as numberUtil from '../util/number';
+import IntervalScale from './Interval';
+import { parseAxisModelMinMax } from '../coord/scaleRawExtentInfo';
+import { ScaleDataValue } from '../util/types';
+import { getScaleExtent, niceScaleExtent } from '../coord/axisHelper';
+import { AxisBaseModel } from '../coord/AxisBaseModel';
+import LogScale from './Log';
+import Scale from './Scale';
+import { warn } from '../util/log';
const roundNumber = numberUtil.round;
+const mathLog = Math.log;
type intervalScaleNiceTicksResult = {
interval: number,
intervalPrecision: number,
niceTickExtent: [number, number]
};
+
+export function isIntervalOrLogScale(scale: Scale): scale is LogScale | IntervalScale {
+ return scale.type === 'interval' || scale.type === 'log';
+}
/**
* @param extent Both extent[0] and extent[1] should be valid number.
* Should be extent[0] < extent[1].
@@ -61,6 +75,106 @@ export function intervalScaleNiceTicks(
return result;
}
+function increaseInterval(interval: number) {
+ const exp10 = Math.pow(10, numberUtil.quantityExponent(interval));
+ // Increase interval
+ let f = interval / exp10;
+ if (f === 2) {
+ f = 3;
+ }
+ else if (f === 3) {
+ f = 5;
+ }
+ else { // f is 1 or 5
+ f *= 2;
+ }
+ return f * exp10;
+}
+
+export function alignScaleTicks(
+ scale: IntervalScale | LogScale,
+ axisModel: AxisBaseModel<Pick<NumericAxisBaseOptionCommon, 'min' | 'max'>>,
+ alignToScale: IntervalScale | LogScale
+) {
+
+ const intervalScaleProto = IntervalScale.prototype;
+
+ // NOTE: There is a precondition for log scale here:
+ // In log scale we store _interval and _extent of exponent value.
+ // So if we use the method of InternalScale to set/get these data.
+ // It process the exponent value, which is linear and what we want here.
+ const alignToTicks = intervalScaleProto.getTicks.call(alignToScale);
+ const alignToNicedTicks = intervalScaleProto.getTicks.call(alignToScale, true);
+ const alignToSplitNumber = alignToTicks.length - 1;
+ const alignToInterval = intervalScaleProto.getInterval.call(alignToScale);
+
+ const fixedMin = parseAxisModelMinMax(scale, axisModel.get('min', true) as ScaleDataValue);
+ const fixedMax = parseAxisModelMinMax(scale, axisModel.get('max', true) as ScaleDataValue);
+
+ niceScaleExtent(scale, axisModel);
+ const rawExtent = intervalScaleProto.getExtent.call(scale);
+ const isMinFixed = fixedMin != null;
+ const isMaxFixed = fixedMax != null;
+
+ let interval = intervalScaleProto.getInterval.call(scale);
+ let min: number = rawExtent[0];
+ let max: number = rawExtent[1];
+
+ if (isMinFixed && isMaxFixed) {
+ // User set min, max, divide to get new interval
+ interval = (max - min) / alignToSplitNumber;
+ }
+ else if (isMinFixed) {
+ max = rawExtent[0] + interval * alignToSplitNumber;
+ // User set min, expand extent on the other side
+ while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1])) {
+ interval = increaseInterval(interval);
+ max = rawExtent[0] + interval * alignToSplitNumber;
+ }
+ }
+ else if (isMaxFixed) {
+ // User set max, expand extent on the other side
+ min = rawExtent[1] - interval * alignToSplitNumber;
+ while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0])) {
+ interval = increaseInterval(interval);
+ min = rawExtent[1] - interval * alignToSplitNumber;
+ }
+ }
+ else {
+ const nicedSplitNumber = scale.getTicks().length - 1;
+ if (nicedSplitNumber > alignToSplitNumber) {
+ interval = increaseInterval(interval);
+ }
+ // PENDING
+ max = Math.ceil(rawExtent[1] / interval) * interval;
+ min = numberUtil.round(max - interval * alignToSplitNumber);
+ }
+
+ // Adjust min, max based on the extent of alignTo. When min or max is set in alignTo scale
+ const t0 = (alignToTicks[0].value - alignToNicedTicks[0].value) / alignToInterval;
+ const t1 = (alignToTicks[alignToSplitNumber].value - alignToNicedTicks[alignToSplitNumber].value) / alignToInterval;
+
+ // NOTE: Must in setExtent -> setInterval -> setNiceExtent order.
+ intervalScaleProto.setExtent.call(scale, min + interval * t0, max + interval * t1);
+ intervalScaleProto.setInterval.call(scale, interval);
+ if (t0 || t1) {
+ intervalScaleProto.setNiceExtent.call(scale, min + interval, max - interval);
+ }
+
+ if (__DEV__) {
+ const ticks = intervalScaleProto.getTicks.call(scale);
+ // if (ticks.length !== alignToScale.getTicks().length) {
+ // debugger
+ // }
+ if (ticks[1] && ticks[1].value % interval) {
+ warn(
+ // eslint-disable-next-line
+ `The ticks may be not displayed nice if when set min: ${fixedMin}, max: ${fixedMax} and alignTicks: true`
+ );
+ }
+ }
+}
+
/**
* @return interval precision
*/
diff --git a/src/util/number.ts b/src/util/number.ts
index 2ec02f3..20c1ac9 100644
--- a/src/util/number.ts
+++ b/src/util/number.ts
@@ -483,6 +483,20 @@ export function nice(val: number, round?: boolean): number {
return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;
}
+// /**
+// * Check if value is a nice number.
+// * @param val
+// */
+// export function isValueNice(val: number) {
+// const exp10 = Math.pow(10, quantityExponent(Math.abs(val)));
+// const f = Math.abs(val / exp10);
+// return f === 0
+// || f === 1
+// || f === 2
+// || f === 3
+// || f === 5;
+// }
+
/**
* This code was copied from "d3.js"
* <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.
diff --git a/test/auto-align.html b/test/auto-align.html
new file mode 100644
index 0000000..97b21d0
--- /dev/null
+++ b/test/auto-align.html
@@ -0,0 +1,1270 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <script src="lib/simpleRequire.js"></script>
+ <script src="lib/config.js"></script>
+ <script src="lib/testHelper.js"></script>
+ <link rel="stylesheet" href="lib/reset.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+</head>
+
+<body>
+ <style>
+ body {
+ padding: 0;
+ margin: 0;
+ }
+
+ .chart {
+ width: 100vw;
+ height: 50vh;
+ }
+ </style>
+ <div id="main1" class="chart"></div>
+ <div id="main2" class="chart"></div>
+ <div id="main13" class="chart"></div>
+ <div id="main3" class="chart"></div>
+ <div id="main4" class="chart"></div>
+ <div id="main5" class="chart"></div>
+ <div id="main6" class="chart"></div>
+ <div id="main7" class="chart"></div>
+ <div id="main8" class="chart"></div>
+ <div id="main12" class="chart"></div>
+ <div id="main9" class="chart"></div>
+ <div id="main10" class="chart"></div>
+ <div id="main11" class="chart"></div>
+ <div id="main14" class="chart"></div>
+ <div id="main15" class="chart"></div>
+ <div id="main16" class="chart"></div>
+ <div id="main17" class="chart"></div>
+ <div id="main18" class="chart"></div>
+ <div id="main19" class="chart"></div>
+ <div id="main20" class="chart"></div>
+ <div id="main21" class="chart"></div>
+ <div id="main22" class="chart"></div>
+ <div id="main23" class="chart"></div>
+ <div id="main24" class="chart"></div>
+ <div id="main25" class="chart"></div>
+ <div id="main26" class="chart"></div>
+ <div id="main27" class="chart"></div>
+ <div id="main28" class="chart"></div>
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+
+ var option = {
+ tooltip: {},
+ "yAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "xAxis": [
+ {
+ "name": "A",
+ },
+ {
+ "name": "B",
+ }
+ ],
+ "series": [
+ {
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 998,
+ 101
+ ],
+ "xAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 13
+ ],
+ "xAxisIndex": 1
+ }
+ ]
+ };
+
+ var chart = testHelper.create(echarts, 'main1', {
+ title: [
+ 'Axis auto align',
+ 'Axis X are value axis'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [
+ {
+ "name": "A",
+ },
+ {
+ "name": "B",
+ }
+ ],
+ "series": [
+ {
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 998,
+ 101
+ ],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 13
+ ],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main2', {
+ title: [
+ 'Axis auto align',
+ 'One value axis has significant bigger value'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [
+ {
+ "name": "A",
+ splitNumber: 7
+ },
+ {
+ "name": "B"
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 12,
+ 7
+ ],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 23
+ ],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main13', {
+ title: [
+ 'Axis auto align',
+ 'One axis has splitNumber'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [
+ {
+ "name": "A",
+ splitNumber: 7
+ },
+ {
+ "name": "B",
+ splitNumber: 6
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 12,
+ 7
+ ],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 23
+ ],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main3', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have splitNumber'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [{
+ "name": "A",
+ interval: 7
+ },
+ {
+ "name": "B",
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 12,
+ 7
+ ],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 23
+ ],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main4', {
+ title: [
+ 'Axis auto align',
+ 'One of axis has interval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [{
+ "name": "A",
+ interval: 7
+ },
+ {
+ "name": "B",
+ interval: 6
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 12,
+ 7
+ ],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 23
+ ],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main5', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have interval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [{
+ "name": "A",
+ max: 26,
+ },
+ {
+ "name": "B"
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 12,
+ -3
+ ],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 23
+ ],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main6', {
+ title: [
+ 'Axis auto align',
+ 'One of axis has max'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [
+ {
+ "name": "A",
+ interval: 5,
+ max: 22
+ },
+ {
+ "name": "B",
+ interval: 3,
+ max: 25
+ }
+ ],
+ "series": [
+ {
+ "name": "A",
+ "type": "bar",
+ "data": [
+ -12,
+ -3
+ ],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ -6,
+ -23
+ ],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main7', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have interval and max'
+ ],
+ option: option
+ });
+
+ option = {
+ xAxis: {},
+ yAxis: [
+ {
+ "name": "A",
+ interval: 5,
+ max: 31,
+ scale: true
+ },
+ {
+ "name": "B",
+ interval: 3,
+ max: 25,
+ scale: true
+ }
+ ],
+ series: [
+ {
+ symbolSize: 20,
+ data: [
+ [20.0, 18.04],
+ [28.0, 16.95],
+ [23.0, 17.58],
+ [19.0, 18.81],
+ [21.0, 18.33],
+ [24.0, 19.96],
+ [16.0, 17.24],
+ [24.0, 14.26],
+ [22.0, 20.84],
+ [17.0, 14.82],
+ [15.0, 15.68]
+ ],
+ type: 'scatter',
+ yAxisIndex: 0
+ },
+ {
+ symbolSize: 20,
+ data: [
+ [11.0, 18.04],
+ [18.0, 16.95],
+ [23.0, 17.58],
+ [19.0, 18.81],
+ [21.0, 18.33],
+ [24.0, 19.96],
+ [16.0, 17.24],
+ [14.0, 14.26],
+ [22.0, 20.84],
+ [17.0, 14.82],
+ [15.0, 15.68]
+ ],
+ type: 'scatter',
+ yAxisIndex: 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main8', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have scale'
+ ],
+ option: option
+ });
+
+ option = {
+ xAxis: {},
+ yAxis: [
+ {
+ "name": "A",
+ interval: 5,
+ max: 31
+ },
+ {
+ "name": "B",
+ interval: 3,
+ max: 25,
+ scale: true
+ }
+ ],
+ series: [
+ {
+ symbolSize: 20,
+ data: [
+ [20.0, 18.04],
+ [28.0, 16.95],
+ [23.0, 17.58],
+ [19.0, 18.81],
+ [21.0, 18.33],
+ [24.0, 19.96],
+ [16.0, 17.24],
+ [24.0, 14.26],
+ [22.0, 20.84],
+ [17.0, 14.82],
+ [15.0, 15.68]
+ ],
+ type: 'scatter',
+ yAxisIndex: 0
+ },
+ {
+ symbolSize: 20,
+ data: [
+ [11.0, 18.04],
+ [18.0, 16.95],
+ [23.0, 17.58],
+ [19.0, 18.81],
+ [21.0, 18.33],
+ [24.0, 19.96],
+ [16.0, 17.24],
+ [14.0, 14.26],
+ [22.0, 20.84],
+ [17.0, 14.82],
+ [15.0, 15.68]
+ ],
+ type: 'scatter',
+ yAxisIndex: 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main12', {
+ title: [
+ 'Axis auto align',
+ 'One axis has scale'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [{
+ "name": "A",
+ interval: 7,
+ splitNumber: 3
+ },
+ {
+ "name": "B",
+ interval: 6,
+ splitNumber: 4
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 22,
+ 7
+ ],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 23
+ ],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main9', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have splitNumber and interval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2']
+ }],
+ "yAxis": [{
+ "name": "A",
+ interval: 7,
+ splitNumber: 3,
+ max: 23
+ },
+ {
+ "name": "B",
+ interval: 6,
+ splitNumber: 4,
+ max: 25
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [
+ 22,
+ 7
+ ],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [
+ 6,
+ 23
+ ],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main10', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have splitNumber, interval and max'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ splitNumber: 3,
+ minInterval: 333
+ },
+ {
+ "name": "B",
+ splitNumber: 4,
+ minInterval: 11
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 390, 330, 220],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main11', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have minInterval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ minInterval: 333
+ },
+ {
+ "name": "B"
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 390, 330, 220],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main14', {
+ title: [
+ 'Axis auto align',
+ 'One axis have minInterval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ maxInterval: 98
+ },
+ {
+ "name": "B"
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 390, 330, 220],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main15', {
+ title: [
+ 'Axis auto align',
+ 'One axis have maxInterval'
+ ],
+ option: option
+ });
+
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ maxInterval: 98
+ },
+ {
+ "name": "B",
+ maxInterval: 7
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 1
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 390, 330, 220],
+ "yAxisIndex": 0
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main16', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have maxInterval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3
+ },
+ {
+ "name": "B"
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 390, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main17', {
+ title: [
+ 'Axis auto align',
+ 'One axis has min option'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3
+ },
+ {
+ "name": "B",
+ min: -53
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main18', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min option'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43
+ },
+ {
+ "name": "B",
+ min: -53
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main19', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min option, and one has max option'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main20', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43,
+ splitNumber: 9
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main21', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option, one have splitNumber'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43,
+ splitNumber: 9
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511,
+ splitNumber: 11
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main22', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option, both have splitNumber'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43,
+ interval: 7
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main23', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option, one has interval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43,
+ interval: 7
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511,
+ interval: 111
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main24', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option, both have interval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43,
+ minInterval: 7
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main25', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option, one has minInterval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43,
+ minInterval: 8
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511,
+ minInterval: 113
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main26', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option, both have minInterval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43,
+ maxInterval: 8
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main27', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option, one has maxInterval'
+ ],
+ option: option
+ });
+
+ option = {
+ tooltip: {},
+ "xAxis": [{
+ "data": ["test", 'test2', "test3", 'test4', "test5", 'test6', "test7"]
+ }],
+ "yAxis": [{
+ "name": "A",
+ min: 3,
+ max: 43,
+ maxInterval: 8
+ },
+ {
+ "name": "B",
+ min: -53,
+ max: 511,
+ maxInterval: 113
+ }
+ ],
+ "series": [{
+ "name": "A",
+ "type": "bar",
+ "data": [10, 2, 20, 33, 39, 33, 22],
+ "yAxisIndex": 0
+ },
+ {
+ "name": "B",
+ "type": "bar",
+ "data": [10, 52, 200, 334, 490, 330, 220],
+ "yAxisIndex": 1
+ }
+ ]
+ };
+
+ chart = testHelper.create(echarts, 'main28', {
+ title: [
+ 'Axis auto align',
+ 'Both axis have min and max option, both have maxInterval'
+ ],
+ option: option
+ });
+
+ });
+
+ </script>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/test/axis-align-ticks-random.html b/test/axis-align-ticks-random.html
new file mode 100644
index 0000000..42e0858
--- /dev/null
+++ b/test/axis-align-ticks-random.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <script src="lib/simpleRequire.js"></script>
+ <script src="lib/config.js"></script>
+ <script src="lib/jquery.min.js"></script>
+ <script src="lib/facePrint.js"></script>
+ <script src="lib/testHelper.js"></script>
+ <!-- <script src="ut/lib/canteen.js"></script> -->
+ <link rel="stylesheet" href="lib/reset.css" />
+ </head>
+ <body>
+ <style>
+ h1 {
+ line-height: 60px;
+ height: 60px;
+ background: #aaa;
+ text-align: center;
+ font-weight: bold;
+ color: #eee;
+ font-size: 14px;
+ }
+
+ .chart {
+ width: 260px;
+ height: 150px;
+ display: inline-block;
+ }
+ </style>
+
+ <h1>Ticks of right axis should be aligned and the ticks looks nice. All data are random</h1>
+ <div id="main-default"></div>
+ <h1>Min is fixed on the left axis</h1>
+ <div id="main-min"></div>
+ <h1>Max is fixed on the left axis</h1>
+ <div id="main-max"></div>
+ <h1>Min, max are both fixed on the left axis.</h1>
+ <div id="main-min-max"></div>
+ <h1>Min is fixed to -50 on the right axis</h1>
+ <div id="main-right-min"></div>
+ <h1>Max is fixed to 50 on the right axis</h1>
+ <div id="main-right-max"></div>
+ <h1>Min, max are both fixed to -50/50 on the right axis.</h1>
+ <div id="main-right-min-max"></div>
+ <h1>Min is fixed to 'dataMin' on the right axis</h1>
+ <div id="main-right-min2"></div>
+ <h1>Max is fixed to 'dataMax' on the right axis</h1>
+ <div id="main-right-max2"></div>
+ <h1>Min, max are both fixed to 'dataMin'/'dataMax' on the right axis.</h1>
+ <div id="main-right-min-max2"></div>
+ <h1>Right axis should follow split numbers from left axis.</h1>
+ <div id="main-split-number"></div>
+
+
+
+
+
+
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+
+
+ function makeOption(leftMin, leftMax, rightMin, rightMax, splitNumber) {
+
+ const seriesData = [];
+
+ for (let d = 0; d < 2; d++) {
+ const data = [];
+ seriesData.push(data);
+ const minY = Math.random() * 100 - 50;
+ const range = Math.random() * 100;
+ for (let k = 0; k < 10; k++) {
+ data.push(minY + range * Math.random());
+ }
+ }
+
+ return {
+ animation: false,
+ grid: {
+ top: 10,
+ bottom: 20,
+ containLabel: true,
+ left: 5,
+ right: 5
+ },
+ xAxis: {
+ data: new Array(10).fill(10).map((a, idx) => idx + '')
+ },
+ yAxis: [{
+ splitNumber,
+ showMinLabel: true,
+ showMaxLabel: true,
+ min: leftMin,
+ max: leftMax,
+ axisLabel: {
+ fontSize: 10,
+ formatter: (val) => +val.toFixed(2)
+ }
+ }, {
+ alignTicks: true,
+ showMinLabel: true,
+ showMaxLabel: true,
+ min: rightMin,
+ max: rightMax,
+ axisLabel: {
+ fontSize: 10,
+ formatter: (val) => +val.toFixed(2)
+ }
+ }],
+ series: [{
+ type: 'bar',
+ yAxisIndex: 0,
+ data: seriesData[0]
+ }, {
+ type: 'line',
+ yAxisIndex: 1,
+ showSymbol: false,
+ data: seriesData[1]
+ }]
+ }
+ }
+
+ function makeTestCharts(containerId, leftMin, leftMax, rightMin, rightMax) {
+ const container = document.querySelector(containerId);
+ for (let i = 0; i < 15; i++) {
+ const dom = document.createElement('div');
+ dom.className = 'chart';
+ const option = makeOption(leftMin, leftMax, rightMin, rightMax);
+ container.appendChild(dom);
+ const chart = echarts.init(dom);
+ chart.setOption(option);
+ }
+ }
+
+ makeTestCharts('#main-default')
+ makeTestCharts('#main-min', 'dataMin');
+ makeTestCharts('#main-max', undefined, 'dataMax');
+ makeTestCharts('#main-min-max', 'dataMin', 'dataMax');
+ makeTestCharts('#main-right-min', undefined, undefined, -50);
+ makeTestCharts('#main-right-max', undefined, undefined, undefined, 50);
+ makeTestCharts('#main-right-min-max', undefined, undefined, -50, 50);
+ makeTestCharts('#main-right-min2', undefined, undefined, 'dataMin');
+ makeTestCharts('#main-right-max2', undefined, undefined, undefined, 'dataMax');
+ makeTestCharts('#main-right-min-max2', undefined, undefined, 'dataMin', 'dataMax');
+
+ // Different split numbers
+ for (let i = 0; i < 15; i++) {
+ const splitNumber = i + 2;
+ const dom = document.createElement('div');
+ dom.className = 'chart';
+ const option = makeOption(undefined, undefined, undefined, undefined, splitNumber);
+ document.querySelector('#main-split-number').appendChild(dom);
+ const chart = echarts.init(dom);
+ chart.setOption(option);
+ }
+ });
+ </script>
+
+
+ </body>
+</html>
+
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org