-
Notifications
You must be signed in to change notification settings - Fork 606
/
translate.ts
114 lines (103 loc) · 3.44 KB
/
translate.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
import {NewSignal} from 'vega';
import {parseSelector} from 'vega-event-selector';
import {SelectionComponent} from '.';
import {ScaleChannel, X, Y} from '../../channel';
import {UnitModel} from '../unit';
import {BRUSH as INTERVAL_BRUSH} from './interval';
import {SelectionProjection} from './project';
import scalesCompiler, {domain} from './scales';
import {SelectionCompiler} from '.';
const ANCHOR = '_translate_anchor';
const DELTA = '_translate_delta';
const translate: SelectionCompiler<'interval'> = {
defined: selCmpt => {
return selCmpt.type === 'interval' && selCmpt.translate;
},
signals: (model, selCmpt, signals) => {
const name = selCmpt.name;
const boundScales = scalesCompiler.defined(selCmpt);
const anchor = name + ANCHOR;
const {x, y} = selCmpt.project.hasChannel;
let events = parseSelector(selCmpt.translate, 'scope');
if (!boundScales) {
events = events.map(e => ((e.between[0].markname = name + INTERVAL_BRUSH), e));
}
signals.push(
{
name: anchor,
value: {},
on: [
{
events: events.map(e => e.between[0]),
update:
'{x: x(unit), y: y(unit)' +
(x !== undefined ? `, extent_x: ${boundScales ? domain(model, X) : `slice(${x.signals.visual})`}` : '') +
(y !== undefined ? `, extent_y: ${boundScales ? domain(model, Y) : `slice(${y.signals.visual})`}` : '') +
'}'
}
]
},
{
name: name + DELTA,
value: {},
on: [
{
events,
update: `{x: ${anchor}.x - x(unit), y: ${anchor}.y - y(unit)}`
}
]
}
);
if (x !== undefined) {
onDelta(model, selCmpt, x, 'width', signals);
}
if (y !== undefined) {
onDelta(model, selCmpt, y, 'height', signals);
}
return signals;
}
};
export default translate;
function onDelta(
model: UnitModel,
selCmpt: SelectionComponent,
proj: SelectionProjection,
size: 'width' | 'height',
signals: NewSignal[]
) {
const name = selCmpt.name;
const anchor = name + ANCHOR;
const delta = name + DELTA;
const channel = proj.channel as ScaleChannel;
const boundScales = scalesCompiler.defined(selCmpt);
const signal = signals.find(s => s.name === proj.signals[boundScales ? 'data' : 'visual']);
const sizeSg = model.getSizeSignalRef(size).signal;
const scaleCmpt = model.getScaleComponent(channel);
const scaleType = scaleCmpt && scaleCmpt.get('type');
const reversed = scaleCmpt && scaleCmpt.get('reverse'); // scale parsing sets this flag for fieldDef.sort
const sign = !boundScales ? '' : channel === X ? (reversed ? '' : '-') : reversed ? '-' : '';
const extent = `${anchor}.extent_${channel}`;
const offset = `${sign}${delta}.${channel} / ${boundScales ? `${sizeSg}` : `span(${extent})`}`;
const panFn =
!boundScales || !scaleCmpt
? 'panLinear'
: scaleType === 'log'
? 'panLog'
: scaleType === 'symlog'
? 'panSymlog'
: scaleType === 'pow'
? 'panPow'
: 'panLinear';
const arg = !boundScales
? ''
: scaleType === 'pow'
? `, ${scaleCmpt.get('exponent') ?? 1}`
: scaleType === 'symlog'
? `, ${scaleCmpt.get('constant') ?? 1}`
: '';
const update = `${panFn}(${extent}, ${offset}${arg})`;
signal.on.push({
events: {signal: delta},
update: boundScales ? update : `clampRange(${update}, 0, ${sizeSg})`
});
}