# Layout Manipulation

The Global Context API offers a way to perform layout manipulation dynamically (after viewer instanciation) through open(), close() and swap() methods.

The following example illustrate how these methods can be used in simple plugins.

Split layout plugin: when clicked, this button plugin will modify the layout as follow:

  • If both a 3D and 2D viewers are already open then close current window (local context).
  • Else if the current window is a 3D viewer then split the layout and open a new 2D viewer beside it.
  • Else if the current window is a 2D viewer then split the layout and open a new 3D viewer beside it.

Swap layout plugin: swap the content of the first two windows in the layout.

# Demo

# Code

Plugin definitions:

// file: split-layout.plugin.js
export default {
  name: "splitLayoutPlugin",
  addToWindows: ["3d", "2d"],
  i18n: {
    en: { tooltip: "" },
  },
  button: {
    position: "right",
    tooltip: "splitLayoutPlugin.tooltip",
    icon: {
      component: "BIMDataIconWindowRight",
      options: { size: "m" },
    },
  },
  component: {
    onOpen() {
      if (
        this.$viewer.globalContext.getLocalContexts("3d").length > 0 &&
        this.$viewer.globalContext.getLocalContexts("2d").length > 0
      ) {
        // If both 3D and 2D viewers are open the close current window
        this.$viewer.localContext.close();
      } else {
        // Else if this is a 3D (resp. 2D) viewer window then open a 2D (resp. 3D) window beside it
        const windowName = this.$viewer.localContext.window.name;
        const modelIds = this.$viewer.localContext.loadedModelIds;
        const split = windowToOpen => {
          this.$viewer.globalContext.open({
            ratio: 50,
            direction: "row",
            insertAfter: true,
            windowName: windowToOpen,
            windowState: { modelIds }
          });
        };
  
        if (windowName === "3d") split("2d");
        if (windowName === "2d") split("3d");
      }

      setTimeout(() => this.$close());
    },
  }
};
// file: swap-layout.plugin.js
export default {
  name: "swapLayoutPlugin",
  addToWindows: ["3d", "2d"],
  i18n: {
    en: { tooltip: "" },
  },
  button: {
    position: "right",
    tooltip: "swapLayoutPlugin.tooltip",
    icon: {
      component: "BIMDataIconSwap",
      options: { size: "m" },
    },
  },
  component: {
    onOpen() {
      // Get the first two contexts in the local context list
      const [ctx1, ctx2] = this.$viewer.globalContext.localContexts;

      if (ctx2) this.$viewer.globalContext.swap(ctx1.id, ctx2.id);

      setTimeout(() => this.$close());
    },
  }
};

Viewer instanciation:

// file: main.js
import makeBIMDataViewer from "@bimdata/viewer";
import SplitLayoutPlugin from "./split-layout.plugin.js";
import SwapLayoutPlugin from "./swap-layout.plugin.js";

const viewer = makeBIMDataViewer({
  api: {
    // ...
  },
});

viewer.registerPlugin(SplitLayoutPlugin);
viewer.registerPlugin(SwapLayoutPlugin);

viewer.mount(viewerId, "3d");