9 Aug 2017

Enumerating leaf nodes on Viewer

Default blog image

When manipulating elements on the Viewer we often need to identify the leaf nodes on the hierarchy tree, meaning only the dbIds that are selectable on the model, or in other words, those who do not have children.

There are some samples around this, including this old blog post I wrote, but some of them rely on unsupported attributes. Ideally we should only use methods on the API, which are supported and not expected to change. Data structure may change from one version to the next.

Back to our topic, on a model like showing below, we're looking for "Basic Wall [123456]" leaf, not the parent nodes (e.g. STB 30.0, Basic Wall, or Walls).

Model browser

To implement it we need to first .getObjectTree() of the model, then .getRootId() and check if is a leaf with .getChildCount(), if grater than 0 (zero), use .enumNodeChildren to check the next level on the hierarchy. As everything is based on callbacks, the code below uses a callback count to know when it's done.

function getAllLeafComponents(viewer, callback) {
    var cbCount = 0; // count pending callbacks
    var components = []; // store the results
    var tree; // the instance tree

    function getLeafComponentsRec(parent) {
        cbCount++;
        if (tree.getChildCount(parent) != 0) {
            tree.enumNodeChildren(parent, function (children) {
                getLeafComponentsRec(children);
            }, false);
        } else {
            components.push(parent);
        }
        if (--cbCount == 0) callback(components);
    }
    viewer.getObjectTree(function (objectTree) {
        tree = objectTree;
        var allLeafComponents = getLeafComponentsRec(tree.getRootId());
    });
}

To test it on the browser console, you can use something like:

getAllLeafComponents(NOP_VIEWER, function (dbIds) {
    console.log('Found ' + dbIds.length + ' leaf nodes');
})

Related Article