Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dolly camera controls #247

Merged
merged 2 commits into from
May 30, 2024
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
75 changes: 70 additions & 5 deletions docs/Centering.mdx → docs/CameraControls.mdx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Meta, Story, ArgsTable } from '@storybook/blocks';
import { GraphCanvas } from '../src';

<Meta title="Docs/Advanced/Centering" />
<Meta title="Docs/Advanced/Camera Controls" />

# Camera Controls
Reagraph provides a set of camera controls that allow you to interact with the graph view. These controls include the ability to center the camera view around specific nodes, zoom in and out, and pan the camera view.

# Centering
Reagraph supports the ability to dynamically center nodes using the `centerGraph` and `fitNodesInView` methods from the `GraphCanvasRef`. These methods allows you to programmatically center the camera view around specific nodes or the entire graph.

### Usage
## Usage
First, you need to get a reference to the `GraphRef`:

```jsx
Expand All @@ -16,8 +17,12 @@ return (
<GraphCanvas ref={graphRef} {...} />
)
```
This ref will allow you to access the camera controls methods.

Then, you can use the `fitNodesInView` method to center all nodes within view of the camera:
## Centering
Reagraph supports the ability to dynamically center nodes using the `centerGraph` and `fitNodesInView` methods from the `GraphCanvasRef`. These methods allows you to programmatically center the camera view around specific nodes or the entire graph.

Use the `fitNodesInView` method to center all nodes within view of the camera:

```js
graphRef.current?.fitNodesInView();
Expand Down Expand Up @@ -77,3 +82,63 @@ const MyComponent = ({ nodes }) => {
return <GraphCanvas ref={graphRef} {...} />;
};
```

## Zooming/Dollying

Use the `zoomIn` and `zoomOut` methods to zoom in and out of the graph. This will adjust the camera's zoom level, not the camera's position:

```js
graphRef.current?.zoomIn();
graphRef.current?.zoomOut();
```

You can use the `dollyIn` and `dollyOut` methods to move the camera closer or further away from the graph:

```js
graphRef.current?.dollyIn();
graphRef.current?.dollyOut();
```

### Examples
In this example, clicking the "Zoom In" and "Zoom Out" buttons will zoom in and out of the graph:
```jsx
import React, { useRef } from 'react';
import { GraphCanvas } from 'reagraph';

const MyComponent = () => {
const graphRef = useRef<GraphCanvasRef | null>(null);

const zoomIn = () => {
graphRef.current?.zoomIn();
};

const zoomOut = () => {
graphRef.current?.zoomOut();
};

return (
<div>
<GraphCanvas ref={graphRef} {...} />
<button onClick={zoomIn}>Zoom In</button>
<button onClick={zoomOut}>Zoom Out</button>
</div>
);
};
```

## Panning
Use the `panUp`, `panDown`, `panLeft`, and `panRight` methods to pan the camera view:

```js
graphRef.current?.panUp();
graphRef.current?.panDown();
graphRef.current?.panLeft();
graphRef.current?.panRight();
```

## Reset Controls
Use the `resetCamera` method to reset the camera controls to their default values:

```js
graphRef.current?.resetCamera();
```
2 changes: 2 additions & 0 deletions docs/demos/Controls.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export const All = () => {
<br />
<button style={{ display: 'block', width: '100%' }} onClick={() => ref.current?.zoomIn()}>Zoom In</button>
<button style={{ display: 'block', width: '100%' }} onClick={() => ref.current?.zoomOut()}>Zoom Out</button>
<button style={{ display: 'block', width: '100%' }} onClick={() => ref.current?.dollyIn()}>Dolly In</button>
<button style={{ display: 'block', width: '100%' }} onClick={() => ref.current?.dollyOut()}>Dolly Out</button>
<br />
<button style={{ display: 'block', width: '100%' }} onClick={() => ref.current?.panDown()}>Pan Down</button>
<button style={{ display: 'block', width: '100%' }} onClick={() => ref.current?.panUp()}>Pan Up</button>
Expand Down
16 changes: 16 additions & 0 deletions src/CameraControls/CameraControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,20 @@ export const CameraControls: FC<
cameraRef.current?.zoom(-camera.zoom / 2, animated);
}, [animated, camera.zoom]);

const dollyIn = useCallback(
distance => {
cameraRef.current?.dolly(distance, animated);
},
[animated]
);

const dollyOut = useCallback(
distance => {
cameraRef.current?.dolly(distance, animated);
},
[animated]
);

const panRight = useCallback(
event => {
if (!isOrbiting) {
Expand Down Expand Up @@ -296,6 +310,8 @@ export const CameraControls: FC<
controls: cameraRef.current,
zoomIn: () => zoomIn(),
zoomOut: () => zoomOut(),
dollyIn: (distance = 1000) => dollyIn(distance),
dollyOut: (distance = -1000) => dollyOut(distance),
panLeft: (deltaTime = 100) => panLeft({ deltaTime }),
panRight: (deltaTime = 100) => panRight({ deltaTime }),
panDown: (deltaTime = 100) => panDown({ deltaTime }),
Expand Down
12 changes: 12 additions & 0 deletions src/CameraControls/useCameraControls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ export interface CameraControlsContextProps {
*/
zoomOut: () => void;

/**
* A function that dollies in the camera.
*/
dollyIn: (distance?: number) => void;

/**
* A function that dollies out the camera.
*/
dollyOut: (distance?: number) => void;

/**
* A function that pans the camera to the left.
*/
Expand All @@ -49,6 +59,8 @@ export const CameraControlsContext = createContext<CameraControlsContextProps>({
resetControls: () => undefined,
zoomIn: () => undefined,
zoomOut: () => undefined,
dollyIn: () => undefined,
dollyOut: () => undefined,
panLeft: () => undefined,
panRight: () => undefined,
panUp: () => undefined,
Expand Down
2 changes: 2 additions & 0 deletions src/GraphCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ export const GraphCanvas: FC<GraphCanvasProps & { ref?: Ref<GraphCanvasRef> }> =
rendererRef.current?.fitNodesInView(nodeIds, opts),
zoomIn: () => controlsRef.current?.zoomIn(),
zoomOut: () => controlsRef.current?.zoomOut(),
dollyIn: distance => controlsRef.current?.dollyIn(distance),
dollyOut: distance => controlsRef.current?.dollyOut(distance),
panLeft: () => controlsRef.current?.panLeft(),
panRight: () => controlsRef.current?.panRight(),
panDown: () => controlsRef.current?.panDown(),
Expand Down
Loading