Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.11.2

- Fix: handle camera fixing better by adding a dedicated prop called `cameraIsFixed`. Previously, the lasso end interaction would unset the camera fixing. ([#94](https://github.com/flekschas/regl-scatterplot/issues/94))

## 1.11.1

- Fix: ensure that the drawing order of points cannot be manipulated via `scatterplot.filter()` ([#197](https://github.com/flekschas/regl-scatterplot/issues/197))
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,8 @@ can be read and written via [`scatterplot.get()`](#scatterplot.get) and [`scatte
| cameraTarget | tuple | `[0, 0]` | | `true` | `false` |
| cameraDistance | float | `1` | > 0 | `true` | `false` |
| cameraRotation | float | `0` | | `true` | `false` |
| cameraView | Float32Array | `[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1`] | | `true` | `false` |
| cameraView | Float32Array | `[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]` | | `true` | `false` |
| cameraIsFixed | boolean | `false` | | `true` | `false` |
| colorBy | string | `null` | See [data encoding](#property-by) | `true` | `true` |
| sizeBy | string | `null` | See [data encoding](#property-by) | `true` | `true` |
| opacityBy | string | `null` | See [data encoding](#property-by) | `true` | `true` |
Expand Down
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ export const Z_NAMES = new Set(['z', 'valueZ', 'valueA', 'value1', 'category']);
export const W_NAMES = new Set(['w', 'valueW', 'valueB', 'value2', 'value']);
export const DEFAULT_IMAGE_LOAD_TIMEOUT = 15000;
export const DEFAULT_SPATIAL_INDEX_USE_WORKER = undefined;
export const DEFAULT_CAMERA_IS_FIXED = false;

// Error messages
export const ERROR_POINTS_NOT_DRAWN = 'Points have not been drawn';
22 changes: 19 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
DEFAULT_ANNOTATION_LINE_COLOR,
DEFAULT_ANNOTATION_LINE_WIDTH,
DEFAULT_BACKGROUND_IMAGE,
DEFAULT_CAMERA_IS_FIXED,
DEFAULT_COLOR_ACTIVE,
DEFAULT_COLOR_BG,
DEFAULT_COLOR_BY,
Expand Down Expand Up @@ -287,6 +288,7 @@ const createScatterplot = (
annotationLineColor = DEFAULT_ANNOTATION_LINE_COLOR,
annotationLineWidth = DEFAULT_ANNOTATION_LINE_WIDTH,
annotationHVLineLimit = DEFAULT_ANNOTATION_HVLINE_LIMIT,
cameraIsFixed = DEFAULT_CAMERA_IS_FIXED,
} = initialProperties;

let currentWidth = width === AUTO ? 1 : width;
Expand Down Expand Up @@ -888,7 +890,7 @@ const createScatterplot = (
};

const lassoEnd = (lassoPoints, lassoPointsFlat, { merge = false } = {}) => {
camera.config({ isFixed: false });
camera.config({ isFixed: cameraIsFixed });
lassoPointsCurr = [...lassoPoints];
const pointsInLasso = findPointsInLasso(lassoPointsFlat);
select(pointsInLasso, { merge });
Expand Down Expand Up @@ -2722,7 +2724,7 @@ const createScatterplot = (
'transitionEnd',
() => {
resolve();
camera.config({ isFixed: false });
camera.config({ isFixed: cameraIsFixed });
},
1,
);
Expand Down Expand Up @@ -2921,6 +2923,11 @@ const createScatterplot = (
}
};

const setCameraIsFixed = (isFixed) => {
cameraIsFixed = Boolean(isFixed);
camera.config({ isFixed: cameraIsFixed });
};

const setLassoColor = (newLassoColor) => {
if (!newLassoColor) {
return;
Expand Down Expand Up @@ -3296,6 +3303,10 @@ const createScatterplot = (
return camera.view;
}

if (property === 'cameraIsFixed') {
return cameraIsFixed;
}

if (property === 'canvas') {
return canvas;
}
Expand Down Expand Up @@ -3616,6 +3627,10 @@ const createScatterplot = (
setCameraView(properties.cameraView);
}

if (properties.cameraIsFixed !== undefined) {
setCameraIsFixed(properties.cameraIsFixed);
}

if (properties.colorBy !== undefined) {
setColorBy(properties.colorBy);
}
Expand Down Expand Up @@ -3873,6 +3888,7 @@ const createScatterplot = (
const initCamera = () => {
if (!camera) {
camera = createDom2dCamera(canvas, {
isFixed: cameraIsFixed,
isPanInverted: [false, true],
defaultMouseDownMoveAction:
mouseMode === MOUSE_MODE_ROTATE ? 'rotate' : 'pan',
Expand Down Expand Up @@ -4083,7 +4099,7 @@ const createScatterplot = (
};

const cancelFrameListener = renderer.onFrame(() => {
// Update camera: this needs to happen on every
// Update camera: this needs to happen on every frame
isViewChanged = camera.tick();

if (!((isPointsDrawn || isAnnotationsDrawn) && (draw || isTransitioning))) {
Expand Down
1 change: 1 addition & 0 deletions src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ interface BaseOptions {
xScale: null | Scale;
yScale: null | Scale;
pointScaleMode: PointScaleMode;
cameraIsFixed: boolean;
}

// biome-ignore lint/style/useNamingConvention: KDBush is a library name
Expand Down
2 changes: 2 additions & 0 deletions tests/constructor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import createScatterplot, {
} from '../src';

import {
DEFAULT_CAMERA_IS_FIXED,
DEFAULT_COLOR_NORMAL,
DEFAULT_COLOR_ACTIVE,
DEFAULT_COLOR_HOVER,
Expand Down Expand Up @@ -73,6 +74,7 @@ test('createScatterplot()', () => {
expect(scatterplot.get('opacityInactiveScale')).toBe(DEFAULT_OPACITY_INACTIVE_SCALE);
expect(scatterplot.get('width')).toBe(DEFAULT_WIDTH);
expect(scatterplot.get('height')).toBe(DEFAULT_HEIGHT);
expect(scatterplot.get('cameraIsFixed')).toBe(DEFAULT_CAMERA_IS_FIXED);

scatterplot.destroy();
});
Expand Down
63 changes: 62 additions & 1 deletion tests/get-set.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import '@babel/polyfill';
import { nextAnimationFrame } from '@flekschas/utils';
import { assert, expect, test } from 'vitest';

import { version } from '../package.json';
Expand Down Expand Up @@ -451,7 +452,7 @@ test(
);

expect(scatterplot.get('pointConnectionOpacityActive')).toBe(
scatterplot.get('pointConnectionOpacityActive'),
DEFAULT_POINT_CONNECTION_OPACITY_ACTIVE,
);

scatterplot.set({
Expand Down Expand Up @@ -630,3 +631,63 @@ test(
scatterplot.destroy();
}
);

test('set({ cameraIsFixed })', async () => {
const canvas = createCanvas();
const scatterplot = createScatterplot({ canvas });

await scatterplot.draw([
[-1, 1],
[1, 1],
[0, 0],
[-1, -1],
[1, -1],
]);

canvas.dispatchEvent(new WheelEvent('wheel', { deltaY: -100 }));

await nextAnimationFrame();

console.log('1. camera distance', scatterplot.get('camera').distance[0]);

// We expect the distance to be less than one because we zoomed into the plot
// via wheeling
expect(scatterplot.get('camera').distance[0]).toBeLessThan(1);

await scatterplot.zoomToOrigin();

expect(scatterplot.get('camera').distance[0]).toBe(1);

scatterplot.set({ cameraIsFixed: true });
expect(scatterplot.get('cameraIsFixed')).toBe(true);

canvas.dispatchEvent(new WheelEvent('wheel', { deltaY: -100 }));

await nextAnimationFrame();

// We expect the distance to be one because we fixed the camera
expect(scatterplot.get('camera').distance[0]).toBe(1);

scatterplot.set({ cameraIsFixed: false });
expect(scatterplot.get('cameraIsFixed')).toBe(false);

canvas.dispatchEvent(new WheelEvent('wheel', { deltaY: -100 }));

await nextAnimationFrame();

// We expect the distance to be less than one because we unfixed the camera
expect(scatterplot.get('camera').distance[0]).toBeLessThan(1);

await scatterplot.zoomToOrigin();
expect(scatterplot.get('camera').distance[0]).toBe(1);

scatterplot.set({ cameraIsFixed: true });
await scatterplot.zoomToPoints([2]);

// Even though the camera is fixed, programmatic zooming still works. Only
// mouse wheel interactions are prevented
expect(scatterplot.get('cameraIsFixed')).toBe(true);
expect(scatterplot.get('camera').distance[0]).toBeLessThan(1);

scatterplot.destroy();
});
Loading