You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

定制Autodesk Forge Viewer文档浏览器扩展以支持多模型

自定义Autodesk Forge DocumentBrowser扩展支持多模型的问题解决

问题背景

我正在使用Autodesk Forge Viewer及Autodesk.DocumentBrowser扩展,目标是扩展该文档浏览器的功能以同时支持多模型。目前该扩展仅显示单个模型的图纸和视图,我希望自定义它以展示Viewer中所有已加载模型的图纸和视图。

查阅资料后发现该功能默认未实现,因此尝试基于DocumentBrowser扩展的源码创建自定义扩展。在DocumentBrowser源码中,_hookToModel方法用于设置Autodesk.Viewing.UI.Tree根节点,当前TreeView仅接受单个模型的BubbleNode作为父节点。我尝试创建包含所有模型根节点的父节点,但显示空树,以下是尝试的代码:

尝试代码1:_hookToModel方法

_hookToModel() {
                var models = this.viewer.getVisibleModels();//获取所有已加载模型的数组
                this.rootNodes = models.map(model => {
                    var docNode = model.getDocumentNode();
                    if (!docNode) return null;
                    this.currNode = docNode.findParentGeom2Dor3D();
                    let rootNode = docNode.getRootNode();
                    this.geometries = rootNode.search({ 'type': 'geometry' });
                    return rootNode;
                }).filter(node => node !== null);


                let cache = this.getCache();
                if (cache.ui) {
                    this.ui = cache.ui;
                    cache.ui = null;
                } else {
                    this.ui = new _uiController__WEBPACK_IMPORTED_MODULE_0__.UiController(this.viewer);
                }
                this.ui.createUi(this.currNode, this.options, this.rootNodes); // 尝试传递模型根节点以调整树和缩略图
                this.ui.setChangeModelHandler(this._changeModel.bind(this));
            }

尝试代码2:createUi方法

/**
* 创建UI。
* @param {Autodesk.Viewing.BubbleNode} currNode  - 加载到Viewer中的节点
* @param {Object} [options]
* @param {bool} [options.openDocumentBrowserOnLoad=false] - 扩展加载时是否打开文档浏览器面板。
* @param {bool} [options.showThumbnails=true] - 显示或隐藏文档浏览器中的缩略图,默认显示。
*/
createUi(currNode, options, rootNodes) {

                    this.currNode = currNode;
                    this.rootNodes = rootNodes;
                    this._addToolbarButton();

                    if (!this.panel) {
                        this.panel = new _Panel__WEBPACK_IMPORTED_MODULE_0__.Panel(this.viewer, this.currNode, this.rootNodes);//将rootNodes传递给面板构造函数
                        this.panel.setChangeModelHandler(this._changeModelFn);
                        this.panel.addVisibilityListener(this._onPanelVisibilityChange);

                        // 显示或隐藏缩略图
                        if (options && options.showThumbnails !== undefined) {
                            this.panel.setThumbnailVisibility(options.showThumbnails);
                        }

                        if (options && options.openDocumentBrowserOnLoad) {
                            this.panel.toggleVisibility();
                        }
                    } else {
                        // 同步超链接触发的选择状态变更的UI调整
                        this.panel.setCurrentNode(currNode);
                    }

                    this._updateButtonState();
                }

尝试代码3:_createTreeView方法

_createTreeView() {
                        if (this.myTree) return;
                        var rootNode = new Autodesk.Viewing.BubbleNode("Aggregated-Models", this.rootNodes);//尝试创建父根节点但显示空树
                        //var rootNode = this.currNode.getRootNode();//仅加载单个模型

                        var delegate = (0, _TreeViewDelegate__WEBPACK_IMPORTED_MODULE_1__.createTreeViewDelegate)(rootNode, this);
                        var options = {
                            leafClassName: 'docBrowserLeaf',
                            selectedClassName: 'selected-ex'
                        };

                        var container = this._getTabDiv(TAB_ID_TREE);

                        this.myTree = new Autodesk.Viewing.UI.Tree(
                            delegate,
                            rootNode,
                            container,
                            options
                        );
                    }

问题现象

空树输出


问题分析

你的代码主要存在以下几个核心问题:

  1. BubbleNode构造函数使用错误
    你试图直接通过new Autodesk.Viewing.BubbleNode("Aggregated-Models", this.rootNodes)将子节点数组传入构造函数,但BubbleNode的构造函数并不支持这种用法,导致聚合根节点没有正确关联子节点,最终树显示为空。

  2. TreeViewDelegate不兼容多根结构
    原DocumentBrowser的TreeViewDelegate是为单个模型的树结构设计的,它的子节点获取逻辑默认只会处理单个模型根节点的层级,无法识别你创建的聚合根节点下的多个模型节点。

  3. currNode赋值逻辑错误
    在_hookToModel的循环中,你反复覆盖this.currNode的值,最终它只会保留最后一个模型的节点,这会导致后续UI同步、节点切换等逻辑出现异常。


修正方案

1. 正确创建聚合根节点并添加子节点

修改_createTreeView方法,先创建空的聚合根节点,再手动添加各个模型的根节点作为子节点:

_createTreeView() {
    if (this.myTree) return;
    // 创建空的聚合根节点,第二个参数传null表示无父节点
    var rootNode = new Autodesk.Viewing.BubbleNode("Aggregated-Models", null);
    // 遍历所有模型根节点,添加为聚合节点的子节点
    this.rootNodes.forEach(modelRoot => {
        rootNode.addChild(modelRoot);
    });

    var delegate = (0, _TreeViewDelegate__WEBPACK_IMPORTED_MODULE_1__.createTreeViewDelegate)(rootNode, this);
    var options = {
        leafClassName: 'docBrowserLeaf',
        selectedClassName: 'selected-ex'
    };

    var container = this._getTabDiv(TAB_ID_TREE);

    this.myTree = new Autodesk.Viewing.UI.Tree(
        delegate,
        rootNode,
        container,
        options
    );
}

2. 修改TreeViewDelegate的子节点获取逻辑

找到createTreeViewDelegate的实现,调整getChildren方法,让它能正确处理聚合根节点:

// 在TreeViewDelegate的getChildren方法中修改
getChildren(node, callback) {
    // 判断是否是我们创建的聚合根节点
    if (node.name === "Aggregated-Models") {
        // 直接返回聚合节点的子节点列表
        callback(null, node.getChildren());
    } else {
        // 保留原有的单个模型节点的子节点获取逻辑
        node.getChildren((err, children) => {
            // 可以根据需要过滤子节点,比如只保留视图/图纸节点
            callback(err, children);
        });
    }
}

3. 修正currNode的赋值逻辑

在_hookToModel中,避免循环覆盖this.currNode,改为保存每个模型的geom节点,并设置默认的currNode:

_hookToModel() {
    var models = this.viewer.getVisibleModels();
    this.rootNodes = models.map(model => {
        var docNode = model.getDocumentNode();
        if (!docNode) return null;
        // 给每个模型对象附加geom节点,方便后续使用
        model._geomNode = docNode.findParentGeom2Dor3D();
        let rootNode = docNode.getRootNode();
        // 合并所有模型的geometry节点
        this.geometries = [...(this.geometries || []), ...rootNode.search({ 'type': 'geometry' })];
        return rootNode;
    }).filter(node => node !== null);

    // 设置默认currNode为第一个模型的geom节点
    this.currNode = this.rootNodes.length > 0 ? this.rootNodes[0].getDocumentNode().findParentGeom2Dor3D() : null;

    let cache = this.getCache();
    if (cache.ui) {
        this.ui = cache.ui;
        cache.ui = null;
    } else {
        this.ui = new _uiController__WEBPACK_IMPORTED_MODULE_0__.UiController(this.viewer);
    }
    this.ui.createUi(this.currNode, this.options, this.rootNodes);
    this.ui.setChangeModelHandler(this._changeModel.bind(this));
}

4. 调整模型切换逻辑

修改_changeModel方法,确保切换节点时能激活对应的模型:

_changeModel(node) {
    // 获取节点所属的模型
    const targetModel = node.getModel();
    if (targetModel) {
        // 激活当前模型
        this.viewer.setActiveModel(targetModel);
    }
    // 保留原有的节点选择、视图加载逻辑
    this.viewer.select(node);
    // 其他原有逻辑(比如切换视图/图纸)...
}

内容的提问来源于stack exchange,提问作者Ahmed Shawky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 22:44:55