diff --git a/docs/api-reference/core/deck.md b/docs/api-reference/core/deck.md
index 9ca84f62459..def0032eeaf 100644
--- a/docs/api-reference/core/deck.md
+++ b/docs/api-reference/core/deck.md
@@ -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}
+
+
Get the closest pickable and visible object at the given screen coordinate.
```js
@@ -657,6 +732,8 @@ Returns:
#### `pickMultipleObjects` {#pickmultipleobjects}
+
+
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
@@ -683,6 +760,8 @@ Notes:
#### `pickObjects` {#pickobjects}
+
+
Get all pickable and visible objects within a bounding box.
```js
diff --git a/docs/api-reference/react/deckgl.md b/docs/api-reference/react/deckgl.md
index 236a2bb5546..f87a99b6da6 100644
--- a/docs/api-reference/react/deckgl.md
+++ b/docs/api-reference/react/deckgl.md
@@ -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`
diff --git a/docs/developer-guide/interactivity.md b/docs/developer-guide/interactivity.md
index 158d9d639e8..a7cc2fb5a33 100644
--- a/docs/developer-guide/interactivity.md
+++ b/docs/developer-guide/interactivity.md
@@ -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.
@@ -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);
}
});
@@ -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);
}
});
@@ -1011,13 +1011,13 @@ import {PickingInfo} from '@deck.gl/core';
function App() {
const deckRef = useRef();
- const onClick = useCallback((evt: React.MouseEvent) => {
+ const onClick = useCallback(async (evt: React.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);
}, [])
@@ -1031,7 +1031,7 @@ function App() {
-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
diff --git a/modules/core/src/lib/deck-picker.ts b/modules/core/src/lib/deck-picker.ts
index e13036669b0..77a9f14167d 100644
--- a/modules/core/src/lib/deck-picker.ts
+++ b/modules/core/src/lib/deck-picker.ts
@@ -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);
@@ -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);
diff --git a/modules/core/src/lib/deck.ts b/modules/core/src/lib/deck.ts
index 47906599727..d0904926d8e 100644
--- a/modules/core/src/lib/deck.ts
+++ b/modules/core/src/lib/deck.ts
@@ -611,6 +611,66 @@ export default class Deck {
}
/** 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 {
+ 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 {
+ 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 {
+ 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;
@@ -627,7 +687,10 @@ export default class Deck {
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;
@@ -646,7 +709,10 @@ export default class Deck {
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;
@@ -704,6 +770,47 @@ export default class Deck {
// 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;
+
+ 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,
diff --git a/modules/react/src/deckgl.ts b/modules/react/src/deckgl.ts
index c60e1486785..ae99ffec26d 100644
--- a/modules/react/src/deckgl.ts
+++ b/modules/react/src/deckgl.ts
@@ -44,6 +44,9 @@ export type DeckGLProps = Omit<
export type DeckGLRef = {
deck?: Deck;
+ pickObjectAsync: Deck['pickObjectAsync'];
+ pickObjectsAsync: Deck['pickObjectsAsync'];
+ pickMultipleObjectsAsync: Deck['pickMultipleObjectsAsync'];
pickObject: Deck['pickObject'];
pickObjects: Deck['pickObjects'];
pickMultipleObjects: Deck['pickMultipleObjects'];
@@ -57,6 +60,9 @@ function getRefHandles(
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)