Implementing a Flowchart Editor Using jsPlumb – Part 3

Hi all, today in my blog post I am going to continue the session on implementing a flowchart diagram editor using jsPlumb. This is the 3rd and last part of the session. The initial implementation of this editor can be found in my previous two blog posts. They are,

Almost all the requirements of the editor is now completed. The remaining two requirements are as follows:

  • User should be able to delete an element/connection by clicking a delete icon that appear on it when the user clicks the element. (See Fig 1)

delete

Figure 1 – Delete icon that appears on the element

  • User should be able to save the flowchart diagram. As the most convenient way of saving, I will show how the diagram can be saved in to a JSON string so that users can later retrieve the diagram easily.

To implement the 1st requirement, we have to add a delete icon (provided by font-awesome library) to each and every element. That is why we used the following line within the createElement() function (See tutorial Part 2).

elm.append("<i style='display: none; margin-left: -5px; margin-top: -50px' " +             "class=\"fa fa-trash fa-lg close-icon desc-text\"><\/i>");

Note: To include this icon you need to have font-awesome.min.css in your CSS directory. The easiest way to do this is to include the CSS file within the head tag as follows:

	<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css">

To view the delete icon, we can write the following function;

$(document).on("click", ".custom", function () {
    if ($(this).attr("class").indexOf("diamond") == -1) {
        var marginLeft = $(this).outerWidth() + 8 + "px";
        $(".close-icon").prop("title", "Delete the element");
        $(this).find("i").css({'margin-left': marginLeft, 'margin-top': "-10px"}).show();
    } else {
        $(this).find("i").css({'margin-left': "35px", 'margin-top': "-40px"}).show();
    }
});

Note: The decision element was created by rotating the step element. Hence the position of the delete icon differs from that of the other elements. That is why I used an If-Else condition in the above function. The positions are calculated based on the element width.

To make the border highlighted with red, we can write the following function:

$('#canvas').on('click', function (e) {
    $(".jtk-node").css({'outline': "none"});
    $(".close-icon").hide();
    if (e.target.nodeName == "P") {
        e.target.parentElement.parentElement.style.outline = "4px solid red";
    } else if (e.target.nodeName == "STRONG") {
        e.target.parentElement.style.outline = "4px solid red";
    } else if (e.target.getAttribute("class") != null && e.target.getAttribute("class").indexOf("jtk-node") > -1) {//when clicked the step, decision or i/o elements
        e.target.style.outline = "4px solid red";
    }
});

The 3 different conditions had to be checked as the basic elements contains paragraph and strong element tags and user might click on one of those elements when selecting the whole element.

Let’s write the function to delete an element when the delete icon is clicked. We use the jsPlumb functionalities to accomplish this task. We can remove elements from the canvas using the jsPlumb.remove() function.

$(document).on("click", ".close-icon", function () {
    jsPlumbInstance.remove($(this).parent().attr("id"));
});

Up to now we completed the 1st requirement!

Now we can move on to implement the 2nd requirement which is to save the flowchart diagram to a JSON string. This is quite straight forward. If you know how to extract the required details using the jsPlumb API, then implementing this functionality is very easy.

I recommend you to try first before using the function I implemented. However, as a starting point, I will define the structure of the JSON string (keep in mind that you can define your own structure. I am giving this to make it easy for you!). The structure would be as follows:

flowchart{
    nodes: {
	elementId, nodeType, positionX, positionY, className, label, width, height
    },
    connections:{
	connectionId, sourceUUID, targetUUID, label, labelWidth
    },
    numberOfElements
}

The implementation of the function is:

_saveFlowchart = function () {
    var totalCount = 0;
    if (elementCount > 0) {
        var nodes = [];

        //check whether the diagram has a start element
        var elm = $(".start.jtk-node");
        if (elm.length == 0) {
            alertify.error("The flowchart diagram should have a start element");
        } else {
            $(".jtk-node").each(function (index, element) {
                totalCount++;
                var $element = $(element);
                var type = $element.attr('class').toString().split(" ")[1];
                if (type == "step" || type == "diamond" || type == "parallelogram") {
                    nodes.push({
                        elementId: $element.attr('id'),
                        nodeType: type,
                        positionX: parseInt($element.css("left"), 10),
                        positionY: parseInt($element.css("top"), 10),
                        clsName: $element.attr('class').toString(),
                        label: $element.text(),
                        width: $element.outerWidth(),
                        height: $element.outerHeight()
                    });
                } else {
                    nodes.push({
                        elementId: $element.attr('id'),
                        nodeType: $element.attr('class').toString().split(" ")[1],
                        positionX: parseInt($element.css("left"), 10),
                        positionY: parseInt($element.css("top"), 10),
                        clsName: $element.attr('class').toString(),
                        label: $element.text()
                    });
                }
            });

            var connections = [];
            $.each(jsPlumbInstance.getConnections(), function (index, connection) {
                connections.push({
                    connectionId: connection.id,
                    sourceUUId: connection.endpoints[0].getUuid(),
                    targetUUId: connection.endpoints[1].getUuid()
                });
            });

            var flowchart = {};
            flowchart.nodes = nodes;
            flowchart.connections = connections;
            flowchart.numberOfElements = totalCount;
            alert(JSON.stringify(flowchart));
        }
    }
}

That’s it! Now we implemented the 2nd remaining requirement thereby finishing the whole flowchart diagram editor. Since I gave almost every code segment for this editor, I would like to present a homework for the reader. Now you are familiar enough with jsPlumb and it is time for you to write your own functionality to display a delete icon on top of the connections and delete the corresponding connection by clicking the icon. This can be easily done using the jsPlumb Overlays.

This is the end of the 3rd and final part of the tutorial I wrote to implement a flowchart diagram editor using jsPlumb. I hope this may be useful to you. Please comment your suggestions as well as problems if you get any while reading the post.

[Note: This tutorial was based on the flowchart diagram editor I implemented for the WSO2 Process Center during my internship training period.)

Advertisements

5 thoughts on “Implementing a Flowchart Editor Using jsPlumb – Part 3

  1. Hi, this post is fantastic however my coding isn’t quiet up to par so I think I missing some things. Do you happen to have to files that are the end result of each step or the final product which you can share?
    Thanks!
    C

    Like

  2. Hi Dilini Mampitiya an thank you for posting this interesting tutorial.
    I’ve followed the 3 lessons with interest, but, cause my lack of experience, I’m not been able to make the whole working.
    What I’m going to ask You is if you could kindly post the whole needed files and subfolders within a packed zipped file, so that we could unpack the “working” version ready to be enjoyed (I would really like to see that project working).
    please, don’t misunderstand me, I’m not lazy, but even after several attempts, I’m still in trouble to make it work.
    Thank You again
    Gianni from Italy

    Like

      1. thank you very much Dilini,
        studying the working script you kindly posted on github also helps me to understand how to use the whole jsplumb system.
        Nice example!
        I wish You happy days 🙂
        Bye and many thanks again
        Gianni

        Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s