-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjitter.ts
64 lines (59 loc) · 1.79 KB
/
jitter.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
import { Band } from '@antv/scale';
import { deepMix } from '@antv/util';
import { Primitive, TransformComponent as TC } from '../runtime';
import { JitterTransform } from '../spec';
import { column, columnOf } from './utils/helper';
import { domainOf } from './utils/order';
export type JitterOptions = Omit<JitterTransform, 'type'>;
export function rangeOf(
value: Primitive[],
scaleOptions: Record<string, any>,
padding: number,
): [number, number] {
if (value === null) return [-0.5, 0.5];
const domain = domainOf(value, scaleOptions);
const scale = new Band({ domain, range: [0, 1], padding });
const step = scale.getBandWidth();
return [-step / 2, step / 2];
}
export function interpolate(t: number, a: number, b: number): number {
return a * (1 - t) + b * t;
}
/**
* The jitter transform produce dx and dy channels for marks (especially for point)
* with ordinal x and y dimension, say to make them jitter in their own space.
*/
export const Jitter: TC<JitterOptions> = (options = {}) => {
const {
padding = 0,
paddingX = padding,
paddingY = padding,
random = Math.random,
} = options;
return (I, mark) => {
const { encode, scale } = mark;
const { x: scaleX, y: scaleY } = scale;
const [X] = columnOf(encode, 'x');
const [Y] = columnOf(encode, 'y');
const rangeX = rangeOf(X, scaleX, paddingX);
const rangeY = rangeOf(Y, scaleY, paddingY);
const DY = I.map(() => interpolate(random(), ...rangeY));
const DX = I.map(() => interpolate(random(), ...rangeX));
return [
I,
deepMix(
{
scale: {
x: { padding: 0.5 },
y: { padding: 0.5 },
},
},
mark,
{
encode: { dy: column(DY), dx: column(DX) },
},
),
];
};
};
Jitter.props = {};