在线CAD二次开发中实现交互绘制的详细步骤
前言
在线CAD的二次开发中对于交互绘制的使用频率非常高,MxCAD的思路是通过调取命令功能和取点对象来实现动态绘制,下面文章我们会详细讲解一下这三个步骤,如果对WEB CAD的二次开发还不熟悉可以参考入门教程。
一、什么是命令功能
mxdraw.js库提供了一种可以通过输入一些特定的命令调用绘制方法,并在动态绘制过程中实现参数化绘图的功能,即为命令功能。例如想用命令功能绘制一个圆,可在命令行内调用绘圆方法,并根据用户输入圆的半径参数来确定圆的大小,下面是实现步骤。
1、监听输入
因用户在命令模式下绘图,需要输入命令,系统会即时输出提示消息或相关命令消息,所以需要在画布所在页面添加输入框和文本显示框。此外还需利用方法Mx.MxFun.setCommandLineInputData()
来设置命令行消息数据,利用方法Mx.MxFun.listenForCommandLineInput()来监听命令行消息动态更新的数据、在取点对象中设置的命令等,当监听到用户输入命令并触发enter事件时,自动执行命令。监听代码如下:
<input id="mxCmdText"/>
let event = document.getElementById('mxCmdText')
// 设置命令行消息数据 (在监听input输入框的onKeydown事件的回调函数中调用)
event.onkeydown = function (e) {
Mx.MxFun.setCommandLineInputData(event.value, e.keyCode)
}
2、编写绘制函数
在使用命令功能时,编写绘制函数的过程中可以通过取点对象调用setMessage方法给用户提示必要的操作信息,以及获取到使用者的输入信息或关键词,下面以绘制线段函数为例:
// 线段函数async function BR_Line() { const getPoint = new Mx.MrxDbgUiPrPoint(); // 交互提示 getPoint.setMessage("\n指定直线起点:"); getPoint.go(async (status:number)=>{ if(status != Mx.MrxDbgUiPrBaseReturn.kOk) return let pt1 = getPoint.value(); let line = new Mx.MxDbLine(); line.pt1 = pt1; getPoint.setMessage("\n指定直线终点:"); getPoint.setUserDraw((pt:any,pw:any)=>{ line.pt2 = pt; pw.drawCustomEntity(line) }); line.pt2 = await getPoint.go(); Mx.MxFun.getCurrentDraw().addMxEntity(line);})}
3、注册命令
将写好的绘制函数通过Mx.MxFun.addCommand()方法进行注册命令,代码如下:
// 注册命令名 BR_Line:命令名 Mx.MxFun.addCommand("BR_Line", ()=> { // 是否正在运行某个命令 if(Mx.MxFun.isRunningCommand()) { return } // 目标绘制函数 BR_Line()})
4、执行命令、输出消息
注册好目标命令后,用户可通过Mx.MxFun.sendStringToExecute()方法手动执行输入的命令。此外,用户还可以通过Mx.MxFun.listenForCommandLineInput()方法按需输出提示消息或命令内容,参考代码如下:
// 手动执行命令 Mx.MxFun.sendStringToExecute("目标命令"); // 监听正在绘制中的命令提示 Mx.MxFun.listenForCommandLineInput(({ msCmdTip, msCmdDisplay, msCmdText }) => { console.log(msCmdTip, msCmdDisplay, msCmdText)})
命令功能效果完整示例代码如下:
<!DOCTYPE html><html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MxDbLine 示例</title>
<script src="https://unpkg.com/mxdraw/dist/mxdraw.umd.js"></script></head>
<body>
<div style="height: 80vh; overflow: hidden;">
<canvas id="mxdraw"></canvas>
</div>
<div>
<textarea id="mxCmdArea" rows="5" style="width:100%;overflow: scroll;"
placeholder="命令:" readonly></textarea>
<input type="text" id="mxCmdText" />
</div></body><script type="module">
Mx.loadCoreCode().then(async () => {
// 创建控件对象
Mx.MxFun.createMxObject({
canvasId: "mxdraw", // canvas元素的id
});
})
let event = document.getElementById('mxCmdText')
// 设置命令行消息数据 (在监听input输入框的onKeydown事件的回调函数中调用)
event.onkeydown = function (e) {
Mx.MxFun.setCommandLineInputData(event.value, e.keyCode)
}
// 直线函数
async function BR_Line() {
const getPoint = new Mx.MrxDbgUiPrPoint();
// 交互提示
getPoint.setMessage("\n指定直线起点:");
let pt1 = await getPoint.go();
if (!pt1) return
let line = new Mx.MxDbLine();
line.pt1 = pt1;
getPoint.setMessage("\n指定直线终点:");
getPoint.setUserDraw((pt, pw) => {
line.pt2 = pt;
pw.drawCustomEntity(line)
});
const pt2 = await getPoint.go()
if (!pt2) return
line.pt2 = pt2;
Mx.MxFun.getCurrentDraw().addMxEntity(line);
}
// 注册命名
Mx.MxFun.addCommand("BR_Line", () => {
// 是否正在运行某个命令
if (Mx.MxFun.isRunningCommand()) {
return
}
BR_Line()
})
// 监听正在绘制中的命令提示
Mx.MxFun.listenForCommandLineInput(({ msCmdTip, msCmdDisplay, msCmdText }) => {
console.log(msCmdTip, msCmdDisplay, msCmdText)
document.getElementById('mxCmdArea').innerHTML = msCmdTip
document.getElementById("mxCmdArea").scrollTop = document.getElementById("mxCmdArea").scrollHeight;
})
</script>
</html>
二、取点对象
在画布中绘制基本图形前,先要学会点对象的绘制(复杂图形都由点、线、面组成),mxdraw.js中提供了API MrxDbgUiPrPoint用于构建一个取点对象,并提供一系列方法属性辅助用户绘图,点击MrxDbgUiPrPoint API查看详细属性和方法说明。
1、基础取点
调用MrxDbgUiPrPoint中的方法go()记录鼠标开始拖动的点位置,用户可利用该方法记录画布中的目标点位,执行go()方法,若取点成功则返回点的位置,默认点值为THREE.Vector3();若取点失败则返回null,示例代码如下:
Mx.loadCoreCode().then(async () => { // 创建控件对象 Mx.MxFun.createMxObject({ canvasId: "mxdraw", // canvas元素的id callback: (mxDrawObject, dom ) => { //图纸展示控件创建完成后的回调函数 回调参数mxDraw和dom console.log(mxDrawObject, dom) }, }); const getPoint = new Mx.MxFun.MrxDbgUiPrPoint() const pt = await getPoint.go() if(!pt) return console.log('目标点位' , pt)})
此外若用户需要连续取点,则可以结合while函数调用go()方法,代码如下:
const getPoint = new Mx.MxFun.MrxDbgUiPrPoint()while(true){ const pt = await getPoint.go() if(!pt) break}
2、辅助命令功能
结合命令功能和mxdraw.js中取点对象提供的一系列方法对绘图操作时所进行的操作,提供相应提示和操作选项,以下面两种常用方法为例。
2.1设置提示字符串:setMessage()方法对绘图操作时所进行的操作进行提示,代码如下:
const getPoint = new Mx.MxFun.MrxDbgUiPrPoint() getPoint.setMessage('设置提示字符串') const pt = await getPoint.go()
2.2关键字:setKeyWords()方法可为当前命令设置关键字选项,keyWordPicked()方法可返回用户选择的关键字,代码如下:
const getPoint = new Mx.MxFun.MrxDbgUiPrPoint() // 设置关键字列表 getPoint.setKeyWords('[闭合(C)/ 放弃(U)]') // 获取用户选择关键字 getPoint.isKeyWordPicked('关键字')
3.取点对象动态绘制
取点对象中还提供了setUserDraw()方法设置交互过程的动态绘制调用对象,在该过程中所绘制的图像都是临时绘制,不会保存在画布中。该方法提供了两个回调参数:currentPoint、pWorldDraw。
currentPoint为当前光标所在点的点位,pWorldDraw为一个动态绘制回调对象,可根据用户设置动态绘制目标图形,点击动态绘制回调对象查看详细属性和方法说明,示例代码如下:
async function draw_line(){ const line = new Mx.MxDbLine() const getPoint = new Mx.MxFun.MrxDbgUiPrPoint() const pt1 = await getPoint.go() if(!pt1) return line.pt1 = pt1 // 动态绘制 getPoint.setUserDraw((currentPoint, pWorldDraw)=>{ line.pt2 = currentPoint pWorldDraw.drawCustomEntity(line) }) const pt2 = await getPoint.go() if(!pt2) return line.pt2 = pt2 // 获取控件对象并将线段对象line添加到画布中 Mx.MxFun.getCurrentDraw().addMxEntity(line);}
三、动态绘制
1.基础绘制
mxdraw.js提供了两种实现动态绘制的方式,它们可以在不改变图形类的情况下,改变图形的大小、方向等,帮助用户更快捷地绘制目标图形。这两种动态绘制的方式都是结合取点对象来实现动态绘制图形的功能。
方式一
利用API McEdGetPointWorldDrawObject构建一个动态绘制回调对象,再通过取点对象中的setUserDraw()方法调用该对象。
点击Mx.McEdGetPointWorldDrawObject API查看详细属性和方法说明,参考代码:
// 实例化取点对象 const getPoint = new Mx.MrxDbgUiPrPoint(); // 实例化线段对象line let line = new Mx.MxDbLine() const pt1 = await getPoint.go() line.setPoint1(pt1) // 实例化动态绘制对象 const worldDrawComment = new Mx.McEdGetPointWorldDrawObject(); // 设置动态绘制回调函数 worldDrawComment.setDraw((currentPoint) => { line.setPoint2(currentPoint); worldDrawComment.drawCustomEntity(line) }); // 使用动态绘制对象 getPoint.setUserDraw(worldDrawComment)
方式二
直接运用取点对象提供的setUserDraw()方法设置交互过程的动态绘制调用对象。详细描述可参考取点对象动态绘制,示例代码如下:
const getPoint = new Mx.MrxDbgUiPrPoint() // 实例化线段对象line let line = new Mx.MxDbLine(); const pt1 = await getPoint.go() if(!pt1) return line.pt1 = pt1 // 实例化动态绘制对象 getPoint.setUserDraw((currentPoint, worldDrawComment)=>{ line.pt2 = currentPoint worldDrawComment.drawCustomEntity(line) }); const pt2 = await getPoint.go() if(!pt2) return line.pt2 = pt2;
在动态绘制中的绘制的图形都是临时的,意味着这些图形最终是不会保持在画布上的,如果需要将动态绘制的图形保存在画布上请调用取点对象的drawReserve方法
2.图形对象的动态绘制
我们的图形对象是继承自自定义图形对象的,而任何的图形对象都可以通过动态绘制对象实现动态绘制的效果。图形对象具体如何实现动态绘制的请前往自定义图形查看详情,示例代码如下:
// 实例化取点对象 const getPoint = new Mx.MrxDbgUiPrPoint(); // 实例化动态绘制对象 const worldDrawComment = new Mx.McEdGetPointWorldDrawObject(); const pt1 = await getPoint.go() if(!pt1) return // 设置动态绘制回调函数 worldDrawComment.setDraw((currentPoint) => { // 绘制线段对象 worldDrawComment.drawLine(pt1, currentPoint); // 在绘制过程中还可以一起绘制其他图形 绘制过程结束时,不会保留这些图形,如: // 绘制以下图形使用红色 worldDrawComment.setColor('#ff0000') // 绘制半径为6的圆 worldDrawComment.drawCircle(currentPoint, 6) // 绘制字体大小为36的 “文字” 角度为0 worldDrawComment.drawText("文字" ,36 , 0, currentPoint) // 绘制矩形 pt1, currentPoint为矩形两对角 worldDrawComment.drawRect(pt1, currentPoint) }); // 使用动态绘制对象 getPoint.setUserDraw(worldDrawComment)
浙公网安备 33010602011771号