前言

用户在网页中浏览编辑DWG图纸之后,会在图纸上进行审图批注,批注的内容会保存到服务器或原图纸中,本章节我们讲一下保存批注信息的方法,如果你还不会创建一个在线浏览编辑CAD图纸的前端应用,请参考使用:
MxDraw云图开发包的文档:https://help.mxdraw.com/?pid=32
mxcad库:https://mxcadx.gitee.io/mxcad_docs/zh/

在线功能测试:https://demo.mxdraw3d.com:3000/mxcad/

操作界面如下:

打开网易新闻 查看更多图片

实现步骤

用mxdraw绘制的批注图形,要保存到图纸上, 需要使用MxDraw云图开发包中对应服务进行保存 下面将详细讲解保存图纸批注的每一步。

首先下载MxDraw云图开发包(https://gitee.com/link?target=https%3A%2F%2Fwww.mxdraw.com%2Fdownload.html)开发包, 然后解压。可得到一个解压后的目录MxDrawCloudServer, 进入该目录, 运行Mx3dServer.exe软件。

点击按钮开始服务,再点击按钮VueBrowse 会加载一个网页,这个网页加载了一个在线浏览的图纸。

该网页的源码在开发包的MxDrawCloudServer\SRC\sample\Browse\2d\Browse目录, 在该目录下找到src\test\SaveDwg.ts文件, 代码如下:

  • let mxobj = MxFun.getCurrentDraw();
  • let saveData:any = mxobj.saveMxEntityToObject(true);
  • saveData.savefile = "../../SRC/TsWeb/public/demo/hhhhnew.dwg";
  • saveData.filename = "../../SRC/TsWeb/public/demo/hhhh.dwg";

  • console.log(saveData);
  • //前端附带身份凭证的请求,服务器Access-Control-Allow-Origin 设为*不会生效.
  • //所以需要 $api.defaults.withCredentials = false
  • $api.defaults.withCredentials = false
  • //$api.post("http://localhost:1337/savecomment", {
  • $api.post(MxFun.getHostUrl() + ":1337/savecomment", {
  • param: saveData
  • }).then((response: any) => {
  • if(response.data.ret == 0)
  • // 后台程序TsWebNodejs\routes\savedwg.js,它会调用MxFileConvert.exe使用MxDrawNode\src\mxconvert\SaveCommentToDwg.ts把批注数据,保存到demo目录下的hhhhnew.dwg文件中.
  • const sSaveUrl = MxFun.getHostUrl() + ":3000/demo/hhhhnew.dwg";
  • alert("保存成功,新文件下载地址:" + sSaveUrl);
  • else{
  • alert("保存失败,错误码:" + response.data.ret);
  • console.log(response.data);
  • .catch((error: any)=> {
  • alert("保存失败")

保存批注使用mxdraw提供的方法MxFun.getCurrentDraw().saveMxEntityToObject()得到一个JSON对象, 包含了页面中绘制的所有批注数据。

保存的两种方式

第一种方式是将这个数据保存在服务器的数据库中,再次打开这张图纸的时候,再去请求得到对应的批注数据,通过MxFun.getCurrentDraw().loadMxEntityFromJson(jsonString)在前端页面中直接恢复对应的批注。

第二种方式是直接保存到图纸上, 从上面代码得知,我们得到了所有批注数据的对象,在这个对象上设置了savefile表示保存了包含了批注的新图纸服务器上的地址。而filename就是现在网页上打开的图纸的原图纸在服务器上的地址。

然后发起了一个post请求, 下面我们看看在服务器中是如何处理的。

首先我们在开发包中找到MxDrawCloudServer\Bin\MxDrawServer\Windows\routes\savecomment.js

这里就是这个post请求接口定义的位置:

  • param.cmd = "savecomment";
  • (0, convert_1.callMxNodeJS)(param, (ret) => {
  • res.json(ret);

接下来我们找到callMxNodeJS这个函数, 在同目录下的convert.js文件中:

  • function callMxNodeJS(param, retcall) {
  • if (!param["cmd"]) {
  • retcall({ code: 6, message: "param.cmd empty" });
  • return;
  • let converparamFile;
  • if (param["file"]) {
  • if (mxconfig_1.default.isAbsolutePath(param.file)) {
  • converparamFile = param.file + "_param.json";
  • else {
  • converparamFile = mxconfig_1.default.getUploadPath() + param.file + "_param.json";
  • else {
  • converparamFile = mxconfig_1.default.getUploadPath() + createUuid() + "_param.json";
  • converparamFile = converparamFile.replace(/\\/g, '/');
  • param = JSON.stringify(param);
  • fs.writeFile(converparamFile, param, function (error) {
  • if (error) {
  • retcall({ code: 2, message: "write param file error" });
  • //fs.unlink(converparamFile);
  • return;
  • var pathConvertExt = '"' + mxconfig_1.default.getMxNodeAppPath() + '"';
  • var pathMxconvertJs = mxconfig_1.default.getMxBinPath() + "mxconvert.js";
  • //var cmdparam = '"' + pathMxconvertJs + '"' + ' "{\\"paramfile\\":\\"' + converparamFile + '\\"}"';
  • var cmdparam = '"' + pathMxconvertJs + '"' + ' fileparam filepath="' + converparamFile + '"';
  • var cmd = pathConvertExt + " " + cmdparam;
  • const exec = child_process.exec;
  • exec(cmd, (err, stdout, stderr) => {
  • if (err) {
  • retcall({ code: 3, message: "exec cmd failed" });
  • else {
  • try {
  • let index = stdout.lastIndexOf("{");
  • if (index != -1) {
  • stdout = stdout.substr(index);
  • let retCmd = JSON.parse(stdout);
  • retCmd.code = 0;
  • if (retCmd["resultfile"]) {
  • let strparam = fs.readFileSync(retCmd["resultfile"]);
  • if (strparam) {
  • let paramobj = JSON.parse(strparam);
  • retCmd.resultfile = paramobj;
  • if (retCmd["ret"] && retCmd["ret"] != 0)
  • retCmd.code = 7;
  • retcall(retCmd);
  • catch (err) {
  • console.log(err);
  • retcall({ code: 5, message: "exec cmd return error" });

可以看见,这里在组装参数, 然后运行mxconvert.js这个文件, 要找到这个文件的位置,我们要看mxconfig_1.default.getMxBinPath()这个函数的返回值。

这个方法在MxDrawCloudServer\Bin\MxDrawServer\Windows\mxconfig.js中,最终我们可用的返回值是在同目录下的ini.js中配置的:

  • function MxINI() {
  • this.uploadPath = "./public/file/";
  • this.mxbinPath = "../../Release/";
  • var mxIni = new MxINI();
  • module.exports = mxIni;

如上所知,callMxNodeJS函数运行的就是这个文件MxDrawCloudServer\Bin\Release\mxconvert.js

  • // 加载梦想控件服务程序
  • var mxweb = require('./MxNode.node');
  • var Mx2D = require('./Mx2DNode.node');
  • // 加载消息处理程序
  • var mxFun = require('./mxfun');

  • try{
  • const mxDraw_1 = require("./mxdraw/MxDraw");
  • mxDraw_1.init(mxFun, Mx2D);

  • var MxConvert_1 = require('./mxconvert/MxConvert');

  • const args = process.argv.slice(2);

  • if(args.length == 0){
  • console.log(mxweb.getVersionInformation());
  • else
  • MxConvert_1.Call(args);
  • catch(err)
  • console.log(err);
  • mxweb.stopAll();

同理,在同目录下找到mxconvert/MxConvert.js

  • function saveComment(param) {
  • let save = new SaveCommentToDWG_1.SaveCommentToDWG();
  • return save.Do(param);
  • function Call(aryParam) {
  • aryCmd["savecomment"] = saveComment;
  • aryCmd[sCmd](cmdParam)

如上,最终我们要在aryParam参数中找到cmd字符串调用对应命令,这里的字符串就是savecomment然后调用new SaveCommentToDWG_1.SaveCommentToDWG().DO()我们可用在同目录下找到SaveCommentToDWG.js

  • class SaveCommentToDWG {
  • Do(param) {
  • if (!param.filename) {
  • return { ret: 1 };
  • if (!param.savefile) {
  • return { ret: 4 };
  • let curPath = Mx2DDraw.getCurrentPath();
  • if (param.userConvertPath) {
  • curPath = Mx2DDraw.getConvertPath();
  • let dwgFilePath = curPath + "/" + param.filename;
  • // 打开dwg文件。
  • if (!mxConvert.openFile(dwgFilePath)) {
  • return { ret: 2 };
  • Mx2DDraw.makeBackgroundToCurrent();
  • this.matDocToCad = new MxMath_1.MathMatrix4d;
  • if (param["matDoc2Cad"]) {
  • this.matDocToCad.fromArray(param.matDoc2Cad.elements);
  • let saveFilePath = curPath + "/" + param.savefile;
  • let entitys = param["entitys"];
  • let i = 0;
  • for (i = 0; i < entitys.length; i++) {
  • // 绘制对象.
  • let ent = entitys[i];
  • if (ent.TypeName == "MxDbLine") {
  • let pt1 = new Mx.McGePoint3dClass();
  • this.DocPt2DCoordToCAD(ent.pt1);
  • pt1.x = ent.pt1.x;
  • pt1.y = ent.pt1.y;
  • let pt2 = new Mx.McGePoint3dClass();
  • this.DocPt2DCoordToCAD(ent.pt2);
  • pt2.x = ent.pt2.x;
  • pt2.y = ent.pt2.y;
  • //Mx2DDraw.setColor([255, 200, 0]);
  • Mx2DDraw.drawLine(pt1, pt2);
  • else if (ent.TypeName == "MxDbLeadComment") {
  • this.DrawMxDbLeadComment(ent, this);
  • else if (ent.TypeName == "MxDbAnyLine") {
  • MxDbAnyLine_1.DrawMxDbAnyline(ent, this);
  • else if (ent.TypeName == "MxDbSplineCurve") {
  • MxDbSplineCurve_1.DrawMxDbSplineCurve(ent, this);
  • else if (ent.TypeName == "MxDbCloudLine") {
  • MxDbCloudLine_1.DrawMxDbCloudLine(ent, this);
  • else if (ent.TypeName == "MxDbRectBoxLeadComment") {
  • MxDbRectBoxLeadComment_1.DrawMxDbRectBoxLeadComment(ent, this);
  • else if (ent.TypeName == "MxDbRect") {
  • MxDbRect_1.DrawMxDbRect(ent, this);
  • else if (ent.TypeName == "MxDbCircle") {
  • MxDbCircle_1.DrawMxDbCircle(ent, this);
  • else if (ent.TypeName == "MxDbEllipse") {
  • MxDbEllipse_1.DrawMxDbEllipse(ent, this);
  • else if (ent.TypeName == "MxDbText") {
  • MxDbText_1.DrawMxDbText(ent, this);
  • else if (ent.TypeName == "MxDbRegularPolygon") {
  • MxDbRegularPolygon_1.DrawMxDbRegularPolygon(ent, this);
  • // 保存图纸
  • if (!mxConvert.writeFile(saveFilePath)) {
  • return { ret: 3 };
  • return { ret: 0 };

如上代码中,将各种不同的批注都绘制到图纸中, 最后将图纸保存在参数提供的savefile中。

我们发现将这些图形绘制在图纸上是通过MxDrawCloudServer\Bin\Release\
MxNode.node和MxDrawCloudServer\Bin\Release\Mx2DNode.node提供的方法调用的, 你可以根据源码中使用方式,完善绘制更多自定义的图形到图纸中。

mxdraw实现自定义批注:点击查看对应文档(https://mxcadx.gitee.io/mxdraw_docs/previewAnnotation/bases.html#%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E8%87%AA%E5%AE%9A%E4%B9%89%E6%89%B9%E6%B3%A8)

查看文档后, 这些批注中的getTypeName方式就是服务端得到的参数TypeName, 其他参数数据就是dwgOut返回的对应的这个图形需要的一些数据, 最终组成这样一个个的批注数据上传到服务器中。服务器根据这些批注数据, 绘制出对应图形到图纸中。

根据上文所述,我们知道了保存批注到图纸中的整个实现,可用参考代码或者直接使用这个接口。

注意以上代码为代码片段,请自行下载MxDraw云图开发包(https://gitee.com/link?target=https%3A%2F%2Fwww.mxdraw.com%2Fdownload.html)按照上文步骤了解保存批注的整个实现流程和实现细节。