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

如何在Autodesk Forge Viewer中实现嵌入停靠面板的模型元素属性DataTable

Forge Viewer: Implement DataTable in Docking Panel for Model Properties

Hey there! Let's tackle your questions and get that DataTable working in your docking panel. First, let's clear up your technical doubts, then walk through the revised implementation.

Technical Doubts Clarified

1. When to Initialize the DataTable?

You should create and initialize the DataTable after your docking panel is created. The panel needs to exist first so you can attach the table to its DOM container. Typically, you'll set up the DataTable inside your custom panel's constructor, or right after the panel is instantiated and visible.

2. DataTable Constructor Parameters

Yes, the Forge Viewer's DataTable expects:

  • Column configuration: An array of objects, each defining a column's key (matches your data property), label (display name), and optional settings like sortable.
  • Row data: An array of arrays, where each sub-array contains values corresponding to the columns (in the same order as your column config).

Since you only want to display properties that an element actually has, we'll dynamically build both columns and rows based on the properties retrieved from the model.

Revised Implementation

First, let's fix your extension code and define a proper custom docking panel that integrates the DataTable. Here's the complete working example:

// Custom Docking Panel with DataTable
class ModelSummaryPanel extends Autodesk.Viewing.UI.DockingPanel {
    constructor(viewer, container, id, title, options) {
        super(container, id, title, options);
        this.viewer = viewer;
        // Set panel size and style
        this.container.style.width = '600px';
        this.container.style.height = '400px';
        this.container.style.overflow = 'auto';
        // Create DataTable container
        this.tableContainer = document.createElement('div');
        this.tableContainer.style.padding = '10px';
        this.container.appendChild(this.tableContainer);
        // Initialize DataTable (we'll set data later)
        this.dataTable = new Autodesk.Viewing.UI.DataTable(this.tableContainer);
    }

    // Method to update table with new data and columns
    updateTable(columns, rows) {
        this.dataTable.clear();
        this.dataTable.setColumns(columns);
        this.dataTable.setRows(rows);
        this.dataTable.render();
    }
}

class testTest extends Autodesk.Viewing.Extension {
    constructor(viewer, options) {
        super(viewer, options);
        this._group = null;
        this._button = null;
        this._panel = null;
    }

    load() {
        console.log('testTest has been loaded');
        return true;
    }

    unload() {
        if (this._group) {
            this._group.removeControl(this._button);
            if (this._group.getNumberOfControls() === 0) {
                this.viewer.toolbar.removeControl(this._group);
            }
        }
        console.log('testTest has been unloaded');
        return true;
    }

    getAllLeafComponents(callback) {
        this.viewer.getObjectTree(function (tree) {
            let leaves = [];
            tree.enumNodeChildren(tree.getRootId(), function (dbId) {
                if (tree.getChildCount(dbId) === 0) {
                    leaves.push(dbId);
                }
            }, true);
            callback(leaves);
        });
    }

    onToolbarCreated() {
        this._group = this.viewer.toolbar.getControl('allMyAwesomeExtensionsToolbar');
        if (!this._group) {
            this._group = new Autodesk.Viewing.UI.ControlGroup('allMyAwesomeExtensionsToolbar');
            this.viewer.toolbar.addControl(this._group);
        }

        this._button = new Autodesk.Viewing.UI.Button('testTest');
        this._button.onClick = (ev) => {
            if (!this._panel) {
                this._panel = new ModelSummaryPanel(this.viewer, this.viewer.container, 'modelSummaryPanel', 'Model Element Properties');
            }
            this._panel.setVisible(!this._panel.isVisible());
            if (!this._panel.isVisible()) return;

            const targetProps = ['Level', 'Name', 'Comments', 'Area', 'Type Name'];

            this.getAllLeafComponents((dbIds) => {
                this.viewer.model.getBulkProperties(dbIds, targetProps, (items) => {
                    // Step 1: Collect all unique properties that exist in the elements
                    const availableProps = new Set();
                    items.forEach(item => {
                        item.properties.forEach(prop => availableProps.add(prop.displayName));
                    });
                    // Filter to only keep our target props that are actually present
                    const validColumns = Array.from(availableProps).filter(prop => targetProps.includes(prop));
                    // Map to DataTable column config
                    const columns = validColumns.map(prop => ({
                        key: prop,
                        label: prop,
                        sortable: true
                    }));

                    // Step 2: Build row data - each row corresponds to an element
                    const rows = items.map(item => {
                        // For each valid column, get the property value (or empty string if missing)
                        return validColumns.map(colKey => {
                            const prop = item.properties.find(p => p.displayName === colKey);
                            return prop ? prop.displayValue : '';
                        });
                    });

                    // Update the panel's DataTable
                    this._panel.updateTable(columns, rows);
                }, (err) => {
                    console.error('Failed to get bulk properties:', err);
                });
            });
        };

        this._button.setToolTip('Model Element Properties');
        this._button.addClass('testTest');
        this._group.addControl(this._button);
    }
}

Autodesk.Viewing.theExtensionManager.registerExtension('testTest', testTest);

Key Changes & Explanations

  1. Custom Panel with DataTable: We defined ModelSummaryPanel extending Autodesk.Viewing.UI.DockingPanel, which creates a container for the DataTable and includes an updateTable method to refresh data.
  2. Dynamic Columns: We first collect all properties from elements that are in our target list (targetProps), so we only show columns for properties that actually exist in the model.
  3. Row Data Construction: For each element, we map the valid columns to their corresponding values (or empty string if the element doesn't have that property).
  4. Fixed Typo: Corrected DataTabe to DataTable in your original code.
  5. Replaced Count Logic: Instead of counting property occurrences, we now build a row per element with its actual property values, which is what you need for a DataTable.

How It Works

  • When you click the toolbar button, the panel toggles visibility.
  • If visible, it fetches all leaf elements, retrieves their target properties.
  • It dynamically creates columns for properties that exist in the elements.
  • It builds rows of data for each element, matching the column order.
  • Finally, it updates the DataTable in the panel with the new columns and rows.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 18:28:16