Skip to content
On this page

Parameterized Drawing with MxCAD

MxCAD provides the functionality for parameterized drawing. You can create drawings with various entities by examining classes that inherit from McDbEntity. These entities can be customized using parameters to create drawings.

First, let's start by displaying a drawing on a page. You can follow the instructions in the Getting Started documentation or view the code in the GitHub | Gitee repository for initializing various example projects.

Parameterized Drawing

Drawing a Point

ts
import { MxCpp, McDbPoint, McCmColor } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const point = new McDbPoint()
const color = new McCmColor()
color.setRGB(0, 255, 255)
point.trueColor = color
point.setPosition(200, 200)
mxcad.drawEntity(point)

Drawing Multiline Text

ts
import { MxCpp, McGePoint3d, McCmColor, McDb, McDbMText } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const mText = new McDbMText()
const textId = mxcad.drawEntity(mText)
const text = textId.getMcDbEntity() as McDbMText
text.attachment = McDb.AttachmentPoint.kTopLeft
text.contents = "Content \\P Content"
text.location = new McGePoint3d(10, 20)
text.trueColor = new McCmColor(255, 0, 255)
text.textHeight = 10
mxcad.updateDisplay()

Drawing Single-Line Text

ts
import { MxCpp, McGePoint3d, McCmColor, McDb, McDbText } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const text = new McDbText()
text.widthFactor = 1
text.horizontalMode = McDb.TextHorzMode.kTextCenter
text.verticalMode = McDb.TextVertMode.kTextBottom
text.textString = "Content"
text.position = new McGePoint3d(-10, -20)
text.trueColor = new McCmColor(255, 0, 255)
text.height = 10
mxcad.drawEntity(text)
mxcad.updateDisplay()

Drawing Aligned Dimension

ts
import { MxCpp, McGePoint3d, McCmColor, McDb, McDbAlignedDimension } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const mDimension = new McDbAlignedDimension()
const dimensionId = mxcad.drawEntity(mDimension)
const dimension = dimensionId.getMcDbEntity() as McDbAlignedDimension
dimension.xLine1Point = new McGePoint3d(0, 255)
dimension.xLine2Point = new McGePoint3d(30, 60)
dimension.dimLinePoint = new McGePoint3d(88, 88)
dimension.textAttachment = McDb.AttachmentPoint.kTopLeft
dimension.trueColor = new McCmColor(200, 255, 0)
dimension.oblique = 0
mxcad.updateDisplay()

Drawing Rotated Dimension

ts
import { MxCpp, McGePoint3d, McCmColor, McDb, McDbRotatedDimension } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const mDimension = new McDbRotatedDimension()
const dimensionId = mxcad.drawEntity(mDimension)
const dimension = dimensionId.getMcDbEntity() as McDbRotatedDimension
dimension.xLine1Point = new McGePoint3d(100, -137)
dimension.xLine2Point = new McGePoint3d(161,30)
dimension.dimLinePoint = new McGePoint3d(80, -60)
dimension.textAttachment = McDb.AttachmentPoint.kTopLeft
dimension.textRotation = 0.23
dimension.trueColor = new McCmColor(200, 255, 0)
dimension.oblique = 0
dimension.rotation = 0
mxcad.updateDisplay()

Drawing a Line

ts
import { MxCpp, McCmColor, McDbLine } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const line = new McDbLine(0, 0, 0, -80, -80, 0)
line.trueColor = new McCmColor(255, 0, 0)
mxcad.drawEntity(line)

Drawing a Circle

ts
import { MxCpp, McCmColor, McDbCircle } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const circle = a new McDbCircle(-100, 300, 0, 20)
circle.trueColor = new McCmColor(255, 0, 0)
mxcad.drawEntity(circle)

Drawing a Polyline

ts
import { MxCpp, McGePoint3d, McDbPolyline } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const polyline = new McDbPolyline()
polyline.isClosed = false
polyline.constantWidth = 10
polyline.addVertexAt(new McGePoint3d(100, 100))
polyline.addVertexAt(new McGePoint3d(200, 100), 0.2, 1, 5, 1)
polyline.addVertexAt(new McGePoint3d(100, 200), 0.2, 5, 1, 2)
mxcad.drawEntity(polyline)

Drawing an Arc

ts
import { MxCpp, McGePoint3d, McDbArc, McCmColor } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const arc = new McDbArc()
arc.center = new McGePoint3d(-100, -100),
arc.radius = 20
arc.startAngle = Math.PI / 2
arc.endAngle = Math.PI * 3 / 2
arc.trueColor = new McCmColor(255, 233, 0)
mxcad.drawEntity(arc)

Drawing an Ellipse

ts
import { MxCpp, McGePoint3d, McDbEllipse, McCmColor, McGeVector3d } from "mxcad"
const mxcad = MxCpp.App.getCurrentMxCAD()
const ellipse = new McDbEllipse()
ellipse.center = new McGePoint3d(-200, -200),
ellipse.majorAxis = new McGeVector3d(0, 300, 0)
ellipse.minorAxis = new McGeVector3d(33, 0, 0)
ellipse.radiusRatio = 0.5
ellipse.startAngle = Math.PI / 2
ellipse.endAngle = Math.PI * 3 / 2
ellipse.trueColor = new McCmColor(255, 233, 0)
mxcad.drawEntity(ellipse)

图块

ts
import { MxCpp, McDbBlockTableRecord, McDbBlockReference, McDbLine } from "mxcad"
let mxcad = MxCpp.getCurrentMxCAD();
// First get the block table from the database
let blkTable =  mxcad.getDatabase().getBlockTable();
// Add a new block record to the block table
let blkRecId = blkTable.add(new McDbBlockTableRecord());

// Get the block record you just added again according to ObjectId
let blkTableRecord:McDbBlockTableRecord = blkRecId.getMcDbBlockTableRecord()

// Add two segments and then assign the specific attributes of each segment in the block record, such as the start point and the end point.
const line = new McDbLine()
const line1 = new McDbLine()
blkTableRecord.appendAcDbEntity(line);
blkTableRecord.appendAcDbEntity(line1);

// The base point of the block is generally the point in the bounding box, which can be specified arbitrarily.
blkTableRecord.origin = new McGePoint3d(0,0,0);

// For instantiating blocks, refer to here to set the ObjectId we just added to the block record.
let blkRef = new McDbBlockReference();
blkRef.blockTableRecordId = blkRecId;
// Finally, set the position to render it.
blkRef.position = new McGePoint3d(0,0,0);

mxcad.drawEntity(blkRef);

For more information on drawing other shapes, please refer to the provided code examples and the API documentation.

This will help you get started with parameterized drawing using MxCAD.

Interactive Drawing

In the above Parameterized Drawing code, some attributes are hardcoded, such as the position attribute, which should be obtained from user input through clicks or input fields.

MxCAD provides a set of drawing processes to obtain user input and incorporate it into the drawing. The most common way is to obtain CAD drawing coordinates by clicking with the mouse:

ts
import { MxCADUiPrPoint } from "mxcad"
const getPoint = new MxCADUiPrPoint()
const point = await getPoint.go()
console.log(point)

The code above prints a coordinate point obtained from the user by clicking with the mouse, which represents the position on the drawing.

User input can also come from text input fields to determine parameters other than coordinates:

ts
import { MxFun } from "mxdraw"
const input = document.createElement("input")
input.addEventListener("keydown", (e: KeyboardEvent) => {
    // Set the command line input data
    MxFun.setCommandLineInputData((e.target as HTMLInputElement).value, e.keyCode);
}) 
document.body.appendChild(input)

MxCAD references mxdraw, which is automatically downloaded as a dependency when you install MxCAD, so you only need to install MxCAD to use mxdraw.

As shown in the code above, you can pass the user's input and the corresponding keyCode value by setting the message.

ts
const getInt = new MxCADUiPrInt()
const getKey = new MxCADUiPrKeyWord
const getStr = new MxCADUiPrString()
getInt.setMessage("Prompt the user to enter a number:")
const intVal = await getInt.go()
console.log(intVal)
getKey.setMessage("Prompt the user to enter a keyword A, B, C:")
getKey.setKeyWords("A B C")
const keyVal = await getKey.go()
console.log(keyVal)
getStr.setMessage("Prompt the user to enter a string:")
const strVal = await getStr.go()
console.log(strVal)

The code above will execute after the user inputs data of the corresponding type and presses the Enter or Esc key. You can set prompts using the setMessage method.

Finally, you can retrieve the user's input data using the following code:

ts
import { MxFun } from "mxdraw"
MxFun.listenForCommandLineInput(({ msCmdTip, msCmdDisplay, msCmdText }) => {
    console.log(msCmdTip, msCmdDisplay, msCmdText)
 });

If you don't understand the purpose of a particular function in the code, you can search for it in the mxdraw API documentation or the MxCAD API documentation.

Drawing Text Workflow

Here's an example of a parametric text drawing workflow, and drawing other shapes is recommended to follow a similar approach:

ts
import { MxFun } from "mxdraw"
import { MxCADUiPrInt, MxCADUiPrKeyWord, MxCADUiPrString, MxCADUiPrPoint, McDbText, MxCpp } from "mxcad"
MxFun.addCommand("Mx_draw_Text", async () => {
    const getInt = new MxCADUiPrInt()
    const getKey = new MxCADUiPrKeyWord()
    const getStr = new MxCADUiPrString()
    const getPoint = new MxCADUiPrPoint()
    const text = new McDbText()
    getPoint.setMessage("Please click to determine the text position")

    const position = await getPoint.go()
    if (!position) return
    text.position = position

    getInt.setMessage("Enter the text height")
    const height = await getInt.go()
    if (!height) return
    text.height = height

    getKey.setMessage("Select horizontal alignment: Shortcut keys L: Left C: Center R: Right A: Align M: Middle F: Fit")

    getKey.setKeyWords("L C R A M F")

    await getKey.go()
    if (getKey.isKeyWordPicked("L")) text.horizontalMode = McDb.TextHorzMode.kTextLeft
    if (getKey.isKeyWordPicked("C")) text.horizontalMode = McDb.TextHorzMode.kTextCenter
    if (getKey.isKeyWordPicked("R")) text.horizontalMode = McDb.TextHorzMode.kTextRight
    if (getKey.isKeyWordPicked("A")) text.horizontalMode = McDb.TextHorzMode.kTextAlign
    if (getKey.isKeyWordPicked("M")) text.horizontalMode = McDb.TextHorzMode.kTextMid
    if (getKey.isKeyWordPicked("F")) text.horizontalMode = McDb.TextHorzMode.kTextFit

    getStr.setMessage("Enter the text content")
    const str = await getStr.go()
    if (!str) return
    text.textString = str
    const mxcad = MxCpp.App.getCurrentMxCAD()
    mxcad.drawEntity(text)
})

You can download the complete source code for the above example here.

Selecting Graphics

You can use the MxCADUiPrEntity to select graphics by clicking with the mouse:

ts
import { MxCADUiPrEntity, MxCpp } from "mxcad"
// Get the current control
const mxcad = MxCpp.App.getCurrentMxCAD();
// Instantiate a class provided by mxcad to obtain the ID of the entity by clicking with the mouse
let getEnt = new MxCADUiPrEntity();
let id = await getEnt.go();
// Get the graphics data object based on the ID
let ent = id.getMcDbEntity();
if (ent) {
    const color = ent.trueColor.clone()
    color.setRGB(255, 0, 0)
    ent.trueColor = color
    mxcad.updateDisplay()
}

This code allows you to select a graphic by clicking with the mouse and change its color to red.

Dynamic Interactive Drawing

In addition to creating CAD graphics and rendering through instantiation, we can also create graphics through function methods for dynamic interactive drawing.

There are more interactive behaviors to draw some graphics, in CAD these drawing functions will become the form of commands through the user's input to determine the parameters of the graph.

Because mxcad uses the drawing ability of mxdraw, it also inherits the [command mode (click to view)] (https://mxcadx.gitee.io/mxdraw_docs/commandMode/basedOnnUsing.html#注册执行命令) in mxdraw

If we complete the corresponding implementation in the command mode according to the requirements, we can use some of the dynamic interactive drawing functions that have been implemented by mxcad.

Functions for Dynamic Interactive Drawing

We can directly export functions from mxcad that start with draw. Each function corresponds to a specific dynamic drawing feature.

These functions typically involve some command-line interactions (input parameters, keywords), similar to drawing functions in most CAD systems.

We can either call these functions directly with default commands or choose to export and call them.

ts
import { drawLine } from "mxcad"
// Call through function
drawLine()
// Call through command
MxFun.sendStringToExecute("Mx_Line");

The implementation of these functions is similar to the text drawing process. The only difference is that drawing text doesn't often require dynamic drawing effects. In many cases, users want to dynamically draw other types of graphics.

In ESM modularization, you might need to import the corresponding functions to use the associated commands.

Below is a list of functions and corresponding commands provided by mxcad for interactive drawing of graphics:

FunctionCommandDescription
drawLineMx_LineDraw a straight line
drawArcMx_ArcDraw an arc
drawCircleMx_CircleDraw a circle
drawEllipseMx_EllipseDraw an ellipse
drawEllipticalArcMx_EllipseArcDraw an elliptical arc
drawMTextDraw multiline text
drawTextDraw text
drawPolygonMx_PolygonDraw a regular polygon
drawPolyLineMx_PlineDraw a polyline
drawRectangMx_RectangDraw a rectangle

Dynamic Drawing Functions during Interaction

In the text drawing process, we used some classes with the prefix MxCADUiPr. In these instances, there is a method called setUserDraw.

We can use this method to set a dynamic drawing function. When we set this function before calling the go method, it will callback the coordinates of the mouse on the drawing when waiting for user input (mouse click).

We can use these coordinates for dynamic drawing.

ts
import { MxCADUiPrPoint, McDbLine } from "mxcad"
const getPoint = new MxCADUiPrPoint()
getPoint.go().then((point) => {
  getPoint.setUserDraw((pt, pw) => {
    // pt is the coordinates of the mouse on the drawing
    // pw provides some dynamic drawing methods
    if (!point) return
    const line = new McDbLine(point, pt)
    // Dynamically draw a line
    pw.drawMcDbEntity(line)
  })
  // During the waiting period for mouse click, the callback function in the dynamic drawing function will be executed
  getPoint.go()
})

When we need to perform multiple clicks and establish a reference or set the previous point, we can utilize the setBasePoint and setLastInputPoint methods for setting the base point and last input point, respectively. The following code demonstrates how to achieve this using the MxCAD library:

typescript
import { MxCADUiPrPoint, McDbLine } from "mxcad"

// Create an instance of MxCADUiPrPoint
const getPoint = new MxCADUiPrPoint()

// Perform the first click to get a point
getPoint.go().then(async (point) => {
  // Set the base point, which will be connected to the dynamically changing point 'pt'
  // even if a dynamic drawing function is not explicitly set
  getPoint.setBasePoint(point)

  // Set the position of the last input point
  getPoint.setLastInputPoint(point)

  // Perform the second click to get another point
  await getPoint.go()
})

In this code, the MxCADUiPrPoint class is used to obtain user input for points. The setBasePoint method is employed to set the base point, which is connected to the dynamically changing point referred to as 'pt' in a dynamic drawing function. Additionally, the setLastInputPoint method is used to set the position of the last input point. The code structure ensures that these points are appropriately configured for dynamic drawing operations.

Path Drawing

In the createMxCad function exported by mxcad for creating controls, there are methods for path drawing.

These methods often start with path.

ts
import { MxCpp } from "mxcad"
const mxcad = MxCpp.getCurrentMxCAD();
// Draw a rectangle using a path

// Define the starting point of the path
mxcad.pathMoveTo(0, 300);

// Add the next point to the path
mxcad.pathLineTo(100, 300);

// Add the next point to the path
mxcad.pathLineTo(100, 400);

// Add the next point to the path
mxcad.pathLineTo(0, 400);

// Close the path
mxcad.pathMakeClosed();

// Generate a polyline for the rectangle
mxcad.drawPathToPolyline();

// Alternatively, you can choose to fill the path. The parameter here is the pattern scale.
// mxcad.drawPathToHatch(1);

// You can also convert the path into a spline curve
// mxcad.drawPathToSpline()

Drawing Graphics with Controls

Usually, we draw graphics by instantiating a graphics object. The methods in controls that start with draw are often used for drawing graphics.

We can set some drawing attributes in advance, and subsequent graphics drawn will default to these drawing attributes.

ts
import { MxCpp, ColorIndexType } from "mxcad"
const mxcad = MxCpp.getCurrentMxCAD();
// Set the drawing color to red; all subsequent graphics will be red. Use true color values for input.
mxcad.drawColor = new McCmColor(255, 0, 0)
// You can also change the color by setting the color index. It accepts index values from 0 to 256. ColorIndexType records common or special index values.
// For example, ColorIndexType.kBylayer means the color is the same as the current layer's color, and ColorIndexType.kByblock means the color is the same as the current block's color.
mxcad.drawColorIndex = ColorIndexType.kBylayer
// Draw a line
mxcad.drawLine(0, 0, 1000, 1000)

Methods in controls that start with draw usually set global properties for drawing graphics, while methods starting with draw are generally used to draw a specific type of graphic.