@itwin/core-backend
Version:
iTwin.js backend components
411 lines (410 loc) • 17.1 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 Elements
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnnotationTextStyle = exports.TextAnnotation3d = exports.TextAnnotation2d = void 0;
const core_common_1 = require("@itwin/core-common");
const Element_1 = require("../Element");
const core_bentley_1 = require("@itwin/core-bentley");
const TextBlockLayout_1 = require("./TextBlockLayout");
const TextAnnotationGeometry_1 = require("./TextAnnotationGeometry");
const ElementDrivesTextAnnotation_1 = require("./ElementDrivesTextAnnotation");
function parseTextAnnotationData(json) {
if (!json)
return undefined;
try {
return JSON.parse(json);
}
catch {
return undefined;
}
}
function getElementGeometryBuilderParams(iModel, modelId, _placementProps, stringifiedAnnotationProps, categoryId, _subCategory) {
const annotationProps = parseTextAnnotationData(stringifiedAnnotationProps);
const textBlock = core_common_1.TextAnnotation.fromJSON(annotationProps).textBlock;
const textStyleResolver = new TextBlockLayout_1.TextStyleResolver({ textBlock, iModel, modelId });
const layout = (0, TextBlockLayout_1.layoutTextBlock)({ iModel, textBlock, textStyleResolver });
const builder = new core_common_1.ElementGeometry.Builder();
(0, TextAnnotationGeometry_1.appendTextAnnotationGeometry)({ layout, textStyleResolver, annotationProps: annotationProps ?? {}, builder, categoryId });
return { entryArray: builder.entries };
}
/** An element that displays textual content within a 2d model.
* The text is stored as a [TextAnnotation]($common) from which the element's [geometry]($docs/learning/common/GeometryStream.md) and [Placement]($common) are computed.
* @see [[setAnnotation]] to change the textual content.
* @public @preview
*/
class TextAnnotation2d extends Element_1.AnnotationElement2d /* implements ITextAnnotation */ {
/** @internal */
static get className() { return "TextAnnotation2d"; }
/** Optional string containing the data associated with the text annotation. */
_textAnnotationData;
/** Extract the textual content, if present.
* @see [[setAnnotation]] to change it.
*/
getAnnotation() {
const textAnnotationProps = parseTextAnnotationData(this._textAnnotationData);
return textAnnotationProps ? core_common_1.TextAnnotation.fromJSON(textAnnotationProps) : undefined;
}
/** Change the textual content of the `TextAnnotation2d`.
* @see [[getAnnotation]] to extract the current annotation.
* @param annotation The new annotation
*/
setAnnotation(annotation) {
this._textAnnotationData = annotation ? JSON.stringify(annotation.toJSON()) : undefined;
}
constructor(props, iModel) {
super(props, iModel);
this._textAnnotationData = props.textAnnotationData;
}
/** Creates a new instance of `TextAnnotation2d` from its JSON representation. */
static fromJSON(props, iModel) {
return new TextAnnotation2d(props, iModel);
}
/**
* Converts the current `TextAnnotation2d` instance to its JSON representation.
* It also computes the `elementGeometryBuilderParams` property used to create the GeometryStream.
* @inheritdoc
*/
toJSON() {
const props = super.toJSON();
props.textAnnotationData = this._textAnnotationData;
if (this._textAnnotationData) {
props.elementGeometryBuilderParams = getElementGeometryBuilderParams(this.iModel, this.model, this.placement, this._textAnnotationData, this.category);
}
return props;
}
/** Creates a new `TextAnnotation2d` instance with the specified properties.
* @param iModelDb The iModel.
* @param category The category ID for the annotation.
* @param model The model ID where the annotation will be placed.
* @param placement The placement properties for the annotation.
* @param textAnnotationData Optional [[TextAnnotation]] JSON representation used to create the `TextAnnotation2d`. Essentially an empty element if not provided.
* @param code Optional code for the element.
*/
static create(iModelDb, category, model, placement, textAnnotationData, code) {
const props = {
classFullName: this.classFullName,
textAnnotationData: JSON.stringify(textAnnotationData),
placement,
model,
category,
code: code ?? core_common_1.Code.createEmpty(),
};
return new this(props, iModelDb);
}
/**
* Updates the geometry of the TextAnnotation2d on insert.
* @inheritdoc
* @beta
*/
static onInsert(arg) {
super.onInsert(arg);
this.updateGeometry(arg.iModel, arg.props);
}
/**
* Updates the geometry of the TextAnnotation2d on update.
* @inheritdoc
* @beta
*/
static onUpdate(arg) {
super.onUpdate(arg);
this.updateGeometry(arg.iModel, arg.props);
}
/**
* Populates the `elementGeometryBuilderParams` property in the [TextAnnotation2dProps]($common).
* It only does this if the `elementGeometryBuilderParams` is not already set and if there is actually a text annotation to produce geometry for.
*/
static updateGeometry(iModelDb, props) {
if (props.elementGeometryBuilderParams || !props.textAnnotationData) {
return;
}
props.elementGeometryBuilderParams = getElementGeometryBuilderParams(iModelDb, props.model, props.placement ?? core_common_1.Placement2d.fromJSON(), props.textAnnotationData, props.category);
}
/**
* Collects reference IDs used by this `TextAnnotation2d`.
* @inheritdoc
*/
collectReferenceIds(ids) {
super.collectReferenceIds(ids);
const annotation = this.getAnnotation();
if (!annotation) {
return;
}
if (annotation.textBlock.styleId)
ids.addElement(annotation.textBlock.styleId);
}
/** @internal */
getTextBlocks() {
return getTextBlocks(this);
}
/** @internal */
updateTextBlocks(textBlocks) {
return updateTextBlocks(this, textBlocks);
}
/** @internal */
static onInserted(arg) {
super.onInserted(arg);
ElementDrivesTextAnnotation_1.ElementDrivesTextAnnotation.updateFieldDependencies(arg.id, arg.iModel);
}
/** @internal */
static onUpdated(arg) {
super.onUpdated(arg);
ElementDrivesTextAnnotation_1.ElementDrivesTextAnnotation.updateFieldDependencies(arg.id, arg.iModel);
}
}
exports.TextAnnotation2d = TextAnnotation2d;
/** An element that displays textual content within a 3d model.
* The text is stored as a [TextAnnotation]($common) from which the element's [geometry]($docs/learning/common/GeometryStream.md) and [Placement]($common) are computed.
* @see [[setAnnotation]] to change the textual content.
* @public @preview
*/
class TextAnnotation3d extends Element_1.GraphicalElement3d /* implements ITextAnnotation */ {
/** @internal */
static get className() { return "TextAnnotation3d"; }
/** Optional string containing the data associated with the text annotation. */
_textAnnotationData;
/** Extract the textual content, if present.
* @see [[setAnnotation]] to change it.
*/
getAnnotation() {
const textAnnotationProps = parseTextAnnotationData(this._textAnnotationData);
return textAnnotationProps ? core_common_1.TextAnnotation.fromJSON(textAnnotationProps) : undefined;
}
/** Change the textual content of the `TextAnnotation3d`.
* @see [[getAnnotation]] to extract the current annotation.
* @param annotation The new annotation
*/
setAnnotation(annotation) {
this._textAnnotationData = annotation ? JSON.stringify(annotation.toJSON()) : undefined;
}
constructor(props, iModel) {
super(props, iModel);
this._textAnnotationData = props.textAnnotationData;
}
/** Creates a new instance of `TextAnnotation3d` from its JSON representation. */
static fromJSON(props, iModel) {
return new TextAnnotation3d(props, iModel);
}
/**
* Converts the current `TextAnnotation3d` instance to its JSON representation.
* It also computes the `elementGeometryBuilderParams` property used to create the GeometryStream.
* @inheritdoc
*/
toJSON() {
const props = super.toJSON();
props.textAnnotationData = this._textAnnotationData;
if (this._textAnnotationData) {
props.elementGeometryBuilderParams = getElementGeometryBuilderParams(this.iModel, this.model, this.placement, this._textAnnotationData, this.category);
}
return props;
}
/** Creates a new `TextAnnotation3d` instance with the specified properties.
* @param iModelDb The iModel.
* @param category The category ID for the annotation.
* @param model The model ID where the annotation will be placed.
* @param placement The placement properties for the annotation.
* @param textAnnotationData Optional [[TextAnnotation]] JSON representation used to create the `TextAnnotation3d`. Essentially an empty element if not provided.
* @param code Optional code for the element.
*/
static create(iModelDb, category, model, placement, textAnnotationData, code) {
const props = {
classFullName: this.classFullName,
textAnnotationData: JSON.stringify(textAnnotationData),
placement,
model,
category,
code: code ?? core_common_1.Code.createEmpty(),
};
return new this(props, iModelDb);
}
/**
* Updates the geometry of the TextAnnotation3d on insert.
* @inheritdoc
* @beta
*/
static onInsert(arg) {
super.onInsert(arg);
this.updateGeometry(arg.iModel, arg.props);
}
/**
* Updates the geometry of the TextAnnotation3d on update.
* @inheritdoc
* @beta
*/
static onUpdate(arg) {
super.onUpdate(arg);
this.updateGeometry(arg.iModel, arg.props);
}
/**
* Populates the `elementGeometryBuilderParams` property in the [TextAnnotation3dProps]($common).
* It only does this if the `elementGeometryBuilderParams` is not already set and if there is actually a text annotation to produce geometry for.
*/
static updateGeometry(iModelDb, props) {
if (props.elementGeometryBuilderParams || !props.textAnnotationData) {
return;
}
props.elementGeometryBuilderParams = getElementGeometryBuilderParams(iModelDb, props.model, props.placement ?? core_common_1.Placement3d.fromJSON(), props.textAnnotationData, props.category);
}
/**
* Collects reference IDs used by this `TextAnnotation3d`.
* @inheritdoc
*/
collectReferenceIds(ids) {
super.collectReferenceIds(ids);
const annotation = this.getAnnotation();
if (!annotation) {
return;
}
if (annotation.textBlock.styleId)
ids.addElement(annotation.textBlock.styleId);
}
/** @internal */
getTextBlocks() {
return getTextBlocks(this);
}
/** @internal */
updateTextBlocks(textBlocks) {
return updateTextBlocks(this, textBlocks);
}
/** @internal */
static onInserted(arg) {
super.onInserted(arg);
ElementDrivesTextAnnotation_1.ElementDrivesTextAnnotation.updateFieldDependencies(arg.id, arg.iModel);
}
/** @internal */
static onUpdated(arg) {
super.onUpdated(arg);
ElementDrivesTextAnnotation_1.ElementDrivesTextAnnotation.updateFieldDependencies(arg.id, arg.iModel);
}
}
exports.TextAnnotation3d = TextAnnotation3d;
function getTextBlocks(elem) {
const annotation = elem.getAnnotation();
return annotation ? [{ textBlock: annotation.textBlock, id: undefined }] : [];
}
function updateTextBlocks(elem, textBlocks) {
(0, core_bentley_1.assert)(textBlocks.length === 1);
(0, core_bentley_1.assert)(textBlocks[0].id === undefined);
const annotation = elem.getAnnotation();
if (!annotation) {
// We must obtain the TextBlockAndId from the element in the first place, so the only way we could end up here is if
// somebody removed the text annotation after we called getTextBlocks. That's gotta be a mistake.
throw new Error("Text annotation element has no text");
}
annotation.textBlock = textBlocks[0].textBlock;
elem.setAnnotation(annotation);
elem.update();
}
/**
* The definition element that holds text style information.
* The style is stored as a [TextStyleSettings]($common).
* @beta
*/
class AnnotationTextStyle extends Element_1.DefinitionElement {
/** @internal */
static get className() { return "AnnotationTextStyle"; }
/**
* Optional text describing the `AnnotationTextStyle`.
*/
description;
/**
* The text style settings for the `AnnotationTextStyle`.
* @see [[TextStyleSettings]] for more information.
*/
settings;
constructor(props, iModel) {
super(props, iModel);
this.description = props.description;
const settingsProps = AnnotationTextStyle.parseTextStyleSettings(props.settings);
this.settings = core_common_1.TextStyleSettings.fromJSON(settingsProps);
}
/**
* Creates a Code for an `AnnotationTextStyle` given a name that is meant to be unique within the scope of the specified DefinitionModel.
*
* @param iModel - The IModelDb.
* @param definitionModelId - The ID of the DefinitionModel that contains the AnnotationTextStyle and provides the scope for its name.
* @param name - The AnnotationTextStyle name.
*/
static createCode(iModel, definitionModelId, name) {
const codeSpec = iModel.codeSpecs.getByName(core_common_1.BisCodeSpec.annotationTextStyle);
return new core_common_1.Code({ spec: codeSpec.id, scope: definitionModelId, value: name });
}
/**
* Creates a new instance of `AnnotationTextStyle` with the specified properties.
*
* @param iModelDb - The iModelDb.
* @param definitionModelId - The ID of the [[DefinitionModel]].
* @param name - The name to assign to the `AnnotationTextStyle`.
* @param settings - Optional text style settings used to create the `AnnotationTextStyle`. Default settings will be used if not provided.
* @param description - Optional description for the `AnnotationTextStyle`.
*/
static create(iModelDb, definitionModelId, name, settings, description) {
const props = {
classFullName: this.classFullName,
model: definitionModelId,
code: this.createCode(iModelDb, definitionModelId, name).toJSON(),
description,
settings: JSON.stringify(settings),
};
return new this(props, iModelDb);
}
/**
* Converts the current `AnnotationTextStyle` instance to its JSON representation.
* @inheritdoc
*/
toJSON() {
const props = super.toJSON();
props.description = this.description;
props.settings = JSON.stringify(this.settings.toJSON());
return props;
}
/** Creates a new instance of `AnnotationTextStyle` from its JSON representation. */
static fromJSON(props, iModel) {
return new AnnotationTextStyle(props, iModel);
}
/**
* Validates that the AnnotationTextStyle's settings are valid before insert.
* @inheritdoc
* @beta
*/
static onInsert(arg) {
super.onInsert(arg);
this.validateSettings(arg.props);
}
/**
* Validates that the AnnotationTextStyle's settings are valid before update.
* @inheritdoc
* @beta
*/
static onUpdate(arg) {
super.onUpdate(arg);
this.validateSettings(arg.props);
}
static validateSettings(props) {
const settingProps = AnnotationTextStyle.parseTextStyleSettings(props.settings);
if (!settingProps)
return;
const settings = core_common_1.TextStyleSettings.fromJSON(settingProps);
const errors = settings.getValidationErrors();
if (errors.length > 0) {
throw new Error(`Invalid AnnotationTextStyle settings: ${errors.join(", ")}`);
}
}
static parseTextStyleSettings(json) {
if (!json)
return undefined;
try {
return JSON.parse(json);
}
catch {
return undefined;
}
}
}
exports.AnnotationTextStyle = AnnotationTextStyle;
//# sourceMappingURL=TextAnnotationElement.js.map