Skip to content

Commit

Permalink
feat/ordinal: support date input (#160)
Browse files Browse the repository at this point in the history
* feat(scale): accept dates input for ordinal close:#159

* chore: update version to 0.4.3

* feat(types): add date for band

* perf(ordinal): pass benchmark test

* docs: update domain types for ordinal, band and point

* test: increase coverage
  • Loading branch information
pearmini committed Jun 21, 2021
1 parent a07b2f9 commit 5cc43d0
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 15 deletions.
24 changes: 24 additions & 0 deletions __tests__/unit/scales/ordinal.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,30 @@ describe('ordinal scale', () => {
expect(scale.invert('June')).toStrictEqual('一月');
});

test('map date', () => {
// 映射规则类似于 map 方法,这里不再赘述
const date = new Ordinal({
domain: [new Date('2020-02-01'), new Date('2020-02-02'), new Date('2020-02-03')],
range: ['a', 'b', 'c'],
});

expect(date.map(new Date('2020-02-02'))).toStrictEqual('b');
expect(date.map(new Date('2020-02-03'))).toStrictEqual('c');
expect(date.map(new Date('2020-02-01'))).toStrictEqual('a');
});

test('invert date', () => {
// 映射规则类似于 map 方法,这里不再赘述
const date = new Ordinal({
domain: ['a', 'b', 'c'],
range: [new Date('2020-02-01'), new Date('2020-02-02'), new Date('2020-02-03')],
});

expect(date.invert(new Date('2020-02-02'))).toStrictEqual('b');
expect(date.invert(new Date('2020-02-03'))).toStrictEqual('c');
expect(date.invert(new Date('2020-02-01'))).toStrictEqual('a');
});

test('update scale', () => {
const scale = new Ordinal({
domain: ['A', 'B', 'C'],
Expand Down
2 changes: 1 addition & 1 deletion docs/api/scales/band.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ x.getBandWidth(); // 25

| Key | Description | Type | Default|
| ----| ----------- | -----| -------|
| domain | Sets the scale’s domain to the specified array of values. | <code>number[] &#124; string[]</code> | `[]` |
| domain | Sets the scale’s domain to the specified array of values. | <code>number[] &#124; string[] &#124; Date[] </code> | `[]` |
| range | Sets the scale’s range to the specified array of values. | `number[]` | `[0, 1]` |
| unknown | Sets the output value of the scale for `undefined` (or `NaN`) input values. | `any` | `undefined` |
| round | If round option is truthy, the start and stop of each band will be integers. | `boolean` | `false` |
Expand Down
2 changes: 1 addition & 1 deletion docs/api/scales/ordinal.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ time.map('2021-04-20'); // 'C'

| Key | Description | Type | Default|
| ----| ----------- | -----| -------|
| domain | Sets the scale’s domain to the specified array of values. | <code>number[] &#124; string[]</code> | `[]` |
| domain | Sets the scale’s domain to the specified array of values. | <code>number[] &#124; string[] &#124; Date[] | `[]` |
| range | Sets the scale’s range to the specified array of values. | <code>number[] &#124; string[]</code> | `[]` |
| unknown | Sets the output value of the scale for `undefined` (or `NaN`) input values. | `any` | `undefined` |
| compare | Sets the comparator for sorting the domain before mapping. | ```(a: string or number, b: string or number) => number```| `undefined` |
Expand Down
2 changes: 1 addition & 1 deletion docs/api/scales/point.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ scale.getBandWidth(); // always 0

| Key | Description | Type | Default|
| ----| ----------- | -----| -------|
| domain | Sets the scale’s domain to the specified array of values. | <code>number[] &#124; string[]</code> | `[]` |
| domain | Sets the scale’s domain to the specified array of values. | <code>number[] &#124; string[] &#124; Date[] | `[]` |
| range | Sets the scale’s range to the specified array of values. | `number[]` | `[0, 1]` |
| unknown | Sets the output value of the scale for `undefined` (or `NaN`) input values. | `any` | `undefined` |
| round | If round option is truthy, the start and stop of each point will be integers. | `boolean` | `false` |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@antv/scale",
"version": "0.4.2",
"version": "0.4.3",
"description": "Toolkit for mapping abstract data into visual representation.",
"license": "MIT",
"main": "lib/index.js",
Expand Down
30 changes: 22 additions & 8 deletions src/scales/ordinal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { OrdinalOptions, Domain, Range } from '../types';
import { Base } from './base';

interface MapBetweenArrOptions {
type Transform = (x: any) => any;

type MapBetweenArrOptions = {
// 需要映射的值
value: any;
// indexMapper 由定义域生成的映射表,键为定义域的每一个值,值为所在下标
Expand All @@ -12,7 +14,7 @@ interface MapBetweenArrOptions {
to: any[];
// 当 mapper 中查询不到时的返回值
notFoundReturn?: any;
}
};

/**
* 更新 indexMap
Expand All @@ -21,10 +23,10 @@ interface MapBetweenArrOptions {
* @param target 目标 map
* @returns {Map<string, any>} 生成的 indexMap
*/
function updateIndexMap(target: Map<any, number>, arr: any[]) {
function updateIndexMap(target: Map<any, number>, arr: any[], key: Transform) {
for (let i = 0; i < arr.length; i += 1) {
if (!target.has(arr[i])) {
target.set(arr[i], i);
target.set(key(arr[i]), i);
}
}
}
Expand Down Expand Up @@ -72,6 +74,12 @@ export class Ordinal<O extends OrdinalOptions = OrdinalOptions> extends Base<O>
// 排序后的 domain
protected sortedDomain: O['domain'];

// 获得 domain 的 key
protected domainKey: Transform;

// 获得 range 的 key
protected rangeKey: Transform;

// 覆盖默认配置
protected getDefaultOptions() {
return {
Expand All @@ -87,11 +95,11 @@ export class Ordinal<O extends OrdinalOptions = OrdinalOptions> extends Base<O>

public map(x: Domain<O>) {
if (this.domainIndexMap.size === 0) {
updateIndexMap(this.domainIndexMap, this.getDomain());
updateIndexMap(this.domainIndexMap, this.getDomain(), this.domainKey);
}

return mapBetweenArrByMapIndex({
value: x,
value: this.domainKey(x),
mapper: this.domainIndexMap,
from: this.getDomain(),
to: this.getRange(),
Expand All @@ -101,11 +109,11 @@ export class Ordinal<O extends OrdinalOptions = OrdinalOptions> extends Base<O>

public invert(y: Range<O>) {
if (this.rangeIndexMap.size === 0) {
updateIndexMap(this.rangeIndexMap, this.getRange());
updateIndexMap(this.rangeIndexMap, this.getRange(), this.rangeKey);
}

return mapBetweenArrByMapIndex({
value: y,
value: this.rangeKey(y),
mapper: this.rangeIndexMap,
from: this.getRange(),
to: this.getDomain(),
Expand All @@ -115,6 +123,12 @@ export class Ordinal<O extends OrdinalOptions = OrdinalOptions> extends Base<O>

// 因为 ordinal 比例尺更新内部状态的开销较大,所以按需更新
protected rescale(options?: Partial<O>) {
const [d] = this.options.domain;
const [r] = this.options.range;

this.domainKey = d instanceof Date ? (d) => `${d}` : (d) => d;
this.rangeKey = r instanceof Date ? (d) => `${d}` : (d) => d;

// 如果 rangeIndexMap 没有初始化,说明是在初始化阶段
if (!this.rangeIndexMap) {
this.rangeIndexMap = new Map();
Expand Down
2 changes: 1 addition & 1 deletion src/tick-methods/d3-log.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TickMethod } from 'types';
import { TickMethod } from '../types';
import { d3Ticks } from './d3-ticks';
import { pows, logs } from '../utils';

Expand Down
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ export type TimeOptions = ContinuousOptions<Date, number> & {
};

/** OrdinalOptions 比例尺的选项 */
export type OrdinalOptions = BaseOptions<number | string> & { compare?: Comparator };
export type OrdinalOptions = BaseOptions<number | string | Date> & { compare?: Comparator };

/** 详细请参阅 scale/band.ts */
export type BandOptions = BaseOptions<number | string, number> & {
export type BandOptions = BaseOptions<number | string | Date, number> & {
/** 是否取整 */
round?: boolean;
/** 内部边距 */
Expand Down

0 comments on commit 5cc43d0

Please sign in to comment.