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
79 changes: 79 additions & 0 deletions docs/api-reference/core/deck.md
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,83 @@ Parameters:
* `force` (boolean) - if `false`, only redraw if necessary (e.g. changes have been made to views or layers). If `true`, skip the check. Default `false`.


#### `pickObjectAsync` {#pickobjectasync}

Get the closest pickable and visible object at the given screen coordinate.

```ts
await deck.pickObjectAsync({x, y, radius, layerIds, unproject3D})
```

Parameters:

* `x` (number) - x position in pixels
* `y` (number) - y position in pixels
* `radius` (number, optional) - radius of tolerance in pixels. Default `0`.
* `layerIds` (string[], optional) - a list of layer ids to query from. If not specified, then all pickable and visible layers are queried.
* `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`.

Returns:

* a single [`info`](../../developer-guide/interactivity.md#the-pickinginfo-object) object, or `null` if nothing is found.


#### `pickMultipleObjectsAsync` {#pickmultipleobjectsasync}

Performs deep picking. Finds all close pickable and visible object at the given screen coordinate, even if those objects are occluded by other objects.

```ts
await deck.pickMultipleObjectsAsync({x, y, radius, layerIds, depth, unproject3D})
```

Parameters:

* `x` (number) - x position in pixels
* `y` (number) - y position in pixels
* `radius` (number, optional) - radius of tolerance in pixels. Default `0`.
* `layerIds` (string[], optional) - a list of layer ids to query from. If not specified, then all pickable and visible layers are queried.
* `depth` - Specifies the max number of objects to return. Default `10`.
* `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`.

Returns:

* An array of [`info`](../../developer-guide/interactivity.md#the-pickinginfo-object) objects. The array will be empty if no object was picked.

Notes:

* 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.


#### `pickObjectsAsync` {#pickobjectsasync}

Get all pickable and visible objects within a bounding box.

```ts
await deck.pickObjectsAsync({x, y, width, height, layerIds, maxObjects})
```

Parameters:

* `x` (number) - left of the bounding box in pixels
* `y` (number) - top of the bouding box in pixels
* `width` (number, optional) - width of the bouding box in pixels. Default `1`.
* `height` (number, optional) - height of the bouding box in pixels. Default `1`.
* `layerIds` (string[], optional) - a list of layer ids to query from. If not specified, then all pickable and visible layers are queried.
* `maxObjects` (number, optional) - if specified, limits the number of objects that can be returned.

Returns:

* an array of unique [`info`](../../developer-guide/interactivity.md#the-pickinginfo-object) objects

Notes:

* The query methods are designed to quickly find objects by utilizing the picking buffer.
* The query methods offer more flexibility for developers to handle events compared to the built-in hover and click callbacks.

#### `pickObject` {#pickobject}

<img src="https://img.shields.io/badge/WebGPU-❌-brightgreen.svg?style=flat-square" />

Get the closest pickable and visible object at the given screen coordinate.

```js
Expand All @@ -657,6 +732,8 @@ Returns:

#### `pickMultipleObjects` {#pickmultipleobjects}

<img src="https://img.shields.io/badge/WebGPU-❌-brightgreen.svg?style=flat-square" />

Performs deep picking. Finds all close pickable and visible object at the given screen coordinate, even if those objects are occluded by other objects.

```js
Expand All @@ -683,6 +760,8 @@ Notes:

#### `pickObjects` {#pickobjects}

<img src="https://img.shields.io/badge/WebGPU-❌-brightgreen.svg?style=flat-square" />

Get all pickable and visible objects within a bounding box.

```js
Expand Down
3 changes: 3 additions & 0 deletions docs/api-reference/react/deckgl.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@ All [Deck](../core/deck.md#methods) methods are available on the `DeckGL` compon

The public methods you can call explicitly list below:

* `pickObjectAsync`
* `pickMultipleObjectsAsync`
* `pickObjectsAsync`
* `pickObject`
* `pickMultipleObjects`
* `pickObjects`
Expand Down
16 changes: 8 additions & 8 deletions docs/developer-guide/interactivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,7 @@ function App() {

While the default events handle most of the use cases, sometimes applications need more control over when and how picking is performed.

The picking engine is exposed through the [`Deck.pickObject`](../api-reference/core/deck.md#pickobject) and [`Deck.pickObjects`](../api-reference/core/deck.md#pickobjects) methods. These methods allow you to query what layers and objects within those layers are under a specific point or within a specified rectangle. They return `PickingInfo` objects as described above.
The picking engine is exposed through the [`Deck.pickObjectAsync`](../api-reference/core/deck.md#pickobjectasync) and [`Deck.pickObjectsAsync`](../api-reference/core/deck.md#pickobjectsasync) methods. These methods allow you to query what layers and objects within those layers are under a specific point or within a specified rectangle. They return `PickingInfo` objects as described above.


<Tabs groupId="language">
Expand All @@ -976,9 +976,9 @@ import {Deck} from '@deck.gl/core';

const deckInstance = new Deck({
// ...
onClick: ({x, y}) => {
onClick: async ({x, y}) => {
// Query up to 5 overlapping objects under the pointer
const pickInfos = deckInstance.pickMultipleObjects({x, y, radius: 1, depth: 5});
const pickInfos = await deckInstance.pickMultipleObjectsAsync({x, y, radius: 1, depth: 5});
console.log(pickInfo);
}
});
Expand All @@ -992,9 +992,9 @@ import {Deck, PickingInfo} from '@deck.gl/core';

const deckInstance = new Deck({
// ...
onClick: ({x, y}: PickingInfo) => {
onClick: async ({x, y}: PickingInfo) => {
// Query up to 5 overlapping objects under the pointer
const pickInfos: PickingInfo[] = deckInstance.pickMultipleObjects({x, y, radius: 1, depth: 5});
const pickInfos: PickingInfo[] = await deckInstance.pickMultipleObjectsAsync({x, y, radius: 1, depth: 5});
console.log(pickInfo);
}
});
Expand All @@ -1011,13 +1011,13 @@ import {PickingInfo} from '@deck.gl/core';
function App() {
const deckRef = useRef<DeckGL>();

const onClick = useCallback((evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
const onClick = useCallback(async (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
// Get mouse position relative to the containing div
const containerRect = evt.currentTarget.getBoundingClientRect();
const x = evt.clientX - containerRect.left;
const y = evt.clientY = containerRect.top;
// Query up to 5 overlapping objects under the pointer
const pickInfos: PickingInfo[] = deckRef.current?.pickMultipleObjects({x, y, radius: 1, depth: 5});
const pickInfos: PickingInfo[] = await deckRef.current?.pickMultipleObjectsAsync({x, y, radius: 1, depth: 5});
console.log(pickInfo);
}, [])

Expand All @@ -1031,7 +1031,7 @@ function App() {
</Tabs>


Also note that by directly calling `pickObject`, integrating deck.gl into an existing application often becomes easier since you don't have to change the application's existing approach to event handling.
Also note that by directly calling `pickObjectAsync`, integrating deck.gl into an existing application often becomes easier since you don't have to change the application's existing approach to event handling.

### Under The Hood

Expand Down
4 changes: 2 additions & 2 deletions modules/core/src/lib/deck-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export default class DeckPicker {
/**
* Pick the closest info at given coordinate
* @returns picking info
* @deprecated WebGL only - use pickObjectAsync instead
* @note WebGL only - use pickObjectAsync instead
*/
pickObject(opts: PickByPointOptions & PickOperationContext) {
return this._pickClosestObject(opts);
Expand All @@ -122,7 +122,7 @@ export default class DeckPicker {
/**
* Get all unique infos within a bounding box
* @returns all unique infos within a bounding box
* @deprecated WebGL only - use pickObjectAsync instead
* @note WebGL only - use pickObjectAsync instead
*/
pickObjects(opts: PickByRectOptions & PickOperationContext) {
return this._pickVisibleObjects(opts);
Expand Down
111 changes: 109 additions & 2 deletions modules/core/src/lib/deck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,66 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
}

/** Query the object rendered on top at a given point */
async pickObjectAsync(opts: {
/** x position in pixels */
x: number;
/** y position in pixels */
y: number;
/** Radius of tolerance in pixels. Default `0`. */
radius?: number;
/** A list of layer ids to query from. If not specified, then all pickable and visible layers are queried. */
layerIds?: string[];
/** If `true`, `info.coordinate` will be a 3D point by unprojecting the `x, y` screen coordinates onto the picked geometry. Default `false`. */
unproject3D?: boolean;
}): Promise<PickingInfo | null> {
const infos = (await this._pickAsync('pickObjectAsync', 'pickObject Time', opts)).result;
return infos.length ? infos[0] : null;
}

/* Query all rendered objects at a given point */
async pickMultipleObjectsAsync(opts: {
/** x position in pixels */
x: number;
/** y position in pixels */
y: number;
/** Radius of tolerance in pixels. Default `0`. */
radius?: number;
/** Specifies the max number of objects to return. Default `10`. */
depth?: number;
/** A list of layer ids to query from. If not specified, then all pickable and visible layers are queried. */
layerIds?: string[];
/** If `true`, `info.coordinate` will be a 3D point by unprojecting the `x, y` screen coordinates onto the picked geometry. Default `false`. */
unproject3D?: boolean;
}): Promise<PickingInfo[]> {
opts.depth = opts.depth || 10;
return (await this._pickAsync('pickObjectAsync', 'pickMultipleObjects Time', opts)).result;
}

/**
* Query all objects rendered on top within a bounding box
* @note Caveat: this method performs multiple async GPU queries, so state could potentially change between calls.
*/
async pickObjectsAsync(opts: {
/** Left of the bounding box in pixels */
x: number;
/** Top of the bounding box in pixels */
y: number;
/** Width of the bounding box in pixels. Default `1` */
width?: number;
/** Height of the bounding box in pixels. Default `1` */
height?: number;
/** A list of layer ids to query from. If not specified, then all pickable and visible layers are queried. */
layerIds?: string[];
/** If specified, limits the number of objects that can be returned. */
maxObjects?: number | null;
}): Promise<PickingInfo[]> {
return await this._pickAsync('pickObjectsAsync', 'pickObjects Time', opts);
}

/**
* Query the object rendered on top at a given point
* @deprecated WebGL only. Use `pickObjectsAsync` instead
*/
pickObject(opts: {
/** x position in pixels */
x: number;
Expand All @@ -627,7 +687,10 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
return infos.length ? infos[0] : null;
}

/* Query all rendered objects at a given point */
/**
* Query all rendered objects at a given point
* @deprecated WebGL only. Use `pickObjectsAsync` instead
*/
pickMultipleObjects(opts: {
/** x position in pixels */
x: number;
Expand All @@ -646,7 +709,10 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
return this._pick('pickObject', 'pickMultipleObjects Time', opts).result;
}

/* Query all objects rendered on top within a bounding box */
/**
* Query all objects rendered on top within a bounding box
* @deprecated WebGL only. Use `pickObjectsAsync` instead
*/
pickObjects(opts: {
/** Left of the bounding box in pixels */
x: number;
Expand Down Expand Up @@ -704,6 +770,47 @@ export default class Deck<ViewsT extends ViewOrViews = null> {

// Private Methods

private _pickAsync(
method: 'pickObjectAsync',
statKey: string,
opts: PickByPointOptions & {layerIds?: string[]}
): Promise<{
result: PickingInfo[];
emptyInfo: PickingInfo;
}>;
private _pickAsync(
method: 'pickObjectsAsync',
statKey: string,
opts: PickByRectOptions & {layerIds?: string[]}
): Promise<PickingInfo[]>;

private _pickAsync(
method: 'pickObjectAsync' | 'pickObjectsAsync',
statKey: string,
opts: (PickByPointOptions | PickByRectOptions) & {layerIds?: string[]}
) {
assert(this.deckPicker);

const {stats} = this;

stats.get('Pick Count').incrementCount();
stats.get(statKey).timeStart();

const infos = this.deckPicker[method]({
// layerManager, viewManager and effectManager are always defined if deckPicker is
layers: this.layerManager!.getLayers(opts),
views: this.viewManager!.getViews(),
viewports: this.getViewports(opts),
onViewportActive: this.layerManager!.activateViewport,
effects: this.effectManager!.getEffects(),
...opts
});

stats.get(statKey).timeEnd();

return infos;
}

private _pick(
method: 'pickObject',
statKey: string,
Expand Down
6 changes: 6 additions & 0 deletions modules/react/src/deckgl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export type DeckGLProps<ViewsT extends ViewOrViews = null> = Omit<

export type DeckGLRef<ViewsT extends ViewOrViews = null> = {
deck?: Deck<ViewsT>;
pickObjectAsync: Deck['pickObjectAsync'];
pickObjectsAsync: Deck['pickObjectsAsync'];
pickMultipleObjectsAsync: Deck['pickMultipleObjectsAsync'];
pickObject: Deck['pickObject'];
pickObjects: Deck['pickObjects'];
pickMultipleObjects: Deck['pickMultipleObjects'];
Expand All @@ -57,6 +60,9 @@ function getRefHandles<ViewsT extends ViewOrViews>(
return thisRef.deck;
},
// The following method can only be called after ref is available, by which point deck is defined in useEffect
pickObjectAsync: opts => thisRef.deck!.pickObjectAsync(opts),
pickMultipleObjectsAsync: opts => thisRef.deck!.pickMultipleObjectsAsync(opts),
pickObjectsAsync: opts => thisRef.deck!.pickObjectsAsync(opts),
pickObject: opts => thisRef.deck!.pickObject(opts),
pickMultipleObjects: opts => thisRef.deck!.pickMultipleObjects(opts),
pickObjects: opts => thisRef.deck!.pickObjects(opts)
Expand Down
Loading