From 7d9dbb490e88225273d6456b93e2d0a63f0d118a Mon Sep 17 00:00:00 2001 From: Thibaut Tiberghien Date: Thu, 14 Mar 2024 12:14:33 +0800 Subject: [PATCH 1/4] add sync queries --- docs/api-reference/queryclient/furniture.md | 71 +++++++++++++++++++ docs/api-reference/queryclient/geometry.md | 14 ++++ docs/api-reference/queryclient/queryclient.md | 2 + docs/api-reference/queryclient/spaces.md | 20 ++++++ 4 files changed, 107 insertions(+) diff --git a/docs/api-reference/queryclient/furniture.md b/docs/api-reference/queryclient/furniture.md index 2d99155..5f61bd5 100644 --- a/docs/api-reference/queryclient/furniture.md +++ b/docs/api-reference/queryclient/furniture.md @@ -53,6 +53,16 @@ smplrClient.getAllFurnitureInSpace(id: string): Promise - `id` - unique identifier of the space in Smplrspace, something like "fbc5617e-5a27-4138-851e-839446121b2e". - `Furniture` - this main interface is described [here](#furniture-interface). +## getAllFurnitureInSpaceFromCache + +This is the synchronous equivalent of the query right above. + +```ts +smplrClient.getAllFurnitureInSpaceFromCache(id: string): Furniture[] +``` + +where `id` and `Furniture` are as defined in `getAllFurnitureInSpace`. + ## getFurnitureOnLevel To list all furniture from a single level in a space, you can call the following query. @@ -68,6 +78,19 @@ smplrClient.getFurnitureOnLevel({ - `levelIndex` - zero-based index of the level. Refer to the [Furniture interface](#furniture-interface) to learn more. - `Furniture` - this main interface is described [here](#furniture-interface). +## getFurnitureOnLevelFromCache + +This is the synchronous equivalent of the query right above. + +```ts +smplrClient.getFurnitureOnLevelFromCache({ + spaceId: string, + levelIndex: number +}): Furniture[] +``` + +where `spaceId`, `levelIndex`, and `Furniture` are as defined in `getFurnitureOnLevel`. + ## getFurnitureInPolygon To list all furniture contained within an area defined by a polygon, you can call the following query. @@ -87,6 +110,23 @@ smplrClient.getFurnitureInPolygon({ - `polygon` - the definition of the area used as a mask to extract furniture. It has the same schema as the coordinates from the [polygon data layers](/api-reference/space/data-layers#polygon-layer). It is assumed here that all coordinates have the same `levelIndex` value. - `Furniture` - this main interface is described [here](#furniture-interface). +## getFurnitureInPolygonFromCache + +This is the synchronous equivalent of the query right above. + +```ts +smplrClient.getFurnitureInPolygonFromCache({ + spaceId: string, + polygon: { + levelIndex: number, + x: number, + z: number + }[] +}): Furniture[] +``` + +where `spaceId`, `polygon`, and `Furniture` are as defined in `getFurnitureInPolygon`. + ## getFurnitureById To extract a single piece of furniture from a space, identified by its unique identifier, you can call the following query. @@ -104,6 +144,19 @@ smplrClient.getFurnitureById({ Returns `null` if the furniture is not found in the space. +## getFurnitureByIdFromCache + +This is the synchronous equivalent of the query right above. + +```ts +smplrClient.getFurnitureByIdFromCache({ + spaceId: string, + furnitureId: string +}): Furniture | null +``` + +where `spaceId`, `furnitureId`, and `Furniture` are as defined in `getFurnitureById`. + ## isFurnitureInPolygon To know whether a piece of furniture is contained within an area defined by a polygon, you can call the following query. @@ -128,6 +181,24 @@ Returns `null` if the furniture is not found in the space, `false` if it is foun A similar query is available for points, see [isPointInPolygon](/api-reference/queryclient/geometry#ispointinpolygon). +## isFurnitureInPolygonFromCache + +This is the synchronous equivalent of the query right above. + +```ts +smplrClient.isFurnitureInPolygonFromCache({ + spaceId: string, + furnitureId: string, + polygon: { + levelIndex: number, + x: number, + z: number + }[] +}): boolean | null +``` + +where `spaceId`, `furnitureId`, and `polygon` are as defined in `isFurnitureInPolygon`. + ## Need any other data? [Get in touch](mailto:support@smplrspace.com) with any use-case that would require new queries to be exposed. diff --git a/docs/api-reference/queryclient/geometry.md b/docs/api-reference/queryclient/geometry.md index bd76594..bd05e66 100644 --- a/docs/api-reference/queryclient/geometry.md +++ b/docs/api-reference/queryclient/geometry.md @@ -103,6 +103,20 @@ smplrClient.getLevelBoundingBox({ - `levelIndex` - zero-based index of the level. Refer to the [Furniture interface](/api-reference/queryclient/furniture#furniture-interface) to learn more. - `padding` - _optional_ - minimum space between the floor plate's grounds/walls and the bounding box in meters. _Default value: 0_ +## getLevelBoundingBoxFromCache + +This is the synchronous equivalent of the query right above. + +```ts +smplrClient.getLevelBoundingBoxFromCache({ + spaceId: string, + levelIndex: number, + padding?: number +}): BoundingBox +``` + +where `spaceId`, `levelIndex`, `padding`, and `BoundingBox` are as defined in `getLevelBoundingBox`. + ## getPointsConcaveHull The concave hull of a set of points is the smallest polygon that contains all the points, similar to a contour. To get the concave hull of a set of points, you can call the following query. diff --git a/docs/api-reference/queryclient/queryclient.md b/docs/api-reference/queryclient/queryclient.md index d750659..3f94481 100644 --- a/docs/api-reference/queryclient/queryclient.md +++ b/docs/api-reference/queryclient/queryclient.md @@ -35,6 +35,8 @@ const smplrClient = new smplr.QueryClient({ Some queries exposed via `QueryClient` are synchronous, while others return a `Promise` ([MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)) to the resulting data, and throw structured errors if any. You can consume such queries and handle errors as per your preference using `Promise.then().catch()` or `async/await` with a `try/catch` block. +We also provide a synchronous version for most asynchronous queries, relying on the caching of the space information fetched from the API. So, e.g., if you need to get the location of a bunch of furniture pieces, you can call `getSpace` once and then map over furniture synchronously to extract the location with `getFurnitureById`. + ### Using async/await ```js diff --git a/docs/api-reference/queryclient/spaces.md b/docs/api-reference/queryclient/spaces.md index 4b5e0f4..19fecfc 100644 --- a/docs/api-reference/queryclient/spaces.md +++ b/docs/api-reference/queryclient/spaces.md @@ -27,6 +27,16 @@ smplrClient.getSpace(id: string, options?: { useCache?: boolean }): Promise<{ - `options` - _optional_ - as described below. - `options.useCache` - _optional_ - set this to control whether the request should use the client's local cache. _Default value: false_ +## getSpaceFromCache + +This is the synchronous equivalent of the query right above. + +```ts +smplrClient.getSpaceFromCache(id: string): Space +``` + +where `id` and `Space` are as defined in `getSpace`, without the `Promise`. + ## getSpaceAssetmap To get the full assetmap of a space, as saved in the mapper UI, you can call the following query. @@ -39,6 +49,16 @@ smplrClient.getSpaceAssetmap(id: string): Promise Note that this query is currently not typed as the mapper is still in private beta. You should expect an array of "asset groups", each "asset group" being an object. The return value corresponds to the JSON export from the mapper UI. +## getSpaceAssetmapFromCache + +This is the synchronous equivalent of the query right above. + +```ts +smplrClient.getSpaceAssetmapFromCache(id: string): unknown +``` + +where `id` and the return value are as defined in `getSpaceAssetmap`. + ## Need any other data? [Get in touch](mailto:support@smplrspace.com) with any use-case that would require new queries to be exposed. From 98bdb840533a070d035575cbc5c60a621f1abad6 Mon Sep 17 00:00:00 2001 From: Thibaut Tiberghien Date: Thu, 14 Mar 2024 13:04:54 +0800 Subject: [PATCH 2/4] fix previous PR --- docs/api-reference/queryclient/queryclient.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-reference/queryclient/queryclient.md b/docs/api-reference/queryclient/queryclient.md index 3f94481..f84faee 100644 --- a/docs/api-reference/queryclient/queryclient.md +++ b/docs/api-reference/queryclient/queryclient.md @@ -35,7 +35,7 @@ const smplrClient = new smplr.QueryClient({ Some queries exposed via `QueryClient` are synchronous, while others return a `Promise` ([MDN docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)) to the resulting data, and throw structured errors if any. You can consume such queries and handle errors as per your preference using `Promise.then().catch()` or `async/await` with a `try/catch` block. -We also provide a synchronous version for most asynchronous queries, relying on the caching of the space information fetched from the API. So, e.g., if you need to get the location of a bunch of furniture pieces, you can call `getSpace` once and then map over furniture synchronously to extract the location with `getFurnitureById`. +We also provide a synchronous version for most asynchronous queries, relying on the caching of the space information fetched from the API. So, e.g., if you need to get the location of a bunch of furniture pieces, you can call `getSpace` once and then map over furniture synchronously to extract the location with `getFurnitureByIdFromCache`. ### Using async/await From 9857260954316aa11ad79a82a7c11a942da02569 Mon Sep 17 00:00:00 2001 From: Thibaut Tiberghien Date: Thu, 14 Mar 2024 13:26:32 +0800 Subject: [PATCH 3/4] render options --- docs/api-reference/space/custom-ux.md | 97 ++++++++++++++++++--------- 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/docs/api-reference/space/custom-ux.md b/docs/api-reference/space/custom-ux.md index 6de2f6c..211bd59 100644 --- a/docs/api-reference/space/custom-ux.md +++ b/docs/api-reference/space/custom-ux.md @@ -6,31 +6,59 @@ sidebar_position: 3 Smplr.js provides a few options that help you customize the floor plan experience to your requirements. We're regularly adding new options, so [reach out](https://www.smplrspace.com/support) and share what you'd like to do with it. -## Viewer options +## Adapting the look & feel and experience + +### Render options + +To customize how the viewer renders the space, you can pass in a number of options to the rendering engine. Below are the options currently exposed. Render options should be passed through `startViewer` as described [right below](#viewer-options), or updated dynamically as described [further](#update-render-options-dynamically). + +```ts +interface RenderOptions { + backgroundColor?: string; + grounds?: { + render?: boolean; + }; + walls?: { + render?: boolean; + alpha?: number; + maxHeightCm?: number; + showStructuralWalls?: boolean; + }; + objects?: boolean; + annotations?: boolean; + compass?: boolean; + skybox?: boolean; + floorplan?: { + render?: boolean; + alpha?: number; + elevationInCm?: number; + }; +} +``` + +- `backgroundColor` - _optional_ - lets you change the background color used by the viewer. You can pass any valid CSS color string, such as 'pink' or '#81b1b3'. We advise to set the same background color on the container element to keep the load screen consistent. As for the preview image, you can change its background color to match in the editor: go to the 'Services' tab and click 'Create preview image'. +- `walls.render` - _optional_ - set this value to control whether the walls are rendered or not. Note that with `render: false`, doors and windows will not be rendered either. You can use `alpha: 0` instead if you want to render doors and windows but not walls. _Default value: true_ +- `walls.alpha` - _optional_ - is a number between 0 and 1 setting the opacity of the walls, 0 being transparent and 1 opaque. _Default value: 1_ +- `walls.maxHeightCm` - _optional_ - will cap the rendering of walls to the height provided in centimeter, ignoring the actual height of walls. +- `walls.showStructuralWalls` - _optional_ - set this value to control whether the structural walls (if any) are rendered or not. This also removes the controls from the viewer. _Default value: unset (use button control)_ +- `objects` - _optional_ - set this value to control whether the furniture and objects (if any) are rendered or not. _Default value: true_ +- `annotations` - _optional_ - set this value to control whether the annotations (if any) are rendered or not. This also removes the show/hide annotations button from the viewer. _Default value: unset (use button control)_ +- `compass` - _optional_ - set this value to control whether the compass (if any) is rendered or not. This also removes the show/hide compass button from the viewer. _Default value: unset (use button control)_ +- `skybox` - _optional_ - set this value to control whether the skybox is rendered or not. _Default value: false_ +- `floorplan.render` - _optional_ - set this value to control whether the floor plan image (if any) is rendered or not. Note that for multi-storey spaces, all levels will have their floor plan image rendered. _Default value: false_ +- `floorplan.alpha` - _optional_ - is a number between 0 and 1 setting the opacity of the floor plan image, 0 being transparent and 1 opaque. _Default value: 0.5_ +- `floorplan.elevationInCm` - _optional_ - is a number in centimeter setting the elevation from the ground at which the floor plan image is rendered. _Default value: 2_ + +[Get in touch](mailto:support@smplrspace.com) if you have thoughts on other parameters we could expose to better support your needs. + +### Viewer options You can set a number of options when starting the viewer. They are listed below in addition to the basic viewer controls documented in the [overview](./overview#start-the-viewer) page. ```ts space.startViewer({ // ...basicControls - renderOptions?: { - backgroundColor?: string, - walls?: { - render?: boolean, - alpha?: number, - maxHeightCm?: number, - showStructuralWalls?: boolean - }, - objects?: boolean, - annotations?: boolean, - compass?: boolean, - skybox?: boolean, - floorplan?: { - render?: boolean - alpha?: number - elevationInCm?: number - } - }, + renderOptions?: RenderOptions, cameraPlacement?: { alpha: number, beta: number, @@ -48,18 +76,7 @@ space.startViewer({ ``` - `...basicControls` - refer to the [overview](./overview#start-the-viewer) page. -- `renderOptions.backgroundColor` - _optional_ - lets you change the background color used by the viewer. You can pass any valid CSS color string, such as 'pink' or '#81b1b3'. We advise to set the same background color on the container element to keep the load screen consistent. As for the preview image, you can change its background color to match in the editor: go to the 'Services' tab and click 'Create preview image'. -- `renderOptions.walls.render` - _optional_ - set this value to control whether the walls are rendered or not. Note that with `render: false`, doors and windows will not be rendered either. You can use `alpha: 0` instead if you want to render doors and windows but not walls. _Default value: true_ -- `renderOptions.walls.alpha` - _optional_ - is a number between 0 and 1 setting the opacity of the walls, 0 being transparent and 1 opaque. _Default value: 1_ -- `renderOptions.walls.maxHeightCm` - _optional_ - will cap the rendering of walls to the height provided in centimeter, ignoring the actual height of walls. -- `renderOptions.walls.showStructuralWalls` - _optional_ - set this value to control whether the structural walls (if any) are rendered or not. This also removes the controls from the viewer. _Default value: unset (use button control)_ -- `renderOptions.objects` - _optional_ - set this value to control whether the furniture and objects (if any) are rendered or not. _Default value: true_ -- `renderOptions.annotations` - _optional_ - set this value to control whether the annotations (if any) are rendered or not. This also removes the show/hide annotations button from the viewer. _Default value: unset (use button control)_ -- `renderOptions.compass` - _optional_ - set this value to control whether the compass (if any) is rendered or not. This also removes the show/hide compass button from the viewer. _Default value: unset (use button control)_ -- `renderOptions.skybox` - _optional_ - set this value to control whether the skybox is rendered or not. _Default value: false_ -- `renderOptions.floorplan.render` - _optional_ - set this value to control whether the floor plan image (if any) is rendered or not. Note that for multi-storey spaces, all levels will have their floor plan image rendered. _Default value: false_ -- `renderOptions.floorplan.alpha` - _optional_ - is a number between 0 and 1 setting the opacity of the floor plan image, 0 being transparent and 1 opaque. _Default value: 0.5_ -- `renderOptions.floorplan.elevationInCm` - _optional_ - is a number in centimeter setting the elevation from the ground at which the floor plan image is rendered. _Default value: 2_ +- `renderOptions` - _optional_ - is described above in [Render options](#render-options). _Default value: `{}`_. - `cameraPlacement` - _optional_ - set the initial position and direction of the camera. See [camera controls](./custom-ux#camera-controls) for more details. - `disableCameraControls` - _optional_ - set this to true so the camera placement cannot be changed by the user. This disables mouse, touch and keyboard inputs as well as removes the zoom control buttons. _Default value: false_ - `disableCameraRotation` - _optional_ - set this to true to force a top view of the scene. It essentially gets the interactivity to match the 2D mode, but in 3D mode. _Default value: false_ @@ -67,6 +84,16 @@ space.startViewer({ ## Viewer controls +### Update render options dynamically + +Render options are described in details in [Render options](#render-options). They can be set when the viewer starts, but if you need to update them dynamically, you should use the method below: + +```ts +space.updateRenderOptions(options: RenderOptions) => void +``` + +- `options` is an object of the [`RenderOptions`](#render-options) interface, which is deeply merged with the current options used by the viewer. To "unset" an optional value, you can pass `undefined` explicitely. + ### Control which levels are visible This is the programmatic equivalent to pressing the level buttons in the bottom-left controls: @@ -77,6 +104,14 @@ space.showUpToLevel(levelIndex: number) => void - `levelIndex` - zero-based index of the top level you want to see. For example, setting `levelIndex` to `2` is equivalent to pressing the `L3` button. +### Show all levels + +Building on the previous function, you can also reset the viewer back to showing all the floors with: + +```ts +space.showAllLevels() => void +``` + ## Camera controls ### Get the camera placement From cfa3a186b08391eef5127f259a5e7813b6b77d1c Mon Sep 17 00:00:00 2001 From: Thibaut Tiberghien Date: Thu, 14 Mar 2024 13:48:21 +0800 Subject: [PATCH 4/4] include levels --- docs/api-reference/space/custom-ux.md | 26 ++++++++++++++++++++++---- docs/api-reference/space/space.md | 2 +- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/api-reference/space/custom-ux.md b/docs/api-reference/space/custom-ux.md index 211bd59..2022a14 100644 --- a/docs/api-reference/space/custom-ux.md +++ b/docs/api-reference/space/custom-ux.md @@ -59,6 +59,8 @@ You can set a number of options when starting the viewer. They are listed below space.startViewer({ // ...basicControls renderOptions?: RenderOptions, + topShownLevel?: number, + includeLevels?: number[], cameraPlacement?: { alpha: number, beta: number, @@ -77,6 +79,8 @@ space.startViewer({ - `...basicControls` - refer to the [overview](./overview#start-the-viewer) page. - `renderOptions` - _optional_ - is described above in [Render options](#render-options). _Default value: `{}`_. +- `topShownLevel` - _optional_ - lets you set the initial level the viewer should navigate to. See details in [Navigating levels](#navigate-levels). +- `includeLevels` - _optional_ - list of zero-based indices of the levels to render. See [`includeLevels`](#control-which-levels-are-included-in-the-render) for details. - `cameraPlacement` - _optional_ - set the initial position and direction of the camera. See [camera controls](./custom-ux#camera-controls) for more details. - `disableCameraControls` - _optional_ - set this to true so the camera placement cannot be changed by the user. This disables mouse, touch and keyboard inputs as well as removes the zoom control buttons. _Default value: false_ - `disableCameraRotation` - _optional_ - set this to true to force a top view of the scene. It essentially gets the interactivity to match the 2D mode, but in 3D mode. _Default value: false_ @@ -94,7 +98,7 @@ space.updateRenderOptions(options: RenderOptions) => void - `options` is an object of the [`RenderOptions`](#render-options) interface, which is deeply merged with the current options used by the viewer. To "unset" an optional value, you can pass `undefined` explicitely. -### Control which levels are visible +### Navigate levels This is the programmatic equivalent to pressing the level buttons in the bottom-left controls: @@ -104,14 +108,28 @@ space.showUpToLevel(levelIndex: number) => void - `levelIndex` - zero-based index of the top level you want to see. For example, setting `levelIndex` to `2` is equivalent to pressing the `L3` button. -### Show all levels - -Building on the previous function, you can also reset the viewer back to showing all the floors with: +You can also reset the viewer back to showing all the levels with: ```ts space.showAllLevels() => void ``` +### Control which levels are included in the render + +When you have a multi-storey building but would like to only render a few floors, you can call this method: + +```ts +space.includeLevels(levelIndices: number[]) => void +``` + +- `levelIndices` - list of zero-based indices of the levels to render. See [Navigating levels](#navigate-levels) to learn more about `levelIndex` or level indices. + +You can also reset the viewer back to rendering all levels with: + +```ts +space.includeAllLevels() => void +``` + ## Camera controls ### Get the camera placement diff --git a/docs/api-reference/space/space.md b/docs/api-reference/space/space.md index 394a819..7027022 100644 --- a/docs/api-reference/space/space.md +++ b/docs/api-reference/space/space.md @@ -57,7 +57,7 @@ space.startViewer({ - `onReady` - _optional_ - is called once the viewer's initial render is done. - `onError` - _optional_ - is called if an error occur while starting the viewer. - `onResize` - _optional_ - is called whenever the viewer is resized, including after the initial render, when the window is resized, or on mobile when the device is rotated between vertical to horizontal positions. This can be used to reposition custom tooltips (e.g.). -- `onVisibleLevelsChanged` - _optional_ - is called whenever there is a change in the visible levels. This could be through the user clicking the level picker, or through an API call of [`showUpToLevel`](/api-reference/space/custom-ux#control-which-levels-are-visible). It is also called when the space first renders. The handler take a single argument `visibleLevels`, which is the ordered list of zero-based level indices currently visible in the viewer. The last element in that list is always the highest visible level. +- `onVisibleLevelsChanged` - _optional_ - is called whenever there is a change in the visible levels. This could be through the user clicking the level picker, or through an API call of [`showUpToLevel`](/api-reference/space/custom-ux#navigate-levels). It is also called when the space first renders. The handler take a single argument `visibleLevels`, which is the ordered list of zero-based level indices currently visible in the viewer. The last element in that list is always the highest visible level. - `...customUX` represents additional options that let you customise the user experience as documented in the [custom UX](./custom-ux#viewer-options) page. Although not a rule not to break, we generally _recommend_ to use `preview: true` as this avoids loading the space if the user do not intend to interact with it. It also helps with reducing the number of views counted on your spaces.