diff --git a/__tests__/unit/scales/base.spec.ts b/__tests__/unit/scales/base.spec.ts index 9508f352..7abe5c56 100644 --- a/__tests__/unit/scales/base.spec.ts +++ b/__tests__/unit/scales/base.spec.ts @@ -2,6 +2,13 @@ import { Base } from '../../../src/scales/base'; import { BaseOptions, Domain, Range } from '../../../src/types'; class Scale extends Base { + protected getDefaultOptions() { + return { + domain: [0, 1], + range: [0, 1], + }; + } + public map(x: Domain) { return x; } diff --git a/__tests__/unit/scales/continuous.spec.ts b/__tests__/unit/scales/continuous.spec.ts index 42f91f95..fc89457b 100644 --- a/__tests__/unit/scales/continuous.spec.ts +++ b/__tests__/unit/scales/continuous.spec.ts @@ -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 { - 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() { @@ -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', () => { @@ -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', () => { @@ -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', () => { @@ -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); @@ -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); diff --git a/src/scales/band.ts b/src/scales/band.ts index f3feaab0..6494b1df 100644 --- a/src/scales/band.ts +++ b/src/scales/band.ts @@ -113,16 +113,16 @@ function getBandState(opt: BandStateOptions) { */ export class Band extends Ordinal { // 步长,见上图 - 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], @@ -138,18 +138,12 @@ export class Band extends Ordinal { // 显示指定 options 的类型为 OrdinalOptions,从而推断出 O 的类型 constructor(options?: BandOptions) { super(options as O); - this.rescale(); } public clone() { return new Band(this.options); } - public update(updateOptions: Partial) { - super.update(updateOptions); - this.rescale(); - } - public getStep() { return this.step; } @@ -173,6 +167,7 @@ export class Band extends Ordinal { } protected rescale() { + super.rescale(); // 当用户配置了opt.padding 且非 0 时,我们覆盖已经设置的 paddingInner paddingOuter // 我们约定 padding 的优先级较 paddingInner 和 paddingOuter 高 const { align, domain, range, round } = this.options; diff --git a/src/scales/base.ts b/src/scales/base.ts index 39d8d7c0..890e9c01 100644 --- a/src/scales/base.ts +++ b/src/scales/base.ts @@ -20,45 +20,47 @@ export abstract class Base { */ abstract clone(): Base; - /** 比例尺的选项,用于配置数据映射的规则和 ticks 的生成方式 */ - protected options: O; + /** + * 子类需要覆盖的默认配置 + */ + protected abstract getDefaultOptions(): Partial; - /** 比例尺的默认选项,子类可以自定义默认选项 */ - 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 { - return {}; + this.options = deepMix({}, this.getDefaultOptions()); + this.update(options); } /** * 返回当前的所有选项 * @returns 当前的所有选项 */ - public getOptions() { + public getOptions(): O { return this.options; } /** - * 更新选项 + * 更新选项和比例尺的内部状态 * @param updateOptions 需要更新的选项 */ - public update(updateOptions: Partial) { + public update(updateOptions: Partial = {}): 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): void {} } diff --git a/src/scales/constant.ts b/src/scales/constant.ts index 74e7b3cf..0438f546 100644 --- a/src/scales/constant.ts +++ b/src/scales/constant.ts @@ -6,9 +6,11 @@ export class Constant extends Base { * 返回需要覆盖的默认选项 * @returns 需要覆盖的默认选项 */ - protected getOverrideDefaultOptions() { + protected getDefaultOptions(): ConstantOptions { return { range: [0], + domain: [0, 1], + unknown: undefined, }; } diff --git a/src/scales/continuous.ts b/src/scales/continuous.ts index 32985d2c..ed601920 100644 --- a/src/scales/continuous.ts +++ b/src/scales/continuous.ts @@ -1,7 +1,15 @@ import { isNumber, identity } from '@antv/util'; import { Base } from './base'; import { ContinuousOptions, Domain, Range } from '../types'; -import { createInterpolate, createInterpolateRound, createClamp, createNormalize, bisect, compose } from '../utils'; +import { + createInterpolate, + createInterpolateRound, + createClamp, + createNormalize, + bisect, + compose, + d3LinearNice, +} from '../utils'; /** 柯里化后的函数的类型,对输入的值进行处理 */ export type Transform = (x: number) => number; @@ -50,12 +58,6 @@ const createPolyMap: CreateTransform = (domain, range, createInterpolate) => { }; }; -/** 选择一个固定输入的函数 */ -const chooseClamp: CreateTransform = (domain, range, shouldClamp) => { - const n = Math.min(domain.length, range.length); - return shouldClamp ? createClamp(domain[0], domain[n - 1]) : identity; -}; - /** 选择一个分段映射的函数 */ const choosePiecewise: CreateTransform = (domain, range, interpolate, shouldRound?) => { const n = Math.min(domain.length, range.length); @@ -66,10 +68,7 @@ const choosePiecewise: CreateTransform = (domain, range, interpolate, shouldRoun /** * Continuous 比例尺 的输入 x 和输出 y 满足:y = a * f(x) + b - * 对于该类比例尺,根据配置选项的不同会在映射过程中存在一系列分支, - * 在数据量大的情况下这是很影响性能的, - * 所以通过函数柯里化和复合函数可以在映射过程中去掉分支, - * 这样当配置选项更新的时候需要重新合成函数。 + * 通过函数柯里化和复合函数可以在映射过程中去掉分支,提高性能。 * 参考:https://github.com/d3/d3-scale/blob/master/src/continuous.js */ export abstract class Continuous extends Base { @@ -79,25 +78,15 @@ export abstract class Continuous extends Base { /** 实际上将 y 映射为 x 的函数 */ protected input: Transform; - /** 在设置了选项后对 domain 进行优化 */ - protected abstract nice(): void; - - /** 从 domain 获得 ticks */ - protected abstract getTicks(): Domain[]; - - /** - * 根据比例尺 和 options 选择对应的 transform 函数 - * y = a * f(x) + b 中的 f(x) - */ - protected abstract chooseTransform(): Transform; - /** - * 根据比例尺 和 options 选择对应的 untransform 函数 - * x = a * f'(y) + b 中的 f'(y) + * 根据比例尺 和 options 选择对应的 transform 和 untransform 函数 + * y = a * f(x) + b + * x = a * f'(y) + b + * @returns [f(x), f'(y)] */ - protected abstract chooseUntransform(): Transform; + protected abstract chooseTransforms(): Transform[]; - protected getOverrideDefaultOptions() { + protected getDefaultOptions() { return { domain: [0, 1], range: [0, 1], @@ -109,69 +98,60 @@ export abstract class Continuous extends Base { } as O; } + /** + * y = interpolate(normalize(transform(clamp(x)))) + */ public map(x: Domain) { if (!isNumber(x) || Number.isNaN(x)) return this.options.unknown; - if (!this.output) this.composeOutput(); return this.output(x); } + /** + * x = clamp(untransform(interpolate(normalize(y)))) + */ public invert(x: Range) { if (!isNumber(x) || Number.isNaN(x)) return this.options.unknown; - if (!this.input) this.composeInput(); return this.input(x); } - /** - * 这里只要有选项更新,就是清除 input 和 output 函数。 - * - * 更好的做法是,只有依赖选项更新时才清除 input 和 output 函数, - * 但是得到 input 和 output 的函数开销很小,所以这里选择简单的写法。 - * - * 子类在这个函数中可能更新 transform 和 untransform - * @param options 更新的选项 - */ - public update(options: O) { - super.update(options); - this.input = undefined; - this.output = undefined; + protected nice() { + const { nice, domain } = this.options; + if (nice) { + this.options.domain = d3LinearNice(domain); + } } - protected niceDomain() { - if (this.options.nice) { - this.nice(); - } + protected rescale() { + this.nice(); + const clamp = this.chooseClamp(); + const [transform, untransform] = this.chooseTransforms(); + this.composeOutput(transform, clamp); + this.composeInput(transform, untransform, clamp); } - /** - * y = interpolate(normalize(transform(clamp(x)))) - * clamp: x: [a, b] -> x: [d0, d1] - * transform: x: [d0, d1] -> x = f(x) : [f(d0),f(d1)] - * normalize: x: [f(d0), f(d1)] -> t: [0, 1] - * interpolate: t: [0, 1] -> y: [r0, r1] - */ - protected composeOutput() { - this.niceDomain(); - const { clamp: shouldClamp, domain, round, range, interpolate } = this.options; - const clamp = chooseClamp(domain, range, shouldClamp); - const transform = this.chooseTransform(); + protected chooseClamp() { + const { clamp: shouldClamp, domain, range } = this.options; + const n = Math.min(domain.length, range.length); + return shouldClamp ? createClamp(domain[0], domain[n - 1]) : identity; + } + + protected composeOutput(transform: Transform, clamp: Transform) { + const { domain, range, round, interpolate } = this.options; const piecewise = choosePiecewise(domain.map(transform), range, interpolate, round); this.output = compose(piecewise, transform, clamp); } - /** - * x = clamp(untransform(interpolate(normalize(y)))) - * normalize: y: [a, b] -> t: [0, 1] - * interpolate: t: [0, 1] -> x: [f(c), f(d)] - * untransform: x: [f(c), f(d)] -> x = f'(x) : [c, d] - * clamp: x: [c, d] -> x: [d0, d1] - */ - protected composeInput() { - this.niceDomain(); - const { clamp: shouldClamp, domain, range, interpolate } = this.options; - const clamp = chooseClamp(domain, range, shouldClamp); - const untransform = this.chooseUntransform(); - const transform = this.chooseTransform(); + protected composeInput(transform: Transform, untransform: Transform, clamp: Transform) { + const { domain, range, interpolate } = this.options; const piecewise = choosePiecewise(range, domain.map(transform), interpolate); this.input = compose(clamp, untransform, piecewise); } + + public getTicks() { + const { tickCount, tickMethod, domain } = this.options; + const lastIndex = domain.length - 1; + const dMin = domain[0]; + const dMax = domain[lastIndex]; + return tickMethod(dMin, dMax, tickCount); + } } diff --git a/src/scales/identity.ts b/src/scales/identity.ts index 8c7912e0..f0f7d063 100644 --- a/src/scales/identity.ts +++ b/src/scales/identity.ts @@ -8,9 +8,12 @@ export class Identity extends Base { * 返回需要覆盖的默认选项 * @returns 需要覆盖的默认选项 */ - protected getOverrideDefaultOptions() { + protected getDefaultOptions(): IdentityOptions { return { + domain: [0, 1], + range: [0, 1], tickCount: 5, + unknown: undefined, tickMethod: wilkinsonExtended, }; } diff --git a/src/scales/linear.ts b/src/scales/linear.ts index dc633b81..19d6d8f2 100644 --- a/src/scales/linear.ts +++ b/src/scales/linear.ts @@ -2,7 +2,7 @@ import { identity } from '@antv/util'; import { Continuous, Transform } from './continuous'; import { LinearOptions } from '../types'; import { Base } from './base'; -import { createInterpolate, d3LinearNice } from '../utils'; +import { createInterpolate } from '../utils'; import { d3Linear } from '../tick-methods/d3-linear'; /** @@ -10,41 +10,26 @@ import { d3Linear } from '../tick-methods/d3-linear'; * * 构造可创建一个在输入和输出之间具有线性关系的比例尺 */ - export class Linear extends Continuous { - protected getOverrideDefaultOptions() { + protected getDefaultOptions(): LinearOptions { return { + domain: [0, 1], + range: [0, 1], + unknown: undefined, nice: false, clamp: false, round: false, interpolate: createInterpolate, tickMethod: d3Linear, tickCount: 5, - } as LinearOptions; - } - - protected chooseTransform(): Transform { - return identity; + }; } - protected chooseUntransform(): Transform { - return identity; + protected chooseTransforms(): Transform[] { + return [identity, identity]; } public clone(): Base { return new Linear(this.options); } - - public getTicks() { - const { tickCount, domain, tickMethod } = this.options; - const lastIndex = domain.length - 1; - const dMin = domain[0]; - const dMax = domain[lastIndex]; - return tickMethod(dMin, dMax, tickCount); - } - - protected nice() { - const { domain } = this.options; - this.options.domain = d3LinearNice(domain); - } } diff --git a/src/scales/log.ts b/src/scales/log.ts index d151cb50..0f783f5b 100644 --- a/src/scales/log.ts +++ b/src/scales/log.ts @@ -1,6 +1,6 @@ import { Continuous } from './continuous'; -import { LogOptions, PowOptions } from '../types'; -import { createInterpolate, d3LinearNice } from '../utils'; +import { LogOptions } from '../types'; +import { createInterpolate } from '../utils'; import { rPretty } from '../tick-methods/r-pretty'; const reflect = (f) => { @@ -33,7 +33,7 @@ const transformPow = (base: number, shouldReflect: boolean) => { * 构造一个线性的对数比例尺 */ export class Log extends Continuous { - protected getOverrideDefaultOptions() { + protected getDefaultOptions(): LogOptions { return { domain: [1, 10], range: [0, 1], @@ -41,35 +41,16 @@ export class Log extends Continuous { interpolate: createInterpolate, tickMethod: rPretty, tickCount: 5, - } as PowOptions; + }; } - protected chooseTransform() { + protected chooseTransforms() { const { base, domain } = this.options; - const isReflect = domain[0] < 0; - return transformLog(base, isReflect); - } - - protected chooseUntransform() { - const { base, domain } = this.options; - const isReflect = domain[0] < 0; - return transformPow(base, isReflect); + const shouldReflect = domain[0] < 0; + return [transformLog(base, shouldReflect), transformPow(base, shouldReflect)]; } public clone(): Log { return new Log(this.options); } - - protected nice(): void { - const { domain } = this.options; - this.options.domain = d3LinearNice(domain); - } - - public getTicks() { - const { tickCount, domain, tickMethod, base } = this.options; - const lastIndex = domain.length - 1; - const dMin = domain[0]; - const dMax = domain[lastIndex]; - return tickMethod(dMin, dMax, tickCount, base); - } } diff --git a/src/scales/ordinal.ts b/src/scales/ordinal.ts index 97c46e5c..bf7ebd0e 100644 --- a/src/scales/ordinal.ts +++ b/src/scales/ordinal.ts @@ -64,16 +64,16 @@ function mapBetweenArrByMapIndex(options: MapBetweenArrOptions) { */ export class Ordinal extends Base { // 定义域映射表 - private domainIndexMap: Map = new Map(); + private domainIndexMap: Map; // 值域映射表 - private rangeIndexMap: Map = new Map(); + private rangeIndexMap: Map; // 排序后的 domain protected sortedDomain: O['domain']; // 覆盖默认配置 - protected getOverrideDefaultOptions() { + protected getDefaultOptions() { return { domain: [], range: [], @@ -85,17 +85,9 @@ export class Ordinal extends Base { super(options as O); } - private initDomainIndexMap() { - updateIndexMap(this.domainIndexMap, this.getDomain()); - } - - private initRangeIndexMap() { - updateIndexMap(this.rangeIndexMap, this.getRange()); - } - public map(x: Domain) { if (this.domainIndexMap.size === 0) { - this.initDomainIndexMap(); + updateIndexMap(this.domainIndexMap, this.getDomain()); } return mapBetweenArrByMapIndex({ @@ -109,7 +101,7 @@ export class Ordinal extends Base { public invert(y: Range) { if (this.rangeIndexMap.size === 0) { - this.initRangeIndexMap(); + updateIndexMap(this.rangeIndexMap, this.getRange()); } return mapBetweenArrByMapIndex({ @@ -121,15 +113,21 @@ export class Ordinal extends Base { }); } - public update(options: Partial) { - super.update(options); - // TODO: update 直接 clear 有点暴力,在实际情况下前后的数据应该是相似的, 有没有可能 diff 一下在对 Map 进行更新? - // 查看 range 和 domain, 是否更新,如果被更新,我们重置之 - if (options.range) { + // 因为 ordinal 比例尺更新内部状态的开销较大,所以按需更新 + protected rescale(options?: Partial) { + // 如果 rangeIndexMap 没有初始化,说明是在初始化阶段 + if (!this.rangeIndexMap) { + this.rangeIndexMap = new Map(); + this.domainIndexMap = new Map(); + return; + } + + // 否者是在更新阶段 + if (!options || options.range) { this.rangeIndexMap.clear(); } - if (options.domain || options.compare) { + if (!options || options.domain || options.compare) { this.domainIndexMap.clear(); this.sortedDomain = undefined; } diff --git a/src/scales/point.ts b/src/scales/point.ts index 3a39b483..c7675984 100644 --- a/src/scales/point.ts +++ b/src/scales/point.ts @@ -22,7 +22,7 @@ import { PointOptions, BandOptions } from '../types'; */ export class Point extends Band { // 覆盖默认配置 - protected getOverrideDefaultOptions() { + protected getDefaultOptions() { return { domain: [], range: [0, 1], diff --git a/src/scales/pow.ts b/src/scales/pow.ts index 384a4b06..f8bca925 100644 --- a/src/scales/pow.ts +++ b/src/scales/pow.ts @@ -2,7 +2,7 @@ import { identity } from '@antv/util'; import { Continuous, Transform } from './continuous'; import { PowOptions } from '../types'; import { Base } from './base'; -import { createInterpolate, d3LinearNice } from '../utils'; +import { createInterpolate } from '../utils'; import { d3Linear } from '../tick-methods/d3-linear'; const transformPow = (exponent: number) => { @@ -28,7 +28,7 @@ const transformSqrt = (x: number) => { * 即 y = x ^ k 其中 k(指数)可以是任何实数。 */ export class Pow extends Continuous { - protected getOverrideDefaultOptions() { + protected getDefaultOptions() { return { domain: [0, 1], range: [0, 1], @@ -47,33 +47,15 @@ export class Pow extends Continuous { super(options as O); } - protected chooseTransform(): Transform { + protected chooseTransforms(): Transform[] { const { exponent } = this.options; - if (exponent === 1) { - return identity; - } - return exponent === 0.5 ? transformSqrt : transformPow(exponent); - } - - protected chooseUntransform(): Transform { - const { exponent } = this.options; - return exponent === 1 ? identity : transformPowInvert(exponent); + if (exponent === 1) return [identity, identity]; + const transform = exponent === 0.5 ? transformSqrt : transformPow(exponent); + const untransform = transformPowInvert(exponent); + return [transform, untransform]; } public clone(): Base { return new Pow(this.options); } - - public getTicks() { - const { tickCount, domain, tickMethod } = this.options; - const lastIndex = domain.length - 1; - const min = domain[0]; - const max = domain[lastIndex]; - return tickMethod(min, max, tickCount); - } - - protected nice() { - const { domain } = this.options; - this.options.domain = d3LinearNice(domain); - } } diff --git a/src/scales/quantile.ts b/src/scales/quantile.ts index dfb6231e..1455d4aa 100644 --- a/src/scales/quantile.ts +++ b/src/scales/quantile.ts @@ -11,14 +11,14 @@ export class Quantile extends Threshold { // 这里不能给 thresholds 赋值,否者会编译后,会在 constructor 后面执行:this.thresholds = [] private thresholds: QuantileOptions['domain']; - protected getOverrideDefaultOptions() { + protected getDefaultOptions(): QuantileOptions { return { domain: [], range: [], tickCount: 5, unknown: undefined, tickMethod: wilkinsonExtended, - } as QuantileOptions; + }; } constructor(options?: QuantileOptions) { diff --git a/src/scales/quantize.ts b/src/scales/quantize.ts index 2b89db0b..d7d24627 100644 --- a/src/scales/quantize.ts +++ b/src/scales/quantize.ts @@ -10,14 +10,14 @@ export class Quantize extends Threshold { // 这里不能给 thresholds 赋值,否者会编译后,会在 constructor 后面执行:this.thresholds = [] private thresholds: QuantizeOptions['domain']; - protected getOverrideDefaultOptions() { + protected getDefaultOptions(): QuantizeOptions { return { domain: [0, 1], range: [0.5], nice: false, tickCount: 5, tickMethod: wilkinsonExtended, - } as QuantizeOptions; + }; } constructor(options?: QuantizeOptions) { @@ -28,7 +28,7 @@ export class Quantize extends Threshold { return this.thresholds; } - protected niceDomain() { + protected nice() { const { nice, domain } = this.options; if (nice) { this.options.domain = d3LinearNice(domain); @@ -36,7 +36,7 @@ export class Quantize extends Threshold { } protected rescale() { - this.niceDomain(); + this.nice(); const { range, domain } = this.options; const [x0, x1] = domain; diff --git a/src/scales/sqrt.ts b/src/scales/sqrt.ts index 7b789a72..d4d35519 100644 --- a/src/scales/sqrt.ts +++ b/src/scales/sqrt.ts @@ -4,7 +4,7 @@ import { SqrtOptions, PowOptions } from '../types'; import { Pow } from './pow'; export class Sqrt extends Pow { - protected getOverrideDefaultOptions() { + protected getDefaultOptions() { return { domain: [0, 1], range: [0, 1], diff --git a/src/scales/threshold.ts b/src/scales/threshold.ts index a810b125..275d06c0 100644 --- a/src/scales/threshold.ts +++ b/src/scales/threshold.ts @@ -10,7 +10,7 @@ export class Threshold extends Base { /** threshold 的数量 */ protected n: number; - protected getOverrideDefaultOptions() { + protected getDefaultOptions() { return { domain: [0.5], range: [0, 1], @@ -19,7 +19,6 @@ export class Threshold extends Base { constructor(options?: ThresholdOptions) { super(options as O); - this.rescale(); } /** @@ -45,11 +44,6 @@ export class Threshold extends Base { return new Threshold(this.options); } - public update(options?: O) { - super.update(options); - this.rescale(); - } - protected rescale() { const { domain, range } = this.options; this.n = Math.min(domain.length, range.length - 1); diff --git a/src/types.ts b/src/types.ts index 899e69cb..cc1a335a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -63,11 +63,26 @@ export type ContinuousOptions = BaseOptions & /** Linear 比例尺的选项 */ export type LinearOptions = ContinuousOptions; +/** Pow 比例尺的选项 */ +export type PowOptions = ContinuousOptions & { + /** 指数 */ + exponent?: number; +}; + +/** Sqrt 比例尺的选项 */ +export type SqrtOptions = Omit; + +/** Log 比例尺的选项 */ +export type LogOptions = ContinuousOptions & { + /** 底数 */ + base?: number; +}; + /** OrdinalOptions 比例尺的选项 */ export type OrdinalOptions = BaseOptions & { compare?: Comparator }; /** 详细请参阅 scale/band.ts */ -export type BandOptions = BaseOptions & { compare?: Comparator } & { +export type BandOptions = BaseOptions & { /** 是否取整 */ round?: boolean; /** 内部边距 */ @@ -78,6 +93,8 @@ export type BandOptions = BaseOptions & { compare?: Com padding?: number; /** 对齐,取值为 0 - 1 的整数,例如 0.5 表示居中 */ align?: number; + /** 比较器,用于对 domain 进行排序 */ + compare?: Comparator; }; /** Point 比例尺的选项 */ @@ -94,18 +111,3 @@ export type QuantizeOptions = ThresholdOptions & /** Quantile 比例尺的选项 */ export type QuantileOptions = ThresholdOptions & TickOptions; - -/** Pow 比例尺的选项 */ -export type PowOptions = ContinuousOptions & { - /** 指数 */ - exponent?: number; -}; - -/** Sqrt 比例尺的选项 */ -export type SqrtOptions = Omit; - -/** Log 比例尺的选项 */ -export type LogOptions = ContinuousOptions & { - /** 底数 */ - base?: number; -};