MxDbEntity Custom Graphics Object
# How to Implement a Custom Graphics Class
We can implement a custom graphics class by inheriting from Mx.MxDbEntity.
Click Mx.MxDbEntity API (opens new window) to view the detailed implementation specifications.
The following example implements a custom graphics object that can draw arbitrary line segments:
import Mx from "mxdraw"
import THREE from "three"
// Inherit from custom graphics object to implement the function of drawing arbitrary line segments
class MxAnyLine extends Mx.MxDbEntity {
// List of vertices
points = []
// The center point of the line segment
centerPt = new THREE.Vector3()
// Dynamic drawing
worldDraw(pWorldDraw) {
// Create a three.js line object for any line segment
const line = createAnyLine(this.points)
// Calculate the bounding box of the line object
line.geometry.computeBoundingBox()
// Get the center point
line.geometry.boundingBox.getCenter(this.centerPt)
// Dynamically draw this line object
pWorldDraw.drawEntity(line)
}
// Display grip points, and you can move the graphics by clicking on these points
getGripPoints() {
return [this.centerPt]
}
// Display vertex movement events. "index" indicates the point being moved, and "offset" is the offset of the movement
moveGripPointsAt(index, offset) {
this.points.forEach((pt)=> {
pt.add(offset);
})
return true;
}
// A custom object will be recreated when it is drawn.
create() {
return new MxAnyLine()
}
// Because drawing will create new objects continuously, here the attributes of the previous object are copied to the new object
dwgIn(obj) {
// These are the common properties
this.onDwgIn(obj);
// These are the custom attributes of the object
let ary = obj["points"];
this.points = [];
this.centerPt = obj["centerPt"];
ary.forEach((val) => {
this.points.push(val.clone());
});
return true;
}
// The output is the same, which copies the attributes of the new and old objects to ensure that these attribute values exist when drawing
dwgOut(obj) {
// These are the common properties
this.onDwgOut(obj);
obj["points"] = [];
obj["centerPt"] = this.centerPt
this.points.forEach((val) => {
obj["points"].push(val.clone());
});
return obj
}
}
// Create a three.js line segment object for any line. Please refer to the three.js documentation for this section of code
function createAnyLine(points) {
const curve = new THREE.CatmullRomCurve3(points, false, "chordal");
points = curve.getPoints( 50 )
const geometry = new THREE.BufferGeometry()
const divisions = Math.round( 12 * points.length );
let point = new THREE.Vector3();
const positions =[]
const colors = []
const color = new THREE.Color("#ff0000");
for ( let i = 0, l = divisions; i < l; i ++ ) {
const t = i / l;
point = curve.getPoint( t );
positions.push( point.x, point.y, point.z );
colors.push( color.r, color.g, color.b );
}
geometry.setAttribute( 'position',new THREE.Float32BufferAttribute( positions, 3 ) );
geometry.setAttribute( 'color',new THREE.Float32BufferAttribute( colors, 3 ) );
const material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, linewidth: 10 } )
const splineObject = new THREE.Line( geometry, material )
splineObject.computeLineDistances();
return splineObject
}
Explanation of the dynamic drawing of custom graphics objects:
The dynamic drawing "worldDraw" method essentially creates a three.js object and adds it to the scene for rendering.
Each time the dynamic drawing "worldDraw" is triggered, the original instance object will be deleted (and the rendered three.js object will also be deleted), and the instance will be recreated through the "create" method.
Some data needs to be saved in the custom object. The "dwgIn" and "dwgOut" methods ensure that the data used when executing the "worldDraw" method will not be lost after creation.
The "getGripPoints" method provides an operation point when you click on the rendered graphics, and the callback function "moveGripPointsAt" moves the point. These operations will also trigger "worldDraw".
Note:
Implementing custom graphics objects requires knowledge of three.js. It is recommended to learn three.js knowledge that you don't know by referring to this example code in the three.js documentation (opens new window) for study.
View the complete source code of this example: github (opens new window) | gitee (opens new window)
The methods defined in the example code are the methods that must be implemented for custom graphics objects.
Effect: Click to start drawing an arbitrary line
# JSON Formatting Custom Graphics Object to Implement Saving and Recovery
import Mx from "mxdraw"
// Get the current control object
let mxobj = Mx.MxFun.getCurrentDraw();
// Convert the custom graphics object in the canvas to a JSON string
const sSaveData = mxobj.saveMxEntityToJson();
// Delete all custom graphics objects in the canvas
mxobj.eraseAllMxEntity();
// Restore all deleted custom graphics objects through JSON strings
mxobj.loadMxEntityFromJson(sSaveData)
// Finally update the display view
mxobj.updateDisplay();