CADViewer, with it’s flexible design and use of standard toolkits, can be integrated with any Database Management Application and be used with a multitude of custom data-driven applications.

This Tutorial

This tutorial builds on top of the previous CADViewer API tutorials: 1) Automated Creation of Hotspots, 2) Add and Edit Hotspots, 3) Style Hotspots and Images, 4) Introduction to the Canvas API to use the CADViewer full Rules Based Space Management API.

The CADViewer Space Management API provides a set of methods that allows application programmers to determine how spaces on the canvas relates to each others when inserting or moving content on the canvas.

This allows CADViewer to be used as a Space Management tool over a large range of applications, such as Logistics and Facilities Management.

A standard implementation of a Rules Based interaction of Space Objects with the canvas consists of the following steps:

  • 1: Define a CADViewer JSON Space Object data structure.
  • 2: Extend the JSON Space Object data structure with a customContent sub-structure section.
  • 3: In the customContent section, create a placeholder logic for data rules at insert or modify.
  • 4: In the Canvas handler for Space Objects, implement the call-back method to populate the logical rules at insert or modify.
  • 5: Implement myCustomPopUpBody to control the custom menu at any click on Space Objects.
  • 6: Implement a callback in myCustomPopUpBody to control the custom interaction on Space Objects.

Below is a sample definition of a customContent object and some code snippets for a loop that A): Checks that overlapping spaces are not allowed and B): Checks for when placing a space, it must be inside another space with some default characteristics.


1: Defining a CADViewer JSON Space Object Data Structure

In your template code, use the API method cvjs_createNewJSonSpaceObject() to create a default Space Object


/**
 * Return a new JSON structure with default content: 
 * 	var jsonStructure =  	{	"path": path,
 *								"tags": tags, 
 *								"node": node, 
 *								"area": area, 
 *								"outerhtml": outerHTML, 
 *								"occupancy": occupancy, 
 *								"name": name, 
 *								"type": type, 
 *								"id": id, 
 *								"defaultcolor": defaultcolor, 
 *								"highlightcolor": highlightcolor, 
 *								"selectcolor": selectcolor, 
 *								"layer": layer, 
 *								"group": group, 
 *								"linked": linked, 
 *								"attributes": attributes, 
 *								"attributeStatus": attributeStatus, 
 *								"displaySpaceObjects": displaySpaceObjects,
 *								"translate_x": translate_x, 
 *								"translate_y": translate_y, 
 *								"scale_x": scale_x ,
 *								"scale_y": scale_y ,
 *								"rotate": rotate, 
 *								"transform": transform, 
 *								"svgx": svgx, 
 *								"svgy": svgx, 
 *								"dwgx": dwgx, 
 *								"dwgy": dwgy , 
 *                               "customContent" : mycustomcontent }
 * @return {Object} jsonSpaceObject - Object with the entire space objects content
 */
 function cvjs_createNewJSonSpaceObject()

The Space Object can now be added general default information, such as ID, Name, Type, etc.

2: Extending the Space Object Data Structure with a customContent element

The datafield CustomContent offers a handle that can be used to add setting and rules for the Space Object if more than the standard fields are needed:

var customObject = 	{ 
"insertType" :  "mysubtype", 
"generalInfo": { "myotherid": mysubId, "name": myName, 
                "begindate" :  strDate , "enddate" : strDate2 }, 
"dimension" : { "unit" : "m", "width": mywidth, "length": mylength, 
                "rotationInsert": -90 },
"insertRules": {"initialPositionVerified" : false, "positionChanged" : false, 
                "infoAdded": false, "inserted" : false},
"logicalRules" : [],
"userAddedInfo" : {"date1" : date1, "date2" : date2}
};

these are custom controlled, but this structure is generally useful: General information fields, fields for dimension in global coordinates, rotation, specific non-logical insertion rules, the actual rule set for insertion, and fields to add content when returning the data object upon insert or modify.

3: Defining the settings for logical rules

As part of the custom object a good way is to define a logicalRules section that defines names and initialization values of a specific set of rules.

var customObject = 	{ 
"insertType" :  "", 
"generalInfo": {}, 
"dimension" : { },
"insertRules": { },
"logicalRules" : [
        { "rule":"no_overlap_allowed", 
        "active": true, "initValue" : loadSpaceImage_ID, "insertStatus" : none},
        { "rule":"only_inside_space", 
        "active": true, "initValue" : "space_id_02", "insertStatus" : none},
        { "rule":"myrule_01", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_02", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_03", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_04", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_05", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_06", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_07", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_08", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_09", "active": false, "initValue" : none, "insertStatus" : none},
        { "rule":"myrule_10", "active": false, "initValue" : none, "insertStatus" : none},
        ,
                ],
"userAddedInfo" : {}
};

A typical rule could be, that no overlap of space objects are allowed, or an insert space shall only be inside a given space. Any rule is defined with a rule name, if it is active or not, and what its init value is (if any).

4: Code the logical rules

The custom method cvjs_insertSpaceObjectCustomCodePlaceholder() allows application programmers to add code to evaluate the canvas content when inserting or manipulating Space Objects

/**
 * Custom methods that programs rules against the CADViewer Space Management API
 * @param {*} spaceID   the id of the space object currently selected
 * @param {*} jsonObject  the space object itself currently selected
 * @returns {boolean} true if rules conditions are met, false otherwise
 */

function cvjs_insertSpaceObjectCustomCodePlaceholder(spaceID, jsonObject){

We are below illustrating, how two rules can be implemented.


Rule 1 - No Overlay Allowd

This code segment checks if “no_overlap_allowed” is true, and then use the API command cvjs_spaceObjectOverlapAnyOtherObject() to check against any spaces, where those spaces meet the condition: customContent.insertType == mysubtype


            // overlapping Spaces not allowed
            if (jsonObject.customcontent.logicalRules[i].rule == "no_overlap_allowed" && jsonObject.customcontent.logicalRules[i].active == true) {
                process = false;             
                jsonElement = ["customContent", "insertType"];
                process = cvjs_spaceObjectOverlapAnyOtherObject(jsonObject,  jsonElement, "mysubtype");

                console.log("overlap "+process);
                if (process) window.alert("NOTE Rule:"+i+", "+jsonObject.customcontent.logicalRules[i].rule+" not met, with init value:"+jsonObject.customcontent.logicalRules[i].initValue) 
                console.log(jsonObject.customcontent.logicalRules[i].rule+ " result: "+process);

                // we dont want overlay so we reverse the result
                process = !process;
                
                if (!process) return false;
            }            

Rule 2 - Selected Object must be inside specific other Object

This code segment checks if “only_inside_space” is true, and then use the API command cvjs_isSpaceObjectInside() to check if the jsonObject is inside the space jsonObject.customContent.logicalRules[i].initValue:


        if (jsonObject.customContent.logicalRules[i].rule == "only_inside_space" && jsonObject.customContent.logicalRules[i].active == true) {
        process = false;             
        process = process_only_inside_spave(spaceID, i, jsonObject);                    
        if (!process) window.alert("rule:"+i+", "+jsonObject.customContent.logicalRules[i].rule+" not met, with init value:"+jsonObject.customContent.logicalRules[i].initValue) 
        console.log(jsonObject.customcontent.logicalRules[i].rule+ " result: "+process);
        if (!process) return false;
        }            

// rule for inside specific ID
function process_rule_vlcc_dock_1_3(spaceID, i, jsonObject){
    var term = false;
    // let us pull the init value from the spaceObject for the rule number i
    var space_value =jsonObject.customContent.logicalRules[i].initValue;
    // test the coordinates of object against base object. 
    var baseObject = cvjs_returnSpaceObjectID(space_value);

    term = cvjs_isSpaceObjectInside(baseObject, jsonObject)

    if (term) return true;

    // in any case return false
    return false;
}

Implementation of cvjs_insertSpaceObjectCustomCodePlaceholder()

Below is the full implementation of the cvjs_insertSpaceObjectCustomCodePlaceholder() method, where the loop is over all rules in the JSON Space Object, and if any does not match it will return false and Canvas action is aborted:

function cvjs_insertSpaceObjectCustomCodePlaceholder(spaceID, jsonObject){

    try{
        console.log("cvjs_insertSpaceObjectCustomCodePlaceholder(): "+spaceID);
        // myobject = cvjs_returnSpaceObjectID(spaceID);  - cannot use, because object not created yet
        console.log(jsonObject);
        // general check, inside dock or berth areay

        var process = false;
        // loop over all rules rules
        for (var i=0; i<jsonObject.customContent.logicalRules.length; i++){
        
            console.log("    "+jsonObject.customContent.logicalRules[i].rule+" "+jsonObject.customContent.logicalRules[i].active);

            // overlapping Spaces not allowed
            if (jsonObject.customcontent.logicalRules[i].rule == "no_overlap_allowed" && jsonObject.customcontent.logicalRules[i].active == true) {
                process = false;             
                jsonElement = ["customContent", "insertType"];
                process = cvjs_spaceObjectOverlapAnyOtherObject(jsonObject,  jsonElement, "mysubtype");

                console.log("overlap "+process);
                if (process) window.alert("NOTE Rule:"+i+", "+jsonObject.customcontent.logicalRules[i].rule+" not met, with init value:"+jsonObject.customcontent.logicalRules[i].initValue) 
                console.log(jsonObject.customcontent.logicalRules[i].rule+ " result: "+process);
                
                // we dont want overlay so we reverse the result
                process = !process;
                
                if (!process) return false;
            }            

            

            if (jsonObject.customContent.logicalRules[i].rule == "only_inside_space" && jsonObject.customContent.           logicalRules[i].active == true) {
                process = false;             
                process = process_only_inside_spave(spaceID, i, jsonObject);                    
                if (!process) window.alert("rule:"+i+", "+jsonObject.customContent.logicalRules[i].rule+" not met, with init value:"+jsonObject.customContent.logicalRules[i].initValue) 
                console.log(jsonObject.customcontent.logicalRules[i].rule+ " result: "+process);
                
                if (!process) return false;
            }            
        }

        //

    }
    catch(err){
            console.log("cvjs_insertSpaceObjectCustomCodePlaceholder: "+err);
    }

    // return process
    return process;

}


// functions for rules
// rule for inside specific ID
function process_rule_vlcc_dock_1_3(spaceID, i, jsonObject){
    var term = false;
    // let us pull the init value from the spaceObject for the rule number i
    var space_value =jsonObject.customContent.logicalRules[i].initValue;
    // test the coordinates of object against base object. 
    var baseObject = cvjs_returnSpaceObjectID(space_value);

    term = cvjs_isSpaceObjectInside(baseObject, jsonObject)

    if (term) return true;

    // in any case return false
    return false;
}

5: Implement myCustomPopUpBody to control highlight

The custom menu is set up to be populated with entry fields from the JSON space object. It should contain a callback method such as custom_rules_clickmenu1() .

function myCustomPopUpBody(rmid){

    myobject = cvjs_returnSpaceObjectID(rmid);
    //console.log("myCustomPopUpBody is called: "+ rmid+" "+JSON.stringify(myobject));
    try{
        // template pop-up modal body
        cvjsPopUpBody = "<div> Id: <span id=\"mymodal_name_"+myobject.id+"\" >"+myobject.id+"</span><br>";
        cvjsPopUpBody += "Name: <span id=\"mymodal_name_"+myobject.name+"\" >"+myobject.name+"</span><br>";
        cvjsPopUpBody += "Type: <span id=\"mymodal_type_"+myobject.customContent.insertType+"\" >"+myobject.customContent.insertType+"</span><br>";
        cvjsPopUpBody += "Model: <span id=\"mymodal_type_"+myobject.type+"\" >"+myobject.type+"</span><br>";
        cvjsPopUpBody += "Begin Date: <span id=\"mymodal_startdate_"+myobject.customContent.generalInfo.begindate+"\" >"+myobject.customContent.generalInfo.begindate+"</span><br>";
        cvjsPopUpBody += "End Date: <span id=\"mymodal_startdate_"+myobject.customContent.generalInfo.enddate+"\" >"+myobject.customContent.generalInfo.enddate+"</span><br>";
//		cvjsPopUpBody += "Status: <div class=\"cvjs_callback_modal_1\" onclick=\"my_own_clickmenu1("+rmid+");\"><i class=\"glyphicon glyphicon-transfer\"></i>More Info </div>";
        cvjsPopUpBody += "Confirm change: <a href=\"javascript:custom_rules_clickmenu1('"+myobject.id+"');\"><i class=\"glyphicon glyphicon-transfer\" \"></i></a>&nbsp;&nbsp;<span id=\"mymodal_status_01_"+myobject.id+"\"><i style=\"color:gray\" class=\"glyphicon glyphicon-ok\" \"></i></span> ";
        cvjsPopUpBody += "</div>";
    }catch(err){
        // template pop-up modal body
        cvjsPopUpBody = "<div> Id: <span id=\"mymodal_name_"+myobject.id+"\" >"+myobject.id+"</span><br>";
        cvjsPopUpBody += "Name: <span id=\"mymodal_name_"+myobject.name+"\" >"+myobject.name+"</span><br>";
        cvjsPopUpBody += "Type: <span id=\"mymodal_type_"+myobject.type+"\" >"+myobject.type+"</span><br>";
        cvjsPopUpBody += "</div>";
    }
    return cvjsPopUpBody;
}

If a Space Object does not contain a customContent object, it defaults to displaying a few standard values.


6: Callback to control the custom interaction on Space Objects

When an object is inserted or manulated on the canvas the general callback method function cvjs_graphicalObjectOnChange(type, graphicalObject, spaceID) will always fire. To have user driven acceptance of insertion, it is a good idea to implement a method such as custom_rules_clickmenu1() , which let the user confirm any placement of object.

function custom_rules_clickmenu1(){
    
    var id = cvjs_idObjectClicked();
    //		var node = cvjs_NodeObjectClicked();
    window.alert("custom_rules_clickmenu1: this is the callback to DT app with content");

    // change check arrow to green!!!
    jQuery("#mymodal_status_01_"+id).html("<i style=\"color:green\" class=\"glyphicon glyphicon-ok\" \"></i>");

    var myobject = cvjs_returnSpaceObjectID(id);
    // update my internal DB with new JSON myobject 

    
}

Use this method to extract the updated JSON space object, extract apprpriate values and put into DB for further processing on the application side.



ENJOY - and get in touch!