From 5e5933ca2f3d53ee83ef7383ad37998278ba1996 Mon Sep 17 00:00:00 2001 From: Ib Green <7025232+ibgreen@users.noreply.github.com> Date: Mon, 3 Nov 2025 11:47:59 -0500 Subject: [PATCH 1/5] feat(experimental): add pan and zoom widgets --- .../react-graph-layers/graph-gl.tsx | 61 ++--- examples/graph-layers/graph-viewer/app.tsx | 40 +-- modules/experimental/package.json | 3 +- modules/experimental/src/index.ts | 3 + .../src/widgets/long-press-button.tsx | 48 ++++ .../experimental/src/widgets/pan-widget.tsx | 173 +++++++++++++ .../src/widgets/zoom-range-widget.tsx | 235 ++++++++++++++++++ modules/experimental/tsconfig.json | 4 +- .../components/positioned-view-control.tsx | 27 -- modules/react/src/components/view-control.tsx | 172 ------------- modules/react/src/index.ts | 2 - .../test/components/view-control.spec.tsx | 76 ------ 12 files changed, 508 insertions(+), 336 deletions(-) create mode 100644 modules/experimental/src/widgets/long-press-button.tsx create mode 100644 modules/experimental/src/widgets/pan-widget.tsx create mode 100644 modules/experimental/src/widgets/zoom-range-widget.tsx delete mode 100644 modules/react/src/components/positioned-view-control.tsx delete mode 100644 modules/react/src/components/view-control.tsx delete mode 100644 modules/react/test/components/view-control.spec.tsx diff --git a/examples/graph-layers/graph-viewer-legacy/react-graph-layers/graph-gl.tsx b/examples/graph-layers/graph-viewer-legacy/react-graph-layers/graph-gl.tsx index 6ef939c9..9687f1e1 100644 --- a/examples/graph-layers/graph-viewer-legacy/react-graph-layers/graph-gl.tsx +++ b/examples/graph-layers/graph-viewer-legacy/react-graph-layers/graph-gl.tsx @@ -14,8 +14,8 @@ import { SimpleLayout } from '@deck.gl-community/graph-layers'; import type {GraphLayerStylesheet} from '@deck.gl-community/graph-layers'; -import {PositionedViewControl} from '@deck.gl-community/react'; -import {ViewControlWidget} from '@deck.gl-community/graph-layers'; +import {PanWidget, ZoomRangeWidget} from '@deck.gl-community/experimental'; +import '@deck.gl/widgets/stylesheet.css'; import '@deck.gl/widgets/stylesheet.css'; import {extent} from 'd3-array'; @@ -60,7 +60,6 @@ export const GraphGL = ({ // eslint-disable-next-line no-console onError = (error) => console.error(error), initialViewState = INITIAL_VIEW_STATE, - ViewControlComponent = PositionedViewControl, minZoom = -20, maxZoom = 20, viewportPadding = 50, @@ -93,6 +92,25 @@ export const GraphGL = ({ const [{isLoading}, loadingDispatch] = useLoading(engine) as any; + const widgets = useMemo( + () => [ + new PanWidget({ + id: 'legacy-pan-widget', + style: {margin: '20px 0 0 20px'} + }), + new ZoomRangeWidget({ + id: 'legacy-zoom-widget', + style: {margin: '90px 0 0 20px'} + }) + ], + [] + ); + + useEffect(() => { + const zoomWidget = widgets.find((widget) => widget instanceof ZoomRangeWidget); + zoomWidget?.setProps({minZoom, maxZoom}); + }, [widgets, minZoom, maxZoom]); + useLayoutEffect(() => { engine.run(); @@ -128,28 +146,6 @@ export const GraphGL = ({ }); }, [engine, viewState, setViewState, viewportPadding, minZoom, maxZoom]); - // Relatively pan the graph by a specified position vector. - const panBy = useCallback( - (dx, dy) => - setViewState({ - ...viewState, - target: [viewState.target[0] + dx, viewState.target[1] + dy] - }), - [viewState, setViewState] - ); - - // Relatively zoom the graph by a delta zoom level - const zoomBy = useCallback( - (deltaZoom) => { - const newZoom = viewState.zoom + deltaZoom; - setViewState({ - ...viewState, - zoom: Math.min(Math.max(newZoom, minZoom), maxZoom) - }); - }, - [maxZoom, minZoom, viewState, setViewState] - ); - useEffect(() => { if (zoomToFitOnLoad && isLoading) { engine.addEventListener('onLayoutDone', fitBounds, {once: true}); @@ -220,22 +216,10 @@ export const GraphGL = ({ ] ) as any } - widgets={[ - new ViewControlWidget({}) - ]} + widgets={widgets} getTooltip={getTooltip} onHover={onHover} /> - {/* View control component - - */} ); @@ -273,7 +257,6 @@ GraphGL.propTypes = { zoom: PropTypes.number }), /** A component to control view state. */ - ViewControlComponent: PropTypes.func, /** A minimum scale factor for zoom level of the graph. */ minZoom: PropTypes.number, /** A maximum scale factor for zoom level of the graph. */ diff --git a/examples/graph-layers/graph-viewer/app.tsx b/examples/graph-layers/graph-viewer/app.tsx index 6223ca09..894f1f8f 100644 --- a/examples/graph-layers/graph-viewer/app.tsx +++ b/examples/graph-layers/graph-viewer/app.tsx @@ -8,6 +8,8 @@ import {createRoot} from 'react-dom/client'; import DeckGL from '@deck.gl/react'; import {OrthographicView} from '@deck.gl/core'; +import {PanWidget, ZoomRangeWidget} from '@deck.gl-community/experimental'; +import '@deck.gl/widgets/stylesheet.css'; import { GraphEngine, GraphLayer, @@ -22,9 +24,6 @@ import { D3DagLayout } from '@deck.gl-community/graph-layers'; -// import {ViewControlWidget} from '@deck.gl-community/graph-layers'; -// import '@deck.gl/widgets/stylesheet.css'; - import {extent} from 'd3-array'; import {ControlPanel, ExampleDefinition, LayoutType} from './control-panel'; @@ -145,6 +144,20 @@ export function App(props) { const resumeLayoutAfterDragging = false; const zoomToFitOnLoad = false; + const widgets = useMemo( + () => [ + new PanWidget({ + id: 'pan-widget', + style: {margin: '20px 0 0 20px'} + }), + new ZoomRangeWidget({ + id: 'zoom-range-widget', + style: {margin: '90px 0 0 20px'} + }) + ], + [] + ); + const [viewState, setViewState] = useState({ ...INITIAL_VIEW_STATE, ...initialViewState @@ -219,6 +232,11 @@ export function App(props) { engine.removeEventListener('onLayoutDone', fitBounds); }; }, [engine, isLoading, fitBounds, zoomToFitOnLoad]); + + useEffect(() => { + const zoomWidget = widgets.find((widget) => widget instanceof ZoomRangeWidget); + zoomWidget?.setProps({minZoom, maxZoom}); + }, [widgets, minZoom, maxZoom]); const handleExampleChange = useCallback((example: ExampleDefinition, layoutType: LayoutType) => { setSelectedExample(example); setSelectedLayout(layoutType); @@ -291,23 +309,9 @@ export function App(props) { ] : [] } - widgets={[ - // // new ViewControlWidget({}) TODO - fix and enable - ] - // onHover={(info) => console.log('Hover', info)} - } + widgets={widgets} getTooltip={(info) => getToolTip(info.object)} /> - {/* View control component TODO - doesn't work in website, replace with widget * - - */}