Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/tick mode #3092

Merged
merged 5 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion docs/assets/option/en/component/axis-common/base-axis.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,31 @@ tickCount?: (option: {

Forcing the number of ticks to be set ensures that the number of ticks matches the set value, but may cause the tick value to be a decimal due to the data range.

##${prefix} tickMode('average'|'d3') = 'average'
##${prefix} tickMode('average'|'d3'|function) = 'average'

The continuous axis tick generation algorithm, supported since version `1.3.0`, **only takes effect when the axis is a linear axis**.

- 'average': Ticks are evenly distributed based on the axis range as much as possible.
- 'd3': Generates tick values like the default logic of d3, using a base of [1, 2, 5].
- `CustomTicksFunc`: Custom ticks, supported since version `1.12.0`, **only effective when the axis is linear**. The specific usage is as follows:

```ts
/**
* @typedef {function} CustomTicksFunc
* @param {ContinuousScale} scale - The scale object of the continuous axis
* @param {number} tickCount - The number of ticks to generate
* @returns {number[]} - The array of generated ticks
*/
tickMode: CustomTicksFunc<ContinuousScale>;
/**
* @example
*/
tickMode: (scale, tickCount = 5) => {
const domain = scale.domain();
const step = (domain[1] - domain[0]) / (tickCount - 1);
return Array.from({ length: tickCount }, (_, i) => domain[0] + i * step);
};
```

##${prefix} noDecimals(boolean) = false

Expand Down
21 changes: 20 additions & 1 deletion docs/assets/option/zh/component/axis-common/base-axis.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,31 @@ tickCount?: (option: {

强制设置的 tick 数量,可以保证 tick 的数量于设置的数值匹配,但是可能由于数据范围导致 tick 值为小数。

##${prefix} tickMode('average'|'d3') = 'average'
##${prefix} tickMode('average'|'d3'|function) = 'average'

连续轴 tick 生成算法,自`1.3.0`版本开始支持,**仅当轴为线性轴时生效**。

- `'average'`:根据轴范围尽可能均分
- `'d3'`:与 d3 默认逻辑一致,以 [1, 2, 5] 为基数生成;
- `CustomTicksFunc`: 自定义 tick 生成算法,自`1.12.0`版本开始支持,**仅当轴为线性轴时生效**,具体使用方式如下:

```ts
/**
* @typedef {function} CustomTicksFunc
* @param {ContinuousScale} scale - 连续轴的比例尺对象
* @param {number} tickCount - 生成tick的数量
* @returns {number[]} - 生成的 tick 数组
*/
tickMode: CustomTicksFunc<ContinuousScale>;
/**
* @example
*/
tickMode: (scale, tickCount = 5) => {
const domain = scale.domain();
const step = (domain[1] - domain[0]) / (tickCount - 1);
return Array.from({ length: tickCount }, (_, i) => domain[0] + i * step);
};
```

##${prefix} noDecimals(boolean) = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { getTestCompiler } from '../../../../util/factory/compiler';
import { initChartDataSet } from '../../../../util/context';
import type { StringOrNumber } from '../../../../../src/typings/common';
import { getCartesianAxisInfo } from '../../../../../src/component/axis/cartesian/util';
import { wilkinsonExtended } from '@visactor/vscale';

const dataSet = new DataSet();
initChartDataSet(dataSet);
Expand Down Expand Up @@ -587,3 +588,85 @@ test('dynamic tickCount', () => {
expect(tickCount).toEqual(4);
}
});

test('dynamic tickCount', () => {
let spec = getAxisSpec({
orient: 'left',
tick: {
tickMode: (scale: any, count: number) => {
return [0, 25000, 50000];
}
}
});
const transformer = new CartesianAxis.transformerConstructor({
type: 'cartesianAxis-linear',
getTheme: () => ThemeManager.getCurrentTheme(true),
mode: 'desktop-browser'
});
spec = transformer.transformSpec(spec, {}).spec;
const linearAxis = CartesianAxis.createComponent(
{
type: getCartesianAxisInfo(spec).componentName,
spec
},
ctx
);

linearAxis.created();
linearAxis.init({});
// @ts-ignore
linearAxis.updateScaleDomain();
const scale = linearAxis.getScale();
scale.range([0, 50000]);
// @ts-ignore
linearAxis.computeData();
// @ts-ignore
const tickValues = linearAxis
// @ts-ignore
.getTickData()
.getLatestData()
.map((tick: any) => tick.value);
expect(tickValues).toEqual([0, 25000, 50000]);
});

test('dynamic tickCount with wilkson', () => {
let spec = getAxisSpec({
orient: 'left',
tick: {
tickMode: (scale: any, count: number) => {
const d = scale.calculateVisibleDomain(scale.get('_range'));
return wilkinsonExtended(d[0], d[1], count);
}
}
});
const transformer = new CartesianAxis.transformerConstructor({
type: 'cartesianAxis-linear',
getTheme: () => ThemeManager.getCurrentTheme(true),
mode: 'desktop-browser'
});
spec = transformer.transformSpec(spec, {}).spec;
const linearAxis = CartesianAxis.createComponent(
{
type: getCartesianAxisInfo(spec).componentName,
spec
},
ctx
);

linearAxis.created();
linearAxis.init({});
// @ts-ignore
linearAxis.updateScaleDomain();
const scale = linearAxis.getScale();
scale.range([0, 50000]);
scale.domain([0, 100]);
// @ts-ignore
linearAxis.computeData();
// @ts-ignore
const tickValues = linearAxis
// @ts-ignore
.getTickData()
.getLatestData()
.map((tick: any) => tick.value);
expect(tickValues).toEqual([0, 25, 50, 75, 100]);
});
19 changes: 17 additions & 2 deletions packages/vchart/src/component/axis/interface/common.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IBaseScale } from '@visactor/vscale';
import type { ContinuousScale, IBaseScale, CustomTicksFunc } from '@visactor/vscale';
import type { CoordinateType, Datum, IPolarOrientType, StringOrNumber } from '../../../typings';
import type { IComponent } from '../../interface/common';
import type { ICartesianAxisSpec } from '../cartesian/interface';
Expand Down Expand Up @@ -67,10 +67,25 @@ export interface ITickCalculationCfg {
* 连续轴 tick 生成算法:
* 'average': 尽可能均分;
* 'd3':与 d3 默认逻辑一致,以 [1, 2, 5] 为基数生成;
* CustomTicksFunc: 自定义tick生成算法
* @default 'average'
* @since 1.3.0
*
* @typedef {function} CustomTicksFunc
* @param {ContinuousScale} scale - 连续轴的比例尺对象
* @param {number} tickCount - 生成tick的数量
* @returns {number[]} - 生成的 tick 数组
* @since 1.12.0
*
* @example
* // 自定义 tick 生成函数示例
* const customTickFunc: CustomTicksFunc = (scale, tickCount=5) => {
* const domain = scale.domain();
* const step = (domain[1] - domain[0]) / (tickCount - 1);
* return Array.from({ length: tickCount }, (_, i) => domain[0] + i * step);
* };
*/
tickMode?: 'average' | 'd3';
tickMode?: 'average' | 'd3' | CustomTicksFunc<ContinuousScale>;
/**
* 连续轴,是否避免小数 tick。
* @default false
Expand Down
Loading