UNPKG

4.13 kBPlain TextView Raw
1import { assign, head, isEmpty, isFunction, isNil, isNumber, isObject, isString, last, map } from '@antv/util';
2import { getTickMethod } from './tick-method/register';
3import { ScaleConfig, Tick } from './types';
4export default abstract class Scale {
5 /**
6 * 度量的类型
7 */
8 public type: string = 'base';
9 /**
10 * 是否分类类型的度量
11 */
12 public isCategory?: boolean = false;
13 /**
14 * 是否线性度量,有linear, time 度量
15 */
16 public isLinear?: boolean = false;
17 /**
18 * 是否连续类型的度量,linear,time,log, pow, quantile, quantize 都支持
19 */
20 public isContinuous?: boolean = false;
21 /**
22 * 是否是常量的度量,传入和传出一致
23 */
24 public isIdentity: boolean = false;
25
26 public field?: ScaleConfig['field'];
27 public alias?: ScaleConfig['alias'];
28 public values: ScaleConfig['values'] = [];
29 public min?: ScaleConfig['min'];
30 public max?: ScaleConfig['max'];
31 public minLimit?: ScaleConfig['minLimit'];
32 public maxLimit?: ScaleConfig['maxLimit'];
33 public range: ScaleConfig['range'] = [0, 1];
34 public ticks: ScaleConfig['ticks'] = [];
35 public tickCount: ScaleConfig['tickCount'];
36 public tickInterval: ScaleConfig['tickInterval'];
37 public formatter?: ScaleConfig['formatter'];
38 public tickMethod?: ScaleConfig['tickMethod'];
39 protected __cfg__: ScaleConfig; // 缓存的旧配置, 用于 clone
40
41 constructor(cfg: ScaleConfig) {
42 this.__cfg__ = cfg;
43 this.initCfg();
44 this.init();
45 }
46
47 // 对于原始值的必要转换,如分类、时间字段需转换成数值,用transform/map命名可能更好
48 public translate(v: any) {
49 return v;
50 }
51
52 /** 将定义域转换为值域 */
53 public abstract scale(value: any): number;
54
55 /** 将值域转换为定义域 */
56 public abstract invert(scaled: number): any;
57
58 /** 重新初始化 */
59 public change(cfg: ScaleConfig) {
60 // 覆盖配置项,而不替代
61 assign(this.__cfg__, cfg);
62 this.init();
63 }
64
65 public clone(): Scale {
66 return this.constructor(this.__cfg__);
67 }
68
69 /** 获取坐标轴需要的ticks */
70 public getTicks(): Tick[] {
71 return map(this.ticks, (tick: any, idx: number) => {
72 if (isObject(tick)) {
73 // 仅当符合Tick类型时才有意义
74 return tick as Tick;
75 }
76 return {
77 text: this.getText(tick, idx),
78 tickValue: tick, // 原始value
79 value: this.scale(tick), // scaled
80 };
81 });
82 }
83
84 /** 获取Tick的格式化结果 */
85 public getText(value: any, key?: number): string {
86 const formatter = this.formatter;
87 const res = formatter ? formatter(value, key) : value;
88 if (isNil(res) || !isFunction(res.toString)) {
89 return '';
90 }
91 return res.toString();
92 }
93
94 // 获取配置项中的值,当前 scale 上的值可能会被修改
95 protected getConfig(key) {
96 return this.__cfg__[key];
97 }
98
99 // scale初始化
100 protected init(): void {
101 assign(this, this.__cfg__);
102 this.setDomain();
103 if (isEmpty(this.getConfig('ticks'))) {
104 this.ticks = this.calculateTicks();
105 }
106 }
107
108 // 子类上覆盖某些属性,不能直接在类上声明,否则会被覆盖
109 protected initCfg() {}
110
111 protected setDomain(): void {}
112
113 protected calculateTicks(): any[] {
114 const tickMethod = this.tickMethod;
115 let ticks = [];
116 if (isString(tickMethod)) {
117 const method = getTickMethod(tickMethod);
118 if (!method) {
119 throw new Error('There is no method to to calculate ticks!');
120 }
121 ticks = method(this);
122 } else if (isFunction(tickMethod)) {
123 ticks = tickMethod(this);
124 }
125 return ticks;
126 }
127
128 // range 的最小值
129 protected rangeMin() {
130 return head(this.range);
131 }
132
133 // range 的最大值
134 protected rangeMax() {
135 return last(this.range);
136 }
137
138 /** 定义域转 0~1 */
139 protected calcPercent(value: any, min: number, max: number): number {
140 if (isNumber(value)) {
141 return (value - min) / (max - min);
142 }
143 return NaN;
144 }
145
146 /** 0~1转定义域 */
147 protected calcValue(percent: number, min: number, max: number): number {
148 return min + percent * (max - min);
149 }
150}