Search code examples
javascriptconstructorraphaeljointjs

Using a constructor to help populate Raphael & joint.js functionality


I'm building activity diagrams using joint.js, which extends raphael.js. It's pretty simple, here is an example. In this example, var r creates the raphael paper and attaches it to the identified div ID. c1, c2, c3 create the diagram boxes. The x.joint(y) function draws the connectors between the created objects.

var r = Raphael("activity1", 500, 500),
c1 = r.rect(40, 40, 50, 50, 10),
c2 = r.rect(140, 140, 50, 50, 10);
c3 = r.rect(240,40,50,50,10);
c1.joint(c2);
c2.joint(c3);
c1.joint(c3);

Now--what I'm wanting to do is still a little confusing for me, as someone who is still learning as I go with javascript. I could easily just continue doing what I'm doing above. However, what I want to do instead is to create a Constructor for the diagrams and then use the Constructors to populate the diagram a little more easily.

How would I go about creating function diagNode(params){properties and methods}; that would make sense here? I started down this path, but then I feel like I'm not sure what to do next with it...

//create a new constructor for diagram nodes
function diagNode(xStart,yStart,Width,Height,Corner){
    this.xStart = xStart;
    this.yStart = yStart;
    this.wide = Width;
    this.tall = Height;
    this.corner = Corner;
};
diag1 = new diagNode(300,100,100,50,10);

Solution

  • I create a jsfiddle working demo here I create two simple Objects Node and Diagram:

    • Node define a state of the diagram; the constructor accept a spec literal object (spec.uid, spec.x, spec,y, etc) see comments in code
    • the Diagram constructor accept an html id selector and a optional spec object literal (spec.width and spec.height)
    • the Diagram object exspose a public API that permitt to

      • add new node to the diagram by the addState Method (see the comment in the code)
      • add an array of nodes to the diagram by the addStates Method (see the comment in the code)
      • joint two nodes by the jointState Method (see the comment in the code)
      • search a node in the Diagram by the searchState Method

    CODE:

    /*
    ** Node constructor
    ** crate a new Node (or state diagram)
    ** 
    ** @params {object} spec  the specification object (spec.x,spec.y,spec.width,spec.height, spec.radius
    **
    ** @return NodeObject
    */
    var Node = function(spec) {
        spec = spec || {};
        //uid usefull for search this node in a diagram
        this.uid = spec.uid || 0;
        this.x = spec.x || 0;
        this.y = spec.y || 0;
        this.width = spec.width || 0;
        this.height = spec.height || 0;
        this.radius = spec.radius || 0;
    };
    
    /*
    ** Diagram constructor
    ** 
    ** @params {object} selector  the paper selector 
    **
    ** @return Diagram Object
    */
    var Diagram = function(selector, spec) {
        //relay on default value if spec is undefined
        var defaultSpec = {
            width: 500,
            height: 500
        },
            dWidth = spec.width || defaultSpec.width,
            dHeight = spec.height || defaultSpec.height;
    
        //define the paper property
        this.paper = Raphael(selector, dWidth, dHeight);
    
        //define the state array; usefull for search node in diagram
        this.states = [];
    
    };
    
    Diagram.prototype = {
        //inefficent method to search a state by UID in array
        //TODO:optimize! 
        searchState: function(stateId) {
            var instance = this,
                i = 0,
                max = this.states.length,
                currentState, find = false,
                selectedState;
    
            //search the stateId params in diagram states array
            for (; i < max; i++) {
                currentState = instance.states[i];
                if (currentState.node.uid === stateId) {
                    find = true;
                    selectedState = currentState;
                }
            }
    
    
            //return the response object
            return selectedState;
    
        },
    
        //add single state (Node) to diagram    
        addState: function(node) {
            //create a rect shape with state param spec
            var state,
                stateShape = this.paper.rect(node.x, node.y, node.width, node.height, node.radius);
    
            state = {
                node : node,
                shape: stateShape
            };
            //add state to array  
            this.states.push(state);
    
            return this;
        },
    
        //add an array of states (Node) to diagram    
        addStates: function(stateArray) {
            var instance = this,
                i = 0,
                max = stateArray.length,
                currentState;
            for (; i < max; i++) {
                currentState = stateArray[i];
                instance.addState(currentState);
            }
            return this;
        },
    
        //join two states
        jointState: function(sourceState, destinationState) {
            var source = this.searchState(sourceState.uid),
                dest = this.searchState(destinationState.uid);
    
    
            //joint only if all the states passed to the function, already exist in the diagram    
            if (source && dest) {
                source.shape.joint(dest.shape);
            }
            return this;
        }
    };
    
    
    //code
    // define nodes (or states)
    var c1 = new Node({
        uid: 1,
        x: 50,
        y: 40,
        width: 50,
        height: 50,
        radius: 10
    }),
        c2 = new Node({
            uid: 2,
            x: 150,
            y: 140,
            width: 50,
            height: 50,
            radius: 10
        }),
        c3 = new Node({
            uid: 3,
            x: 250,
            y: 50,
            width: 50,
            height: 50,
            radius: 10
        }),
        c4,
        // define an array of state to optionally pass to addStates Diagram function
        allStates = [c1, c2, c3],
        myDiag;
    //create the diagram passing allStates array and settings node (state) joins
    myDiag = new Diagram("activity1", 500, 500).addStates(allStates).jointState(c1, c2).jointState(c2, c3).jointState(c1, c3);
    
    //later create anothe node
    c4 = new Node({
        uid: 4,
        x: 350,
        y: 150,
        width: 50,
        height: 50,
        radius: 10
    });
    
    //add node to diagram
    myDiag.addState(c4);
    //join c3 to c4
    myDiag.jointState(c3, c4);