












在之前的文檔中,我們已對 MxCAD 產品進行了宏觀介紹,並完成了開發環境的初步搭建與 Demo 運行。然而,從“運行官方示例”到“構建自有業務系統”之間,仍存在概念理解與工程落地的鴻溝。本篇文檔的核心目標在於填補這一空白,重點解決以下兩個關鍵問題:
概念理清:深入解析 MxCAD 與 MxDraw 的技術定位與職能邊界。明確 MxCAD 作為“編輯內核”負責原圖數據的深度操作,而 MxDraw 作為“渲染引擎”專注於圖紙瀏覽與非侵入式批註。
工程落地:指導開發者在自己的項目中,從零構建一個具備圖紙加載、視圖瀏覽、獨立批註功能的最小可行性產品(MVP),下面以vue項目為講解示例。
通過本文的學習,您將掌握如何根據業務需求(是僅需審閱批註,還是需要修改原圖)選擇合適的技術組件,並能夠獨立搭建起一個可運行的 Web CAD 基礎框架,為後續開發複雜的在線設計平臺奠定堅實基礎。

在夢想雲圖(DreamCloud CAD)的技術體系中,MxCAD 與 MxDraw 是兩個核心組件。儘管二者在底層緊密耦合,但在業務邏輯與應用場景上存在明確的職能劃分。理解二者的區別是進行二次開發的前提。
定義:MxCAD 是基於 C++ 核心通過 WebAssembly (Wasm) 移植至 Web 端的專業 CAD 開發框架。
核心職能:圖紙數據編輯與深度業務邏輯。
適用場景:Web 端在線繪圖、圖紙深化設計、自動化生成報表、基於圖紙數據的業務系統集成。
在實際的技術架構中,MxCAD 與 MxDraw 並非孤立存在,而是呈現出緊密的層級協作與演進關係:

MxDraw 是夢想雲圖技術體系的基礎層。它提供了核心的 HTML5 Canvas 渲染能力、基礎的圖形交互邏輯以及輕量級的批註功能。其設計初衷是解決“在網頁上快速、高效地展示和標註 CAD 圖紙”這一核心痛點。
MxCAD 則是基於 MxDraw 的全功能升級版本。它在保留並複用 MxDraw 所有渲染與交互優勢的基礎上,通過引入 C++ 內核(編譯為 WebAssembly)和 TypeScript 業務框架,擴展了完整的 CAD 數據解析、實體編輯、幾何計算及複雜命令處理能力。
簡而言之:MxCAD = MxDraw (渲染與交互) + CAD 專業內核 (數據與邏輯)。
默認集成:在大多數應用場景下,開發者引入 MxCAD 開發包時,實際上已經包含了 MxDraw 的功能模塊。MxCAD 內部會自動調用 MxDraw 進行圖形繪製和用戶交互監聽。
按需調用:
無縫切換:由於二者同源,開發者可以在同一個項目中根據權限或功能模塊,動態切換“只讀/批註模式”與“編輯模式”,無需更換底層引擎,保證了用戶體驗的一致性與技術架構的統一性。
這種架構設計既保證了輕量級應用的極致性能,又為專業級應用提供了無限擴展的可能。
環境要求
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.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' // 確保編譯目標支持最新特性 } })
模板結構: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 lang="ts"> 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 配置接口文檔。
重要說明:MxCAD 文件格式限制
MxCAD 引擎內核僅能直接解析和打開特定的 .mxweb 格式文件。它無法直接在瀏覽器端讀取原生的 AutoCAD 格式(如 .dwg 或 .dxf)。
因此,在實現“打開圖紙”功能時,必須遵循以下邏輯:
判斷格式:檢查用戶選擇的文件後綴。
格式轉換:如果文件是 .dwg 或 .dxf,必須先將其上傳至後端轉換服務,由服務端將其轉換為 .mxweb 格式。
加載渲染:只有獲取到 .mxweb 格式的文件流或 URL 後,才能調用 mxcad.openWebFile() 進行加載和渲染。
若跳過轉換步驟直接嘗試加載 DWG 文件,MxCAD 將報錯或無法顯示任何內容。

文件選擇與處理流程
基於上述限制,我們的代碼邏輯分為兩條路徑:
跨域處理配置
由於前端開發服務器(默認 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 lang="ts"> // ... 上述初始化代碼 ... // 打開圖紙處理函數 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>
關鍵點說明:
創建批註(以審圖雲線為例)
此功能通過 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 回調)自動從後端拉取數據並執行加載。
啟動服務:
測試流程:
路徑配置敏感性
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”的映射關係,避免不同圖紙間的批註混淆。
此內容由慣性聚合(RSS閱讀器)自動聚合整理,僅供閱讀參考。 原文來自 — 版權歸原作者所有。