UNPKG

forma-embedded-view-sdk

Version:

The Forma Embedded View SDK is a JavaScript library for creating custom extensions in Autodesk Forma (previously Spacemaker).

234 lines (233 loc) 8.76 kB
import { RepresentationsApi } from "./representations.js"; /** * The Elements API allows you to read all elements and create in a selection of Forma elements systems. * * @remarks * Available via {@link auto.Forma | Forma}.{@link index.EmbeddedViewSdk.elements | elements}. */ export class ElementsApi { #iframeMessenger; floorStack; representations; blobs; /** @hidden */ constructor(iframeMessenger) { this.#iframeMessenger = iframeMessenger; this.floorStack = new FloorStackApi(iframeMessenger); this.representations = new RepresentationsApi(iframeMessenger); this.blobs = new BlobsApi(iframeMessenger); } /** * Get an element by urn. * * The method can return multiple elements. This can happen * if the element has children that are bundled with it. * * This method can also be used to include all the transitive children of the element * by setting the recursive parameter to true. * * @example * // Get the root element of the current proposal * const urn = await Forma.proposal.getRootUrn() * const { element, elements } = await Forma.elements.get({ urn }) * * @returns * A map from identifiers to elements. * A single element for the requested element */ async get(request) { return await this.#iframeMessenger.sendRequest("elements/get-v2", { rootUrn: request.urn, recursive: request.recursive, }); } /** * Get an element hierarchy located at the path relative to the current * root. You default to current proposal by omitting the urn parameter. * * @example * // Get all the building elements of the current proposal * Forma.selection.subscribe(({ paths }) => { * const { element, elements } = await Forma.elements.getByPath({ path: paths[0] }) * }); * * @returns * A map from identifiers to elements. */ async getByPath(request) { return await this.#iframeMessenger.sendRequest("elements/get-v2", request); } /** * Get the world transform of an element relative to the root element. * * The world transform is the affine transformation matrix that transforms * the element from its local coordinate system to the root coordinate system. * * @example * const { transform } = await Forma.elements.getWorldTransform({ path }) * const { element } = await Forma.elements.getByPath({ path }) * * if (element.representations?.footprint) { * const footprint = await Forma.elements.representations.footprint(element) * * const { data: geojson } = footprint * * void Forma.render.geojson.add({ geojson, transform }) * } * * @param request the path to element from root * @returns The affine transformation matrix of the element */ async getWorldTransform(request) { const response = await this.#iframeMessenger.sendRequest("elements/get-world-transform", request); return response; } /** * Allows adding, editing and removing custom properties attached directly to elements. * All properties must live under a namespace which follows `\w{1,20}:\w{1,50}` pattern (e.g.`my:namespace`). * The properties are managed by [JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386) specification. * * Requires edit access to the project. See {@link EmbeddedViewSdk.getCanEdit | getCanEdit} for more info. * * @example * // Add two properties within a namespace to an element and replace its previous urn with the updated urn in a proposal * const addTwoProperties = { * "my:namespace": { * "myFirstProperty": "myFirstValue" * "mySecondProperty": "mySecondValue" * } * } * const result = await Forma.elements.editProperties({urn, propertiesJsonMergePatch: myProperties}); * await Forma.proposal.replaceElement({path, urn: result.urn}) * * @example * // Change value of the first property and remove the second property at the same time * const changeFirstRemoveSecondProperty = { * "my:namespace": { * "myFirstProperty": "veryDifferentValue" * "mySecondProperty": null * } * } * const result = await Forma.elements.editProperties({urn, propertiesJsonMergePatch: changeFirstRemoveSecondProperty}); * await Forma.proposal.replaceElement({path, urn: result.urn}) * * @example * // Remove the whole namespace from the element * const removeWholeNamespace = { * "my:namespace": null * } * const result = await Forma.elements.editProperties({urn, propertiesJsonMergePatch: removeWholeNamespace}); * await Forma.proposal.replaceElement({path, urn: result.urn}) * */ async editProperties(request) { return await this.#iframeMessenger.sendRequest("elements/edit-properties", request); } } /** * API for creating Floor Stack buildings. * * You can use this API together with the Forma.proposal.addElement * API to create a building and add it to a the current proposal. * * @example * // Create a building with 3 floors with a 2 meter setback * // Place it where the user clicks in the scene * const { urn } = await Forma.elements.floorStack.createFromFloors({ * floors: [ * { * polygon: [ [0, 0], [10, 0], [10, 10], [0, 10], [0, 0] ], * height: 3, * }, * { * polygon: [ [0, 0], [10, 0], [10, 10], [0, 10], [0, 0] ], * height: 2.6, * }, * { * polygon: [ [0, 0], [10, 0], [10, 8], [0, 8], [0, 0] ], * height: 2.6, * }, * ], * }) * const point = await Forma.designTool.getPoint() * if (!point) return * const transform = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, point.x, point.y, point.z, 1] * await Forma.proposal.addElement({ urn, transform }); * * @remarks * Available via {@link auto.Forma | Forma}.{@link index.EmbeddedViewSdk.elements | elements}.{@link elements.ElementsApi.floorStack | floorStack}. */ export class FloorStackApi { #iframeMessenger; /** @hidden */ constructor(iframeMessenger) { this.#iframeMessenger = iframeMessenger; } /** * Create a 2.5D building from a stack of floors. * * By 2.5D, we mean that the building only has vertical walls and flat roofs. * The floors are given from bottom to top. * * Requires edit access to the project. See {@link EmbeddedViewSdk.getCanEdit | getCanEdit} for more info. * * @returns URN of the created building element. */ async createFromFloors(request) { const response = await this.#iframeMessenger.sendRequest("elements/floor-stack-v2/create-from-floors", request); return response; } /** * Create multiple 2.5D buildings from stacks of floors. * * By 2.5D, we mean that the building only has vertical walls and flat roofs. * The floors are given from bottom to top. * * Requires edit access to the project. See {@link EmbeddedViewSdk.getCanEdit | getCanEdit} for more info. * * @returns URNs of the created building elements. */ async createFromFloorsBatch(request) { const response = await this.#iframeMessenger.sendRequest("elements/floor-stack-v2/create-from-floors-batch", request); return response; } } /** * The Blobs API allows you to read blobs related to an element * * @remarks * Available via {@link auto.Forma | Forma}.{@link index.EmbeddedViewSdk.elements | elements}.{@link elements.ElementsApi.blobs | blobs}. */ export class BlobsApi { #iframeMessenger; /** @hidden */ constructor(iframeMessenger) { this.#iframeMessenger = iframeMessenger; } /** * Retrieve a blob by its id. * * Blobs are binary data that can be used for various purposes. * A common use case is together with linked representations * * @example * ```typescript * const { element } = await Forma.elements.get({ * urn: "urn:adsk-forma-elements:terrain:pro_cnusxrl4s1:c418dafe-1963-4160-9df5-239a49eef10b:1716818829774", * }) * * if (element.representations?.volumeMesh?.type === "linked") { * const blobResponse = await Forma.elements.blobs.get({ * blobId: element.representations.volumeMesh.blobId, * }) * const arrayBuffer: ArrayBuffer = blobResponse.data * } * ``` * * @returns an object containing the ArrayBuffer of the blob as data */ async get(request) { const response = await this.#iframeMessenger.sendRequest("elements/blobs/get", request); return response; } }