Reference Source
public class | source

TreeViewPlugin

Extends:

Plugin → TreeViewPlugin

A Viewer plugin that provides an HTML tree view to navigate the IFC elements in models.

[Run this example]

Overview

  • A fast HTML tree view, with zero external dependencies, that works with huge numbers of objects.
  • Each tree node has a checkbox to control the visibility of its object.
  • Has three hierarchy modes: "containment", "types" and "storeys".
  • Automatically contains all models (that have metadata) that are currently in the Scene.
  • Allows custom CSS styling.
  • Use ContextMenu to create a context menu for the tree nodes.

Credits

TreeViewPlugin is based on techniques described in Super Fast Tree View in JavaScript by Chris Smith.

Usage

In the example below, we'll add a TreeViewPlugin which, by default, will automatically show the structural hierarchy of the IFC elements in each model we load.

Then we'll use an XKTLoaderPlugin to load the Schependomlaan model from an .xkt file, along with an accompanying JSON IFC metadata file.

[Run this example]

import {Viewer} from "../src/viewer/Viewer.js";
import {XKTLoaderPlugin} from "../src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js";
import {TreeViewPlugin} from "../src/plugins/TreeViewPlugin/TreeViewPlugin.js";

const viewer = new Viewer({
     canvasId: "myCanvas",
     transparent: true
});

viewer.camera.eye = [-2.56, 8.38, 8.27];
viewer.camera.look = [13.44, 3.31, -14.83];
viewer.camera.up = [0.10, 0.98, -0.14];

const treeView = new TreeViewPlugin(viewer, {
    containerElement: document.getElementById("myTreeViewContainer")
});

const xktLoader = new XKTLoaderPlugin(viewer);

const model = xktLoader.load({
    id: "myModel",
    src: "./models/xkt/schependomlaan/schependomlaan.xkt",
    metaModelSrc: "./metaModels/schependomlaan/metaModel.json",
    edges: true
});

Manually Adding Models

Instead of adding models automatically, we can control which models appear in our TreeViewPlugin by adding them manually.

In the next example, we'll configure the TreeViewPlugin to not add models automatically. Then, once the model has loaded, we'll add it manually using TreeViewPlugin#addModel.

const treeView = new TreeViewPlugin(viewer, {
     containerElement: document.getElementById("myTreeViewContainer"),
     autoAddModels: false  // <<---------------- Don't auto-add models
});

const xktLoader = new XKTLoaderPlugin(viewer);

const model = xktLoader.load({
    id: "myModel",
    src: "./models/xkt/schependomlaan/schependomlaan.xkt",
    metaModelSrc: "./metaModels/schependomlaan/metaModel.json",
    edges: true
});

model.on("loaded", () => {
     treeView.addModel(model.id);
});

Initially Expanding the Hierarchy

We can also configure TreeViewPlugin to initially expand each model's nodes to a given depth.

Let's automatically expand the first three nodes from the root, for every model added:

const treeView = new TreeViewPlugin(viewer, {
     containerElement: document.getElementById("myTreeViewContainer"),
     autoExpandDepth: 3
});

Showing a Node by ID

We can show a given node using its ID. This causes the TreeViewPlugin to expand and scroll the node into view.

Let's make the TreeViewPlugin show the node corresponding to whatever object Entity that we pick:

viewer.cameraControl.on("picked", function (e) {
    var objectId = e.entity.id;
    treeView.showNode(objectId);
});

Note that only works if the picked Entity is an object that belongs to a model that's represented in the TreeViewPlugin.

Customizing Appearance

We can customize the appearance of our TreeViewPlugin by defining custom CSS for its HTML elements. See our example's source code for an example of custom CSS rules.

Model Hierarchies

TreeViewPlugin has three hierarchies for organizing its nodes:

  • "containment" - organizes the tree nodes to indicate the containment hierarchy of the MetaObjects.
  • "types" - groups nodes by their IFC types.
  • "storeys" - groups nodes within their IfcBuildingStoreys, and sub-groups them by their IFC types.


The table below shows what the hierarchies look like:

1. Containment Hierarchy 2. Types Hierarchy 3. Storeys Hierarchy


Let's create a TreeViewPlugin that groups nodes by their building stories and IFC types:

const treeView = new TreeViewPlugin(viewer, {
     containerElement: document.getElementById("myTreeViewContainer"),
     hierarchy: "stories"
});

Context menu

TreeViewPlugin fires a "contextmenu" event whenever we right-click on a tree node.

The event contains:

Let's use ContextMenu to show a simple context menu for the node we clicked.

[Run an example]

import {ContextMenu} from "../src/extras/ContextMenu/ContextMenu.js";

const treeViewContextMenu = new ContextMenu({
    items: [
        [
            [
                {
                    title: "Hide",
                    callback: function (context) {
                        context.treeViewPlugin.withNodeTree(context.treeViewNode, (treeViewNode) => {
                            if (treeViewNode.objectId) {
                                const entity = context.viewer.scene.objects[treeViewNode.objectId];
                                if (entity) {
                                    entity.visible = false;
                                }
                            }
                        });
                    }
                },
                {
                    title: "Hide all",
                    callback: function (context) {
                        context.viewer.scene.setObjectsVisible(context.viewer.scene.visibleObjectIds, false);
                    }
                }
            ],
            [
                {
                    title: "Show",
                    callback: function (context) {
                        context.treeViewPlugin.withNodeTree(context.treeViewNode, (treeViewNode) => {
                            if (treeViewNode.objectId) {
                                const entity = context.viewer.scene.objects[treeViewNode.objectId];
                                if (entity) {
                                    entity.visible = true;
                                    entity.xrayed = false;
                                    entity.selected = false;
                                }
                            }
                        });
                    }
                },
                {
                    title: "Show all",
                    callback: function (context) {
                        const scene = context.viewer.scene;
                        scene.setObjectsVisible(scene.objectIds, true);
                        scene.setObjectsXRayed(scene.xrayedObjectIds, false);
                        scene.setObjectsSelected(scene.selectedObjectIds, false);
                    }
                }
            ]
        ]
    ]
});

treeView.on("contextmenu", (e) => {

    const event = e.event;                           // MouseEvent
    const viewer = e.viewer;                         // Viewer
    const treeViewPlugin = e.treeViewPlugin;         // TreeViewPlugin
    const treeViewNode = e.treeViewNode;             // TreeViewNode

    treeViewContextMenu.show(e.event.pageX, e.event.pageY);

    treeViewContextMenu.context = {
        viewer: e.viewer,
        treeViewPlugin: e.treeViewPlugin,
        treeViewNode: e.treeViewNode
    };
});

Constructor Summary

Public Constructor
public

constructor(viewer: Viewer, cfg: *)

Member Summary

Public Members
public set

Sets how the nodes are organized within this tree view.

public get

Gets how the nodes are organized within this tree view.

Method Summary

Public Methods
public

addModel(modelId: String)

Adds a model to this tree view.

public

Collapses all trees within this tree view.

public

Destroys this TreeViewPlugin.

public

Expands the tree to the given depth.

public

removeModel(modelId: String)

Removes a model from this tree view.

public

showNode(objectId: String)

Shows the tree view node that represents the given object Entity.

public

withNodeTree(node: TreeViewNode, callback: Function)

Iterates over a subtree of the tree view's TreeViewNodes, calling the given callback for each node in depth-first pre-order.

Inherited Summary

From class Plugin
public

ID for this Plugin, unique within its Viewer.

public

The Viewer that contains this Plugin.

public

Destroys this Plugin and removes it from its Viewer.

public

error(msg: String)

Logs an error message to the JavaScript developer console, prefixed with the ID of this Plugin.

public

fire(event: String, value: Object)

Fires an event at this Plugin.

public

log(msg: String)

Logs a message to the JavaScript developer console, prefixed with the ID of this Plugin.

public

on(event: String, callback: Function)

Subscribes to an event fired at this Plugin.

public

warn(msg: String)

Logs a warning message to the JavaScript developer console, prefixed with the ID of this Plugin.

Public Constructors

public constructor(viewer: Viewer, cfg: *) source

Creates this Plugin and installs it into the given Viewer.

Override:

Plugin#constructor

Params:

NameTypeAttributeDescription
viewer Viewer

The Viewer.

cfg *

Plugin configuration.

cfg.containerElement HTMLElement

DOM element to contain the TreeViewPlugin.

cfg.autoAddModels Boolean
  • optional
  • default: true

When true (default), will automatically add each model as it's created. Set this false if you want to manually add models using TreeViewPlugin#addModel instead.

cfg.autoExpandDepth Number
  • optional

Optional depth to which to initially expand the tree.

cfg.hierarchy String
  • optional
  • default: "containment"

How to organize the tree nodes: "containment", "storeys" or "types". See the class documentation for details.

Public Members

public set hierarchy: String source

Sets how the nodes are organized within this tree view.

Accepted values are:

  • "containment" - organizes the nodes to indicate the containment hierarchy of the IFC objects.
  • "types" - groups the nodes within their IFC types.
  • "storeys" - groups the nodes within IfcBuildingStoreys and sub-groups them by their IFC types.


This can be updated dynamically.

Default value is "containment".

public get hierarchy: String source

Gets how the nodes are organized within this tree view.

Public Methods

public addModel(modelId: String) source

Adds a model to this tree view.

The model will be automatically removed when destroyed.

To automatically add each model as it's created, instead of manually calling this method each time, provide a autoAddModels: true to the TreeViewPlugin constructor.

Params:

NameTypeAttributeDescription
modelId String

ID of a model Entity in Scene#models.

public collapse() source

Collapses all trees within this tree view.

public destroy() source

Destroys this TreeViewPlugin.

Override:

Plugin#destroy

public expandToDepth(depth: Number) source

Expands the tree to the given depth.

Collapses the tree first.

Params:

NameTypeAttributeDescription
depth Number

Depth to expand to.

public removeModel(modelId: String) source

Removes a model from this tree view.

Params:

NameTypeAttributeDescription
modelId String

ID of a model Entity in Scene#models.

public showNode(objectId: String) source

Shows the tree view node that represents the given object Entity.

Params:

NameTypeAttributeDescription
objectId String

ID of the Entity.

public withNodeTree(node: TreeViewNode, callback: Function) source

Iterates over a subtree of the tree view's TreeViewNodes, calling the given callback for each node in depth-first pre-order.

Params:

NameTypeAttributeDescription
node TreeViewNode

Root of the subtree.

callback Function

Callback called at each TreeViewNode, with the TreeViewNode given as the argument.