Skip to content
Open
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
1 change: 1 addition & 0 deletions docs/modules/widgets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export function App() {
```

The [Pan and Zoom widgets example](/examples/widgets/pan-and-zoom-controls) shows the controls managing an orthographic view over abstract data.
The [React widgets example](/examples/widgets/react-widgets) demonstrates adding the same controls as JSX children via the React wrappers in `@deck.gl-community/react`.

### HTML overlays

Expand Down
94 changes: 94 additions & 0 deletions examples/widgets/react-widgets/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import {useCallback, useMemo, useState} from 'react';
import DeckGL from '@deck.gl/react';
import {OrthographicView} from '@deck.gl/core';
import {ScatterplotLayer} from '@deck.gl/layers';
import {PanWidget, ZoomRangeWidget} from '@deck.gl-community/react';

import '@deck.gl/widgets/stylesheet.css';

const INITIAL_VIEW_STATE = {
target: [0, 0],
zoom: 0
};

const view = new OrthographicView({id: 'ortho'});

export function App() {
const [viewState, setViewState] = useState(INITIAL_VIEW_STATE);

const data = useMemo(() => {
const points: {position: [number, number]; color: [number, number, number, number]}[] = [];
const size = 10;

for (let x = -size; x <= size; x++) {
for (let y = -size; y <= size; y++) {
const distance = Math.sqrt(x * x + y * y);
const intensity = Math.max(0, 1 - distance / size);
points.push({
position: [x * 20, y * 20],
color: [255 * intensity, 128 + 80 * intensity, 200, 200]
});
}
}

return points;
}, []);

const layers = useMemo(
() => [
new ScatterplotLayer({
id: 'points',
data,
getPosition: (d) => d.position,
getFillColor: (d) => d.color,
radiusMinPixels: 4,
radiusMaxPixels: 12,
radiusUnits: 'pixels',
pickable: false
})
],
[data]
);

const handleViewStateChange = useCallback(({viewState: nextViewState}) => {
setViewState(nextViewState);
}, []);

return (
<DeckGL
views={view}
viewState={viewState}
controller={{dragMode: 'pan'}}
onViewStateChange={handleViewStateChange}
layers={layers}
>
<PanWidget style={{margin: '16px 0 0 16px'}} />
<ZoomRangeWidget style={{margin: '96px 0 0 16px'}} minZoom={-3} maxZoom={6} step={0.1} />

<div
style={{
position: 'absolute',
right: 16,
top: 16,
maxWidth: 320,
padding: '12px 16px',
background: 'rgba(255, 255, 255, 0.9)',
borderRadius: '8px',
fontFamily: 'var(--ifm-font-family-base, sans-serif)',
lineHeight: 1.5
}}
>
<h3 style={{margin: '0 0 8px'}}>React wrapper widgets</h3>
<p style={{margin: 0}}>
This example renders the Pan and Zoom range widgets as JSX children using the React wrappers from{' '}
<code style={{marginLeft: 4}}>@deck.gl-community/react</code>. Each widget registers itself through the shared{' '}
<code style={{marginLeft: 4}}>&lt;DeckGL&gt;</code> context, so there is no need to pass a <code>widgets</code> array prop.
</p>
</div>
</DeckGL>
);
}
12 changes: 12 additions & 0 deletions examples/widgets/react-widgets/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React Widgets | deck.gl-community</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./index.tsx"></script>
</body>
</html>
20 changes: 20 additions & 0 deletions examples/widgets/react-widgets/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import React from 'react';
import {createRoot} from 'react-dom/client';

import {App} from './app';

const container = document.getElementById('app');
if (!container) {
throw new Error('Unable to find #app container');
}

const root = createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
23 changes: 23 additions & 0 deletions examples/widgets/react-widgets/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "widgets-react-wrappers-example",
"version": "9.2.0",
"private": true,
"license": "MIT",
"type": "module",
"scripts": {
"start": "vite --open",
"start-local": "vite --config ../../vite.config.local.mjs"
},
"dependencies": {
"@deck.gl-community/react": "workspace:*",
"@deck.gl/core": "~9.2.1",
"@deck.gl/layers": "~9.2.1",
"@deck.gl/react": "~9.2.1",
"@deck.gl/widgets": "~9.2.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"vite": "7.1.1"
}
}
11 changes: 11 additions & 0 deletions examples/widgets/react-widgets/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"baseUrl": "./",
"paths": {
"*": ["./node_modules/*", "./*"]
}
},
"include": ["./**/*.ts", "./**/*.tsx"],
"exclude": ["dist", "node_modules"]
}
2 changes: 2 additions & 0 deletions modules/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
"src"
],
"dependencies": {
"@deck.gl-community/widgets": "^9.2.0-beta.3",
"@deck.gl/react": "~9.2.1",
"@types/styled-react-modal": "^1.2.5",
"boxicons": "^2.1.4",
"prop-types": "^15.8.1",
Expand Down
6 changes: 6 additions & 0 deletions modules/react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ export {EditorModal as Modal} from './components/modal';
export {Button} from './components/modal';
export {Icon} from './components/icon';

// Widgets (from @deck.gl-community/widgets)
export {PanWidget} from './widgets/pan-widget';
export {ZoomRangeWidget} from './widgets/zoom-range-widget';
export {HtmlOverlayWidget} from './widgets/html-overlay-widget';
export {HtmlTooltipWidget} from './widgets/html-tooltip-widget';

// Overlays migrated to @deck.gl-community/widgets
15 changes: 15 additions & 0 deletions modules/react/src/widgets/html-overlay-widget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

/* eslint-disable import/no-unresolved */
import {HtmlOverlayWidget as _HtmlOverlayWidget} from '@deck.gl-community/widgets';
import type {HtmlOverlayWidgetProps} from '@deck.gl-community/widgets';
/* eslint-enable import/no-unresolved */
import {useWidget} from '@deck.gl/react';

/** React wrapper for the HtmlOverlayWidget. */
export const HtmlOverlayWidget = (props: HtmlOverlayWidgetProps = {}) => {
useWidget(_HtmlOverlayWidget, props);
return null;
};
15 changes: 15 additions & 0 deletions modules/react/src/widgets/html-tooltip-widget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

/* eslint-disable import/no-unresolved */
import {HtmlTooltipWidget as _HtmlTooltipWidget} from '@deck.gl-community/widgets';
import type {HtmlTooltipWidgetProps} from '@deck.gl-community/widgets';
/* eslint-enable import/no-unresolved */
import {useWidget} from '@deck.gl/react';

/** React wrapper for the HtmlTooltipWidget. */
export const HtmlTooltipWidget = (props: HtmlTooltipWidgetProps = {}) => {
useWidget(_HtmlTooltipWidget, props);
return null;
};
15 changes: 15 additions & 0 deletions modules/react/src/widgets/pan-widget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

/* eslint-disable import/no-unresolved */
import {PanWidget as _PanWidget} from '@deck.gl-community/widgets';
import type {PanWidgetProps} from '@deck.gl-community/widgets';
/* eslint-enable import/no-unresolved */
import {useWidget} from '@deck.gl/react';

/** React wrapper for the PanWidget. */
export const PanWidget = (props: PanWidgetProps = {}) => {
useWidget(_PanWidget, props);
return null;
};
15 changes: 15 additions & 0 deletions modules/react/src/widgets/zoom-range-widget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// deck.gl-community
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

/* eslint-disable import/no-unresolved */
import {ZoomRangeWidget as _ZoomRangeWidget} from '@deck.gl-community/widgets';
import type {ZoomRangeWidgetProps} from '@deck.gl-community/widgets';
/* eslint-enable import/no-unresolved */
import {useWidget} from '@deck.gl/react';

/** React wrapper for the ZoomRangeWidget. */
export const ZoomRangeWidget = (props: ZoomRangeWidgetProps = {}) => {
useWidget(_ZoomRangeWidget, props);
return null;
};
17 changes: 14 additions & 3 deletions modules/react/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
{
"extends": "../../tsconfig.json",
"include": ["src/**/*"],
"exclude": ["node_modules"],
"exclude": ["node_modules", "../../node_modules/@deck.gl/core/src/**/*"],
"compilerOptions": {
"composite": true,
"rootDir": "src",
"outDir": "dist",
"noEmit": false
}
"noEmit": false,
"baseUrl": ".",
"allowJs": false,
"checkJs": false,
"moduleResolution": "bundler",
"paths": {
"@deck.gl-community/widgets": ["../widgets/dist/index.d.ts"],
"@deck.gl-community/widgets/*": ["../widgets/dist/*"],
"@deck.gl/core": ["../../node_modules/@deck.gl/core/dist/index.d.ts"],
"@deck.gl/core/*": ["../../node_modules/@deck.gl/core/dist/*"]
}
},
"references": [{"path": "../widgets"}]
}
3 changes: 2 additions & 1 deletion website/src/examples-sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ const sidebars = {
label: '@deck.gl-community/widgets',
items: [
"widgets/html-overlays",
"widgets/pan-and-zoom-controls"
"widgets/pan-and-zoom-controls",
"widgets/react-widgets"
]
},
// {
Expand Down
5 changes: 5 additions & 0 deletions website/src/examples/widgets/react-widgets.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# React Widgets

import Demo from './react-widgets';

<Demo />
25 changes: 25 additions & 0 deletions website/src/examples/widgets/react-widgets.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, {Component} from 'react';
import BrowserOnly from '@docusaurus/BrowserOnly';

import {GITHUB_TREE} from '../../constants/defaults';
import {App} from '../../../../examples/widgets/react-widgets/app';

import {makeExample} from '../../components';

class ReactWidgetsDemo extends Component {
static title = 'React Widgets';

static code = `${GITHUB_TREE}/examples/widgets/react-widgets`;

static renderInfo(meta) {
return <></>;
}

render() {
const {...otherProps} = this.props;

return <BrowserOnly>{() => <App {...otherProps} />}</BrowserOnly>;
}
}

export default makeExample(ReactWidgetsDemo, {addInfoPanel: false});
19 changes: 18 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,8 @@ __metadata:
version: 0.0.0-use.local
resolution: "@deck.gl-community/react@workspace:modules/react"
dependencies:
"@deck.gl-community/widgets": "npm:^9.2.0-beta.3"
"@deck.gl/react": "npm:~9.2.1"
"@types/styled-react-modal": "npm:^1.2.5"
boxicons: "npm:^2.1.4"
prop-types: "npm:^15.8.1"
Expand All @@ -1444,7 +1446,7 @@ __metadata:
languageName: unknown
linkType: soft

"@deck.gl-community/widgets@workspace:*, @deck.gl-community/widgets@workspace:modules/widgets":
"@deck.gl-community/widgets@npm:^9.2.0-beta.3, @deck.gl-community/widgets@workspace:*, @deck.gl-community/widgets@workspace:modules/widgets":
version: 0.0.0-use.local
resolution: "@deck.gl-community/widgets@workspace:modules/widgets"
dependencies:
Expand Down Expand Up @@ -20657,6 +20659,21 @@ __metadata:
languageName: unknown
linkType: soft

"widgets-react-wrappers-example@workspace:examples/widgets/react-widgets":
version: 0.0.0-use.local
resolution: "widgets-react-wrappers-example@workspace:examples/widgets/react-widgets"
dependencies:
"@deck.gl-community/react": "workspace:*"
"@deck.gl/core": "npm:~9.2.1"
"@deck.gl/layers": "npm:~9.2.1"
"@deck.gl/react": "npm:~9.2.1"
"@deck.gl/widgets": "npm:~9.2.1"
react: "npm:^18.3.1"
react-dom: "npm:^18.3.1"
vite: "npm:7.1.1"
languageName: unknown
linkType: soft

"word-wrap@npm:^1.2.5":
version: 1.2.5
resolution: "word-wrap@npm:1.2.5"
Expand Down