Skip to content

Commit

Permalink
refactor: unify scale flow and simplify code (#116)
Browse files Browse the repository at this point in the history
* refactor: unify scale flow and simplify code

* refactor(quantize): change niceDomain to nice

* refactor(type): reorder types

* style(linear): remove blank line
  • Loading branch information
pearmini committed Apr 22, 2021
1 parent fd67840 commit 4174d00
Show file tree
Hide file tree
Showing 17 changed files with 163 additions and 298 deletions.
7 changes: 7 additions & 0 deletions __tests__/unit/scales/base.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ import { Base } from '../../../src/scales/base';
import { BaseOptions, Domain, Range } from '../../../src/types';

class Scale extends Base<BaseOptions> {
protected getDefaultOptions() {
return {
domain: [0, 1],
range: [0, 1],
};
}

public map(x: Domain<BaseOptions>) {
return x;
}
Expand Down
78 changes: 6 additions & 72 deletions __tests__/unit/scales/continuous.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,19 @@ import { Interpolate } from '../../../src';
describe('Continuous', () => {
type ScaleOptions = ContinuousOptions;

const niceCallback = jest.fn();
const transformCallback = jest.fn();
const untransformCallback = jest.fn();

class Scale extends Continuous<ScaleOptions> {
protected chooseUntransform() {
return (x) => {
untransformCallback();
protected chooseTransforms() {
const transform = (x) => {
transformCallback();
return identity(x);
};
}

protected chooseTransform() {
return (x) => {
transformCallback();
const untransform = (x) => {
untransformCallback();
return identity(x);
};
}

protected nice() {
niceCallback();
this.options.domain = [0, 2];
return [transform, untransform];
}

public clone() {
Expand All @@ -54,12 +45,6 @@ describe('Continuous', () => {
});

expect(interpolate).toEqual(createInterpolate);

// @ts-ignore
expect(s.output).toBeUndefined();

// @ts-ignore
expect(s.input).toBeUndefined();
});

test('Continuous(options) override defaults', () => {
Expand All @@ -83,9 +68,6 @@ describe('Continuous', () => {
expect(s.map(undefined)).toBe('dirty');
expect(s.map(NaN)).toBe('dirty');
expect(s.map(null)).toBe('dirty');

// @ts-ignore
expect(s.output).toBeUndefined();
});

test('invert(undefined | NaN | null) invert undefined or NaN to options.unknown', () => {
Expand All @@ -95,21 +77,6 @@ describe('Continuous', () => {
expect(s.invert(undefined)).toBe('dirty');
expect(s.invert(NaN)).toBe('dirty');
expect(s.invert(null)).toBe('dirty');

// @ts-ignore
expect(s.input).toBeUndefined();
});

test('map(x) calls transform', () => {
const s = new Scale();

// @ts-ignore
expect(transformCallback).not.toBeCalled();

s.map(0);

// @ts-ignore
expect(transformCallback).toBeCalled();
});

test('invert(x) calls untransform', () => {
Expand All @@ -123,26 +90,6 @@ describe('Continuous', () => {
expect(untransformCallback).toBeCalled();
});

test('map(x) call nice() if options.nice === true', () => {
const s = new Scale({
nice: true,
});

s.map(0);
expect(niceCallback).toBeCalledTimes(1);
expect(s.getOptions().domain).toEqual([0, 2]);
});

test('invert(x) call nice() if options.nice === true', () => {
const s = new Scale({
nice: true,
});

s.invert(0);
expect(niceCallback).toBeCalledTimes(2);
expect(s.getOptions().domain).toEqual([0, 2]);
});

test('map(x) compose the output', () => {
const s = new Scale();
s.map(0);
Expand Down Expand Up @@ -275,19 +222,6 @@ describe('Continuous', () => {
expect(options.domain).toEqual([0, 10]);
});

test('update(options) clears output and input functions', () => {
const s = new Scale();
s.map(0);
s.invert(0);
s.update({ domain: [0, 1] });

// @ts-ignore
expect(s.output).toBeUndefined();

// @ts-ignore
expect(s.input).toBeUndefined();
});

test('options.interpolate sets a custom interpolator factory', () => {
// y^2 = mx + b
const interpolate: Interpolate = (a, b) => (t) => Math.sqrt(a * a * (1 - t) + b * b * t);
Expand Down
13 changes: 4 additions & 9 deletions src/scales/band.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,16 @@ function getBandState(opt: BandStateOptions) {
*/
export class Band<O extends BandOptions> extends Ordinal<O> {
// 步长,见上图
private step: number = 0;
private step: number;

// band 宽度
private bandWidth: number = 0;
private bandWidth: number;

// 转换过的 range
private adjustedRange: O['range'];

// 覆盖默认配置
protected getOverrideDefaultOptions() {
protected getDefaultOptions() {
return {
domain: [],
range: [0, 1],
Expand All @@ -138,18 +138,12 @@ export class Band<O extends BandOptions> extends Ordinal<O> {
// 显示指定 options 的类型为 OrdinalOptions,从而推断出 O 的类型
constructor(options?: BandOptions) {
super(options as O);
this.rescale();
}

public clone() {
return new Band<O>(this.options);
}

public update(updateOptions: Partial<O>) {
super.update(updateOptions);
this.rescale();
}

public getStep() {
return this.step;
}
Expand All @@ -173,6 +167,7 @@ export class Band<O extends BandOptions> extends Ordinal<O> {
}

protected rescale() {
super.rescale();
// 当用户配置了opt.padding 且非 0 时,我们覆盖已经设置的 paddingInner paddingOuter
// 我们约定 padding 的优先级较 paddingInner 和 paddingOuter 高
const { align, domain, range, round } = this.options;
Expand Down
42 changes: 22 additions & 20 deletions src/scales/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,47 @@ export abstract class Base<O extends BaseOptions> {
*/
abstract clone(): Base<O>;

/** 比例尺的选项,用于配置数据映射的规则和 ticks 的生成方式 */
protected options: O;
/**
* 子类需要覆盖的默认配置
*/
protected abstract getDefaultOptions(): Partial<O>;

/** 比例尺的默认选项,子类可以自定义默认选项 */
protected readonly defaultOptions: O;
/**
* 比例尺的选项,用于配置数据映射的规则和 ticks 的生成方式
*/
protected options: O;

/**
* 构造函数,根据自定义的选项和默认选项生成当前选项
* @param options 需要自定义配置的选项
*/
constructor(options?: O) {
const BASE_DEFAULT_OPTIONS = {
domain: [0, 1],
range: [0, 1],
} as O;
this.defaultOptions = deepMix({}, BASE_DEFAULT_OPTIONS, this.getOverrideDefaultOptions());
this.options = deepMix({}, this.defaultOptions, options);
}

/**
* 子类需要覆盖的默认配置
*/
protected getOverrideDefaultOptions(): Partial<O> {
return {};
this.options = deepMix({}, this.getDefaultOptions());
this.update(options);
}

/**
* 返回当前的所有选项
* @returns 当前的所有选项
*/
public getOptions() {
public getOptions(): O {
return this.options;
}

/**
* 更新选项
* 更新选项和比例尺的内部状态
* @param updateOptions 需要更新的选项
*/
public update(updateOptions: Partial<O>) {
public update(updateOptions: Partial<O> = {}): void {
this.options = deepMix({}, this.options, updateOptions);
this.rescale(updateOptions);
}

/**
* 根据需要更新 options 和更新后的 options 更新 scale 的内部状态,
* 在函数内部可以用 this.options 获得更新后的 options
* @param options 需要更新的 options
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
protected rescale(options?: Partial<O>): void {}
}
4 changes: 3 additions & 1 deletion src/scales/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ export class Constant extends Base<ConstantOptions> {
* 返回需要覆盖的默认选项
* @returns 需要覆盖的默认选项
*/
protected getOverrideDefaultOptions() {
protected getDefaultOptions(): ConstantOptions {
return {
range: [0],
domain: [0, 1],
unknown: undefined,
};
}

Expand Down

0 comments on commit 4174d00

Please sign in to comment.