如何在Angular中为Forge Viewer创建导出数据为CSV格式的下载按钮
Forge Viewer SVF属性导出CSV实现方案
基于你现有的ng2-adsk-forge-viewer扩展代码,只需新增属性拉取、CSV格式转换、交互触发三个模块的逻辑即可完成需求,修改后的完整代码如下:
import { Extension } from 'ng2-adsk-forge-viewer'; // 如果你项目用Angular HttpClient,在这里导入 // import { HttpClient } from '@angular/common/http'; declare const THREE: any; export class ForgeExtension extends Extension { // 扩展名称固定 public static extensionName: string = 'ForgeExtension'; private subToolbar: Autodesk.Viewing.UI.ToolBar; private onToolbarCreatedBinded: any; // 如果你用HttpClient,在这里注入 // constructor(viewer, options, private http: HttpClient) { // super(viewer, options); // } public activate() { return true; } public deactivate() { return true; } public load() { console.log('ForgeExtension 已加载!'); this.viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT, (e) => { if (e.dbIdArray.length) { const dbId = e.dbIdArray[0]; this.viewer.setThemingColor(dbId, new THREE.Vector4(0, 1, 1, 1)); } }); // 初始化工具栏 if (this.viewer.toolbar) { this.createUI(); } else { this.onToolbarCreatedBinded = this.onToolbarCreated.bind(this); this.viewer.addEventListener(Autodesk.Viewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded); } return true; } public unload() { if (this.subToolbar) { this.viewer.toolbar.removeControl(this.subToolbar); this.subToolbar = null; } console.log('ForgeExtension 已卸载.'); return true; } public onToolbarCreated() { this.viewer.removeEventListener(Autodesk.Viewing.TOOLBAR_CREATED_EVENT, this.onToolbarCreatedBinded); this.onToolbarCreatedBinded = null; this.createUI(); } private createUI() { // 视角切换按钮(保留原有功能) const button1 = new Autodesk.Viewing.UI.Button('my-view-front-button'); button1.onClick = e => this.setViewCube('front'); button1.addClass('my-view-front-button'); button1.setToolTip('前视图'); const button2 = new Autodesk.Viewing.UI.Button('my-view-back-button'); button2.onClick = e => this.setViewCube('back'); button2.addClass('my-view-back-button'); button2.setToolTip('后视图'); // 新增CSV导出按钮 const exportButton = new Autodesk.Viewing.UI.Button('export-csv-button'); exportButton.onClick = async e => await this.handleExportCsv(); exportButton.addClass('export-csv-button'); exportButton.setToolTip('导出属性为CSV'); // 组装工具栏 this.subToolbar = new Autodesk.Viewing.UI.ControlGroup('my-custom-view-toolbar'); this.subToolbar.addControl(button1); this.subToolbar.addControl(button2); this.subToolbar.addControl(exportButton); this.viewer.toolbar.addControl(this.subToolbar); } private setViewCube(orientation: 'front' | 'back') { const ext = (this.viewer.getExtension('Autodesk.ViewCubeUi') as any); ext.setViewCube(orientation); } // 核心:获取所有带属性的模型元素 private async getAllElementProperties(): Promise<any[]> { const result = []; const instanceTree = this.viewer.model.getInstanceTree(); const rootId = instanceTree.getRootId(); const allDbIds = []; // 遍历所有元素dbId instanceTree.enumNodeChildren(rootId, (dbId) => { allDbIds.push(dbId); }, true); // 批量获取属性,过滤无属性元素 for (const dbId of allDbIds) { const props = await new Promise((resolve) => { this.viewer.getProperties(dbId, resolve, () => resolve(null)); }); if (props?.properties) { // 把属性数组转成对象方便后续处理 const propObj = { dbId: dbId, name: props.name }; props.properties.forEach(p => { propObj[p.displayName] = p.displayValue; }); result.push(propObj); } } return result; } // 转换为CSV格式 private convertToCsv(data: any[]): string { if (!data.length) return ''; // 提取所有表头字段 const headers = Array.from(new Set(data.flatMap(item => Object.keys(item)))); // 处理特殊字符转义 const escapeCsv = (val) => { if (val == null) return ''; const str = String(val); return str.includes(',') || str.includes('"') || str.includes('\n') ? `"${str.replace(/"/g, '""')}"` : str; }; // 拼接CSV内容 return [ headers.join(','), ...data.map(row => headers.map(h => escapeCsv(row[h])).join(',')) ].join('\n'); } // 导出按钮点击事件 private async handleExportCsv() { const propList = await this.getAllElementProperties(); const csvContent = this.convertToCsv(propList); // 功能1:直接下载CSV到本地 const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.setAttribute('download', `模型属性_${Date.now()}.csv`); document.body.appendChild(link); link.click(); document.body.removeChild(link); // 功能2:上传CSV到后端,不需要可以注释 const formData = new FormData(); formData.append('csvFile', blob, `模型属性_${Date.now()}.csv`); // 替换为你自己的后端接口地址 fetch('/api/upload-csv', { method: 'POST', body: formData }).then(res => res.json()).then(res => { console.log('上传成功', res); }).catch(err => { console.error('上传失败', err); }); // 如果用Angular HttpClient,替换为以下写法 // this.http.post('/api/upload-csv', formData).subscribe(res => { // console.log('上传成功', res); // }) } }
注意事项
- 如果需要只导出指定字段,可以在
getAllElementProperties方法中对生成的属性对象做裁剪,删除不需要的字段 - 大模型的属性拉取会有一定耗时,可以自行添加loading交互优化用户体验
- 后端上传部分可以根据你项目的接口规范调整参数格式,支持直接传CSV字符串或者FormData文件格式
内容的提问来源于stack exchange,提问作者user13155928
相关产品推荐
相关产品推荐

