UNPKG

@itwin/core-frontend

Version:
185 lines • 10 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Views */ Object.defineProperty(exports, "__esModule", { value: true }); exports.TwoWayViewportFrustumSync = exports.TwoWayViewportSync = void 0; exports.connectViewports = connectViewports; exports.synchronizeViewportViews = synchronizeViewportViews; exports.synchronizeViewportFrusta = synchronizeViewportFrusta; exports.connectViewportFrusta = connectViewportFrusta; exports.connectViewportViews = connectViewportViews; /** Forms a connection between two or more [[Viewport]]s such that a change in any one of the viewports is reflected in all of the others. * When the connection is first formed, all of the viewports are synchronized to the current state of the **first** viewport in `viewports`. * Thereafter, an event listener registered with each viewport's [[Viewport.onViewChanged]] event is invoked when anything about that viewport's state changes. * Each time such an event occurs, the initating ("source") viewport is passed to `sync` to obtain a function that can be invoked to synchronize each of the other * ("target") viewports with the source viewport's new state. The function returned by `sync` can choose to synchronize any or all aspects of the viewports' states, such as * the viewed volume, display style, viewed categories or models, or anything else. * * To sever the connection, invoke the function returned by this function. For example: * ```ts * // set up the connection. * const disconnect = connectViewports([viewport0, viewport1, viewport2], (changedViewport) => synchronizeViewportFrusta(changedViewport)); * // some time later, sever the connection. * disconnect(); * ``` * * @note [[Viewport.onViewChanged]] can be invoked **very** frequently - sometimes multiple times per frame. Try to avoid performing excessive computations within your synchronization functions. * * @param viewports The viewports to be connected. It should contain at least two viewports and no duplicate viewports. The initial state of each viewport will be synchronized with * the state of the first viewport in this iterable. * @param sync A function to be invoked whenever the state of any viewport in `viewports` changes, returning a function that can be used to synchronize the * state of each viewport. * @returns a function that can be invoked to sever the connection between the viewports. * @see [[connectViewportFrusta]] to synchronize the [Frustum]($common) of each viewport. * @see [[connectViewportViews]] to synchronize every aspect of the viewports. * @see [[TwoWayViewportSync]] to synchronize the state of exactly two viewports. * @see [Multiple Viewport Sample](https://www.itwinjs.org/sample-showcase/?group=Viewer+Features&sample=multi-viewport-sample&imodel=Metrostation+Sample) * @public * @extensions */ function connectViewports(viewports, sync) { const disconnect = []; let echo = false; const synchronize = (source) => { if (echo) return; // Ignore onViewChanged events resulting from synchronization. echo = true; try { const doSync = sync(source); for (const vp of viewports) if (vp !== source) doSync(source, vp); } finally { echo = false; } }; let firstViewport; for (const vp of viewports) { if (!firstViewport) firstViewport = vp; disconnect.push(vp.onViewChanged.addListener(() => synchronize(vp))); } if (firstViewport) synchronize(firstViewport); return () => { for (const f of disconnect) f(); disconnect.length = 0; }; } /** A function that returns a [[SynchronizeViewports]] function that synchronizes every aspect of the viewports' states, including * display style, model and category selectors, [Frustum]($common), etc. * @see [[connectViewportViews]] to establish a connection between viewports using this synchronization strategy. * @public * @extensions */ function synchronizeViewportViews(source) { return (_source, target) => target.applyViewState(source.view.clone(target.iModel)); } /** A function that returns a [[SynchronizeViewports]] function that synchronizes the viewed volumes of each viewport. * @see [[connectViewportFrusta]] to establish a connection between viewports using this synchronization strategy. * @public * @extensions */ function synchronizeViewportFrusta(source) { const pose = source.view.savePose(); return (_source, target) => { const view = target.view.applyPose(pose); target.applyViewState(view); }; } /** Form a connection between two or more [[Viewport]]s such that they all view the same volume. For example, zooming out in one viewport * will zoom out by the same distance in all of the other viewports. * @see [[connectViewports]] to customize how the viewports are synchronized. * @public * @extensions */ function connectViewportFrusta(viewports) { return connectViewports(viewports, (source) => synchronizeViewportFrusta(source)); } /** Form a connection between two or more [[Viewport]]s such that every aspect of the viewports are kept in sync. For example, if the set of models * or categories visible in one viewport is changed, the same set of models and categories will be visible in the other viewports. * @see [[connectViewportFrusta]] to synchronize only the [Frustum]($common) of each viewport. * @see [[connectViewports]] to customize how the viewports are synchronized. * @public * @extensions */ function connectViewportViews(viewports) { return connectViewports(viewports, (source) => synchronizeViewportViews(source)); } /** Forms a bidirectional connection between two [[Viewport]]s such that the [[ViewState]]s of each are synchronized with one another. * For example, panning in one viewport will cause the other viewport to pan by the same distance, and changing the [RenderMode]($common) of one viewport * will change it in the other viewport. * By default, all aspects of the views - display style, category and model selectors, frustum, etc - are synchronized, but this can be customized by * subclassing and overriding the [[syncViewports]] and [[connectViewports]] methods. * @see [Multiple Viewport Sample](https://www.itwinjs.org/sample-showcase/?group=Viewer+Features&sample=multi-viewport-sample&imodel=Metrostation+Sample) * for an interactive demonstration. * @see [[TwoWayViewportFrustumSync]] to synchronize only the frusta of the viewports. * @see [[connectViewportViews]] to synchronize the state of more than two viewports. * @public * @extensions */ class TwoWayViewportSync { _disconnect = []; /** Invoked from [[connect]] to set up the initial synchronization between the two viewports. * `target` should be modified to match `source`. * The default implementation applies a clone of `source`'s [[ViewState]] to `target`. * @see [[syncViewports]] to customize subsequent synchronization. */ connectViewports(source, target) { const viewState = source.view.clone(target.iModel); target.applyViewState(viewState); } /** Invoked each time `source` changes to update `target` to match. * The default implementation applies a clone of `source`'s [[ViewState]] to `target`. * @param source The viewport that changed * @param target The viewport that should be updated to match `source` * @see [[connectViewports]] to set up the initial synchronization between the two viewports. */ syncViewports(source, target) { target.applyViewState(source.view.clone(target.iModel)); } /** Establish the connection between two Viewports. When this method is called, `viewport2` is initialized with the state of `viewport1` via [[connectViewports]]. * Thereafter, any change to the frustum of either viewport will be reflected in the frustum of the other viewport via [[syncViewports]]. */ connect(viewport1, viewport2) { this.disconnect(); this.connectViewports(viewport1, viewport2); this._disconnect.push(connectViewports([viewport1, viewport2], () => (source, target) => this.syncViewports(source, target))); } /** Remove the connection between the two views. */ disconnect() { this._disconnect.forEach((f) => f()); this._disconnect.length = 0; } } exports.TwoWayViewportSync = TwoWayViewportSync; /** Forms a bidirectional connection between two [[Viewport]]s such that the [Frustum]($common)s of each are synchronized with one another. * For example, zooming out in one viewport will zoom out by the same distance in the other viewport. * No other aspects of the viewports are synchronized - they may have entirely different display styles, category/model selectors, etc. * @see [[TwoWayViewportSync]] to synchronize all aspects of the viewports. * @see [[connectViewportFrusta]] to synchronize the frusta of more than two viewports. * @public * @extensions */ class TwoWayViewportFrustumSync extends TwoWayViewportSync { /** Synchronizes the two viewports by applying `source`'s frustum to `target`. */ syncViewports(source, target) { const pose = source.view.savePose(); const view = target.view.applyPose(pose); target.applyViewState(view); } /** Sets up the initial connection between two viewports by applying `source`'s frustum to `target`. */ connectViewports(source, target) { this.syncViewports(source, target); } } exports.TwoWayViewportFrustumSync = TwoWayViewportFrustumSync; //# sourceMappingURL=ViewportSync.js.map