@itwin/core-frontend
Version:
iTwin.js frontend components
282 lines • 11.8 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ViewCreator2d = void 0;
/** @packageDocumentation
* @module Views
*/
/*
API for creating a 2D view from a given modelId and modelType (classFullName).
Additional options (such as background color) can be passed during view creation.
*/
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const core_geometry_1 = require("@itwin/core-geometry");
const DrawingViewState_1 = require("./DrawingViewState");
const ModelState_1 = require("./ModelState");
const SheetViewState_1 = require("./SheetViewState");
/**
* API for creating a [[ViewState2d]] for a 2D model ([[GeometricModel2dState]]). @see [[ViewCreator3d]] to create a view for a 3d model.
* Example usage:
* ```ts
* const viewCreator = new ViewCreator2d(imodel);
* const models = await imodel.models.queryProps({ from: "BisCore.GeometricModel2d" });
* if (models.length > 0)
* const view = await viewCreator.createViewForModel(models[0].id!);
* ```
* @public
* @extensions
*/
class ViewCreator2d {
_imodel;
// Types of 2D models the API supports
static _drawingModelClasses = [ModelState_1.DrawingModelState.classFullName, ModelState_1.SectionDrawingModelState.classFullName];
static _sheetModelClasses = [ModelState_1.SheetModelState.classFullName];
/**
* Constructs a ViewCreator2d using an [[IModelConnection]].
* @param _imodel [[IModelConnection]] to query for categories and/or models.
*/
constructor(_imodel) {
this._imodel = _imodel;
}
/**
* Creates and returns view for the 2D model id passed in.
* @param modelId Id of the 2D model for the view.
* @param [options] Options for creating the view.
* @throws [IModelError]($common) If modelType is not supported.
*/
async createViewForModel(modelId, options) {
const baseClassName = await this._getModelBaseClassName(modelId);
const viewState = await this._createViewState2d(modelId, baseClassName.classFullName, options);
try {
await viewState.load();
}
catch { }
return viewState;
}
/**
* Gets model base class name from id.
* @param modelId of target model.
* @throws [IModelError]($common) if modelId is invalid.
*/
async _getModelBaseClassName(modelId) {
let baseClassName;
const modelProps = await this._imodel.models.getProps(modelId);
if (modelProps.length > 0) {
const modelType = modelProps[0].classFullName;
baseClassName = await this._imodel.findClassFor(modelType, undefined);
}
else
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadModel, "ViewCreator2d._getModelBaseClassName: modelId is invalid");
if (baseClassName === undefined)
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.WrongClass, "ViewCreator2d.getViewForModel: modelType is invalid");
return baseClassName;
}
/**
* Creates view from any 2D model type (Drawing/SectionDrawing/Sheet)
* @param modelId of target model.
* @param modelType classFullName of target 2D model.
* @param options for view creation.
* @throws [IModelError]($common) if modelType is not supported.
*/
async _createViewState2d(modelId, modelType, options) {
let viewState;
if (this._isDrawingModelClass(modelType)) {
const props = await this._createViewStateProps(modelId, options);
viewState = DrawingViewState_1.DrawingViewState.createFromProps(props, this._imodel);
}
else if (this._isSheetModelClass(modelType)) {
let props = await this._createViewStateProps(modelId, options);
props = await this._addSheetViewProps(modelId, props);
viewState = SheetViewState_1.SheetViewState.createFromProps(props, this._imodel);
}
else
throw new core_common_1.IModelError(core_bentley_1.IModelStatus.WrongClass, "ViewCreator2d._createViewState2d: modelType not supported");
return viewState;
}
/**
* Checks to see if given model is of [[DrawingModelState]].
* @param modelType classFullName of model.
*/
_isDrawingModelClass(modelType) {
if (ViewCreator2d._drawingModelClasses.includes(modelType)) {
return true;
}
return false;
}
/**
* Checks to see if given model is of [[SheetModelState]].
* @param modelType classFullName of model.
*/
_isSheetModelClass(modelType) {
if (ViewCreator2d._sheetModelClasses.includes(modelType)) {
return true;
}
return false;
}
/**
* Creates ViewStateProps for the model. ViewStateProps are composed of the 4 sets of Props below.
* @param modelId of target model.
* @param options for view creation.
*/
_createViewStateProps = async (modelId, options) => {
// Use dictionary model in all props
const dictionaryId = core_common_1.IModel.dictionaryId;
const categories = await this._getAllCategories();
// Get bg color from options or default to white
const bgColor = options?.bgColor ? options.bgColor : core_common_1.ColorDef.white;
// model extents
const modelProps = await this._imodel.models.queryExtents(modelId);
const modelExtents = core_geometry_1.Range3d.fromJSON(modelProps[0]?.extents);
let originX = modelExtents.low.x;
let originY = modelExtents.low.y;
let deltaX = modelExtents.xLength();
let deltaY = modelExtents.yLength();
// if vp aspect given, update model extents to fit view
if (options?.vpAspect) {
const modelAspect = deltaY / deltaX;
if (modelAspect > options.vpAspect) {
const xFix = deltaY / options.vpAspect;
originX = originX - xFix / 2;
deltaX = deltaX + xFix;
}
else if (modelAspect < options.vpAspect) {
const yFix = deltaX * options.vpAspect;
originY = originY - yFix / 2;
deltaY = deltaY + yFix;
}
}
const modelSelectorProps = {
models: [modelId],
code: core_common_1.Code.createEmpty(),
model: dictionaryId,
classFullName: "BisCore:ModelSelector",
};
const categorySelectorProps = {
categories,
code: core_common_1.Code.createEmpty(),
model: dictionaryId,
classFullName: "BisCore:CategorySelector",
};
const viewDefinitionProps = {
baseModelId: modelId,
categorySelectorId: "",
displayStyleId: "",
origin: { x: originX, y: originY },
delta: { x: deltaX, y: deltaY },
angle: { radians: 0 },
code: core_common_1.Code.createEmpty(),
model: dictionaryId,
classFullName: "BisCore:ViewDefinition2d",
};
const displayStyleProps = {
code: core_common_1.Code.createEmpty(),
model: dictionaryId,
classFullName: "BisCore:DisplayStyle2d",
jsonProperties: {
styles: {
backgroundColor: bgColor.tbgr,
},
},
};
const viewStateProps = {
displayStyleProps,
categorySelectorProps,
modelSelectorProps,
viewDefinitionProps,
modelExtents,
};
// merge seed view props if needed
return options?.useSeedView ? this._mergeSeedView(modelId, viewStateProps) : viewStateProps;
};
/**
* Adds Sheet view props to given view props.
* @param modelId of target model.
* @param props input ViewStateProps.
*/
async _addSheetViewProps(modelId, props) {
let width = 0;
let height = 0;
for await (const row of this._imodel.createQueryReader(`SELECT Width, Height FROM bis.Sheet WHERE ECInstanceId = ?`, core_common_1.QueryBinder.from([modelId]), { rowFormat: core_common_1.QueryRowFormat.UseJsPropertyNames })) {
width = row.width;
height = row.height;
break;
}
const sheetProps = {
model: modelId,
code: { spec: "", scope: "" },
classFullName: "DrawingSheetModel",
height,
width,
};
props.sheetAttachments = await this._getSheetAttachments(modelId);
props.sheetProps = sheetProps;
return props;
}
/**
* Merges a seed view in the iModel with the passed view state props. It will be a no-op if there are no 2D views for target model.
* @param modelId of target model.
* @param props Input view props to be merged
*/
async _mergeSeedView(modelId, props) {
const viewDefinitionId = await this._getViewDefinitionsIdForModel(modelId);
// Return incase no viewDefinition found.
if (viewDefinitionId === undefined)
return props;
const seedViewState = (await this._imodel.views.load(viewDefinitionId));
const seedViewStateProps = {
categorySelectorProps: seedViewState.categorySelector.toJSON(),
viewDefinitionProps: seedViewState.toJSON(),
displayStyleProps: seedViewState.displayStyle.toJSON(),
};
const mergedDisplayProps = seedViewStateProps.displayStyleProps;
if (mergedDisplayProps.jsonProperties !== undefined) {
mergedDisplayProps.jsonProperties.styles = {
...mergedDisplayProps.jsonProperties.styles,
...props.displayStyleProps.jsonProperties.styles,
};
}
return { ...seedViewStateProps, ...props, displayStyleProps: mergedDisplayProps };
}
/**
* Get all view definitions for a given model.
* @param modelId of target model.
*/
async _getViewDefinitionsIdForModel(modelId) {
const query = `SELECT ECInstanceId from Bis.ViewDefinition2D WHERE BaseModel.Id = ${modelId} AND isPrivate = false LIMIT 1`;
const viewDefinitionsId = await this._executeQuery(query);
return (viewDefinitionsId.length) > 0 ? viewDefinitionsId[0] : undefined;
}
/**
* Get all drawing categories
*/
async _getAllCategories() {
const query = "SELECT ECInstanceId from BisCore.DrawingCategory";
const categories = await this._executeQuery(query);
return categories;
}
/**
* Get all sheet attachments
* @param modelId of target model.
*/
async _getSheetAttachments(modelId) {
const query = `SELECT ECInstanceId FROM Bis.ViewAttachment WHERE Model.Id = ${modelId}`;
const attachments = await this._executeQuery(query);
return attachments;
}
/**
* Helper function to execute ECSql queries.
* @param query statement to execute.
*/
_executeQuery = async (query) => {
const rows = [];
for await (const row of this._imodel.createQueryReader(query, undefined, { rowFormat: core_common_1.QueryRowFormat.UseJsPropertyNames }))
rows.push(row.id);
return rows;
};
}
exports.ViewCreator2d = ViewCreator2d;
//# sourceMappingURL=ViewCreator2d.js.map
;