# 编辑图模关联

创建图模关联组件数据后,可以通过图模关联编辑器进行添加图纸、位置关联、预览设置等操作,在完成操作后,可以通过组件数据管理服务进行数据更新。 图模关联编辑器

# 获取View Token

组件加载需要通过View Token进行鉴权,在组件数据创建成功后,可以通过返回数据中的moduleDataId获取View Token,实现组件管理器的初始化和图模关联组件的加载。View Token获取方法详见接口文档:获取View Token (opens new window)

# 引用BIMFACE JavaScript SDK

在使用BIMFACE JSSDK之前,你需要新建一个HTML文件,并在浏览器中打开。

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>图模关联编辑</title>
  <script src="https://static.bimface.com/api/BimfaceSDKLoader/BimfaceSDKLoader@latest-release.js" charset="utf-8"></script>
</head>

<body>
  <script>
    // 在这里输入BIMFACE JavaScript SDK提供的方法
  </script>
</body>

</html>

# 新建DOM元素

在网页中新建DOM元素,用于显示模型或图纸。

<div id="domId"></div>

# 图模关联数据加载

首先需要构造组件管理器,构造完成后可以通过组件数据的View Token和组件类型加载图模关联组件。在组件加载完成后才可以构造图模关联编辑器,可通过then()方法异步执行。

// 构造组件管理器的配置项
let managerConfig = new Glodon.Bimface.Module.ModuleManagerConfig();
// 构造组件管理器对象
moduleManager = new Glodon.Bimface.Module.ModuleManager(managerConfig);
// 加载组件
moduleManager.loadModule({
  // 组件数据的View Token
  viewToken: viewToken,
  // 组件类型,"Linkage2D3D"为图模关联
  moduleType: "Linkage2D3D"
}).then(() => {
  // 构造图模关联编辑器的配置项
  let editorConfig = new Glodon.Bimface.Module.Linkage2D3D.EditorConfig();
  // 指定存放应用界面的DOM容器
  editorConfig.domElement = document.getElementById("domId");
  // 获取待添加资源列表的方法,该方法需返回一个Promise对象,具体定义见下一小节
  editorConfig.getResourceListHandler = getResourceListHandler;
  // 添加资源时获取对应viewToken的方法,该方法需返回一个Promise对象,具体定义见下一小节
  editorConfig.getViewTokenHandler = getViewTokenHandler;
  // 构造图模联动编辑器
  editor = new Glodon.Bimface.Module.Linkage2D3D.Editor(editorConfig);

  // 获取Viewer3D对象,获取后可以调用Viewer3D类下的方法
  viewer3D = editor.getViewer3D();
  // 获取ViewerDrawing对象,获取后可以调用ViewerDrawing类下的方法,需要在ViewerDrawing初始化完成后执行
  editor.addEventListener(Glodon.Bimface.Module.Linkage2D3D.EditorEvent.ViewerDrawingInitialized, () => {
    viewerDrawing = editor.getViewerDrawing();
  });
});

# 图模关联编辑组件初始化

在上一步中,我们进行了编辑组件的初始化配置,这一小节我们将对初始化的配置参数进行详细说明。

首先,在构造了EditorConfig后,需要设置DOM容器,并定义getResourceListHandler、getViewTokenHandler两个回调函数。

其中getResourceListHandler为图模关联编辑中添加图纸资源时获取待添加图纸资源列表的方法;getViewTokenHandler为添加资源时获取待添加资源viewToken的方法。

# getResourceListHandler

基于编辑组件添加图纸资源时,将通过该方法获取可添加至关联中的图纸列表。该方法需带有Object类型的入参,如图所示,在资源添加过程中,选中列表内对应文件夹、进行文件搜索等操作时会传递对应的参数至该方法中。

添加资源列表

需要注意的是,示例代码中直接使用了BIMFACE的后端接口,业务系统集成时,需要对BIMFACE的后端接口进行封装,避免Access Token暴露在前端,从而影响数据安全。

基于传入参数,可调用获取转换资源列表 (opens new window)的后端接口获取符合条件的图纸,仅支持添加与模型处于同一项目且转换成功的二维图纸文件,即在后端接口body中需限制projectId、suffix、outputFormat、status。

# 传入参数
name type description
config Object 传入参数
config.parentId String 添加资源-点选对应文件夹时,返回该文件夹Id
config.searchKeyword String 添加资源-搜索对应资源时,传入对应搜索关键词
# 返回参数

该方法需返回一个Promise对象,在rosolve中返回符合条件的资源列表。

type description
Promise<Array> 返回Promise对象,resolve中的第一个参数返回需要展示的资源列表数组

返回列表及子项的格式为:

[
  {
    id: '10000007070001',
    isFolder: false,
    name: '一层图纸.dwg'
  },
  {
    id: '10000007070002',
    isFolder: true,  
    name: '文件夹-1'
  }
]
# 代码示例
// 获取待添加的图纸资源列表的回调
async function getResourceListHandler(config) {
  let headers = new Headers();
  // 基于Access Token发起后端接口调用,需要注意的是,示例代码中直接使用了BIMFACE的后端接口,业务系统集成时,需要对BIMFACE的后端接口进行封装,避免Access Token暴露在前端,从而影响数据安全,后端接口文档参考:https://bimface.com/docs/model-derivative/v1/api-reference/getResourceListUsingPOST.html
  headers = {
    "Authorization": "Bearer cn-e9725999-0b36-4c0e-bdca-38ea88888888",
    "Content-Type": "application/json"
  };

  // 需传入组件所在的项目ID,获取转换资源列表。
  let url = "https://api.bimface.com/v1/10000000006014/translations";
  // 后端接口的请求body需限制资源类型
  let body = {
    // 限制文件类型为dwg
    "suffix": "dwg",
    // 限制状态为转换成功
    "status": 99,
    // 限制图纸类型为二维图纸
    "outputFormat": "bdv",
    // 搜索模式时,基于名称进行模糊匹配或基于ID进行精准匹配
    "keyword": config.searchKeyword,
    // 获取指定文件夹下的资源
    "parentId": config.parentId,
  }

  // 获取接口返回值
  let res = await fetch(url, { method: "POST", headers: headers, body: JSON.stringify(body) });
  let resJson = await res.json();
  let result = [];
  resJson.data && resJson.data.list.forEach((item) => {
    // 记录文件ID、文件名称、是否为文件夹
    result.push({
      id: item.fileId || item.integrateId,
      name: item.name,
      isFolder: item.isFolder
    });
  });
  return new Promise((resolve) => resolve(result));
}

# getViewTokenHandler

勾选完待添加的图纸后,通过getResourceListHandler方法可以获取待添加图纸资源的View Token。该方法需带有Array类型的入参,如图所示,在点击“添加”按钮时会传递对应的多个图纸资源的信息至该方法中。

资源viewToken列表

基于传入参数,可调用获取View Token (opens new window)后端接口获取View Token。

# 传入参数
name type description
list Array 传入参数,由需要获取View Token的图纸信息组成的数组

列表及子项的格式为:

[
  {
    id: '10000007070001',
    isFolder: false,
    name: '一层图纸.dwg'
  }
]
# 返回参数

该方法需返回一个Promise对象,在resolve中返回获取到的多个viewToken信息。

type description
Promise<Array> 返回Promise对象,resolve中的第一个参数返回待添加的资源数组

返回列表及子项的格式为:

[
  {
    id: '10000007070001',
    name: '一层平面图.dwg',
    viewToken: 'c6eec7b8b4724da2926959b17c351622',
  }
]
# 代码示例
// 获取ViewToken的回调
function getViewTokenHandler(list) {
  let result = [];
  return new Promise((resolve) => {
    Promise.all(list.map((item) => getViewToken(item.id, item.name, item.isFolder))).then((data) => {
      data.forEach((item) => result.push(...item));
      resolve(result);
    });
  });
}

// 获取单个资源的View Token
async function getViewToken(id, name, isFolder) {
  // 判断传入对象是否为文件夹。若为文件夹,则需先获取文件夹内的资源列表,再获取各资源的viewToken
  if (isFolder) {
    // 获取文件夹内的资源列表
    let folderFileList = await getResourceListHandler({ type: "file", parentId: id });
    let list = [];
    folderFileList.forEach((item) => {
      let newItem = {
        ...item
      };
      list.push(newItem);
    });
    let viewTokenList = await getViewTokenHandler(list);
    return viewTokenList;
  }

  let headers = new Headers();
  // 基于Access Token发起后端接口调用,需要注意的是,示例代码中直接使用了BIMFACE的后端接口,业务系统集成时,需要对BIMFACE的后端接口进行封装,避免Access Token暴露在前端,从而影响数据安全,后端接口文档参考:https://bimface.com/docs/authenticatione/v1/api-reference/getViewTokenByFileIdUsingGET.html
  headers = {
    "Authorization": "Bearer cn-e9725999-0b36-4c0e-bdca-38ea88888888",
    "Content-Type": "application/json"
  };
  // 基于后端接口获取模型的View Token
  let url = `https://api.bimface.com/view/token?fileId=${id}`;
  // 获取后端接口返回值
  let res = await fetch(url, { method: "GET", headers: headers });
  let resJson = await res.json();
  let result = [];
  result.push({
    id: id,
    name: name,
    viewToken: resJson.data
  });
  return result;
}

# 编辑组件数据更新

通过编辑器完成图模关联后,需要更新组件数据。因此需要在页面中添加一个按钮,用来控制数据的更新。首先需要构造一个“保存”按钮,然后在按钮的点击事件中实现组件数据的更新流程。在class为buttons的div下输入如下内容:

<button class='button' onclick="save()">保存</button>

我们可以通过css代码对按钮的样式进行定义:

.button {
  margin: 5px 0 5px 5px;
  width: 100px;
  height: 30px;
  border-radius: 3px;
  border: none;
  background: #32D3A6;
  color: #FFFFFF;
  margin-right: 20px;
  margin-bottom: 4px;
}

接下来就需要在“保存”按钮的点击事件中实现关联数据的更新流程。

图模关联编辑组件中提供了获取编辑后的组件数据的接口:getCurrentData(),该接口能够返回当前编辑后最新的组件数据信息,包括关联的图纸列表、位置信息、预览配置等。基于返回的数据可以调用后端接口更新组件数据 (opens new window)进行数据更新。

// 更新组件数据
function save() {
  let body = {
    // 基于编辑组件返回的数据进行组件数据更新
    ...editor.getCurrentData()
  };
  return new Promise((resolve) => {
    // 基于后端接口进行组件数据更新,需将ID替换为当前进行编辑的组件数据ID
    let url = "https://api.bimface.com/module/v1/module-data/2502933573946112";
    let headers = new Headers();
    // 基于Access Token发起后端接口调用,业务系统集成时,需要对BIMFACE的后端接口进行封装,避免Access Token暴露在前端,从而影响数据安全
    headers = {
      "Authorization": "Bearer cn-e9725999-0b36-4c0e-bdca-38ea88888888",
      "Content-Type": "application/json"
    };

    fetch(url, { method: "PATCH", headers: headers, body: JSON.stringify(body) }).then((response) => {
      console.log('更新成功', response);
    })
  });
}

# 完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>图模关联编辑</title>
  <style type="text/css">
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      height: 100%;
    }

    .buttons {
      font-size: 0;
    }

    .button {
      margin: 5px 0 5px 5px;
      width: 100px;
      height: 30px;
      border-radius: 3px;
      border: none;
      background: #32D3A6;
      color: #FFFFFF;
      margin-right: 20px;
      margin-bottom: 4px;
    }

    .main {
      display: flex;
      flex-direction: column;
      overflow: hidden;
      height: 100%;
    }

    .footer {
      width: 100%;
      height: 50px;
      align-items: center;
      justify-content: end;
      display: flex;
    }

    #domId {
      flex: 1;
    }
  </style>
  <!-- 引用BIMFACE的JavaScript显示组件库 -->
  <script src="https://static.bimface.com/api/BimfaceSDKLoader/BimfaceSDKLoader@latest-release.js"
    charset="utf-8"></script>
</head>

<body>
  <div class="main">
    <!-- 定义DOM元素,用于在该DOM元素中显示组件 -->
    <div id="domId"></div>
    <div class="footer" id="buttons">
      <button class="button" onclick="save()">保存</button>
    </div>
  </div>

  <script type="text/javascript">
    // 声明变量
    let moduleManager;
    let editor;
    let viewer3D;
    let viewerDrawing;
    let projectId = "10000000006014";
    let moduleDataId = "2502933573946112";
    let viewToken = "5789250cb0624f148e120e000482ecb7";

    // 构造组件管理器的配置项
    let managerConfig = new Glodon.Bimface.Module.ModuleManagerConfig();
    // 构造组件管理器对象
    moduleManager = new Glodon.Bimface.Module.ModuleManager(managerConfig);
    // 加载组件
    moduleManager.loadModule({
      // 组件数据的View Token
      viewToken: viewToken,
      // 组件类型,"Linkage2D3D"为图模联动
      moduleType: "Linkage2D3D"
    }).then(() => {
      // 构造图模联动编辑器的配置项
      let editorConfig = new Glodon.Bimface.Module.Linkage2D3D.EditorConfig();
      // 指定存放应用界面的DOM容器
      editorConfig.domElement = document.getElementById("domId");
      // 设置图纸工具条Button对象
      editorConfig.drawingButtons = ["Home", "RectZoom", "DrawingMeasure", "Map", "Sheets", "Layers", "Setting", "FullScreen"];
      // 设置模型工具条Button对象
      editorConfig.modelButtons = ['Home', 'View', 'RectangleSelect', 'Measure', 'Section', 'Walk', 'Map', 'Property', 'Setting', 'Information', 'FullScreen'];
      // 获取待添加资源列表的方法,该方法需返回一个Promise对象
      editorConfig.getResourceListHandler = getResourceListHandler;
      // 添加资源时获取对应viewToken的方法,该方法需返回一个Promise对象
      editorConfig.getViewTokenHandler = getViewTokenHandler;
      // 构造图模联动编辑器
      editor = new Glodon.Bimface.Module.Linkage2D3D.Editor(editorConfig);

      // 获取Viewer3D对象,获取后可以调用Viewer3D类下的方法
      viewer3D = editor.getViewer3D();
      // 获取ViewerDrawing对象,获取后可以调用ViewerDrawing类下的方法,需要在ViewerDrawing初始化完成后执行
      editor.addEventListener(Glodon.Bimface.Module.Linkage2D3D.EditorEvent.ViewerDrawingInitialized, () => {
        viewerDrawing = editor.getViewerDrawing();
      });
    });


    // 获取待添加资源列表的回调
    async function getResourceListHandler(config) {
      let headers = new Headers();
      // 基于Access Token发起后端接口调用,需要注意的是,业务系统集成时,需要对BIMFACE的后端接口进行封装,避免Access Token暴露在前端,从而影响数据安全,后端接口文档参考:https://bimface.com/docs/model-derivative/v1/api-reference/getResourceListUsingPOST.html
      headers = {
        "Authorization": "Bearer cn-79d115e2-3523-4835-bfa1-625e42a2b124",
        "Content-Type": "application/json"
      };

      // 需传入场景所在的项目ID,获取转换资源列表
      let url = "https://api.bimface.com/v1/10000000006014/translations";
      // 后端接口的请求body需限制资源为dwg文件
      let body = {
        // 限制资源为dwg文件
        "suffix": "dwg",
        // 限制状态为转换成功或集成成功
        "status": 99,
        // 限制图纸类型为二维图纸
        "outputFormat": "bdv",
        // 搜索模式时,基于名称进行模糊匹配或基于ID进行精准匹配
        "keyword": config.searchKeyword,
        // 获取指定文件夹下的资源
        "parentId": config.parentId,
      }

      // 获取接口返回值
      let res = await fetch(url, { method: "POST", headers: headers, body: JSON.stringify(body) });
      let resJson = await res.json();
      let result = [];
      resJson.data && resJson.data.list.forEach((item) => {
        // 记录文件ID、文件名称、是否为文件夹
        result.push({
          id: item.fileId,
          name: item.name,
          isFolder: item.isFolder
        });
      });
      return new Promise((resolve) => resolve(result));
    }

    // 获取ViewToken的回调
    function getViewTokenHandler(list) {
      let result = [];
      return new Promise((resolve) => {
        Promise.all(list.map((item) => getViewToken(item.id, item.name, item.isFolder))).then((data) => {
          data.forEach((item) => result.push(...item));
          resolve(result);
        });
      });
    }

    // 获取单个资源的View Token
    async function getViewToken(id, name, isFolder) {
      // 判断传入对象是否为文件夹。若为文件夹,则需先获取文件夹内的资源列表,再获取各资源的View Token
      if (isFolder) {
        // 获取文件夹内的资源列表
        let folderFileList = await getResourceListHandler({ type: "file", parentId: id });
        let list = [];
        folderFileList.forEach((item) => {
          let newItem = {
            ...item
          };
          list.push(newItem);
        });
        let viewTokenList = await getViewTokenHandler(list);
        return viewTokenList;
      }

      let headers = new Headers();
      // 基于Access Token发起后端接口调用,需要特别注意的是,业务系统集成时,需要对BIMFACE的后端接口进行封装,避免Access Token暴露在前端,从而影响数据安全,后端接口文档参考:https://bimface.com/docs/authentication/v1/api-reference/getViewTokenByFileIdUsingGET.html
      headers = {
        "Authorization": "Bearer cn-79d115e2-3523-4835-bfa1-625e42a2b124",
        "Content-Type": "application/json"
      };
      // 基于后端接口获取模型的View Token
      let url = `https://api.bimface.com/view/token?fileId=${id}`;
      // 获取后端接口返回值
      let res = await fetch(url, { method: "GET", headers: headers });
      let resJson = await res.json();
      let result = [];
      result.push({
        id: id,
        name: name,
        viewToken: resJson.data
      });
      return result;
    }

    // 更新组件数据
    function save() {
      let body = {
        // 基于编辑组件返回的数据进行组件数据更新
        ...editor.getCurrentData()
      };
      return new Promise((resolve) => {
        // 基于后端接口进行组件数据更新,需将ID替换为当前进行编辑的组件数据ID
        let url = "https://api.bimface.com/module/v1/module-data/2502933573946112";
        let headers = new Headers();
        // 基于Access Token发起后端接口调用,业务系统集成时,需要对BIMFACE的后端接口进行封装,避免Access Token暴露在前端,从而影响数据安全
        headers = {
          "Authorization": "Bearer cn-79d115e2-3523-4835-bfa1-625e42a2b124",
          "Content-Type": "application/json"
        };

        fetch(url, { method: "PATCH", headers: headers, body: JSON.stringify(body) }).then((response) => {
          console.log('更新成功', response);
        });
      });
    }

  </script>
</body>

</html>