Custom

4/22/2022

# How to implement a custom graph

We can implement a custom graphics class by inheriting Mx.MxDbEntity. The following is an example of implementing a custom graphics object that can draw any line segment.

Click on Mx MxDbEntity API (opens new window) to check the detailed implementation rules.

import Mx from "mxdraw"
import THREE from "three"

// Inherit custom graphics objects to achieve the function of drawing arbitrary line segments
class MxAnyLine extends  Mx.MxDbEntity {
    // List of vertices
    points = []

    // Line center point
    centerPt = new THREE.Vector3()

    // Dynamic rendering
    worldDraw(pWorldDraw) {
        // Create a line object for any line segment three.js
        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)
        // Draw the line object dynamically
        pWorldDraw.drawEntity(line)
    }
    // Show the vertex of the operation Click on this vertex to move the operation
    getGripPoints() {
        return [this.centerPt]
    }

    // Displays the vertex move event, index indicates which point was moved and offset is the offset of the move
    moveGripPointsAt(index, offset) {
        this.points.forEach((pt)=> {
            pt.add(offset);
        })
        
        return true;
    }

    // Custom objects are recreated when drawn
    create() {
        return new MxAnyLine()
    }

    // Since drawing is constantly creating new objects, here we copy the properties of the previous object to the new object
    dwgIn(obj) {
        // Here are the public attributes
        this.onDwgIn(obj);

        // Here is the custom object's own property
        let ary = obj["points"];
        this.points = [];
        this.centerPt  = obj["centerPt"];
        ary.forEach((val) => {
            this.points.push(val.clone());
        });
        return true;
    }
    // The output is similarly a copy of the properties of the new object and the old object to ensure that those values are present at the time of drawing
    dwgOut(obj) {
        // Here are the public attributes
        this.onDwgOut(obj);
        obj["points"] = [];
        obj["centerPt"] = this.centerPt
        this.points.forEach((val) => {
            obj["points"].push(val.clone());
        });
        return obj
    }
}


// Please refer to the three.js documentation for the code for creating three.js line segment objects for arbitrary lines
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
}

Instructions for dynamic drawing of custom graphics objects:

1, the dynamic drawing 'worldDraw' method is essentially creating three.js object objects and adding them to the scene rendering

2, each time the dynamic draw 'worldDraw' is triggered, the original instance object will be deleted (it will also delete the rendered three.js object object), and the instance will be recreated through the 'create' method

3, some data is needed to save in the custom object, 'dwgIn' and 'dwgOut' method is to ensure that the data used in the execution of 'worldDraw' method will not be lost after creation

4, 'getGripPoints' method is to provide an action point when clicking this rendered graph, click the action point to move the callback function' moveGripPointsAt ', obviously these operations will also trigger 'worldDraw' method

  • The realization of custom graphics objects requires the knowledge of three.js, Recommended in combination with the example code in three.js document (opens new window) to find not three. Js knowledge to learn : : :

Effect: Reference Draw anyline mxdbanyline

JSON format custom graphics objects to save and restore

import Mx from "mxdraw"
// Gets the current control object
let mxobj = Mx.MxFun.getCurrentDraw();

// Converts a custom graphic object in the canvas to a JSON string
const sSaveData = mxobj.saveMxEntityToJson();

// Delete all custom graphics objects from the canvas
mxobj.eraseAllMxEntity();


// Restore all deleted custom graphics objects using JSON strings
mxobj.loadMxEntityFromJson(sSaveData)

// Finally update the display view
mxobj.updateDisplay();