-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhelper.ts
173 lines (154 loc) · 4.17 KB
/
helper.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import { DisplayObject } from '@antv/g';
import { lowerFirst, upperFirst, isPlainObject } from '@antv/util';
export function identity<T>(x: T): T {
return x;
}
type Func<R> = (x: R, ...args: any[]) => R;
/**
* Composes functions from left to right.
*/
export function compose<R>(fns: Func<R>[]): Func<R> {
return fns.reduce(
(composed, fn) =>
(x, ...args) =>
fn(composed(x, ...args), ...args),
identity,
);
}
/**
* Composes single-argument async functions from left to right.
*/
export function composeAsync<R>(
fns: ((x: R) => Promise<R> | R)[],
): (x: R) => Promise<R> | R {
return fns.reduce(
(composed, fn) => async (x) => {
const value = await composed(x);
return fn(value);
},
identity,
);
}
export function capitalizeFirst(str: string): string {
return str.replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
}
export function error(message = ''): never {
throw new Error(message);
}
export function copyAttributes(target: DisplayObject, source: DisplayObject) {
const { attributes } = source;
const exclude = new Set(['id', 'className']);
for (const [key, value] of Object.entries(attributes)) {
if (!exclude.has(key)) {
target.attr(key, value);
}
}
}
export function defined(x: any) {
return x !== undefined && x !== null && !Number.isNaN(x);
}
export function random(a: number, b: number): number {
return a + (b - a) * Math.random();
}
export function useMemo<T = unknown, U = unknown>(
compute: (key: T) => U,
): (key: T) => U {
const map = new Map<T, U>();
return (key) => {
if (map.has(key)) return map.get(key);
const value = compute(key);
map.set(key, value);
return value;
};
}
export function appendTransform(node: DisplayObject, transform: any) {
const { transform: preTransform } = node.style;
const unset = (d) => d === 'none' || d === undefined;
const prefix = unset(preTransform) ? '' : preTransform;
node.style.transform = `${prefix} ${transform}`.trimStart();
}
export function subObject(
obj: Record<string, any>,
prefix: string,
): Record<string, any> {
return maybeSubObject(obj, prefix) || {};
}
export function maybeSubObject(
obj: Record<string, any>,
prefix: string,
): Record<string, any> {
const entries = Object.entries(obj || {})
.filter(([key]) => key.startsWith(prefix))
.map(([key, value]) => [lowerFirst(key.replace(prefix, '').trim()), value])
.filter(([key]) => !!key);
return entries.length === 0 ? null : Object.fromEntries(entries);
}
export function prefixObject(
obj: Record<string, any>,
prefix: string,
): Record<string, any> {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => {
return [`${prefix}${upperFirst(key)}`, value];
}),
);
}
export function filterPrefixObject(
obj: Record<string, any>,
prefix: string[],
): Record<string, any> {
return Object.fromEntries(
Object.entries(obj).filter(([key]) =>
prefix.find((p) => key.startsWith(p)),
),
);
}
export function omitPrefixObject(
obj: Record<string, any>,
...prefixes: string[]
) {
return Object.fromEntries(
Object.entries(obj).filter(([key]) =>
prefixes.every((prefix) => !key.startsWith(prefix)),
),
);
}
export function maybePercentage(x: number | string, size: number) {
if (x === undefined) return null;
if (typeof x === 'number') return x;
const px = +x.replace('%', '');
return Number.isNaN(px) ? null : (px / 100) * size;
}
export function isStrictObject(d: any): boolean {
return (
typeof d === 'object' &&
!(d instanceof Date) &&
d !== null &&
!Array.isArray(d)
);
}
export function isUnset(value) {
return value === null || value === false;
}
export function deepAssign(
dist: Record<string, unknown>,
src: Record<string, unknown>,
maxLevel = 5,
level = 0,
): Record<string, unknown> {
if (level >= maxLevel) return;
for (const key of Object.keys(src)) {
const value = src[key];
if (!isPlainObject(value) || !isPlainObject(dist[key])) {
dist[key] = value;
} else {
deepAssign(
dist[key] as Record<string, unknown>,
value as Record<string, unknown>,
maxLevel,
level + 1,
);
}
}
return dist;
}