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

如何在单网页加载2D及3D Forge查看器并实现双向元素联动

现有初始化代码问题修正

你的初始化逻辑存在两个明显问题:

  • 变量名不匹配:你声明的查看器实例变量是firstModel和secondModel,后续回调里用的是未定义的viewer1、viewer2,运行时会直接报错
  • 重复调用初始化方法:Autodesk.Viewing.Initializer只需调用一次即可,不需要为两个查看器分别初始化,只要用同一套授权token配置初始化一次,在回调中依次初始化两个查看器就行

正确的初始化代码示例:

let viewer2D, viewer3D;
let isSyncing = false; // 防止联动时事件循环触发的锁变量
const options = {
  env: 'AutodeskProduction',
  accessToken: '你的访问token'
};

// 全局只需初始化一次
Autodesk.Viewing.Initializer(options, async function() {
  // 初始化2D图纸查看器
  viewer2D = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('MyViewerDiv1'));
  viewer2D.start();
  await viewer2D.loadDocumentNode(/* 你的2D文档节点参数 */);
  
  // 初始化3D模型查看器
  viewer3D = new Autodesk.Viewing.Private.GuiViewer3D(document.getElementById('MyViewerDiv2'));
  viewer3D.start();
  await viewer3D.loadDocumentNode(/* 你的3D文档节点参数 */);
  
  // 两个模型都加载完成后绑定联动事件、构建ID映射
  buildIdMapping();
  bindSyncEvents();
});
双向联动功能实现

要实现2D、3D的双向同步,核心是先建立两端构件的ID映射关系,再监听两端的操作事件做同步处理,具体实现步骤如下:

1. 构建2D-3D构件ID映射表

同一套Revit文件导出的2D图纸和3D模型中,同一个构件的externalId是全局一致的,可以以此为桥梁构建两端dbId的映射:

let dbId2DTo3D = new Map();
let dbId3DTo2D = new Map();

async function buildIdMapping() {
  // 批量获取2D所有构件的externalId
  const 2dProps = await new Promise(resolve => {
    viewer2D.model.getBulkProperties(viewer2D.model.getInstanceTree().getRootId(), ['externalId'], resolve);
  });
  // 批量获取3D所有构件的externalId
  const 3dProps = await new Promise(resolve => {
    viewer3D.model.getBulkProperties(viewer3D.model.getInstanceTree().getRootId(), ['externalId'], resolve);
  });
  // 建立双向映射关系
  const extIdTo3dDbId = new Map(3dProps.map(p => [p.externalId, p.dbId]));
  2dProps.forEach(p => {
    const matched3dDbId = extIdTo3dDbId.get(p.externalId);
    if (matched3dDbId) {
      dbId2DTo3D.set(p.dbId, matched3dDbId);
      dbId3DTo2D.set(matched3dDbId, p.dbId);
    }
  });
}

2. 选中与隔离联动

监听两个查看器的选中事件,同步选中和隔离对应构件,通过锁变量避免事件循环触发重复同步:

function bindSyncEvents() {
  // 监听2D侧选中事件
  viewer2D.addEventListener(Autodesk.Viewing.AGGREGATE_SELECTION_CHANGED_EVENT, (e) => {
    if (isSyncing) return;
    isSyncing = true;
    const selected2dDbIds = e.selections.map(s => s.dbIdArray).flat();
    const mapped3dDbIds = selected2dDbIds.map(id => dbId2DTo3D.get(id)).filter(Boolean);
    
    // 同步到3D侧:选中+隔离
    viewer3D.select(mapped3dDbIds);
    viewer3D.isolate(mapped3dDbIds);
    isSyncing = false;
  });
  
  // 监听3D侧选中事件
  viewer3D.addEventListener(Autodesk.Viewing.AGGREGATE_SELECTION_CHANGED_EVENT, (e) => {
    if (isSyncing) return;
    isSyncing = true;
    const selected3dDbIds = e.selections.map(s => s.dbIdArray).flat();
    const mapped2dDbIds = selected3dDbIds.map(id => dbId3DTo2D.get(id)).filter(Boolean);
    
    // 同步到2D侧:选中+隔离
    viewer2D.select(mapped2dDbIds);
    viewer2D.isolate(mapped2dDbIds);
    isSyncing = false;
  });
}

3. 颜色修改同步

你可以封装统一的颜色修改方法,调用时两端同时设置主题色即可:

function syncElementColor(dbId, color, isFrom2D = true) {
  const rgbColor = new THREE.Vector4(color.r/255, color.g/255, color.b/255, color.a || 1);
  if (isFrom2D) {
    const target3dDbId = dbId2DTo3D.get(dbId);
    viewer2D.setThemingColor(dbId, rgbColor);
    target3dDbId && viewer3D.setThemingColor(target3dDbId, rgbColor);
  } else {
    const target2dDbId = dbId3DTo2D.get(dbId);
    viewer3D.setThemingColor(dbId, rgbColor);
    target2dDbId && viewer2D.setThemingColor(target2dDbId, rgbColor);
  }
}

如果需要监听用户通过查看器界面修改颜色的操作,绑定对应的颜色修改事件触发上述同步逻辑即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 04:18:00