UNPKG

4.43 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.Ordinal = exports.defaultUnknown = void 0;
4const base_1 = require("./base");
5exports.defaultUnknown = Symbol('defaultUnknown');
6/**
7 * 更新 indexMap
8 *
9 * @param arr 初始的数组
10 * @param target 目标 map
11 * @returns {Map<string, any>} 生成的 indexMap
12 */
13function updateIndexMap(target, arr, key) {
14 for (let i = 0; i < arr.length; i += 1) {
15 if (!target.has(arr[i])) {
16 target.set(key(arr[i]), i);
17 }
18 }
19}
20/**
21 * 基于 indexMap 进行映射
22 *
23 * @param options 相关选项
24 * @see MapBetweenArrOptions
25 * @return {any} 映射结果
26 */
27function mapBetweenArrByMapIndex(options) {
28 const { value, from, to, mapper, notFoundReturn } = options;
29 let mappedIndex = mapper.get(value);
30 // index 不存在时,
31 // 如果用户显式设置了 unknown 的值,那么就返回 unknown 的值
32 // 否者我们将 value 添加到原数组, 并更新 Map
33 if (mappedIndex === undefined) {
34 if (notFoundReturn !== exports.defaultUnknown) {
35 return notFoundReturn;
36 }
37 mappedIndex = from.push(value) - 1;
38 mapper.set(value, mappedIndex);
39 }
40 return to[mappedIndex % to.length];
41}
42function createKey(d) {
43 if (d instanceof Date)
44 return (d) => `${d}`;
45 if (typeof d === 'object')
46 return (d) => JSON.stringify(d);
47 return (d) => d;
48}
49/**
50 * Ordinal 比例尺
51 *
52 * 该比例尺具有离散的域和范围,例如将一组命名类别映射到一组颜色
53 *
54 * - 使用 for 替代一些基于 map 的遍历,for 循环性能远高于 forEach, map
55 * - 阻止无意义的更新,只有到用户调用 map、invert 或者 update 之后才会进行相应的更新
56 * - 两个 map 只初始化一次,在之后的更新中复用他们,这样我们避免了重复 new Map 带来的性能问题
57 * 在大量调用 update 函数场景下,较 d3-scale 效率有质的提高
58 */
59class Ordinal extends base_1.Base {
60 // 覆盖默认配置
61 getDefaultOptions() {
62 return {
63 domain: [],
64 range: [],
65 unknown: exports.defaultUnknown,
66 };
67 }
68 // 显示指定 options 的类型为 OrdinalOptions,从而推断出 O 的类型
69 constructor(options) {
70 super(options);
71 }
72 map(x) {
73 if (this.domainIndexMap.size === 0) {
74 updateIndexMap(this.domainIndexMap, this.getDomain(), this.domainKey);
75 }
76 return mapBetweenArrByMapIndex({
77 value: this.domainKey(x),
78 mapper: this.domainIndexMap,
79 from: this.getDomain(),
80 to: this.getRange(),
81 notFoundReturn: this.options.unknown,
82 });
83 }
84 invert(y) {
85 if (this.rangeIndexMap.size === 0) {
86 updateIndexMap(this.rangeIndexMap, this.getRange(), this.rangeKey);
87 }
88 return mapBetweenArrByMapIndex({
89 value: this.rangeKey(y),
90 mapper: this.rangeIndexMap,
91 from: this.getRange(),
92 to: this.getDomain(),
93 notFoundReturn: this.options.unknown,
94 });
95 }
96 // 因为 ordinal 比例尺更新内部状态的开销较大,所以按需更新
97 rescale(options) {
98 const [d] = this.options.domain;
99 const [r] = this.options.range;
100 this.domainKey = createKey(d);
101 this.rangeKey = createKey(r);
102 // 如果 rangeIndexMap 没有初始化,说明是在初始化阶段
103 if (!this.rangeIndexMap) {
104 this.rangeIndexMap = new Map();
105 this.domainIndexMap = new Map();
106 return;
107 }
108 // 否者是在更新阶段
109 if (!options || options.range) {
110 this.rangeIndexMap.clear();
111 }
112 if (!options || options.domain || options.compare) {
113 this.domainIndexMap.clear();
114 this.sortedDomain = undefined;
115 }
116 }
117 clone() {
118 return new Ordinal(this.options);
119 }
120 getRange() {
121 return this.options.range;
122 }
123 getDomain() {
124 // 如果设置了比较器,就排序
125 if (this.sortedDomain)
126 return this.sortedDomain;
127 const { domain, compare } = this.options;
128 this.sortedDomain = compare ? [...domain].sort(compare) : domain;
129 return this.sortedDomain;
130 }
131}
132exports.Ordinal = Ordinal;
133//# sourceMappingURL=ordinal.js.map
\No newline at end of file