@itwin/core-frontend
Version:
iTwin.js frontend components
336 lines • 11.6 kB
JavaScript
"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.SheetViewAttachments = void 0;
const core_common_1 = require("@itwin/core-common");
const core_bentley_1 = require("@itwin/core-bentley");
const IModelApp_1 = require("../IModelApp");
const ViewAttachmentRenderer_1 = require("./ViewAttachmentRenderer");
const Frustum2d_1 = require("../Frustum2d");
/** Stateless state for a sheet that has no view attachments. */
class EmptyAttachments {
// We only need one instance of this stateless class.
static _instance;
static get() {
return this._instance ?? (this._instance = new EmptyAttachments());
}
constructor() { }
clone() {
return this;
}
preload() { }
async postload() {
return this;
}
get attachmentIds() {
return [];
}
}
/** Holds the element Ids of the view attachments to be loaded for display. */
class AttachmentIds {
_ids;
constructor(ids) {
this._ids = ids;
}
get attachmentIds() {
return this._ids;
}
clone() {
return new AttachmentIds([...this._ids]);
}
preload(request) {
request.sheetViewAttachmentIds = core_bentley_1.CompressedId64Set.sortAndCompress(this._ids);
request.viewStateLoadProps = {
displayStyle: {
omitScheduleScriptElementIds: !IModelApp_1.IModelApp.tileAdmin.enableFrontendScheduleScripts,
compressExcludedElementIds: true,
},
};
}
async postload(response, iModel) {
if (undefined === response.sheetViewViews || undefined === response.sheetViewAttachmentProps) {
return this;
}
const viewStateProps = response.sheetViewViews;
const promises = [];
for (const viewProps of viewStateProps) {
const loadView = async () => {
try {
if (viewProps === undefined)
return undefined;
const view = await iModel.views.convertViewStatePropsToViewState(viewProps);
return view;
}
catch {
return undefined;
}
};
promises.push(loadView());
}
const views = await Promise.all(promises);
const attachmentProps = response.sheetViewAttachmentProps;
(0, core_bentley_1.assert)(views.length === attachmentProps.length);
const infos = [];
for (let i = 0; i < views.length; i++) {
const view = views[i];
if (view && !(view.isSheetView())) {
const props = attachmentProps[i];
props.attachedView = view;
infos.push(props);
}
}
return new AttachmentInfos(infos);
}
}
/** Fully loaded view attachments. */
class AttachmentInfos {
infos;
constructor(infos) {
this.infos = infos;
}
get attachmentIds() {
return this.infos.map((x) => (0, core_bentley_1.expectDefined)(x.id));
}
clone(iModel) {
const infos = this.infos.map((info) => {
return {
...info,
attachedView: info.attachedView.clone(iModel),
};
});
return new AttachmentInfos(infos);
}
preload() {
// already loaded.
}
async postload() {
// already loaded.
return this;
}
}
/** Reloads the attachments after a change to the database. */
async function reloadAttachments(sheetModelId, iModel) {
const ecsql = `SELECT ECInstanceId as attachmentId FROM bis.ViewAttachment WHERE model.Id=${sheetModelId}`;
const ids = [];
for await (const row of iModel.createQueryReader(ecsql)) {
ids.push(row[0]);
}
const attachmentProps = await iModel.elements.getProps(ids);
const promises = [];
for (const attachment of attachmentProps) {
const loadView = async () => {
try {
const view = await iModel.views.load(attachment.view.id);
return view;
}
catch {
return undefined;
}
};
promises.push(loadView());
}
const views = await Promise.all(promises);
(0, core_bentley_1.assert)(views.length === attachmentProps.length);
const infos = [];
for (let i = 0; i < views.length; i++) {
const view = views[i];
if (view && !view.isSheetView()) {
const props = attachmentProps[i];
props.attachedView = view;
infos.push(props);
}
}
return new AttachmentInfos(infos);
}
function disposeRenderers(renderers) {
if (renderers) {
for (const renderer of renderers) {
renderer[Symbol.dispose]();
}
}
}
/** Manages the set of ViewAttachment elements to be rendered by a SheetViewState.
* Takes care of reloading them after ViewAttachment elements are modified, deleted, or inserted.
*/
class SheetViewAttachments {
_impl;
_reload;
_maxDepth = Frustum2d_1.Frustum2d.minimumZDistance;
_rendererArgs;
_renderers;
get maxDepth() {
return this._maxDepth;
}
*getSecondaryViewports() {
if (this._renderers) {
for (const renderer of this._renderers) {
if (renderer.viewport) {
yield renderer.viewport;
}
}
}
}
constructor(impl) {
this._impl = impl;
}
[Symbol.dispose]() {
disposeRenderers(this._renderers);
this._renderers = this._rendererArgs = undefined;
this._reload = undefined;
}
static create(attachmentIds) {
const impl = attachmentIds.length === 0 ? EmptyAttachments.get() : new AttachmentIds([...attachmentIds]);
return new this(impl);
}
get attachmentIds() {
return this._impl.attachmentIds;
}
clone(iModel) {
return new SheetViewAttachments(this._impl.clone(iModel));
}
preload(request) {
this._impl.preload(request);
}
async postload(response, iModel) {
this._impl = await this._impl.postload(response, iModel);
}
async reload(sheetModelId, iModel) {
const renderers = this._renderers;
const reload = this._reload = reloadAttachments(sheetModelId, iModel);
const impl = await this._reload;
// We keep the previous renderers until reloading completes, to avoid drawing a blank view while waiting.
// Afterward, always destroy the previous renderers.
disposeRenderers(renderers);
// If reload was not called again while we waited...
if (this._reload === reload) {
this._impl = impl;
this._reload = this._renderers = undefined;
if (this._rendererArgs) {
// We are attached to a Viewport - reload the renderers.
this.loadRenderers();
}
}
}
attachToViewport(args) {
(0, core_bentley_1.assert)(undefined === this._renderers);
(0, core_bentley_1.assert)(undefined === this._rendererArgs);
this._rendererArgs = args;
this.loadRenderers();
}
detachFromViewport() {
(0, core_bentley_1.assert)(undefined !== this._rendererArgs);
this._rendererArgs = undefined;
disposeRenderers(this._renderers);
this._renderers = undefined;
}
areAllTileTreesLoaded(displayedExtents) {
if (this._reload) {
return false;
}
else if (!this._renderers) {
return true;
}
return this._renderers.every((renderer) => {
const attachmentRange = core_common_1.Placement2d.fromJSON(renderer.viewAttachmentProps.placement).calculateRange();
return !attachmentRange.intersectsRangeXY(displayedExtents) || renderer.areAllTileTreesLoaded;
});
}
discloseTileTrees(trees) {
for (const renderer of this.renderers()) {
trees.disclose(renderer);
}
}
collectStatistics(stats) {
for (const renderer of this.renderers()) {
renderer.collectStatistics(stats);
}
}
addToScene(context) {
for (const renderer of this.renderers()) {
renderer.addToScene(context);
}
}
getAttachmentViewport(args) {
const renderer = args.viewAttachmentId ? this.findRendererById(args.viewAttachmentId) : undefined;
if (!renderer) {
return undefined;
}
return args.inSectionDrawingAttachment ? renderer.viewport?.view.getAttachmentViewport({ inSectionDrawingAttachment: true }) : renderer.viewport;
}
computeDisplayTransform(args) {
const renderer = undefined !== args.viewAttachmentId ? this.findRendererById(args.viewAttachmentId) : undefined;
const ortho = renderer?.ortho;
const sheetTransform = ortho?.toSheet;
if (!sheetTransform) {
return undefined;
}
const sectionTransform = args.inSectionDrawingAttachment ? ortho.view.computeDisplayTransform(args) : undefined;
if (!sectionTransform) {
return sheetTransform.clone(args.output);
}
return sheetTransform.multiplyTransformTransform(sectionTransform, args.output);
}
/** Strictly for tests. */
areAllAttachmentsLoaded() {
return !this._reload && (!this._renderers || this._renderers.every((x) => x.areAllTileTreesLoaded));
}
/** Strictly for tests. */
get attachments() {
return this._renderers;
}
/** Strictly for tests. */
get attachmentProps() {
const infos = this._impl.infos;
if (!infos) {
return [];
}
return infos.map((x) => {
return {
...x,
attachedView: undefined,
};
});
}
/** Strictly for tests. */
get attachmentInfos() {
const infos = this._impl.infos;
return infos ?? this._impl.attachmentIds;
}
loadRenderers() {
const args = this._rendererArgs;
(0, core_bentley_1.assert)(undefined !== args);
(0, core_bentley_1.assert)(undefined === this._renderers);
this._maxDepth = Frustum2d_1.Frustum2d.minimumZDistance;
const infos = this._impl.infos;
if (!infos) {
return;
}
this._renderers = infos.map((info) => {
const renderer = (0, ViewAttachmentRenderer_1.createViewAttachmentRenderer)({
...args,
props: info,
view: info.attachedView,
});
this._maxDepth = Math.max(this._maxDepth, renderer.zDepth);
return renderer;
});
}
*renderers() {
if (this._renderers) {
for (const renderer of this._renderers) {
yield renderer;
}
}
}
findRendererById(id) {
return this._renderers?.find((x) => x.viewAttachmentProps.id === id);
}
}
exports.SheetViewAttachments = SheetViewAttachments;
//# sourceMappingURL=SheetViewAttachments.js.map