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/29 06:13:37 UTC
[echarts] branch axis-align updated: feat(alignTicks): fix log axis align. add more test cases
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
The following commit(s) were added to refs/heads/axis-align by this push:
new f862adc feat(alignTicks): fix log axis align. add more test cases
f862adc is described below
commit f862adc182f2726a8dd84ff2691b8cfa8009f646
Author: pissang <bm...@gmail.com>
AuthorDate: Wed Dec 29 14:12:32 2021 +0800
feat(alignTicks): fix log axis align. add more test cases
---
src/coord/radar/Radar.ts | 5 -
src/scale/helper.ts | 68 ++++++----
src/util/number.ts | 14 --
test/axis-align-ticks.html | 332 ++++++++++++++++++++++++++++++++++++++-------
4 files changed, 326 insertions(+), 93 deletions(-)
diff --git a/src/coord/radar/Radar.ts b/src/coord/radar/Radar.ts
index f80ec8e..68fb878 100644
--- a/src/coord/radar/Radar.ts
+++ b/src/coord/radar/Radar.ts
@@ -22,17 +22,12 @@
import IndicatorAxis from './IndicatorAxis';
import IntervalScale from '../../scale/Interval';
import * as numberUtil from '../../util/number';
-import {
- getScaleExtent,
- niceScaleExtent
-} from '../axisHelper';
import { CoordinateSystemMaster, CoordinateSystem } from '../CoordinateSystem';
import RadarModel from './RadarModel';
import GlobalModel from '../../model/Global';
import ExtensionAPI from '../../core/ExtensionAPI';
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';
diff --git a/src/scale/helper.ts b/src/scale/helper.ts
index bd1ce78..8c752fc 100644
--- a/src/scale/helper.ts
+++ b/src/scale/helper.ts
@@ -18,17 +18,14 @@
*/
import { NumericAxisBaseOptionCommon } from '../coord/axisCommonTypes';
-import * as numberUtil from '../util/number';
+import {getPrecisionSafe, getPrecision, round, nice, quantityExponent} from '../util/number';
import IntervalScale from './Interval';
-import { parseAxisModelMinMax } from '../coord/scaleRawExtentInfo';
-import { ScaleDataValue } from '../util/types';
-import { getScaleExtent, niceScaleExtent } from '../coord/axisHelper';
+import { getScaleExtent } 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 = {
@@ -37,6 +34,16 @@ type intervalScaleNiceTicksResult = {
niceTickExtent: [number, number]
};
+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;
+}
+
export function isIntervalOrLogScale(scale: Scale): scale is LogScale | IntervalScale {
return scale.type === 'interval' || scale.type === 'log';
}
@@ -55,7 +62,7 @@ export function intervalScaleNiceTicks(
const result = {} as intervalScaleNiceTicksResult;
const span = extent[1] - extent[0];
- let interval = result.interval = numberUtil.nice(span / splitNumber, true);
+ let interval = result.interval = nice(span / splitNumber, true);
if (minInterval != null && interval < minInterval) {
interval = result.interval = minInterval;
}
@@ -66,8 +73,8 @@ export function intervalScaleNiceTicks(
const precision = result.intervalPrecision = getIntervalPrecision(interval);
// Niced extent inside original extent
const niceTickExtent = result.niceTickExtent = [
- roundNumber(Math.ceil(extent[0] / interval) * interval, precision),
- roundNumber(Math.floor(extent[1] / interval) * interval, precision)
+ round(Math.ceil(extent[0] / interval) * interval, precision),
+ round(Math.floor(extent[1] / interval) * interval, precision)
];
fixExtent(niceTickExtent, extent);
@@ -76,7 +83,7 @@ export function intervalScaleNiceTicks(
}
function increaseInterval(interval: number) {
- const exp10 = Math.pow(10, numberUtil.quantityExponent(interval));
+ const exp10 = Math.pow(10, quantityExponent(interval));
// Increase interval
let f = interval / exp10;
if (!f) {
@@ -111,14 +118,24 @@ export function alignScaleTicks(
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);
+ const scaleExtent = getScaleExtent(scale, axisModel);
+ let rawExtent = scaleExtent.extent;
+ const isMinFixed = scaleExtent.fixMin;
+ const isMaxFixed = scaleExtent.fixMax;
+
+ if (scale.type === 'log') {
+ const logBase = mathLog((scale as LogScale).base);
+ rawExtent = [mathLog(rawExtent[0]) / logBase, mathLog(rawExtent[1]) / logBase];
+ }
- niceScaleExtent(scale, axisModel);
+ scale.setExtent(rawExtent[0], rawExtent[1]);
+ scale.calcNiceExtent({
+ splitNumber: alignToSplitNumber,
+ fixMin: isMinFixed,
+ fixMax: isMaxFixed
+ });
const extent = intervalScaleProto.getExtent.call(scale);
- const rawExtent = getScaleExtent(scale, axisModel).extent;
- const isMinFixed = fixedMin != null;
- const isMaxFixed = fixedMax != null;
+
// Need to update the rawExtent.
// Because value in rawExtent may be not parsed. e.g. 'dataMin', 'dataMax'
if (isMinFixed) {
@@ -157,18 +174,20 @@ export function alignScaleTicks(
if (nicedSplitNumber > alignToSplitNumber) {
interval = increaseInterval(interval);
}
- max = Math.ceil(rawExtent[1] / interval) * interval;
- min = numberUtil.round(max - interval * alignToSplitNumber);
+ const range = interval * alignToSplitNumber;
+ max = Math.ceil(rawExtent[1] / interval) * interval;
+ min = round(max - range);
// Not change the result that crossing zero.
if (min < 0 && rawExtent[0] >= 0) {
min = 0;
- max = numberUtil.round(interval * alignToSplitNumber);
+ max = round(range);
}
else if (max > 0 && rawExtent[1] <= 0) {
max = 0;
- min = numberUtil.round((-interval * alignToSplitNumber));
+ min = -round(range);
}
+
}
// Adjust min, max based on the extent of alignTo. When min or max is set in alignTo scale
@@ -184,13 +203,12 @@ export function alignScaleTicks(
if (__DEV__) {
const ticks = intervalScaleProto.getTicks.call(scale);
- // if (ticks.length !== alignToScale.getTicks().length) {
- // debugger
- // }
- if (ticks[1] && ticks[1].value % interval) {
+ if (ticks[1]
+ && (!isValueNice(interval) || getPrecisionSafe(ticks[1].value) > getPrecisionSafe(interval))
+ ) {
warn(
// eslint-disable-next-line
- `The ticks may be not displayed nice if when set min: ${fixedMin}, max: ${fixedMax} and alignTicks: true`
+ `The ticks may be not displayed nice if when set min: ${axisModel.get('min')}, max: ${axisModel.get('max')} and alignTicks: true`
);
}
}
@@ -201,7 +219,7 @@ export function alignScaleTicks(
*/
export function getIntervalPrecision(interval: number): number {
// Tow more digital for tick.
- return numberUtil.getPrecision(interval) + 2;
+ return getPrecision(interval) + 2;
}
function clamp(
diff --git a/src/util/number.ts b/src/util/number.ts
index 20c1ac9..2ec02f3 100644
--- a/src/util/number.ts
+++ b/src/util/number.ts
@@ -483,20 +483,6 @@ 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/axis-align-ticks.html b/test/axis-align-ticks.html
index 1b38f8f..c1e6250 100644
--- a/test/axis-align-ticks.html
+++ b/test/axis-align-ticks.html
@@ -38,44 +38,28 @@ under the License.
<div id="main0"></div>
-
-
-
+ <div id="main1"></div>
+ <div id="main2"></div>
+ <div id="main3"></div>
+ <div id="main4"></div>
+ <div id="main5"></div>
+ <div id="main6"></div>
<script>
- require([
- 'echarts',
- // 'map/js/china',
- // './data/nutrients.json'
- ], function (echarts) {
- var option;
- const colors = ["#5470C6", "#91CC75", "#EE6666"];
- option = {
+ var colors = ['#5470C6', '#91CC75', '#EE6666'];
+ var commonOption = {
color: colors,
- tooltip: {
- trigger: "axis",
- axisPointer: {
- type: "cross"
- }
- },
grid: {
- right: "20%"
- },
- toolbox: {
- feature: {
- dataView: { show: true, readOnly: false },
- restore: { show: true },
- saveAsImage: { show: true }
- }
+ right: '20%'
},
legend: {
- data: ["Evaporation", "Precipitation", "Temperature"]
+ data: ['Evaporation', 'Precipitation', 'Temperature']
},
xAxis: [
{
- type: "category",
+ type: 'category',
axisTick: {
alignWithLabel: true
},
@@ -85,9 +69,10 @@ under the License.
],
yAxis: [
{
- type: "value",
- name: "Evaporation",
- position: "right",
+ type: 'value',
+ name: 'Evaporation',
+ position: 'right',
+ alignTicks: true,
axisLine: {
show: true,
lineStyle: {
@@ -95,13 +80,13 @@ under the License.
}
},
axisLabel: {
- formatter: "{value} ml"
+ formatter: '{value} ml'
}
},
{
- type: "value",
- name: "Precipitation",
- position: "right",
+ type: 'value',
+ name: 'Precipitation',
+ position: 'right',
alignTicks: true,
offset: 80,
axisLine: {
@@ -111,13 +96,13 @@ under the License.
}
},
axisLabel: {
- formatter: "{value} ml"
+ formatter: '{value} ml'
}
},
{
- type: "value",
- name: "温度",
- position: "left",
+ type: 'value',
+ name: '温度',
+ position: 'left',
alignTicks: true,
axisLine: {
show: true,
@@ -126,22 +111,22 @@ under the License.
}
},
axisLabel: {
- formatter: "{value} °C"
+ formatter: '{value} °C'
}
}
],
series: [
{
- name: "Evaporation",
- type: "bar",
+ name: 'Evaporation',
+ type: 'bar',
data: [
2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4,
3.3
]
},
{
- name: "Precipitation",
- type: "bar",
+ name: 'Precipitation',
+ type: 'bar',
yAxisIndex: 1,
data: [
2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0,
@@ -149,8 +134,8 @@ under the License.
]
},
{
- name: "Temperature",
- type: "line",
+ name: 'Temperature',
+ type: 'line',
yAxisIndex: 2,
data: [
2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2
@@ -158,20 +143,269 @@ under the License.
}
]
};
+ </script>
+
+
+
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+ var option = JSON.parse(JSON.stringify(commonOption));
var chart = testHelper.create(echarts, 'main0', {
title: [
- 'Should align to the first axis'
+ 'Should align to the first axis if all set alignTicks'
],
option: option
- // height: 300,
- // buttons: [{text: 'btn-txt', onclick: function () {}}],
- // recordCanvas: true,
});
});
</script>
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+ var option = JSON.parse(JSON.stringify(commonOption));
+
+ const tmp = option.yAxis;
+ option.yAxis = option.xAxis;
+ option.xAxis = tmp;
+ option.xAxis[1].alignTicks = false;
+ option.xAxis[1].splitNumber = 20;
+ option.xAxis[1].offset = 30;
+ option.grid.top = 100;
+
+ option.series[0].xAxisIndex = 0;
+ option.series[1].xAxisIndex = 1;
+ option.series[2].xAxisIndex = 2;
+
+ option.series[0].yAxisIndex = 0;
+ option.series[1].yAxisIndex = 0;
+ option.series[2].yAxisIndex = 0;
+
+ var chart = testHelper.create(echarts, 'main1', {
+ title: [
+ 'xAxis can alignTicks',
+ 'Should align to the second xAxis with splitNumber: 20'
+ ],
+ option: option
+ });
+ });
+ </script>
+
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+
+ var option = JSON.parse(JSON.stringify(commonOption));
+ option.yAxis.unshift({
+ type: 'category',
+ offset: 50,
+ data: ['foo', 'bar', 'baz']
+ });
+ option.series[0].yAxisIndex = 1;
+ option.series[1].yAxisIndex = 2;
+ option.series[2].yAxisIndex = 3;
+
+ var chart = testHelper.create(echarts, 'main2', {
+ title: [
+ 'Should not align to the category axis'
+ ],
+ option: option
+ });
+ });
+ </script>
+
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+
+ var option = {
+ legend: {},
+ xAxis: {
+ type: 'category',
+ name: 'x',
+ splitLine: { show: false },
+ data: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
+ },
+ yAxis: [{
+ type: 'log',
+ alignTicks: true,
+ minorSplitLine: {
+ show: true
+ },
+ }, {
+ type: 'value'
+ }],
+ series: [
+ {
+ name: 'Log',
+ type: 'line',
+ data: [1, 3, 9, 27, 81, 247, 741, 2223, 6669]
+ },
+ {
+ name: 'Linear',
+ type: 'line',
+ yAxisIndex: 1,
+ data: [1, 2, 3, 4, 2, 8, 11, 3, 1]
+ }
+ ]
+ }
+
+ var chart = testHelper.create(echarts, 'main3', {
+ title: [
+ 'Log axis can alignTicks to value axis'
+ ],
+ option: option
+ });
+ });
+ </script>
+
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+
+ var option = {
+ legend: {},
+ xAxis: {
+ type: 'category',
+ name: 'x',
+ splitLine: { show: false },
+ data: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
+ },
+ yAxis: [{
+ type: 'log',
+ minorSplitLine: {
+ show: true
+ },
+ }, {
+ alignTicks: true,
+ type: 'value'
+ }],
+ series: [
+ {
+ name: 'Log',
+ type: 'line',
+ data: [1, 3, 9, 27, 81, 247, 741, 2223, 6669]
+ },
+ {
+ name: 'Linear',
+ type: 'line',
+ yAxisIndex: 1,
+ data: [1, 2, 3, 4, 2, 8, 11, 3, 1]
+ }
+ ]
+ }
+
+ var chart = testHelper.create(echarts, 'main4', {
+ title: [
+ 'Value axis can alignTicks to log axis'
+ ],
+ option: option
+ });
+ });
+ </script>
+
+ <script>
+ require([
+ 'echarts'
+ ], function (echarts) {
+ var option = {
+ title: {
+ text: 'Rainfall and Flow Relationship',
+ left: 'center'
+ },
+ grid: {
+ bottom: 80
+ },
+ legend: {
+ data: ['Flow', 'Rainfall'],
+ left: 10
+ },
+ dataZoom: [
+ {
+ show: true,
+ realtime: true,
+ start: 65,
+ end: 85
+ },
+ {
+ type: 'inside',
+ realtime: true,
+ start: 65,
+ end: 85
+ }
+ ],
+ xAxis: [
+ {
+ type: 'category',
+ boundaryGap: false,
+ axisLine: { onZero: false },
+ // prettier-ignore
+ data: [
+ '2009/6/12 2:00', '2009/6/12 3:00', '2009/6/12 4:00', '2009/6/12 5:00', '2009/6/12 6:00', '2009/6/12 7:00', '2009/6/12 8:00', '2009/6/12 9:00', '2009/6/12 10:00', '2009/6/12 11:00', '2009/6/12 12:00', '2009/6/12 13:00', '2009/6/12 14:00', '2009/6/12 15:00', '2009/6/12 16:00', '2009/6/12 17:00', '2009/6/12 18:00', '2009/6/12 19:00', '2009/6/12 20:00', '2009/6/12 21:00', '2009/6/12 22:00', '2009/6/12 23:00', '2009/6/13 0:00', '2009/6/13 1:00', '2009/6/13 2:0 [...]
+ ].map(function (str) {
+ return str.replace(' ', '\n');
+ })
+ }
+ ],
+ yAxis: [
+ {
+ name: 'Flow(m^3/s)',
+ type: 'value'
+ },
+ {
+ name: 'Rainfall(mm)',
+ nameLocation: 'start',
+ type: 'value',
+ alignTicks: true,
+ inverse: true
+ }
+ ],
+ series: [
+ {
+ name: 'Flow',
+ type: 'line',
+ areaStyle: {},
+ lineStyle: {
+ width: 1
+ },
+ showSymbol: false,
+ // prettier-ignore
+ data: [
+ 0.97, 0.96, 0.96, 0.95, 0.95, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94 [...]
+ ]
+ },
+ {
+ name: 'Rainfall',
+ type: 'line',
+ yAxisIndex: 1,
+ areaStyle: {},
+ lineStyle: {
+ width: 1
+ },
+ showSymbol: false,
+ // prettier-ignore
+ data: [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.005, 0.017, 0.017, 0.017, 0.017, 0.011, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.021, 0.026, 0.03, 0.036, 0.036, 0.195, 0.221, 0.019, 0.013, 0.017, 0.03, 0.03, 0.03, 0.046, 0.045, 0.038, 0.084, 0.0 [...]
+ ]
+ }
+ ]
+ };
+
+ var chart = testHelper.create(echarts, 'main5', {
+ title: [
+ 'Should always been aligned in dataZoom'
+ ],
+ option: option
+ });
+ });
+ </script>
</body>
</html>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org