Skip to main content

ElementProperties

Source

Copying and pasting? We've got you covered! You can find the full source code of this tutorial here.

Displaying data the simplest way 🔥🔥


What is a good BIM app if you don't give users a nice way to visualize its model properties, right? Well, hold tight as here you will learn all you need to know in order to use the power of UI Components to accomplish that!

Loading a model and computing it's relations

First things first... let's load a model 👇

const ifcLoader = components.get(OBC.IfcLoader);
await ifcLoader.setup();
const file = await fetch(
"https://thatopen.github.io/engine_ui-components/resources/small.ifc",
);
const buffer = await file.arrayBuffer();
const typedArray = new Uint8Array(buffer);
const model = await ifcLoader.load(typedArray);
world.scene.three.add(model);
tip

You don't need to add the model into the scene to display its properties. However, as we are going to display the properties for each selected element, then having the model into the scene is obvious, right?

Now, in order to get the most out of the properties table, you need to calculate the relations index of your model. To do it, you will need to use the IfcRelationsIndexer component from @thatopen/components to speed up the process.

const indexer = components.get(OBC.IfcRelationsIndexer);
await indexer.process(model);

Once the relations are processed, the Element Properties component has everything it needs in order to display the properties in a cool way 😎.

Creating the properties table

Let's create an instance of the functional component, like this:

const [propertiesTable, updatePropertiesTable] = CUI.tables.elementProperties({
components,
fragmentIdMap: {},
});

propertiesTable.preserveStructureOnFilter = true;
propertiesTable.indentationInText = false;
tip

The elementProperties functional component is a simplified version that shows any model entity data. However, if you like a more complete properties table, use the entityAttributes component.

Cool! properties table created. Then after, let's tell the properties table to update each time the user makes a selection over the model. For it, we will use the highlighter from @thatopen/components-front:

const highlighter = components.get(OBF.Highlighter);
highlighter.setup({ world });

highlighter.events.select.onHighlight.add((fragmentIdMap) => {
updatePropertiesTable({ fragmentIdMap });
});

highlighter.events.select.onClear.add(() =>
updatePropertiesTable({ fragmentIdMap: {} }),
);

Creating a panel to append the table

Allright! Let's now create a BIM Panel to control some aspects of the properties table and to trigger some functionalities like expanding the rows children and copying the values to TSV, so you can paste your element values inside a spreadsheet application 😉

const propertiesPanel = BUI.Component.create(() => {
const onTextInput = (e: Event) => {
const input = e.target as BUI.TextInput;
propertiesTable.queryString = input.value !== "" ? input.value : null;
};

const expandTable = (e: Event) => {
const button = e.target as BUI.Button;
propertiesTable.expanded = !propertiesTable.expanded;
button.label = propertiesTable.expanded ? "Collapse" : "Expand";
};

const copyAsTSV = async () => {
await navigator.clipboard.writeText(propertiesTable.tsv);
};

return BUI.html`
<bim-panel label="Properties">
<bim-panel-section label="Element Data">
<div style="display: flex; gap: 0.5rem;">
<bim-button @click=${expandTable} label=${propertiesTable.expanded ? "Collapse" : "Expand"}></bim-button>
<bim-button @click=${copyAsTSV} label="Copy as TSV"></bim-button>
</div>
<bim-text-input @input=${onTextInput} placeholder="Search Property" debounce="250"></bim-text-input>
${propertiesTable}
</bim-panel-section>
</bim-panel>
`;
});

Finally, let's create a BIM Grid element and provide both the panel and the viewport to display everything.

const app = document.createElement("bim-grid");
app.layouts = {
main: {
template: `
"propertiesPanel viewport"
/25rem 1fr
`,
elements: { propertiesPanel, viewport },
},
};

app.layout = "main";
document.body.append(app);

Congratulations! You have now created a fully working properties table for your app in less than 5 minutes of work. Keep going with more tutorials! 💪