ITPub博客

首页 > 应用开发 > Javascript > 在线CAD开发包实现批注和图纸查看(web端修改DWG图纸)

在线CAD开发包实现批注和图纸查看(web端修改DWG图纸)

原创 Javascript 作者:MxCAD 时间:2026-05-27 15:38:14 0 删除 编辑

前言

在之前的文档中,我们已对 MxCAD 产品进行了宏观介绍,并完成了开发环境的初步搭建与 Demo 运行。然而,从 “ 运行官方示例 ” 到 “ 构建自有业务系统 ” 之间,仍存在概念理解与工程落地的鸿沟。本篇文档的核心目标在于填补这一空白,重点解决以下两个关键问题:

概念理清: 深入解析 MxCAD   与 MxDraw   的技术定位与职能边界。明确 MxCAD   作为 “ 编辑内核 ” 负责原图数据的深度操作,而 MxDraw   作为 “ 渲染引擎 ” 专注于图纸浏览与非侵入式批注。

工程落地: 指导开发者在自己的项目中,从零构建一个具备图纸加载、视图浏览、独立批注功能的最小可行性产品(MVP ),下面以 vue 项目为讲解示例。

通过本文的学习,您将掌握如何根据业务需求(是仅需审阅批注,还是需要修改原图)选择合适的技术组件,并能够独立搭建起一个可运行的 Web CAD 基础框架,为后续开发复杂的在线设计平台奠定坚实基础。

一 . 核心架构解析:MxCAD 与 MxDraw 的功能界定

在梦想云图(DreamCloud CAD )的技术体系中, MxCAD   与 MxDraw   是两个核心组件。尽管二者在底层紧密耦合,但在业务逻辑与应用场景上存在明确的职能划分。理解二者的区别是进行二次开发的前提。

1.1 MxDraw:轻量级前端渲染与批注引擎

·   定义 : MxDraw   是一个基于 HTML5 Canvas 及 WebGL 技术的前端图形渲染引擎。

·   核心职能 :图纸浏览与非侵入式批注。

o   渲染展示 :负责将 CAD 矢量数据高效地绘制于浏览器端,支持平移、缩放、旋转等视图操作。

o   批注处理 :提供独立的批注图层管理功能。用户可在图纸上层添加云线、文字注释、测量标记等信息。

o   数据隔离 : MxDraw   的批注操作 不修改 原始 DWG/DXF 文件的几何数据与数据库结构。批注信息通常以独立文件(如 JSON 或专用批注格式)存储,或与原图分离保存,确保原图的完整性与安全性。

·   适用场景 :图纸在线审阅、协同设计标注、移动端轻量化查看、无需修改原图的设计评审。

1.2 MxCAD:全功能 CAD 业务内核

定义 : MxCAD   是基于 C++ 核心通过 WebAssembly (Wasm) 移植至 Web 端的专业 CAD 开发框架。

核心职能 :图纸数据编辑与深度业务逻辑。

o   数据解析 :完整解析 AutoCAD 原生格式( DWG/DXF ),支持所有版本及复杂实体。

o   实体编辑 :提供对图纸底层数据库的直接读写能力。支持实体的创建、修改、删除、属性变更等操作,这些操作会直接改变原图纸的数据结构。

适用场景 :Web 端在线绘图、图纸深化设计、自动化生成报表、基于图纸数据的业务系统集成。

1.3 协作机制与版本演进

在实际的技术架构中, MxCAD   与 MxDraw   并非孤立存在,而是呈现出紧密的层级协作与演进关系:

基础与升级的关系

MxDraw   是梦想云图技术体系的基础层。它提供了核心的 HTML5 Canvas 渲染能力、基础的图形交互逻辑以及轻量级的批注功能。其设计初衷是解决 “ 在网页上快速、高效地展示和标注 CAD 图纸 ” 这一核心痛点。

MxCAD   则是基于 MxDraw   的全功能升级版本。它在保留并复用 MxDraw   所有渲染与交互优势的基础上,通过引入 C++ 内核(编译为 WebAssembly )和 TypeScript 业务框架,扩展了完整的 CAD 数据解析、实体编辑、几何计算及复杂命令处理能力。

简而言之 : MxCAD = MxDraw ( 渲染与交互 ) + CAD 专业内核 ( 数据与逻辑 ) 。


协作模式

默认集成: 在大多数应用场景下,开发者引入 MxCAD   开发包时,实际上已经包含了 MxDraw   的功能模块。 MxCAD   内部会自动调用 MxDraw   进行图形绘制和用户交互监听。

按需调用:  

o   若业务场景仅需查看与批注(如图纸审阅、移动端巡查),可直接利用 MxCAD   中集成的 MxDraw   接口模式。此时系统表现为轻量级引擎,不加载重型编辑内核(或仅使用其渲染部分),确保启动速度与运行性能。

o   若业务场景涉及原图修改、参数化设计或数据提取,则激活 MxCAD   的完整内核功能,对底层数据库进行读写操作。

无缝切换: 由于二者同源,开发者可以在同一个项目中根据权限或功能模块,动态切换 “ 只读 / 批注模式 ” 与 “ 编辑模式 ” ,无需更换底层引擎,保证了用户体验的一致性与技术架构的统一性。

这种架构设计既保证了轻量级应用的性能,又为专业级应用提供了无限扩展的可能。

二 . 构建基础CAD项目:图纸预览与批注实战

2.1 环境准备与项目初始化

环境要求

Node.js : ≥ v16

包管理器 : npm / pnpm


构建工具 :

Vite  ( 推荐,配置简单,开发速度快 )

Webpack  ( 支持,需配置 worker-loader   或相关 WASM 处理规则 )

其他:Rollup, Parcel 等支持自定义 Loader/Plugin 的构建工具均可。


后端服务 : 需运行云图开发包提供的图纸转换服务,用于处理 DWG/DXF 转 MXWEB 。

可直接开启云图开发包 3000 端口下的服务。

也可自行根据 图纸转换文档 规则设置新的转换接口。


创建或集成项目

您可新建项目或在现有项目中添加 CAD 模块:

# 新建 Vue3 + TypeScript 项目
npm create vite@latest cad-viewer -- --template vue-ts
cd cad-viewer
npm install

安装核心依赖

# 安装 mxcad 核心包
npm install mxcad
# 若使用 pnpm,请额外安装 mxdraw (通常 mxcad 已包含,视具体版本策略而定)
# pnpm add mxdraw

配置构建工具支持多线程

MxCAD 的高性能渲染依赖 SharedArrayBuffer ,这要求服务器响应头必须包含 Cross-Origin-Opener-Policy: same-origin   和 Cross-Origin-Embedder-Policy: require-corp 。 无论使用何种打包工具(Webpack 、 Rollup 等),都必须进行此配置 ,否则引擎将无法启动或自动降级。

下面以  Vite  为例演示配置方法,修改  vite.config.ts ,在  server.headers  中添加响应头 :

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
  plugins: [vue()],
  server: {
    // 开发环境:直接在此处配置响应头
    headers: {
      "Cross-Origin-Opener-Policy": "same-origin",
      "Cross-Origin-Embedder-Policy": "require-corp",
    }
  },
  build: {
    target: 'esnext' // 确保编译目标支持最新特性
  }
})

2.2 创建 Canvas 容器与初始化 MxCAD 引擎

模板结构:Canvas 与文件上传控件

在组件模板中定义渲染容器和文件选择器,并添加控制按钮。

<template>
  <!-- CAD 渲染区域 -->
  <div style="width: 100vw; height: 95vh; overflow: hidden;">
    <canvas id="myCanvas"></canvas>
  </div>
  <!-- 控制栏 -->
  <div style="margin-top: 10px; padding: 10px; background: #f5f5f5;">
    <!-- 隐藏的文件输入框 -->
    <input
      type="file"
      ref="fileInput"
      accept=".dwg,.dxf,.mxweb"
      @change="openDwgFile"
      style="display:none"
    />
    
    <!-- 功能按钮 -->
    <button @click="$refs.fileInput.click()" :disabled="!mxcadReady">打开图纸</button>
    <button @click="startCloudMark" :disabled="!mxcadReady">绘制云线批注</button>
    <button @click="saveMarkup" :disabled="!mxcadReady">保存批注</button>
    <button @click="loadMarkup" :disabled="!mxcadReady">加载批注</button>
  </div>
</template>


初始化 MxCAD 实例

在 Vue 组件的 onMounted   生命周期中调用 createMxCad ,完成 Canvas 绑定、 WASM 核心文件路径定位、字体库路径设置以及初始化完成的回调处理。

<script setup>
import { onMounted, ref } from 'vue';
import { createMxCad, MxCpp } from 'mxcad';
const mxcadReady = ref(false);
const fileInput = ref<HTMLInputElement | null>(null);
onMounted(() => {
  // 自动检测浏览器环境:支持 SharedArrayBuffer 则启用多线程 (2d),否则降级为单线程 (2d-st)
  const mode = "SharedArrayBuffer" in window ? "2d" : "2d-st";
  createMxCad({
    canvas: "#myCanvas",
    // 动态定位 WASM 文件路径,兼容 Vite/Webpack 等构建工具
    locateFile: (fileName: string) => {
      return new URL(
        `../../node_modules/mxcad/dist/wasm/${mode}/${fileName}`,
        import.meta.url
      ).href;
    },
    fileUrl: "", // 初始不加载文件,等待用户通过 UI 选择
    fontspath: new URL(
      "../../node_modules/mxcad/dist/fonts",
      import.meta.url
    ).href,
    // 初始化完成回调
    onInit: () => {
      console.log("MxCAD 引擎初始化完成");
      mxcadReady.value = true;
    }
  });
});
</script>

更多配置项 : createMxCad   支持丰富的自定义配置(如背景色、多选配置、视区移动方式等)。如需了解完整的配置参数列表及详细说明,请访问官方文档:[MxCadConfig 配置接口文档。

2.3 打开图纸并预览(关键格式说明)

重要说明: MxCAD 文件格式限制

MxCAD引擎内核仅能直接解析和打开特定的 .mxweb 格式文件 。它无法直接在浏览器端读取原生的 AutoCAD 格式(如 .dwg   或 .dxf )。

因此,在实现 “打开图纸”功能时,必须遵循以下逻辑:

判断格式 :检查用户选择的文件后缀。

格式转换 :如果文件是 .dwg   或 .dxf , 必须 先将其上传至后端转换服务,由服务端将其转换为 .mxweb   格式。

加载渲染 :只有获取到 .mxweb   格式的文件流或 URL 后,才能调用 mxcad.openWebFile()   进行加载和渲染。

若跳过转换步骤直接尝试加载 DWG 文件,MxCAD 将报错或无法显示任何内容。

文件选择与处理流程

基于上述限制,我们的代码逻辑分为两条路径:

·   路径 A (.mxweb) :浏览器原生支持,直接生成临时 URL 加载。

·   路径 B (.dwg/.dxf) :调用本地转换服务 localhost:3000/uploadfile   上传 -> 服务端自动转换 -> 返回 / 生成 .mxweb   路径 -> 加载。

跨域处理配置

由于前端开发服务器(默认 localhost:5173 )与图纸转换服务( localhost:3000 )端口不同,直接请求会触发浏览器的 跨域限制 (CORS) 。

无论使用何种打包工具(Webpack 、 Rollup 等) ,在开发环境下都必须配置代理(Proxy )或将请求转发至同源,以解决跨域问题。生产环境通常通过 Nginx 反向代理统一入口来解决。

以下以 Vite   为例演示开发环境的代理配置:

修改 vite.config.ts ,添加 server.proxy   配置,将 /api   或特定路径的请求转发至转换服务:

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
  plugins: [vue()],
  server: {
    // ....其他配置
      
    // 开发环境跨域代理配置
    proxy: {
      // 匹配所有以 /api 开头的请求(建议前端请求时加上 /api 前缀)
      '/api': {
        target: 'http://localhost:3000', // 图纸转换服务地址
        changeOrigin: true,              // 修改 Host 头为 target
        rewrite: (path) => path.replace(/^\/api/, ''), // 去掉 /api 前缀再转发
      },
      // 或者直接代理特定的转换接口路径
      //'/uploadfile': {
      //  target: 'http://localhost:3000',
      //  changeOrigin: true,
      // },
      // '/demo': {
      //  target: 'http://localhost:3000',
      //  changeOrigin: true,
      // }
    }
  }
})

前端代码适配示例: 配置代理后,前端请求地址需调整为相对路径或带前缀的路径:

// 原地址:http://localhost:3000/uploadfile
// 代理后地址:/api/uploadfile (需在 proxy 中配置 rewrite) 或直接 /uploadfile
const res = await fetch("/api/uploadfile", { // Vite 会自动拦截并转发到 localhost:3000/uploadfile
  method: "POST",
  body: formData,
});

代码实现:打开网络图纸

图纸的加载与渲染核心依赖于 MxCAD 提供的 openWebFile  API 。该接口支持从网络 URL 直接加载 .mxweb   或转换后的图纸数据,并提供了丰富的参数控制(如是否使用多线程、加载策略等)。

<script setup>
// ... 上述初始化代码 ...
// 打开图纸处理函数
const openDwgFile = async (event: Event) => {
  const target = event.target as HTMLInputElement;
  const file = target.files?.[0];
  
  if (!file) return;
  
  const fileName = file.name;
  // 获取文件后缀并转为小写
  const fileExt = fileName.slice(fileName.lastIndexOf(".")).toLowerCase();
  const mxcad = MxCpp.getCurrentMxCAD();
  if (fileExt === ".dwg" || fileExt === ".dxf") {
    // DWG/DXF 需要后端转换
    const formData = new FormData();
    formData.append("file", file);
    
    try {
      // 调用代理后的上传接口
      const res = await fetch("/upfile/mxcad", {
        method: "POST",
        body: formData,
      });
      
      if (!res.ok) throw new Error(`请求失败:${res.status}`);
      
      // 约定:转换后的文件位于 /demo/ 目录下,文件名不变,后缀变为 .mxweb
      const mxwebFullUrl = `/demo/${fileName}.mxweb`;
      mxcad.openWebFile(mxwebFullUrl);
      
    } catch (err) {
      console.error(err);
      alert("上传或转换失败,请检查后端服务是否启动");
    }
  } else if (fileExt === ".mxweb") {
    // MXWEB 直接读取
    const tempUrl = URL.createObjectURL(file);
    mxcad.openWebFile(tempUrl);
  } else {
    alert("不支持该文件格式,请上传 .dwg, .dxf 或 .mxweb");
  }
  
  // 重置 input value,允许重复选择同一文件
  target.value = "";
};
</script>

  关键点说明:

·   转换接口 : //localhost:3000/uploadfile   是云图开发包自带的演示服务,实际生产环境请替换为您的后端地址。

·   路径约定 : 代码假设转换服务会将结果固定在 /demo/   目录下,且文件名保持原名仅后缀变为 .mxweb 。

·   API 调用 : 无论源文件是什么,最终都统一调用 mxcad.openWebFile(url)   进行渲染。 openWebFile   支持更多高级参数,例如控制是否使用工作线程 ( isWorkThread ) 、指定数据加载到内存还是 IndexedDB ( fetchAttributes ) 等。如需了解完整的参数定义及详细说明,请访问官方文档: McObject.openWebFile API 文档 。

2.4 批注功能实现(创建、保存、回显)

创建批注(以审图云线为例)

此功能通过 MxDraw   提供的交互接口,让用户在图上绘制云线并添加文字说明。

import {
  MxFun,
  MrxDbgUiPrPoint,
  McEdGetPointWorldDrawObject,
  MrxDbgUiPrBaseReturn,
  MxDbRectBoxLeadComment,
} from "mxdraw";
// 绘制云线批注函数
function startCloudMark() {
  const point = new MrxDbgUiPrPoint(); // 获取点交互对象
  const mxDraw = MxFun.getCurrentDraw(); // 获取当前绘图对象
  const worldDrawComment = new McEdGetPointWorldDrawObject(); // 动态绘制辅助对象
  const mxCheckDraw = new MxDbRectBoxLeadComment(); // 云线批注实体对象
  // 设置云线半径(屏幕坐标转文档坐标)
  mxCheckDraw.radius = MxFun.screenCoordLong2Doc(5);
  mxCheckDraw.setLineWidth(3);
  mxCheckDraw.setLineWidthByPixels(true);
  // 第一步:获取起始点
  point.setMessage("\n云线框起始点: ");
  point.go((status) => {
    if (status != MrxDbgUiPrBaseReturn.kOk) return;
    
    mxCheckDraw.point1 = point.value();
    
    // 动态预览:移动鼠标时绘制矩形
    worldDrawComment.setDraw((currentPoint) => {
      mxCheckDraw.point2 = currentPoint;
      worldDrawComment.drawCustomEntity(mxCheckDraw);
    });
    point.setUserDraw(worldDrawComment);
    point.setMessage("\n云线框结束点: ");
    
    // 第二步:获取结束点
    point.go((status) => {
      if (status != MrxDbgUiPrBaseReturn.kOk) return;
      
      mxCheckDraw.point2 = point.value();
      
      // 动态预览:确定文本位置
      worldDrawComment.setDraw((currentPoint) => {
        mxCheckDraw.point3 = currentPoint;
        worldDrawComment.drawCustomEntity(mxCheckDraw);
      });
      // 设置批注文本属性
      mxCheckDraw.text = "审图批注";
      mxCheckDraw.textWidth = MxFun.screenCoordLong2Doc(100);
      mxCheckDraw.textHeight = MxFun.screenCoordLong2Doc(50);
      mxCheckDraw.fixedSize = true;
      if (mxCheckDraw.fixedSize) {
        mxCheckDraw.textHeight = 20;
        mxCheckDraw.textWidth = 130;
      }
      point.setMessage("\n审图标注点: ");
      
      // 第三步:获取文本引出点
      point.go((status) => {
        if (status != MrxDbgUiPrBaseReturn.kOk) return;
        
        mxCheckDraw.point3 = point.value();
        // 将实体添加到图纸数据库
        mxDraw.addMxEntity(mxCheckDraw);
      });
    });
  });
}

绘制效果如下所示:


保存批注数据

使用官方推荐的 saveMxEntityToJson()   方法,将当前图纸上的所有 非原生实体 (即批注)序列化为 JSON 字符串。本示例暂存至 localStorage   模拟数据库存储。

import { MxFun } from "mxdraw";
// 保存图纸批注
const saveMarkup = () => {
  const draw = MxFun.getCurrentDraw();
  if (!draw) return;
  
  // 序列化批注数据
  const jsonData = draw.saveMxEntityToJson();
  localStorage.setItem("mx-markup-data", jsonData);
  alert("批注已保存至本地存储");
};

回显批注数据

当用户再次打开图纸时,从存储中读取 JSON 数据,并调用 loadMxEntityFromJson()   还原批注。

import { MxFun } from "mxdraw";
// 恢复图纸批注
const loadMarkup = () => {
  const draw = MxFun.getCurrentDraw();
  if (!draw) return;
  const jsonData = localStorage.getItem("mx-markup-data");
  if (jsonData) {
    draw.loadMxEntityFromJson(jsonData);
    alert("批注已加载");
  } else {
    alert("未找到保存的批注数据");
  }
};

最佳实践提示 :在实际业务中,应将 saveMarkup  生成的 JSON 数据通过 AJAX/Fetch 发送给后端,与图纸 ID 关联存储; loadMarkup  应在图纸加载完成后(监听 onOpenFileComplete  回调)自动从后端拉取数据并执行加载。

2.5 运行验证

启动服务:

o   确保云图转换服务已在 localhost:3000   运行。

o   启动前端项目: npm run dev 。

测试流程:

o   预览 MXWEB :点击 “ 打开图纸 ” ,选择 .mxweb   文件 → 图纸秒开。

o   预览 DWG :点击 “ 打开图纸 ” ,选择 .dwg   文件 → 自动上传转换 → 加载转换后的图纸。

o   绘制批注 :点击 “ 绘制云线批注 ” ,在图上依次点击起始点、结束点、文字引出点 → 云线绘制成功。

o   保存 :点击 “ 保存批注 ” → 检查浏览器 LocalStorage 是否有 mx-markup-data   键值。

o   回显 :刷新页面(清空内存),重新打开同一张图纸 → 点击 “ 加载批注 ” → 确认云线准确还原。

三 . 常见问题与注意事项

路径配置敏感性

Wasm 文件和字体文件的路径配置必须精确。若控制台出现 404 错误或 Wasm 编译失败,请首先检查 public   目录结构及初始化参数中的 locateFile   和 fontspath   路径字符串是否正确。

跨域隔离策略 (COOP/COEP)

较新版本的 MxCAD 利用 SharedArrayBuffer   进行多线程优化以提升性能。若在 Chrome/Edge 中遇到 SharedArrayBuffer is not defined   相关报错,必须在 Web 服务器(或 Vite 配置)的响应头中严格配置:

Cross-Origin-Opener-Policy: same-origin

Cross-Origin-Embedder-Policy: require-corp

字体缺失处理

若图纸文字显示为问号或乱码,通常是因为缺少对应的 SHX 字体文件。请确保开发包中的 fonts   目录已完整部署到项目中,或在后端转换服务中配置字体映射。

大文件性能

对于超过 50MB 的超大图纸,建议在加载前进行前端提示。可考虑启用 SDK 中的按需加载功能或简化显示模式(如关闭抗锯齿、隐藏填充图案)以优化渲染帧率。

批注数据管理

批注数据是独立于原图存在的。务必在前端或后端建立 “ 图纸 ID - 批注 JSON” 的映射关系,避免不同图纸间的批注混淆。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70041755/viewspace-3172351/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2024-10-16

  • 博文量
    32
  • 访问量
    33346