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
1 change: 1 addition & 0 deletions docs/api-reference/widgets/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This module contains the following widgets:

- [FullscreenWidget](./fullscreen-widget.md)
- [SplitterWidget](./splitter-widget.md)
- [View Layout](./view-layout.md)

### Information Widgets

Expand Down
9 changes: 6 additions & 3 deletions docs/api-reference/widgets/splitter-widget.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ function App() {
## Constructor

```ts
import {_SplitterWidget as SplitterWidget, type SplitterWidgetProps} from '@deck.gl/widgets';
import {
_SplitterWidget as SplitterWidget,
type SplitterWidgetProps
} from '@deck.gl/widgets';
new SplitterWidget<ViewType[]>({} satisfies SplitterWidgetProps);
```

Expand All @@ -150,7 +153,7 @@ new SplitterWidget<ViewType[]>({} satisfies SplitterWidgetProps);

The `SplitterWidget` accepts the generic [`WidgetProps`](../core/widget.md#widgetprops) and:

#### `viewLayout` (ViewLayout, required) {#viewlayout}
#### `viewLayout` (SplitterWidgetViewLayout, required) {#viewlayout}

Layout descriptor of how views are arranged on the canvas. Contains the following fields:

Expand All @@ -161,7 +164,7 @@ Layout descriptor of how views are arranged on the canvas. Contains the followin
- `minSplit` (number, optional) - Min value of the split. The user cannot make the first view smaller than this ratio. Default `0.05`.
- `maxSplit` (number, optional) - Max value of the split. The user cannot make the first view larger than this ratio. Default `0.95`.

You may also replace one or both item in `views` with a `ViewLayout` object, composing more than two views into a complex layout.
You may also replace one or both items in `views` with a nested `SplitterWidgetViewLayout` object, composing more than two views into a complex layout.


#### `onChange` (Function, optional) {#onchange}
Expand Down
133 changes: 133 additions & 0 deletions docs/api-reference/widgets/view-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# View Layout

The view layout helpers build stable deck.gl view arrays from a declarative layout tree. They are generic utilities for applications that need multiple coordinated views without hand-computing every view rectangle in render code.

```js
import {buildViewsFromViewLayout} from '@deck.gl/widgets';
```

## Usage

Start by defining the deck.gl `View` instances that your application needs. Then place them in a plain layout object tree and compile that tree for the current deck canvas size.

```tsx
import React from 'react';
import {DeckGL} from '@deck.gl/react';
import {OrthographicView} from '@deck.gl/core';
import {buildViewsFromViewLayout} from '@deck.gl/widgets';
import type {ViewLayout} from '@deck.gl/widgets';

const VIEW_LAYOUT = {
type: 'column',
children: [
new OrthographicView({id: 'header', height: 48, controller: false}),
{
type: 'row',
children: [
new OrthographicView({id: 'sidebar', controller: false}),
{
type: 'overlay',
children: [
new OrthographicView({id: 'main', controller: true}),
new OrthographicView({
id: 'minimap',
x: 'calc(100% - 180px)',
y: 16,
width: 164,
height: 120,
controller: false,
clear: true
})
]
}
]
}
]
} satisfies ViewLayout;

export function App({width, height, layers}) {
const compiled = buildViewsFromViewLayout({layout: VIEW_LAYOUT, width, height});
return <DeckGL views={compiled.views} layers={layers} />;
}
```

The returned `compiled.rectsById` map contains the same resolved rectangles keyed by view id. Use it when you need to position DOM overlays next to deck views, debug the generated layout, or scope non-layer UI to a view rectangle.

The returned `compiled.splittersById` map contains splitter metadata for rows and columns that declare a `splitId`. For two-child splits, the splitter id is exactly `splitId`. For three or more children, the compiler creates one splitter between each adjacent pair using generated ids such as `splitId-0`, `splitId-1`, and so on. Applications that store split values can pass them back into `buildViewsFromViewLayout` via `splitValues`.

Layout items may also define `minPixels` and `maxPixels` to constrain their size in the parent stack axis. The compiler combines those pixel constraints with percentage-based `width` or `height` values, and with `minSplit` and `maxSplit` when returning splitter metadata.

Use `viewPropsById` when an application needs to control layout-only bounds for a view without rebuilding the static layout tree. Override values use the same length syntax as authored view props.

The layout tree is a discriminated union of plain objects:

- `row`: lays out children left to right.
- `column`: lays out children top to bottom.
- `overlay`: gives each child the same parent rectangle.
- `spacer`: reserves empty fixed or flexible space.

Raw deck.gl `View` instances are leaf nodes in `children`. Put layout-only `width`, `height`, `x`, and `y` props directly on the `View` when a leaf needs fixed sizing or overlay positioning.

For split layouts, `ViewLayout` also accepts the `SplitterWidgetViewLayout`-style aliases `orientation: 'horizontal' | 'vertical'` and `views`. A horizontal orientation is equivalent to `type: 'row'`; a vertical orientation is equivalent to `type: 'column'`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that's necessary... We just need a helper inside SplitterWidget to convert the old format to the new one.


`buildViewsFromViewLayout` compiles a layout tree into:

- `views`: concrete deck.gl views with numeric `x`, `y`, `width`, and `height`.
- `rectsById`: resolved rectangles keyed by deck view id.
- `splittersById`: resolved splitter metadata keyed by split id.

## Layout Sizing

`width`, `height`, `x`, and `y` accept numbers or CSS-like length strings such as percentages and simple `calc(...)` expressions. The compiler resolves those values against the current parent rectangle before passing numeric bounds to deck.gl.

```ts
new OrthographicView({
id: 'overlay',
x: '50%',
width: 'calc(50% - 12px)',
height: 80
});
```

## View Reuse

Pass the previous `CompiledDeckViews` result back to `buildViewsFromViewLayout` when a caller needs structural view reuse across renders. A previous view is reused when its id, constructor, and resolved props match the next compilation.

```ts
let compiled = buildViewsFromViewLayout({layout, width, height});

compiled = buildViewsFromViewLayout({
layout,
width,
height,
previous: compiled
});
```

## Types

### `ViewLayout`

Plain discriminated layout object. Children may be nested layout objects, raw deck.gl `View` instances, or falsey optional children.

### `buildViewsFromViewLayout`

Compiles a layout tree for the current deck canvas size.

Parameters:

- `layout` (`ViewLayout`) - Root layout tree to compile.
- `width` (`number`) - Current deck width in pixels.
- `height` (`number`) - Current deck height in pixels.
- `previous` (`CompiledDeckViews`, optional) - Previous compilation for view reuse.
- `splitValues` (`Record<string, number>`, optional) - Controlled split ratios keyed by layout `splitId`.
- `viewPropsById` (`Record<string, {x?, y?, width?, height?}>`, optional) - Controlled layout-only view prop overrides keyed by deck view id.

Returns:

- `views` (`View[]`) - Concrete deck.gl views.
- `rectsById` (`Record<string, {x, y, width, height}>`) - Resolved rectangles keyed by view id.

## Source

[modules/widgets/src/view-layout/build-views-from-view-layout.ts](https://github.com/visgl/deck.gl/tree/master/modules/widgets/src/view-layout/build-views-from-view-layout.ts)
3 changes: 2 additions & 1 deletion docs/table-of-contents.json
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@
"type": "category",
"label": "@deck.gl/react",
"items": [
"api-reference/react/overview",
"api-reference/react/overview",
"api-reference/react/deckgl",
"api-reference/react/use-widget"
]
Expand Down Expand Up @@ -338,6 +338,7 @@
"api-reference/widgets/theme-widget",
"api-reference/widgets/timeline-widget",
"api-reference/widgets/toggle-widget",
"api-reference/widgets/view-layout",
"api-reference/widgets/zoom-widget"
]
}
Expand Down
4 changes: 4 additions & 0 deletions modules/main/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export {
// View widgets
FullscreenWidget,
_SplitterWidget,
buildViewsFromViewLayout,
// Information widgets
InfoWidget,
PopupWidget,
Expand Down Expand Up @@ -244,6 +245,9 @@ export type {
StatsWidgetProps,
ContextMenuWidgetProps,
SplitterWidgetProps,
SplitterWidgetViewLayout,
CompiledDeckViews,
ViewLayout,
TimelineWidgetProps,
SelectorWidgetProps,
GimbalWidgetProps,
Expand Down
7 changes: 6 additions & 1 deletion modules/widgets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export {GeocoderWidget as _GeocoderWidget} from './geocoder-widget';
// View widgets
export {FullscreenWidget} from './fullscreen-widget';
export {SplitterWidget as _SplitterWidget} from './splitter-widget';
export {
buildViewsFromViewLayout,
type CompiledDeckViews
} from './view-layout/build-views-from-view-layout';
export type {ViewLayout} from './view-layout/view-layout';

// Information widgets
export {InfoWidget} from './info-widget';
Expand Down Expand Up @@ -49,7 +54,7 @@ export type {InfoWidgetProps} from './info-widget';
export type {PopupWidgetProps} from './popup-widget';
export type {StatsWidgetProps} from './stats-widget';
export type {ContextMenuWidgetProps} from './context-menu-widget';
export type {SplitterWidgetProps} from './splitter-widget';
export type {SplitterWidgetProps, SplitterWidgetViewLayout} from './splitter-widget';
export type {TimelineWidgetProps} from './timeline-widget';
export type {SelectorWidgetProps} from './selector-widget';
export type {GimbalWidgetProps} from './gimbal-widget';
Expand Down
Loading
Loading