flekschas / regl-scatterplot

Scalable WebGL-based scatter plot library build with Regl
https://flekschas.github.io/regl-scatterplot/
MIT License
184 stars 21 forks source link

feat: add ability to hover, select, and filter points upon `draw()` #142

Closed flekschas closed 1 year ago

flekschas commented 1 year ago

This PR adds the ability to hover, select, and filter points at the time when draw() is called.

Description

What was changed in this pull request?

I added three new properties to the draw options: hover, select, and filter. Those options allow to immediately hover, select, or filter points as they are drawn. E.g.:

const points = [[0, 0], [0.5, 0.5], [1, 1]];
scatterplit.draw(points, { hover: 0, select: [0, 2], filter: [0, 1] });

In the above example, upon drawing the three points, the first point is hovered and selected and the last point is filtered out. While we also attempted to select the last point it's not going to be selected because we filter it out.

For convenience, this PR also expose hoveredPoint via scatterplot.get('hoveredPoint').

Why is it necessary?

Previously, one had to filter after the draw call which leds to flickering as shown in the gif.

const points = generatePoints(numPoints);

const filter = points.x.map((x, i) => [x, i]).filter(([x]) => x < 0).map(([x, i]) => i);

const filterSet = new Set(Array.from({ length: filter.length }, (_, i) => i));
const select = [];
for (let i = 0; i < 20; i++) {
  const idx = Math.floor(Math.random() * filterSet.size);
  select.push(filter[idx]);
  filterSet.delete(idx);
}

const hover = select[Math.floor(Math.random() * select.length)];

scatterplot.draw(points).then(() => {
  // Since we first have to wait until the points are drawn before we can hover, select, and filter
  // there's a split second where all points are shown
  scatterplot.filter(filter);
  scatterplot.select(select);
  scatterplot.hover(hover);
});

filter-hover-select-after-draw

Now, one can directly hover, select, and filter at the time of drawing the points, which avoid the flickering.

const points = generatePoints(numPoints);

const filter = points.x.map((x, i) => [x, i]).filter(([x]) => x < 0).map(([x, i]) => i);

const filterSet = new Set(Array.from({ length: filter.length }, (_, i) => i));
const select = [];
for (let i = 0; i < 20; i++) {
  const idx = Math.floor(Math.random() * filterSet.size);
  select.push(filter[idx]);
  filterSet.delete(idx);
}

const hover = select[Math.floor(Math.random() * select.length)];

scatterplot.draw(points, { hover, select, filter });

draw-with-filter-hover-select

Checklist

flekschas commented 1 year ago

@insertmike Since we've talked about avoiding the flicker upon drawing new points and filtering them down, what do you think of this addition?

flekschas commented 1 year ago

think we should expose this in the README doc too. Otherwise we risk letting it die in the README. Except if this is built automatically by the build script (haven't looked at).

Good call! I updated the README to reflect the new draw() signature