From a046575e57d8dc9fbf302fdd4eeca8407313ea3d Mon Sep 17 00:00:00 2001 From: Xiaoji Chen Date: Mon, 18 May 2026 19:12:53 -0700 Subject: [PATCH] consolidate widget test apps --- test/apps/widgets-9.2/index.html | 15 -- test/apps/widgets-infovis/README.md | 17 -- test/apps/widgets-infovis/package.json | 19 -- test/apps/widgets-multi-view-9.2/README.md | 17 -- test/apps/widgets-multi-view-9.2/package.json | 20 -- .../apps/widgets-multi-view-9.2/react-app.tsx | 43 ---- test/apps/{widgets-9.2 => widgets}/README.md | 0 test/apps/widgets/geospatial.html | 28 +++ .../app.ts => widgets/geospatial.ts} | 12 +- test/apps/widgets/index.html | 21 ++ .../index.html => widgets/infovis.html} | 2 +- .../app.ts => widgets/infovis.ts} | 40 ++-- .../react.html => widgets/multiview.html} | 2 +- .../app.ts => widgets/multiview.ts} | 26 +- .../{widgets-9.2 => widgets}/package.json | 6 +- test/apps/widgets/react-geospatial.html | 12 + test/apps/widgets/react-geospatial.tsx | 225 ++++++++++++++++++ test/apps/widgets/react-infovis.html | 14 ++ test/apps/widgets/react-infovis.tsx | 123 ++++++++++ .../react-multiview.html} | 5 +- test/apps/widgets/react-multiview.tsx | 92 +++++++ 21 files changed, 558 insertions(+), 181 deletions(-) delete mode 100644 test/apps/widgets-9.2/index.html delete mode 100644 test/apps/widgets-infovis/README.md delete mode 100644 test/apps/widgets-infovis/package.json delete mode 100644 test/apps/widgets-multi-view-9.2/README.md delete mode 100644 test/apps/widgets-multi-view-9.2/package.json delete mode 100644 test/apps/widgets-multi-view-9.2/react-app.tsx rename test/apps/{widgets-9.2 => widgets}/README.md (100%) create mode 100644 test/apps/widgets/geospatial.html rename test/apps/{widgets-9.2/app.ts => widgets/geospatial.ts} (96%) create mode 100644 test/apps/widgets/index.html rename test/apps/{widgets-infovis/index.html => widgets/infovis.html} (87%) rename test/apps/{widgets-infovis/app.ts => widgets/infovis.ts} (77%) rename test/apps/{widgets-multi-view-9.2/react.html => widgets/multiview.html} (80%) rename test/apps/{widgets-multi-view-9.2/app.ts => widgets/multiview.ts} (77%) rename test/apps/{widgets-9.2 => widgets}/package.json (73%) create mode 100644 test/apps/widgets/react-geospatial.html create mode 100644 test/apps/widgets/react-geospatial.tsx create mode 100644 test/apps/widgets/react-infovis.html create mode 100644 test/apps/widgets/react-infovis.tsx rename test/apps/{widgets-multi-view-9.2/index.html => widgets/react-multiview.html} (74%) create mode 100644 test/apps/widgets/react-multiview.tsx diff --git a/test/apps/widgets-9.2/index.html b/test/apps/widgets-9.2/index.html deleted file mode 100644 index 2707109f812..00000000000 --- a/test/apps/widgets-9.2/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - deck.gl Example - - - -
- - - diff --git a/test/apps/widgets-infovis/README.md b/test/apps/widgets-infovis/README.md deleted file mode 100644 index 10f985a2938..00000000000 --- a/test/apps/widgets-infovis/README.md +++ /dev/null @@ -1,17 +0,0 @@ -## Example: deck.gl widgets with non-geospatial data - -Uses [Vite](https://vitejs.dev/) to bundle and serve files. - -## Usage - -To install dependencies: - -```bash -npm install -# or -yarn -``` - -Commands: -* `npm start` is the development target, to serve the app and hot reload. -* `npm run build` is the production target, to create the final bundle and write to disk. diff --git a/test/apps/widgets-infovis/package.json b/test/apps/widgets-infovis/package.json deleted file mode 100644 index 9058a8e1f45..00000000000 --- a/test/apps/widgets-infovis/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "deckgl-example-pure-js-widgets-infovis", - "version": "0.0.0", - "private": true, - "license": "MIT", - "scripts": { - "start": "vite --open", - "start-local": "vite --config ../vite.config.local.mjs", - "build": "vite build" - }, - "dependencies": { - "@deck.gl/core": "^9.2.0-beta.1", - "@deck.gl/layers": "^9.2.0-beta.1", - "@deck.gl/widgets": "^9.2.0-beta.1" - }, - "devDependencies": { - "vite": "^7.3.1" - } -} diff --git a/test/apps/widgets-multi-view-9.2/README.md b/test/apps/widgets-multi-view-9.2/README.md deleted file mode 100644 index 277a76dc22d..00000000000 --- a/test/apps/widgets-multi-view-9.2/README.md +++ /dev/null @@ -1,17 +0,0 @@ -## Example: Use deck.gl with widgets - -Uses [Vite](https://vitejs.dev/) to bundle and serve files. - -## Usage - -To install dependencies: - -```bash -npm install -# or -yarn -``` - -Commands: -* `npm start` is the development target, to serve the app and hot reload. -* `npm run build` is the production target, to create the final bundle and write to disk. diff --git a/test/apps/widgets-multi-view-9.2/package.json b/test/apps/widgets-multi-view-9.2/package.json deleted file mode 100644 index 0fdf1c72476..00000000000 --- a/test/apps/widgets-multi-view-9.2/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "deckgl-example-widgets-multi-view", - "version": "0.0.0", - "private": true, - "type": "module", - "license": "MIT", - "scripts": { - "start": "vite --open", - "start-local": "vite --config ../vite.config.local.mjs", - "build": "vite build" - }, - "dependencies": { - "@deck.gl/core": "^9.2.0-beta.1", - "@deck.gl/layers": "^9.2.0-beta.1", - "@deck.gl/widgets": "^9.2.0-beta.1" - }, - "devDependencies": { - "vite": "^7.3.1" - } -} diff --git a/test/apps/widgets-multi-view-9.2/react-app.tsx b/test/apps/widgets-multi-view-9.2/react-app.tsx deleted file mode 100644 index 5edbaee6831..00000000000 --- a/test/apps/widgets-multi-view-9.2/react-app.tsx +++ /dev/null @@ -1,43 +0,0 @@ -// deck.gl -// SPDX-License-Identifier: MIT -// Copyright (c) vis.gl contributors - -import React, {useState, useEffect} from 'react'; -import {createRoot} from 'react-dom/client'; -import {View} from '@deck.gl/core'; -import {DeckGL} from '@deck.gl/react'; -import {LightTheme, DarkTheme, _SplitterWidget as SplitterWidget} from '@deck.gl/widgets'; -import '@deck.gl/widgets/stylesheet.css'; - -import {INITIAL_VIEW_STATE, LAYERS, VIEW_LAYOUT} from './app'; - -function App() { - const [, setVersion] = useState(0); - const [views, setViews] = useState([]); - - // This is used to force a rerender of the DeckGL component - // to test for conflicting setters of the views prop - // useEffect(() => { - // const timer = setInterval(() => { - // setVersion(v => v + 1); - // }, 1000); - - // return () => clearInterval(timer); - // }, []) - - return ( - - ); -} - -createRoot(document.body.appendChild(document.createElement('div'))).render(); diff --git a/test/apps/widgets-9.2/README.md b/test/apps/widgets/README.md similarity index 100% rename from test/apps/widgets-9.2/README.md rename to test/apps/widgets/README.md diff --git a/test/apps/widgets/geospatial.html b/test/apps/widgets/geospatial.html new file mode 100644 index 00000000000..f93dc07fe09 --- /dev/null +++ b/test/apps/widgets/geospatial.html @@ -0,0 +1,28 @@ + + + + + deck.gl Example + + + +
+ +

Geospatial Widget Test

+

This is a very long body of text to test widget behavior with page scrolling.

+
+ +
+ + + diff --git a/test/apps/widgets-9.2/app.ts b/test/apps/widgets/geospatial.ts similarity index 96% rename from test/apps/widgets-9.2/app.ts rename to test/apps/widgets/geospatial.ts index 8bb77311cbb..d5e41c82ed7 100644 --- a/test/apps/widgets-9.2/app.ts +++ b/test/apps/widgets/geospatial.ts @@ -41,7 +41,7 @@ const INITIAL_VIEW_STATE = { pitch: 30 }; -function getLayers(filterRange = [2, 9]) { +export function getLayers(filterRange = [2, 9]) { return [ new WMSLayer({ data: 'https://ows.terrestris.de/osm/service', @@ -79,7 +79,7 @@ function getLayers(filterRange = [2, 9]) { new ArcLayer({ id: 'arcs', data: AIR_PORTS, - dataTransform: d => d.features.filter(f => f.properties.scalerank < 4), + dataTransform: (d: any) => d.features.filter(f => f.properties.scalerank < 4), // Styles getSourcePosition: f => [-0.4531566, 51.4709959], // London getTargetPosition: f => f.geometry.coordinates, @@ -91,7 +91,7 @@ function getLayers(filterRange = [2, 9]) { } const deck = new Deck({ - parent: document.getElementById('app'), + parent: document.getElementById('map') as HTMLDivElement, views: new MapView({repeat: true}), initialViewState: INITIAL_VIEW_STATE, controller: true, @@ -135,11 +135,10 @@ const deck = new Deck({ closeOnClickOutside: true }), new _TimelineWidget({ - placement: 'bottom-left', + _container: document.getElementById('controls') as HTMLDivElement, timeRange: [2, 9], step: 1, - initialTime: 0, - playInterval: 1000, + playInterval: 500, // eslint-disable-next-line no-console, no-undef onTimeChange: time => deck.setProps({ @@ -199,7 +198,6 @@ function getTooltip(info: PickingInfo, widget: InfoWidget) { text = `${info.object.properties.name} (${info.object.properties.abbrev})`; break; case 'click': - case 'static': text = `\ ${info.object.properties.name} (${info.object.properties.abbrev}) ${info.object.properties.type} diff --git a/test/apps/widgets/index.html b/test/apps/widgets/index.html new file mode 100644 index 00000000000..89e6bbfe263 --- /dev/null +++ b/test/apps/widgets/index.html @@ -0,0 +1,21 @@ + + + + + deck.gl Example + + + +
+ Pure JS - Geospatial + Pure JS - Multiview + Pure JS - Infovis + React - Geospatial + React - Multiview + React - Infovis +
+ + diff --git a/test/apps/widgets-infovis/index.html b/test/apps/widgets/infovis.html similarity index 87% rename from test/apps/widgets-infovis/index.html rename to test/apps/widgets/infovis.html index 129f837687a..31e874ecbb5 100644 --- a/test/apps/widgets-infovis/index.html +++ b/test/apps/widgets/infovis.html @@ -9,6 +9,6 @@ - + diff --git a/test/apps/widgets-infovis/app.ts b/test/apps/widgets/infovis.ts similarity index 77% rename from test/apps/widgets-infovis/app.ts rename to test/apps/widgets/infovis.ts index 2b0cf5136c8..68e00578ec1 100644 --- a/test/apps/widgets-infovis/app.ts +++ b/test/apps/widgets/infovis.ts @@ -16,7 +16,7 @@ import { FullscreenWidget, ResetViewWidget, ScrollbarWidget, - _TimelineWidget as TimelineWidget, + InfoWidget, ThemeWidget, DarkTheme, LightTheme @@ -54,7 +54,17 @@ const INITIAL_VIEW_STATE = { new Deck({ views: [ new OrbitView({id: 'orbit-view', x: 0, width: '50%', controller: true}), - new OrthographicView({id: 'ortho-view', x: '50%', width: '50%', controller: true}) + new OrthographicView({ + id: 'ortho-view', + x: '50%', + width: '50%', + controller: { + maxBounds: [ + [-50, -50, -50], + [50, 50, 50] + ] + } + }) ], initialViewState: INITIAL_VIEW_STATE, layers: [ @@ -75,24 +85,17 @@ new Deck({ new FullscreenWidget(), new ResetViewWidget(), new ThemeWidget({ - // darkModeTheme: DarkTheme, - // lightModeTheme: LightTheme, + darkModeTheme: DarkTheme, + lightModeTheme: LightTheme }), - new TimelineWidget({ - viewId: 'orbit-view', - timeRange: [0, 600], - formatLabel: (t: number) => - `${Math.floor(t / 60) - .toString() - .padStart(2, '0')}: ${(t % 60).toFixed(0).padStart(2, '0')}` - // autoPlay: true + new InfoWidget({ + viewId: 'ortho-view', + mode: 'hover', + getTooltip: ({object}) => object ? 'point' : null, }), new ScrollbarWidget({ + id: 'scrollbar-v', viewId: 'ortho-view', - contentBounds: [ - [-50, -50, -50], - [50, 50, 50] - ], // decorations: [ // { // contentBounds: [[10, 10, 0], [20, 20, 50]], @@ -104,11 +107,8 @@ new Deck({ orientation: 'vertical' }), new ScrollbarWidget({ + id: 'scrollbar-h', viewId: 'ortho-view', - contentBounds: [ - [-50, -50, -50], - [50, 50, 50] - ], placement: 'bottom-right', orientation: 'horizontal' }) diff --git a/test/apps/widgets-multi-view-9.2/react.html b/test/apps/widgets/multiview.html similarity index 80% rename from test/apps/widgets-multi-view-9.2/react.html rename to test/apps/widgets/multiview.html index 6251b5b15f1..1b5f6f0c548 100644 --- a/test/apps/widgets-multi-view-9.2/react.html +++ b/test/apps/widgets/multiview.html @@ -8,5 +8,5 @@ - + diff --git a/test/apps/widgets-multi-view-9.2/app.ts b/test/apps/widgets/multiview.ts similarity index 77% rename from test/apps/widgets-multi-view-9.2/app.ts rename to test/apps/widgets/multiview.ts index 62afe5e2f0c..d0f1b6938fb 100644 --- a/test/apps/widgets-multi-view-9.2/app.ts +++ b/test/apps/widgets/multiview.ts @@ -4,7 +4,7 @@ import {Deck, MapView} from '@deck.gl/core'; import {GeoJsonLayer, ArcLayer} from '@deck.gl/layers'; -import {LightTheme, DarkTheme, _SplitterWidget as SplitterWidget} from '@deck.gl/widgets'; +import {_SplitterWidget as SplitterWidget, SplitterWidgetProps} from '@deck.gl/widgets'; import '@deck.gl/widgets/stylesheet.css'; // source: Natural Earth http://www.naturalearthdata.com/ via geojson.xyz @@ -13,13 +13,13 @@ const COUNTRIES = const AIR_PORTS = 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson'; -export const INITIAL_VIEW_STATE = { +const INITIAL_VIEW_STATE = { latitude: 51.47, longitude: 0.45, zoom: 4 }; -export const LAYERS = [ +const LAYERS = [ new GeoJsonLayer({ id: 'base-map', data: COUNTRIES, @@ -47,7 +47,7 @@ export const LAYERS = [ new ArcLayer({ id: 'arcs', data: AIR_PORTS, - dataTransform: d => d.features.filter(f => f.properties.scalerank < 4), + dataTransform: (d: any) => d.features.filter(f => f.properties.scalerank < 4), // Styles getSourcePosition: f => [-0.4531566, 51.4709959], // London getTargetPosition: f => f.geometry.coordinates, @@ -57,7 +57,7 @@ export const LAYERS = [ }) ]; -export const VIEW_LAYOUT = { +const VIEW_LAYOUT: SplitterWidgetProps['viewLayout'] = { orientation: 'horizontal', views: [ new MapView({id: 'left', controller: true}), @@ -69,13 +69,11 @@ export const VIEW_LAYOUT = { ] } ] -} as const; +}; -export function main() { - new Deck({ - initialViewState: INITIAL_VIEW_STATE, - // controller: true, - layers: LAYERS, - widgets: [new SplitterWidget({viewLayout: VIEW_LAYOUT})] - }); -} +new Deck({ + // @ts-expect-error intentionally use the same initial state for all views + initialViewState: INITIAL_VIEW_STATE, + layers: LAYERS, + widgets: [new SplitterWidget({viewLayout: VIEW_LAYOUT})] +}); diff --git a/test/apps/widgets-9.2/package.json b/test/apps/widgets/package.json similarity index 73% rename from test/apps/widgets-9.2/package.json rename to test/apps/widgets/package.json index f987e4b0bec..709a9441825 100644 --- a/test/apps/widgets-9.2/package.json +++ b/test/apps/widgets/package.json @@ -10,9 +10,9 @@ "build": "vite build" }, "dependencies": { - "@deck.gl/core": "^9.2.0-beta.1", - "@deck.gl/layers": "^9.2.0-beta.1", - "@deck.gl/widgets": "^9.2.0-beta.1" + "@deck.gl/core": "^9.3.0", + "@deck.gl/layers": "^9.3.0", + "@deck.gl/widgets": "^9.3.0" }, "devDependencies": { "vite": "^7.3.1" diff --git a/test/apps/widgets/react-geospatial.html b/test/apps/widgets/react-geospatial.html new file mode 100644 index 00000000000..443629c1bd4 --- /dev/null +++ b/test/apps/widgets/react-geospatial.html @@ -0,0 +1,12 @@ + + + + + deck.gl Example + + + + + diff --git a/test/apps/widgets/react-geospatial.tsx b/test/apps/widgets/react-geospatial.tsx new file mode 100644 index 00000000000..f67d08a74c2 --- /dev/null +++ b/test/apps/widgets/react-geospatial.tsx @@ -0,0 +1,225 @@ +// deck.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import React, {useRef, useState} from 'react'; +import {createRoot} from 'react-dom/client'; +import {MapView, type PickingInfo} from '@deck.gl/core'; +import {DataFilterExtension} from '@deck.gl/extensions'; +import {GeoJsonLayer, ArcLayer} from '@deck.gl/layers'; +import {_WMSLayer as WMSLayer} from '@deck.gl/geo-layers'; +import { + CompassWidget, + ZoomWidget, + FullscreenWidget, + ScreenshotWidget, + ResetViewWidget, + PopupWidget, + IconWidget, + ToggleWidget, + SelectorWidget, + _GeocoderWidget, + _ScaleWidget, + LoadingWidget, + ThemeWidget, + InfoWidget, + ContextMenuWidget, + _TimelineWidget, + _StatsWidget, + DeckGL, + type InfoWidgetProps +} from '@deck.gl/react'; +import '@deck.gl/widgets/stylesheet.css'; + +// source: Natural Earth http://www.naturalearthdata.com/ via geojson.xyz +const COUNTRIES = + 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson'; //eslint-disable-line +const AIR_PORTS = + 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson'; + +const INITIAL_VIEW_STATE = { + latitude: 51.47, + longitude: 0.45, + zoom: 4, + bearing: 0, + pitch: 30 +}; + +function getLayers(filterRange = [2, 9]) { + return [ + new WMSLayer({ + data: 'https://ows.terrestris.de/osm/service', + serviceType: 'wms', + layers: ['OSM-WMS'] + }), + new GeoJsonLayer({ + id: 'base-map', + data: COUNTRIES, + stroked: true, + filled: true, + lineWidthMinPixels: 2, + opacity: 0.4, + getLineColor: [60, 60, 60], + getFillColor: [200, 200, 200] + }), + new GeoJsonLayer({ + id: 'airports', + data: AIR_PORTS, + filled: true, + pointRadiusMinPixels: 2, + pointRadiusScale: 2000, + getPointRadius: f => 11 - f.properties.scalerank, + getFillColor: [200, 0, 80, 180], + pickable: true, + autoHighlight: true, + getFilterValue: f => f.properties.scalerank, + filterRange, + extensions: [new DataFilterExtension({filterSize: 1})] + }), + new ArcLayer({ + id: 'arcs', + data: AIR_PORTS, + dataTransform: (d: any) => d.features.filter(f => f.properties.scalerank < 4), + getSourcePosition: f => [-0.4531566, 51.4709959], + getTargetPosition: f => f.geometry.coordinates, + getSourceColor: [0, 128, 200], + getTargetColor: [200, 0, 80], + getWidth: 1 + }) + ]; +} + +const getTooltip: InfoWidgetProps['getTooltip'] = (info, widget) => { + if (!info.object || info.layer?.id !== 'airports') { + return null; + } + + let text: string; + switch (widget.props.mode) { + case 'hover': + text = `${info.object.properties.name} (${info.object.properties.abbrev})`; + break; + case 'click': + text = `\ +${info.object.properties.name} (${info.object.properties.abbrev}) +${info.object.properties.type} +${info.object.properties.featureclass} (${info.object.properties.location}) +`; + break; + } + + return { + position: info.object.geometry.coordinates, + text, + style: {minWidth: '200px'} + }; +}; + +function createPin() { + const div = document.createElement('div'); + Object.assign(div.style, { + width: '32px', + height: '32px', + transform: 'translate(-50%,-24px)' + }); + div.innerHTML = + ''; + return div; +} + +function App() { + const [layers, setLayers] = useState(() => getLayers()); + const pinRef = useRef(null); + + if (!pinRef.current) { + pinRef.current = createPin(); + } + + return ( + + <_GeocoderWidget geocoder="coordinates" _geolocation /> + + + + + + + <_ScaleWidget placement="bottom-right" /> + + { + const name = info.layer?.id === 'airports' && info.object?.properties.name; + return ( + name && [ + {label: `Airport: ${name}`}, + {value: 'open', label: 'Open in new tab'}, + {value: 'favorite', label: 'Set as favorite'}, + {value: 'filter', label: 'Exclude from filter'} + ] + ); + }} + onMenuItemSelected={console.log} + /> + + + <_TimelineWidget + timeRange={[2, 9]} + step={1} + playInterval={500} + onTimeChange={time => setLayers(getLayers([2, time]))} + /> + <_StatsWidget type="deck" /> + console.log('Running...')} + /> + console.log(checked ? 'faved' : 'unfaved')} + /> + ` + }, + { + value: 'split-horizontal', + label: 'Split views horizontal', + icon: `data:image/svg+xml,` + }, + { + value: 'split-vertical', + label: 'Split views vertical', + icon: `data:image/svg+xml,` + } + ]} + onChange={console.log} + /> + + ); +} + +createRoot(document.body.appendChild(document.createElement('div'))).render(); diff --git a/test/apps/widgets/react-infovis.html b/test/apps/widgets/react-infovis.html new file mode 100644 index 00000000000..de43ae55950 --- /dev/null +++ b/test/apps/widgets/react-infovis.html @@ -0,0 +1,14 @@ + + + + + deck.gl non-geospatial widgets example + + + + + + + diff --git a/test/apps/widgets/react-infovis.tsx b/test/apps/widgets/react-infovis.tsx new file mode 100644 index 00000000000..276d3b62f4e --- /dev/null +++ b/test/apps/widgets/react-infovis.tsx @@ -0,0 +1,123 @@ +// deck.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import React, {useState, useCallback} from 'react'; +import {createRoot} from 'react-dom/client'; +import { + OrbitView, + type OrbitViewState, + OrthographicView, + type OrthographicViewState +} from '@deck.gl/core'; +import {ScatterplotLayer} from '@deck.gl/layers'; +import { + DeckGL, + FullscreenWidget, + GimbalWidget, + ResetViewWidget, + ScrollbarWidget, + InfoWidget, + ThemeWidget, + ZoomWidget +} from '@deck.gl/react'; +import {DarkTheme, LightTheme} from '@deck.gl/widgets'; +import '@deck.gl/widgets/stylesheet.css'; + +function generateData(count) { + const result: {position: number[]; color: number[]}[] = []; + for (let i = 0; i < count; i++) { + result.push({ + position: [Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50], + color: [Math.random() * 255, Math.random() * 255, Math.random() * 255] + }); + } + return result; +} + +const INITIAL_ORBIT_VIEW_STATE = { + target: [0, 0, 0], + rotationX: 45, + rotationOrbit: 0, + zoom: 0 +} as const satisfies OrbitViewState; + +const INITIAL_ORTHO_VIEW_STATE = { + target: [0, 0, 0], + zoom: 0 +} as const satisfies OrthographicViewState; + +const VIEWS = [ + new OrbitView({id: 'orbit-view', x: 0, width: '50%', controller: true}), + new OrthographicView({ + id: 'ortho-view', + x: '50%', + width: '50%', + controller: { + maxBounds: [ + [-50, -50, -50], + [50, 50, 50] + ] + } + }) +]; + +const LAYERS = [ + new ScatterplotLayer({ + id: 'scatter', + data: generateData(500), + getPosition: d => d.position, + getFillColor: d => d.color, + getRadius: 3, + pickable: true, + autoHighlight: true, + billboard: true + }) +]; + +function App() { + const [viewState, setViewState] = useState({ + 'orbit-view': INITIAL_ORBIT_VIEW_STATE, + 'ortho-view': INITIAL_ORTHO_VIEW_STATE + }); + const onViewStateChange = useCallback( + ({viewId, viewState}: {viewId: string; viewState: OrthographicViewState}) => { + setViewState(curr => ({...curr, [viewId]: viewState})); + }, + [] + ); + + return ( + + + + + + + object ? 'point' : null} + /> + + + + ); +} + +createRoot(document.body.appendChild(document.createElement('div'))).render(); diff --git a/test/apps/widgets-multi-view-9.2/index.html b/test/apps/widgets/react-multiview.html similarity index 74% rename from test/apps/widgets-multi-view-9.2/index.html rename to test/apps/widgets/react-multiview.html index dd423891b11..c90c9e0f400 100644 --- a/test/apps/widgets-multi-view-9.2/index.html +++ b/test/apps/widgets/react-multiview.html @@ -8,8 +8,5 @@ - + diff --git a/test/apps/widgets/react-multiview.tsx b/test/apps/widgets/react-multiview.tsx new file mode 100644 index 00000000000..40873eb98c7 --- /dev/null +++ b/test/apps/widgets/react-multiview.tsx @@ -0,0 +1,92 @@ +// deck.gl +// SPDX-License-Identifier: MIT +// Copyright (c) vis.gl contributors + +import React, {useState} from 'react'; +import {createRoot} from 'react-dom/client'; +import {View, MapView} from '@deck.gl/core'; +import {GeoJsonLayer, ArcLayer} from '@deck.gl/layers'; +import {DeckGL, _SplitterWidget as SplitterWidget, SplitterWidgetProps} from '@deck.gl/react'; + +import '@deck.gl/widgets/stylesheet.css'; + +// source: Natural Earth http://www.naturalearthdata.com/ via geojson.xyz +const COUNTRIES = + 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson'; //eslint-disable-line +const AIR_PORTS = + 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_10m_airports.geojson'; + +const INITIAL_VIEW_STATE = { + latitude: 51.47, + longitude: 0.45, + zoom: 4 +}; + +const LAYERS = [ + new GeoJsonLayer({ + id: 'base-map', + data: COUNTRIES, + // Styles + stroked: true, + filled: true, + lineWidthMinPixels: 2, + opacity: 0.4, + getLineColor: [60, 60, 60], + getFillColor: [200, 200, 200] + }), + new GeoJsonLayer({ + id: 'airports', + data: AIR_PORTS, + // Styles + filled: true, + pointRadiusMinPixels: 2, + pointRadiusScale: 2000, + getPointRadius: f => 11 - f.properties.scalerank, + getFillColor: [200, 0, 80, 180], + // Interactive props + pickable: true, + autoHighlight: true + }), + new ArcLayer({ + id: 'arcs', + data: AIR_PORTS, + dataTransform: (d: any) => d.features.filter(f => f.properties.scalerank < 4), + // Styles + getSourcePosition: f => [-0.4531566, 51.4709959], // London + getTargetPosition: f => f.geometry.coordinates, + getSourceColor: [0, 128, 200], + getTargetColor: [200, 0, 80], + getWidth: 1 + }) +]; + +const VIEW_LAYOUT: SplitterWidgetProps['viewLayout'] = { + orientation: 'horizontal', + views: [ + new MapView({id: 'left', controller: true}), + { + orientation: 'vertical', + views: [ + new MapView({id: 'right-top', controller: true}), + new MapView({id: 'right-bottom', controller: true}) + ] + } + ] +}; + +function App() { + const [views, setViews] = useState([new MapView({id: 'left'})]); + + return ( + + + + ); +} + +createRoot(document.body.appendChild(document.createElement('div'))).render();