# Customize the UI

# Overview

Viewer with three windows.

Viewer with two windows. Viewer with one window without header.

The viewer UI is composed of three main parts :

  • First, there is the menu. The menu is where some useful actions can be performed like customizing the rest of the UI using the window manager. The menu is not displayed on the bottom-right image. It is a special case where the user wants to hide it. By default, a button (top-right) is automatically added to customize the windows.
  • Next, there is the main view where windows are displayed. The user can resize, add, delete, split or swap windows to create his own workspace, according to his needs. On the images above there is one, two or three windows with spatial arborescence, a 2d and 3d representations of the model displayed on different windows.
  • Last, there are plugins displayed on windows. Different display possibilities are shown on the image below (full, left, right, small...).

Viewer with opened plugins.

By default, the menu is always displayed as a top bar. However, it can be changed if only one window is present, or totally removed if you need to.

# Hidden menu

To hide the menu on a single window, the menu property on a window configuration object must be set to false.

const bimdataViewer = makeBIMDataViewer(/* {...} */);

const windowConfigurationObject = {
  name: "windowName",
  menu: false,
  plugins: [
    /* plugins */
  ],
};

bimdataViewer.registerWindow(windowConfigurationObject);

Then, if this window is displayed, the menu will be hidden like on the image below.

Flying header on siple window.

If there is more than one windows displayed, even if they have the menu property set to false, the header will be displayed as a top bar. To completely hide it, set the viewer ui.menuVisible property to false:

const bimdataViewer = makeBIMDataViewer({
  /* */
  ui: {
    menuVisible: false,
  },
});

# Window manager tools

The menu contains the window manager tools.

Menu window manager.

It is displayed on the right of the bar or as a right plugin if the menu is hidden.

No menu window manager.

You can choose to disable it to do not let the user update the UI:

const bimdataViewer = makeBIMDataViewer({
  /* */
  ui: {
    windowManager: false,
  },
});

# Window

A window is composed of plugins and can be registered using two ways :

  • The first is by adding a window configuration object in a plugin configuration.
  • The second is by registering it directly on the BIMData viewer object.

# Window configuration object

Property Description
name: string Required The name of the window. Must be unique.
label: string The label that is displayed to the user. Can be a key to be translated like : "viewer3d.window_label".
plugins: array An array of plugins which will be added to the window.
icon.imgUri: string A string that is injected into an img HTML element as a src. This image will be displayed while selecting the window on the window selector
menu: boolean Default to true. If false, the menu is hidden if there is only one window displayed.
const bimdataViewer = makeBIMDataViewer(/* {...} */);

const windowConfigurationObject = {
  name: "windowName",
  plugins: [
    /* plugins */
  ],
};

// first way
bimdataViewer.registerPlugin({
  /* plugin specific fields */
  window: windowConfigurationObject,
});

// second way
bimdataViewer.registerWindow(windowConfigurationObject);

# Plugin

The viewer is shipped with native BIMData plugins but others can be added to add new features and more possibilities. A plugin is mainly either a Vuejs component (opens new window) or/and a simple function that is run when the viewer is mounted into the DOM (opens new window).

TIP

See the plugins documentation to know how to develop a plugin and add new features to the viewer.

A plugin is added to the viewer by registering it :

import makeBIMDataViewer from "@bimdata/viewer";
import MyPlugin from "@myOrganisation/plugin";

const bimdataViewer = makeBIMDataViewer(/* {...} */);

bimdataViewer.registerPlugin(MyPlugin);

# Plugin registration API

The registerPlugin method take an object as argument. The options are the followings:

Property Description
name: string Required The name of the plugin. Must be unique.
component: object A Vuejs (v2.x) component.
i18n: object An object containing translations for internationalization.
startupScript($viewer) A function that is executed when the viewer is mounted, with $viewer as argument.
button: object An object that describe the display of the plugin if the plugin is shown as button.
window: object An object used to register a window with this plugin in it.
addToWindows: string[] An array of window name in which to include this plugin.

# Button

Property Description
position: string "left" or "right". The position of the button in the window.
content: string "simple", "panel" or "free"(default). Different way to display the component when the button is clicked. (see images below)
tooltip: string A string that is displayed when the plugin button is hovered. It can be a key to be translated ex: "myPluginName.tooltip"
keepOpen: boolean Default to false. If true, the plugin stay open even if the user click away from it.
icon.imgUri: string An uri to an image for the button.

If only the icon is defined, the corresponding image is always displayed on the button. A similar option, iconOpen can be defined to display a different icon when the button is open.

The images below show the different way to display plugin as button. (top-left : content = simple, top-right : content = free, bottom : content = panel)

Viewer plugin button simple. Viewer plugin button free.

Viewer plugin button panel.

The simple mode display the component in a small div adapted for small menu interfaces like switching between few options.

The free mode display the component in a div. The developer of the plugin is responsible to decide the style of the component because the div is related to the component size.

The panel mode open the component in a Panel. The panel height is 100% of the window.

# Window content

A plugin that is not displayed as a button is displayed on the window content. The viewer 3D and the viewer 2D are plugins displayed this way.

Example: this is the file content (simplified) used to register the viewer 3D:

import Viewer3D from "./Viewer3D.vue";

export default {
  name: "viewer3d",
  component: Viewer3D,
  window: {
    name: "3d",
  },
};

There is no button configuration in this file. The viewer 3D is registered as "viewer3d" and a window named "3d" is created with the viewer 3d plugin as a child.

# mount

Once created, the BIMDataViewer must be mounted to a DOM (opens new window) element in order to be displayed to the user.

bimdataViewer.mount("#app"); // 'app' is the id of an existing element.

The mount method take an optional second argument: the layout. The layout is the configuration of the windows displayed at startup. The default value is "3d", which is the name of a window registered by default. The "3d" window includes many BIMData plugins like "viewer3d", "section", "projection", "structure-properties"...

# Layout

The layout object can be either a string or an object.

  • If string, it must be the name of a registered window.
  • If object, the layout is a recursive object representing a container of window names. A container have ratios that represent the amount of space taken by given windows, a direction that can be "column" or "row"(default) and an array of children. A child can be a window name as string or another container as object.

Examples :

# A simple window name

bimdataViewer.mount("#app", "3d");
Layout "3d"

# A container with two windows

bimdataViewer.mount("#app", {
  ratios: [40, 60],
  direction: "row",
  children: ["structure", "2d"],
});
Layout row 2 windows

# Nested containers

bimdataViewer.mount("#app", {
  ratios: [55, 45],
  direction: "column",
  children: [
    {
      ratios: [50, 50],
      children: ["structure", "2d"],
    },
    "3d",
  ],
});
Layout 3 windows

# Embed Design System

The BIMData design system (opens new window) is globally available on the viewer and can be use to quickly stylize the components:

const component = {
  template: `
    <div style="display: flex; justify-content: center; align-items: center; height: 100%; flex-direction: column;">
      <p>Plugin Window component content.</p>
      <BIMDataButton color="primary" fill radius @click="onClick">Click Me !</BimdataButton>
    </div>
  `,
  methods: {
    onClick() {
      console.log("button clicked !");
    },
  },
};

In this example, there is no need to import BIMDataButton (opens new window).

# Complete UI example

<body>
  <div id="app"></div>
  <script type="module">
    import makeBIMDataViewer from "@bimdata/viewer";

    const bimdataViewer = makeBIMDataViewer({
      api: {
        modelIds: [15097],
        cloudId: 10344,
        projectId: 237466,
        accessToken: "TAbdyPzoQeYgVSMe4GUKoCEfYctVhcwJ", // Demo token
      },
    });

    bimdataViewer.registerPlugin({
      name: "buttonPlugin",
      component: {
        render(h) {
          return h("div", "Plugin Button component content.");
        },
      },
      button: {
        position: "left",
        content: "panel",
      },
    });

    bimdataViewer.registerPlugin({
      name: "windowPlugin",
      component: {
        template: `
          <div style="display: flex; justify-content: center; align-items: center; height: 100%; flex-direction: column;">
            <p>Plugin Window component content.</p>
            <BIMDataButton color="primary" fill radius @click="onClick">Click Me !</BimdataButton>
          </div>
        `,
        methods: {
          onClick() {
            console.log("button clicked !");
          },
        },
      },
      window: {
        name: "window-1",
        plugins: ["buttonPlugin"],
      },
    });

    bimdataViewer.registerWindow({
      name: "window-2",
      plugins: ["buttonPlugin"],
    });

    bimdataViewer.mount("#app", {
      ratios: [30, 70],
      children: [
        "window-1",
        {
          ratios: [40, 60],
          direction: "column",
          children: ["window-2", "3d"],
        },
      ],
    });
  </script>
</body>
Complete layout example.