Skip to main content

UIManager

๐ŸŽ›๏ธ Making your user interactiveโ€‹


One of the most important things about making a BIM app is to give the user the ability to interact with the functionalities you are creating ๐Ÿš€. The catch is you need to create a decent user interface so your end-user is able to interact in an easy and intuitive way. While creating a simple set of buttons is not particularly difficult, we all agree is time-consuming โฑ๏ธ. This is where UI Components come to the rescue!

Components, but for UI

The UI Components are similar to the rest of the components of the library. The only difference is that their mission is to display an UI in HTML structures, including buttons, toolbars, menus, windows, etc.

๐ŸŽจ Adding stylesโ€‹

The first step is to get the CSS file with the default styles. You can get it from ..................

๐Ÿงฐ Creating a toolbarโ€‹


We need buttons to allow the user to interact with our viewer. But even before that, we need a place to put them: this place is called a Toolbar. Creating and adding a Toolbar to the viewer is as simple as this:

const mainToolbar = new OBC.Toolbar(components, { name: 'Main Toolbar', position: 'bottom' });
components.ui.addToolbar(mainToolbar);

By default, the toolbar is added to the bottom ๐Ÿ‘‡ of the viewer container, so you technically don't need to type position: "bootom" in the options argument of your toolbar, but we just did it so that you know you can change the toolbar position to either top, right, bottom or left.

What about more complex layouts?

You can create multiple toolbars in the same position, and the component just takes care about stacking all toolbars nice and neat ๐Ÿคฏ.

๐ŸŽข Using existing UIsโ€‹


If you are using components from this library or from the marketplace, you won't need to create any UI: components usually include ready-to-use menus so that you can add them to your app in seconds. These components implement the UI Interface. Let's see them in action! ๐Ÿ‘‡


๐Ÿ‘จโ€๐ŸŽจ Creating your own UIsโ€‹


Of course, UI Components can also be used stand-alone, either to build your own components or to add menus to your app very fast! Let's start with a simple one: a Button Component that sends an alert message. ๐Ÿผ Button components can only be added inside a toolbar. To do so, we can simply add the following code:

const alertButton = new OBC.Button(components, { materialIconName: 'info' });
mainToolbar.addButton(alertButton);
alertButton.onclick = () => {
alert('I\'ve been clicked!');
}
Where do these cool icons come from?

We are fetching the icons from material icons, a very popular icon repository. You can simply pass the name of the icon in materialIconName and the button will display it! ๐Ÿงจ

๐ŸŒ Preparing the sceneโ€‹


Of course, this UI is not very exciting, because it only adds a single button that throws an alert. But we can do much more with UI components. Let's build a menu that creates and deletes geometry in our scene! We will make a simple tool that creates and delete boxes from the scene. First, we'll need to define basic information of the boxes. We will also create a super simple function to get a random number within a given limit:

const boxes = [];
const boxGeometry = new THREE.BoxGeometry();
const boxMaterial = new THREE.MeshLambertMaterial({ color: 'red' });

๐Ÿ”ข Next, let's define some simple functions. To create a random number:

function getRandomNumber(limit) {
return Math.random() * limit;
}

โœ…๐Ÿ“ฆ To delete a box from the scene:

function createBox() {
const mesh = new THREE.Mesh(boxGeometry, boxMaterial);
scene.add(mesh);
mesh.position.x = getRandomNumber(10);
mesh.position.y = getRandomNumber(10);
mesh.position.z = getRandomNumber(10);
boxes.push(mesh);
}

โŽ๐Ÿ“ฆ To delete a box from the scene:

function deleteBox() {
if(!boxes.length) return;
const box = boxes.pop();
box.removeFromParent();
}

โŽ๐Ÿ“ฆ๐Ÿ“ฆ๐Ÿ“ฆ To delete all existing boxes:

function deleteAllBoxes() {
const count = boxes.length;
for(let i = 0; i < count; i++) {
deleteBox();
}
}

๐Ÿ”„๐Ÿ“ฆ๐Ÿ“ฆ๐Ÿ“ฆ And to animate all the boxes, so that our scene is more interesting:

function animateBoxes() {
const oneDegree = Math.PI / 180;
for(const box of boxes) {
box.rotation.x += oneDegree;
box.rotation.y += oneDegree;
box.rotation.z += oneDegree;
}
}
components.renderer.beforeUpdate.on(animateBoxes);

๐ŸŒฒ Composing menusโ€‹


Buttons can be nested to build complex menus! For example, let's say that we want 3 buttons that add a box, delete a box and delete all boxes respectively. We want to organize these menus together, so let's start by creating a button that will contain the rest:

const cubeTools = new OBC.Button(components, {
materialIconName: 'widgets'
});
mainToolbar.addButton(cubeTools);

Let's start with the button to create boxes. This buttons needs a couple of extra things:

  • A name so that it displays the text.
  • A closeOnClick: false so that the menu doesn't close after being clicked
  • An onclick event so that the function createBox is triggered after pressing the button.
const createCubeButton = new OBC.Button(components, {
materialIconName: 'add_box',
name: 'Create box',
closeOnClick: false
});
createCubeButton.onclick = () => createBox();
cubeTools.addButton(createCubeButton);

Now, let's go with the "delete single" and "delete all buttons" buttons. Both are related, so we will group them together (yes, multiple-level nesting is allowed!). So first, let's create the parent button:

const deleteCubeButtons = new OBC.Button(components, {
materialIconName: 'disabled_by_default',
name: 'Delete box'
});
cubeTools.addButton(deleteCubeButtons);

Next, the "delete single" button:

const deleteSingleCubeButton = new OBC.Button(components, {
materialIconName: 'disabled_by_default',
name: 'Single',
closeOnClick: false
});
deleteSingleCubeButton.onclick = () => deleteBox();
deleteCubeButtons.addButton(deleteSingleCubeButton);

And finally the "delete all" button:

const deleteAllCubesButton = new OBC.Button(components, {
materialIconName: 'disabled_by_default',
name: 'All'
});
deleteAllCubesButton.onclick = () => deleteAllBoxes();
deleteCubeButtons.addButton(deleteAllCubesButton);

And this is it! Easy, right? You can now create add menus to your components and easily share them with other BIM software developers!

๐Ÿ Context menuโ€‹


There's a special menu that is used in menu BIM applications: the context menu! You know, that menu that shows up when you right-click somewhere. Don't worry, this is also supported by UI Components! The UI Manager has a default Toolbar that is already set up as a context menu. All the nesting logic mentioned before works here as well:

const contextDeleteButtons = new OBC.Button(components, {
materialIconName: 'widgets',
name: "Delete"
});
const deleteAllCubesContextButton = new OBC.Button(components, {
materialIconName: 'widgets',
name: "All cubes"
});
deleteAllCubesContextButton.onclick = () => deleteAllBoxes();
contextDeleteButtons.addButton(deleteAllCubesContextButton);
components.ui.contextMenu.addButton(contextDeleteButtons);

And this is it! ๐Ÿฅณ Cool, right? Now you can easily use the UI elements in the components of this library and the marketplace, as well as create your own custom menus in minutes. ๐Ÿ’ช๐ŸŽจ You are now one step closer to create your BIM applications from scratch. ๐Ÿ”ฅ