Skip to content

Commit 82902eb

Browse files
committed
Merge remote-tracking branch 'origin/master' into chrisgervang/basemap-browser-use-device-pixels
2 parents fd19f6d + 6795cc9 commit 82902eb

161 files changed

Lines changed: 3104 additions & 572 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/api-reference/core/deck.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ Parameters:
776776
* `y` (number) - y position in pixels
777777
* `radius` (number, optional) - radius of tolerance in pixels. Default `0`.
778778
* `layerIds` (string[], optional) - a list of layer ids to query from. If not specified, then all pickable and visible layers are queried.
779-
* `depth` - Specifies the max number of objects to return. Default `10`.
779+
* `depth` - Specifies the max number of objects to return. Default `10`. For layers without explicit picking index buffers, only the default depth of 10 unique objects per layer is guaranteed; higher custom depths may return duplicate results for these layers.
780780
* `unproject3D` (boolean, optional) - if `true`, `info.coordinate` will be a 3D point by unprojecting the `x, y` screen coordinates onto the picked geometry. Default `false`.
781781
782782
Returns:
@@ -786,6 +786,7 @@ Returns:
786786
Notes:
787787
788788
* Deep picking is implemented as a sequence of simpler picking operations and can have a performance impact. Should this become a concern, you can use the `depth` parameter to limit the number of matches that can be returned, and thus the maximum number of picking operations.
789+
* Layers that provide explicit picking index buffers support buffer mutation between picking passes and are not subject to the default-depth unique-object guarantee.
789790
790791
791792
#### `pickObjects` {#pickobjects}

docs/api-reference/core/globe-controller.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ new Deck({
3838
Supports all [Controller options](./controller.md#options) with the following default behavior:
3939

4040
- `dragPan`: default `'pan'` (drag to pan)
41-
- `dragRotate`: not effective, this view does not currently support rotation
42-
- `touchRotate`: not effective, this view does not currently support rotation
41+
- `dragRotate`: shift+drag or right-click drag to change bearing and pitch
42+
- `touchRotate`: multi-touch rotate to change bearing
4343
- `keyboard`: arrow keys to pan, +/- to zoom
44+
- `inertia`: when set to a number (milliseconds), the globe continues spinning after a fling gesture with exponential decay
4445
- `maxBounds` - constrains the viewport to the specified bounding box `[[minLng, minLat], [maxLng, maxLat]]`
4546

4647
## Custom GlobeController

docs/api-reference/core/globe-view.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ It's recommended that you read the [Views and Projections guide](../../developer
1818
## Limitations
1919

2020
The goal of `GlobeView` is to provide a generic solution to rendering and navigating data in the 3D space.
21-
In the initial release, this class mainly addresses the need to render an overview of the entire globe. The following limitations apply, as features are still under development:
2221

23-
- No support for rotation (`pitch` or `bearing`). The camera always points towards the center of the earth, with north up.
2422
- No high-precision rendering at high zoom levels (> 12). Features at the city-block scale may not be rendered accurately.
2523
- Only supports `'lnglat'` (the default value of the `coordinateSystem` prop).
2624
- Known rendering issues when using multiple views mixing `GlobeView` and `MapView`, or switching between the two.
@@ -72,8 +70,14 @@ To render, `GlobeView` needs to be used together with a `viewState` with the fol
7270
- `longitude` (number) - longitude at the viewport center
7371
- `latitude` (number) - latitude at the viewport center
7472
- `zoom` (number) - zoom level
73+
- `bearing` (number, optional) - bearing angle in degrees. Default `0` (north up).
74+
- `pitch` (number, optional) - pitch angle in degrees. `0` looks straight down at the earth. Default `0`.
7575
- `maxZoom` (number, optional) - max zoom level. Default `20`.
7676
- `minZoom` (number, optional) - min zoom level. Default `0`.
77+
- `maxPitch` (number, optional) - max pitch angle. Default `60`.
78+
- `minPitch` (number, optional) - min pitch angle. Default `0`.
79+
80+
When `bearing` is `0` (the default), north is always kept pointing up and the globe behaves like a traditional desk globe — horizontal drag changes longitude, vertical drag changes latitude, and the polar axis stays fixed. When the user changes the bearing (via shift+drag or right-click drag), the globe enters free rotation mode where bearing evolves naturally to avoid orientation discontinuities near the poles.
7781

7882

7983
## Controller

docs/api-reference/core/globe-viewport.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# GlobeViewport (Experimental)
22

3-
The `GlobeViewport` class takes globe view states (`latitude`, `longitude`, and `zoom`), and performs projections between world and screen coordinates. It is a helper class for visualizing the earth as a 3D globe.
3+
The `GlobeViewport` class takes globe view states (`latitude`, `longitude`, `zoom`, `bearing`, and `pitch`), and performs projections between world and screen coordinates. It is a helper class for visualizing the earth as a 3D globe.
44

55
## Usage
66

@@ -25,7 +25,7 @@ viewport.project([-122.45, 37.78]);
2525
## Constructor
2626

2727
```js
28-
new GlobeViewport({width, height, longitude, latitude, zoom});
28+
new GlobeViewport({width, height, longitude, latitude, zoom, bearing, pitch});
2929
```
3030

3131
Parameters:
@@ -40,11 +40,13 @@ Parameters:
4040
+ `latitude` (number, optional) - Latitude of the viewport center on map. Default to `0`.
4141
+ `longitude` (number, optional) - Longitude of the viewport center on map. Default to `0`.
4242
+ `zoom` (number, optional) - Map zoom (scale is calculated as `2^zoom`). Default to `11`.
43+
+ `bearing` (number, optional) - Bearing angle in degrees. Default to `0`.
44+
+ `pitch` (number, optional) - Pitch angle in degrees. Default to `0`.
4345
+ `altitude` (number, optional) - Altitude of camera, 1 unit equals to the height of the viewport. Default to `1.5`.
4446

4547
projection matrix arguments:
4648

47-
+ `nearZMultiplier` (number, optional) - Scaler for the near plane, 1 unit equals to the height of the viewport. Default to `0.1`.
49+
+ `nearZMultiplier` (number, optional) - Scaler for the near plane, 1 unit equals to the height of the viewport. Default to `0.01`.
4850
+ `farZMultiplier` (number, optional) - Scaler for the far plane, 1 unit equals to the distance from the camera to the top edge of the screen. Default to `1`.
4951

5052
Remarks:

docs/api-reference/widgets/overview.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ This module contains the following widgets:
2121

2222
- [FullscreenWidget](./fullscreen-widget.md)
2323
- [SplitterWidget](./splitter-widget.md)
24+
- [View Layout](./view-layout.md)
2425

2526
### Information Widgets
2627

docs/api-reference/widgets/splitter-widget.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,10 @@ function App() {
140140
## Constructor
141141

142142
```ts
143-
import {_SplitterWidget as SplitterWidget, type SplitterWidgetProps} from '@deck.gl/widgets';
143+
import {
144+
_SplitterWidget as SplitterWidget,
145+
type SplitterWidgetProps
146+
} from '@deck.gl/widgets';
144147
new SplitterWidget<ViewType[]>({} satisfies SplitterWidgetProps);
145148
```
146149

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

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

153-
#### `viewLayout` (ViewLayout, required) {#viewlayout}
156+
#### `viewLayout` (SplitterWidgetViewLayout, required) {#viewlayout}
154157

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

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

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

166169

167170
#### `onChange` (Function, optional) {#onchange}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# View Layout
2+
3+
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.
4+
5+
```js
6+
import {buildViewsFromViewLayout} from '@deck.gl/widgets';
7+
```
8+
9+
## Usage
10+
11+
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.
12+
13+
```tsx
14+
import React from 'react';
15+
import {DeckGL} from '@deck.gl/react';
16+
import {OrthographicView} from '@deck.gl/core';
17+
import {buildViewsFromViewLayout} from '@deck.gl/widgets';
18+
import type {ViewLayout} from '@deck.gl/widgets';
19+
20+
const VIEW_LAYOUT = {
21+
type: 'column',
22+
children: [
23+
new OrthographicView({id: 'header', height: 48, controller: false}),
24+
{
25+
type: 'row',
26+
children: [
27+
new OrthographicView({id: 'sidebar', controller: false}),
28+
{
29+
type: 'overlay',
30+
children: [
31+
new OrthographicView({id: 'main', controller: true}),
32+
new OrthographicView({
33+
id: 'minimap',
34+
x: 'calc(100% - 180px)',
35+
y: 16,
36+
width: 164,
37+
height: 120,
38+
controller: false,
39+
clear: true
40+
})
41+
]
42+
}
43+
]
44+
}
45+
]
46+
} satisfies ViewLayout;
47+
48+
export function App({width, height, layers}) {
49+
const compiled = buildViewsFromViewLayout({layout: VIEW_LAYOUT, width, height});
50+
return <DeckGL views={compiled.views} layers={layers} />;
51+
}
52+
```
53+
54+
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.
55+
56+
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`.
57+
58+
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.
59+
60+
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.
61+
62+
The layout tree is a discriminated union of plain objects:
63+
64+
- `row`: lays out children left to right.
65+
- `column`: lays out children top to bottom.
66+
- `overlay`: gives each child the same parent rectangle.
67+
- `spacer`: reserves empty fixed or flexible space.
68+
69+
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.
70+
71+
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'`.
72+
73+
`buildViewsFromViewLayout` compiles a layout tree into:
74+
75+
- `views`: concrete deck.gl views with numeric `x`, `y`, `width`, and `height`.
76+
- `rectsById`: resolved rectangles keyed by deck view id.
77+
- `splittersById`: resolved splitter metadata keyed by split id.
78+
79+
## Layout Sizing
80+
81+
`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.
82+
83+
```ts
84+
new OrthographicView({
85+
id: 'overlay',
86+
x: '50%',
87+
width: 'calc(50% - 12px)',
88+
height: 80
89+
});
90+
```
91+
92+
## View Reuse
93+
94+
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.
95+
96+
```ts
97+
let compiled = buildViewsFromViewLayout({layout, width, height});
98+
99+
compiled = buildViewsFromViewLayout({
100+
layout,
101+
width,
102+
height,
103+
previous: compiled
104+
});
105+
```
106+
107+
## Types
108+
109+
### `ViewLayout`
110+
111+
Plain discriminated layout object. Children may be nested layout objects, raw deck.gl `View` instances, or falsey optional children.
112+
113+
### `buildViewsFromViewLayout`
114+
115+
Compiles a layout tree for the current deck canvas size.
116+
117+
Parameters:
118+
119+
- `layout` (`ViewLayout`) - Root layout tree to compile.
120+
- `width` (`number`) - Current deck width in pixels.
121+
- `height` (`number`) - Current deck height in pixels.
122+
- `previous` (`CompiledDeckViews`, optional) - Previous compilation for view reuse.
123+
- `splitValues` (`Record<string, number>`, optional) - Controlled split ratios keyed by layout `splitId`.
124+
- `viewPropsById` (`Record<string, {x?, y?, width?, height?}>`, optional) - Controlled layout-only view prop overrides keyed by deck view id.
125+
126+
Returns:
127+
128+
- `views` (`View[]`) - Concrete deck.gl views.
129+
- `rectsById` (`Record<string, {x, y, width, height}>`) - Resolved rectangles keyed by view id.
130+
131+
## Source
132+
133+
[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)

docs/developer-guide/custom-layers/attribute-management.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ While most apps rely on their layers to automatically generate appropriate GPU b
4747

4848
While this allows for ultimate performance and control of updates, as well as potential sharing of buffers between layers, the application will need to generate attributes in exactly the format that the layer shaders expect, creating a strong coupling between the application and the layer.
4949

50-
**Note:** The application can provide some buffers and let others be managed by the layer. As an example management of the `instancePickingColors` buffer is normally left to the layer.
50+
**Note:** The application can provide some buffers and let others be managed by the layer. Explicit picking index buffers are only needed when the logical picking id differs from the rendered instance id.
5151

5252

5353
## More information

docs/developer-guide/custom-layers/layer-attributes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ For _variable primitive layers_ there are two options:
5555

5656
2) Copy each descriptive attribute `N` times (`N` being the number of vertices generated for that row during tesselation). This is the method that is used in deck.gl today.
5757

58-
3) Add a single `rowIndex` attribute and copy the same index `N` times as above. In this approach, descriptive values could then be read from textures where they are stored a single time. This provides flexibility at the price of performance (texture access latency) and complexity (working with data in textures).
58+
3) Add a single `rowIndexes` attribute and copy the same index `N` times as above. In this approach, descriptive values could then be read from textures where they are stored a single time. This provides flexibility at the price of performance (texture access latency) and complexity (working with data in textures).
5959

6060

6161
Remarks:

docs/developer-guide/custom-layers/picking.md

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -49,45 +49,50 @@ When other gestures (click, drag, etc.) are detected, deck.gl does not repeat pi
4949
special support is provided for the built-in "picking color" based picking
5050
system, which most layers use.
5151

52-
To take full control of picking, a layer need to take the following steps:
52+
The following sections describe common ways to implement custom picking.
5353

54-
### Creating A Picking Color Attribute
54+
### Default Instanced Picking
5555

56-
Add an attribute for each vertex using the layer's [AttributeManager](../../api-reference/core/attribute-manager.md):
56+
Instanced layer shaders can derive picking colors from the built-in instance id when each rendered instance maps to one picked object. In GLSL, use `picking_setPickingColorFromInstanceID()` or assign `geometry.pickingColor = picking_getPickingColorFromInstanceID()`. In WGSL, add `@builtin(instance_index)` to the vertex inputs and use `picking_getPickingColorFromIndex(instanceIndex)`.
5757

58-
```js
59-
import {GL} from '@luma.gl/webgl/constants';
58+
Add an explicit picking index attribute only when the logical picking id within the current layer is different from the rendered instance id. For example:
59+
60+
* Binary GeoJSON or MVT point sublayers may render local point instances while picking should return a global feature index.
61+
62+
* `PathLayer` tessellates one path into multiple rendered segment or joint instances, so its generated geometry needs explicit picking indexes that map back to the source path index instead of each rendered segment's instance id.
6063

64+
### Creating A Picking Index Attribute
65+
66+
Add an attribute for each vertex or instance using the layer's [AttributeManager](../../api-reference/core/attribute-manager.md). Use the `rowIndexes` attribute name to let deck.gl handle deep-picking buffer mutation.
67+
68+
```js
6169
class MyLayer extends Layer {
6270
initializeState() {
6371
this.state.attributeManager.add({
64-
customPickingColors: {
65-
size: 3,
66-
type: GL.UNSIGNED_BYTE,
67-
update: this.calculatePickingColors
72+
rowIndexes: {
73+
size: 1,
74+
type: 'uint32',
75+
update: this.calculatePickingIndexes
6876
}
6977
});
7078
}
7179
}
7280
```
7381

74-
Populate the attribute by providing a different picking color for every object that you need to differentiate. The default implementation of [`layer.encodePickingColor()`](../../api-reference/core/layer.md#encodepickingcolor) and [`layer.decodePickingColor()`](../../api-reference/core/layer.md#decodepickingcolor) is likely sufficient, but you may need to implement your own pair.
82+
Populate the attribute by providing the logical object index for every rendered vertex or instance that you need to differentiate.
7583

7684
```js
7785
class MyLayer extends Layer {
7886

7987
...
8088

81-
calculatePickingColors(attribute) {
89+
calculatePickingIndexes(attribute) {
8290
const {data} = this.props;
8391
const {value} = attribute;
8492

8593
let i = 0;
8694
for (const object of data) {
87-
const pickingColor = this.encodePickingColor(i);
88-
value[i * 3] = pickingColor[0];
89-
value[i * 3 + 1] = pickingColor[1];
90-
value[i * 3 + 2] = pickingColor[2];
95+
value[i] = i;
9196
i++;
9297
}
9398
}
@@ -119,15 +124,15 @@ All core layers (including composite layers) support picking using luma.gl's `pi
119124

120125
#### Vertex Shader
121126

122-
Vertex shader should set current picking color using `picking_setPickingColor` method provided by picking shader module.
127+
Vertex shader should set current picking color using helpers provided by the picking shader module.
123128

124129
```glsl
125-
attribute vec3 customPickingColors;
130+
in float rowIndexes;
126131
127132
void main(void) {
128133
...
129134
130-
picking_setPickingColor(customPickingColors);
135+
geometry.pickingColor = picking_getPickingColorFromIndex(rowIndexes);
131136
}
132137
```
133138

0 commit comments

Comments
 (0)