-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsymmetryY.ts
60 lines (53 loc) · 1.79 KB
/
symmetryY.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
import { deepMix } from '@antv/util';
import { extent } from 'd3-array';
import { TransformComponent as TC } from '../runtime';
import { SymmetryYTransform } from '../spec';
import { columnOf, column } from './utils/helper';
import { createGroups } from './utils/order';
export type SymmetryYOptions = Omit<SymmetryYTransform, 'type'>;
/**
* The SymmetryY transform apply offset for y channels, say to transform
* them to be symmetry.
*/
export const SymmetryY: TC<SymmetryYOptions> = (options = {}) => {
const { groupBy = 'x' } = options;
return (I, mark) => {
const { encode } = mark;
const { x, ...rest } = encode;
// Extract and create new channels starts with y, such as y, y1.
const Yn = Object.entries(rest)
.filter(([k]) => k.startsWith('y'))
.map(([k]) => [k, columnOf(encode, k)[0]] as const);
const newYn = Yn.map(([k]) => [k, new Array(I.length)] as const);
// Group marks into series by specified keys.
const groups = createGroups(groupBy, I, mark);
const MY = new Array(groups.length);
for (let i = 0; i < groups.length; i++) {
const I = groups[i];
const Y = I.flatMap((i) => Yn.map(([, V]) => +V[i]));
const [minY, maxY] = extent(Y);
MY[i] = (minY + maxY) / 2;
}
const maxMiddleY = Math.max(...MY);
for (let m = 0; m < groups.length; m++) {
const offset = maxMiddleY - MY[m];
const I = groups[m];
for (const i of I) {
for (let j = 0; j < Yn.length; j++) {
const [, V] = Yn[j];
const [, newV] = newYn[j];
newV[i] = +V[i] + offset;
}
}
}
return [
I,
deepMix({}, mark, {
encode: Object.fromEntries(
newYn.map(([k, v]) => [k, column(v, columnOf(encode, k)[1])]),
),
}),
];
};
};
SymmetryY.props = {};