vega-lite
Version:
Vega-Lite is a concise high-level language for interactive visualization.
76 lines (66 loc) • 2.01 kB
text/typescript
import * as log from '../../log/index.js';
import {isPathMark} from '../../mark.js';
import {tooltip} from '../mark/encode/index.js';
import {SelectionCompiler} from './index.js';
const VORONOI = 'voronoi';
const nearest: SelectionCompiler<'point'> = {
defined: (selCmpt) => {
return selCmpt.type === 'point' && selCmpt.nearest;
},
parse: (model, selCmpt) => {
// Scope selection events to the voronoi mark to prevent capturing
// events that occur on the group mark (https://github.com/vega/vega/issues/2112).
if (selCmpt.events) {
for (const s of selCmpt.events) {
s.markname = model.getName(VORONOI);
}
}
},
marks: (model, selCmpt, marks) => {
const {x, y} = selCmpt.project.hasChannel;
const markType = model.mark;
if (isPathMark(markType)) {
log.warn(log.message.nearestNotSupportForContinuous(markType));
return marks;
}
const cellDef = {
name: model.getName(VORONOI),
type: 'path',
interactive: true,
aria: false,
from: {data: model.getName('marks')},
encode: {
update: {
fill: {value: 'transparent'},
strokeWidth: {value: 0.35},
stroke: {value: 'transparent'},
isVoronoi: {value: true},
...tooltip(model, {reactiveGeom: true}),
},
},
transform: [
{
type: 'voronoi',
x: {expr: x || !y ? 'datum.datum.x || 0' : '0'},
y: {expr: y || !x ? 'datum.datum.y || 0' : '0'},
size: [model.getSizeSignalRef('width'), model.getSizeSignalRef('height')],
},
],
};
let index = 0;
let exists = false;
marks.forEach((mark, i) => {
const name = mark.name ?? '';
if (name === model.component.mark[0].name) {
index = i;
} else if (name.includes(VORONOI)) {
exists = true;
}
});
if (!exists) {
marks.splice(index + 1, 0, cellDef);
}
return marks;
},
};
export default nearest;