Skip to content

Commit

Permalink
Add utility functions for applying Saved View to a viewport (#78)
Browse files Browse the repository at this point in the history
### Breaking changes

* `captureSavedViewData`: Remove `captureHiddenModelsAndCategories`
setting from parameter bag. This function now behaves as if its value is
always `true`.
* `createViewState`: Change function signature to take `ViewData`
instead of `SavedViewRepresentation` and use parameter bag for
additional settings
* Remove experimental `ModelCategoryOverrideProvider` class
* Remove experimental `applyExtensionsToViewport` function

### Major changes

* Add `applySavedView` function
* Promote `createViewState` to public API

### Other changes

* Remove support for `VisibilityOverride` extension
  • Loading branch information
roluk authored Jun 3, 2024
1 parent d065e0a commit 1b34f64
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 320 deletions.
12 changes: 12 additions & 0 deletions packages/saved-views-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## [Unreleased](https://github.com/iTwin/saved-views/tree/HEAD/packages/saved-views-react)

### Breaking changes

* `captureSavedViewData`: Remove `captureHiddenModelsAndCategories` setting from parameter bag. This function now behaves as if its value is always `true`.
* `createViewState`: Change function signature to take `ViewData` instead of `SavedViewRepresentation` and use parameter bag for additional settings
* Remove experimental `ModelCategoryOverrideProvider` class
* Remove experimental `applyExtensionsToViewport` function

### Major changes

* Add `applySavedView` function
* Promote `createViewState` to public API

## [0.4.1](https://github.com/iTwin/saved-views/tree/v0.4.1-react/packages/saved-views-react) - 2024-05-28

* Expose parameter types used in `SavedViewsClient` methods
Expand Down
126 changes: 0 additions & 126 deletions packages/saved-views-react/src/ModelCategoryOverrideProvider.ts

This file was deleted.

112 changes: 112 additions & 0 deletions packages/saved-views-react/src/applySavedView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { ViewState, type IModelConnection, type Viewport } from "@itwin/core-frontend";
import { type SavedViewRepresentation } from "@itwin/saved-views-client";

import { createViewState } from "./createViewState.js";
import { extensionHandlers, type ExtensionHandler } from "./translation/SavedViewsExtensionHandlers.js";

export interface ApplySavedViewSettings {
/**
* Strategy to use when other setting does not specify one. By default, viewport is reset to default state and then
* all captured Saved View data is applied on top.
* @default "apply"
*
* @example
* await applySavedView(iModel, viewport, savedView, { all: "keep", viewState: "apply" });
*/
all?: ApplyStrategy | undefined;

/**
* How to handle captured {@link ViewState} data. The default behavior is to generate a new `ViewState` object and
* apply it to viewport.
*
* You can optionally provide a pre-made `ViewState` instance to conserve resources. It is usually obtained from
* {@link createViewState} result.
*
* @example
* import { applySavedView, createViewState } from "@itwin/saved-views-react";
*
* const viewState = await createViewState(iModel, savedView);
* await Promise.all([
* applySavedView(iModel, viewport1, savedView, { viewState }),
* applySavedView(iModel, viewport2, savedView, { viewState }),
* ]);
*/
viewState?: Exclude<ApplyStrategy, "reset"> | ViewState | undefined;

/**
* How to handle visibility of models and categories that exist in iModel but are not captured in Saved View data. Has
* effect only when `modelAndCategoryVisibility` strategy is set to `"apply"`.
* @default "hidden"
*/
modelAndCategoryVisibilityFallback?: "visible" | "hidden" | undefined;

/** How to handle captured element emphasis data. In default state emphasis is turned off. */
emphasis?: ApplyStrategy | undefined;

/**
* How to handle captured {@link Viewport.perModelCategoryVisibility} data. In default state no overrides are present.
*/
perModelCategoryVisibility?: ApplyStrategy | undefined;
}

/**
* Controls how viewport state is going to be altered.
*
* * `"apply"` – Apply captured Saved View state. Falls back to `"reset"` on failure (e.g. missing Saved View data).
* * `"reset"` – Reset to the default viewport state
* * `"keep"` – Keep the current viewport state
*/
type ApplyStrategy = "apply" | "reset" | "keep";

/**
* Updates {@linkcode viewport} state to match captured Saved View.
*
* @example
* // Optionally, you can create and manage ViewState object yourself to avoid redundant work,
* // e.g. when applying the same Saved View to multiple viewports
* const viewState = await createViewState(iModel, savedView);
* await Promise.all([
* applySavedView(iModel, firstViewport, savedView, { viewState }),
* applySavedView(iModel, secondViewport, savedView, { viewState }),
* ]);
*/
export async function applySavedView(
iModel: IModelConnection,
viewport: Viewport,
savedView: Pick<SavedViewRepresentation, "savedViewData" | "extensions">,
settings: ApplySavedViewSettings | undefined = {},
): Promise<void> {
const defaultStrategy = settings.all ?? "apply";

if ((settings.viewState ?? defaultStrategy) !== "keep") {
if (settings.viewState instanceof ViewState) {
viewport.changeView(settings.viewState);
} else {
const { modelAndCategoryVisibilityFallback } = settings;
const viewState = await createViewState(iModel, savedView.savedViewData, { modelAndCategoryVisibilityFallback });
viewport.changeView(viewState);
}
}

const extensions = new Map(savedView.extensions?.map(({ extensionName, data }) => [extensionName, data]));
const processExtension = (extensionHandler: ExtensionHandler, strategy: ApplyStrategy = defaultStrategy) => {
if (strategy === "keep") {
return;
}

extensionHandler.reset(viewport);
if (strategy === "apply") {
const extensionData = extensions.get(extensionHandler.extensionName);
if (extensionData) {
extensionHandler.apply(extensionData, viewport);
}
}
};

processExtension(extensionHandlers.emphasizeElements, settings.emphasis);
processExtension(extensionHandlers.perModelCategoryVisibility, settings.perModelCategoryVisibility);
}
20 changes: 6 additions & 14 deletions packages/saved-views-react/src/captureSavedViewData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,20 @@ import {
} from "./translation/displayStyleExtractor.js";

interface CaptureSavedViewDataArgs {
/** Viewport to capture the view from. */
/** Viewport to capture. */
viewport: Viewport;

/**
* Collect a list of models and categories that are currently not enabled in the {@linkcode viewport}.
* @default true
*/
captureHiddenModelsAndCategories?: boolean | undefined;
}

export async function captureSavedViewData(args: CaptureSavedViewDataArgs): Promise<ViewData> {
const { captureHiddenModelsAndCategories = true } = args;
const hiddenCategoriesPromise = captureHiddenModelsAndCategories
? getMissingCategories(args.viewport.iModel, new Set(args.viewport.view.categorySelector.toJSON().categories))
: undefined;
const hiddenCategoriesPromise = getMissingCategories(
args.viewport.iModel,
new Set(args.viewport.view.categorySelector.toJSON().categories),
);

if (args.viewport.view.isSpatialView()) {
const [hiddenCategories, hiddenModels] = await Promise.all([
hiddenCategoriesPromise,
captureHiddenModelsAndCategories
? getMissingModels(args.viewport.iModel, new Set(args.viewport.view.modelSelector.toJSON().models))
: undefined,
getMissingModels(args.viewport.iModel, new Set(args.viewport.view.modelSelector.toJSON().models)),
]);
return createSpatialSavedViewObject(args.viewport, hiddenCategories, hiddenModels);
}
Expand Down
Loading

0 comments on commit 1b34f64

Please sign in to comment.