Save and load a flowchart on jsPlumb
Asked Answered
C

5

11

What's the best approach to save and load an flowchart on jsPlumb?

Chablis answered 13/9, 2011 at 17:0 Comment(1)
G
9

I managed to save the chart by simply having all the elements inside an array of objects, where each object has source and target nodes, x, y coordinates.

When saving, simply do JSON.stringify(whole_object), and if loading, simply JSON.parse() and manually position the nodes as well as connect them.

Garniture answered 27/5, 2012 at 9:47 Comment(2)
can you please share some code ? I'm confused about how to load and connect them.Romero
Oh.. It was long time ago, but as far as I remember simply save the data by JSON.stringify(objectCollection). There are relations, positions, etc. Now when you want to load, do JSON.parse(generatedStrnig) and then manually go through each node in the object and position it(with CSS) and connect them(with jsPlumb API). Sorry I don't remember exactly :)Garniture
S
7

My solution save and load jsPlumb:

function Save() {
    $(".node").resizable("destroy");
    Objs = [];
    $('.node').each(function() {
        Objs.push({id:$(this).attr('id'), html:$(this).html(),left:$(this).css('left'),top:$(this).css('top'),width:$(this).css('width'),height:$(this).css('height')});
    });
    console.log(Objs);
}


function Load() {
    var s="";
    for(var i in Objs) {
        var o = Objs[i];
        console.log(o);
        s+='<div id="'+ o.id+'" class="node" style="left:'+ o.left+'; top:'+ o.top+'; width:'+ o.width +'; height:'+ o.height +' "> '+ o.html+'</div>';
    }
    $('#main').html(s);
}

UPD Demo: http://jsfiddle.net/Rra6Y/137/

Note: if demo does not work in JsFiddle, make sure it points to an existing jsPlumb link (links are listed in "External Resources" JsFiddle menu item

Shipowner answered 23/5, 2013 at 4:49 Comment(2)
Hi and thanks for these hints. I just try to create an online finite state machine designer with jsplumb and to do the saving / loading correctly, I need to pass more data than the html you added to my array. Something like "state name", "connectedTo" and so on. You know, something to actually save my "state machine", not just my "drawing". You got a hint on how to do this, perhaps? would be great!Cardin
the jsfiddle link doesn't work. Can't drag and no connections are created. There are errors in the console for save, load & clear.Romero
C
4

My save functionality does a bit more than just save the x, y position of the element and its connections. I also added saving a connection Label overlay as well as custom text for each element. You can tailor this solution as per your requirements but here it is basically:

   //save functionality
    function IterateDrawnElements(){  //part of save
        var dict = {};
        $('#id_diagram_container').children('div.window').each(function () {
            var pos = $(this).position()
            var diagram_label = $(this).children('div.asset-label').children('div.asset-diagram-label').text()
            if (diagram_label == null || diagram_label == ''){
                diagram_label='';
            }
            dict[this.id] = [pos.left, pos.top, diagram_label];
        });
        return dict;
    }
    function IterateConnections(){  //part of save
        var list = [];
        var conns = jsPlumb.getConnections()
        for (var i = 0; i < conns.length; i++) {
            var source = conns[i].source.id;
            var target = conns[i].target.id;
            try{
                var label = conns[i].getOverlay("label-overlay").labelText;
            }
            catch(err) {
                label = null
            }
            //list.push([source, target])
            if (source != null && target != null){
                list.push([source, target, label]);
            };
        }
        return list;
    }

I initiate all this when the user hits the save button, an ajax call is made back to the server, in this case Django is intercepting the ajax request and saves the data to the database.

//ajax call when save button pressed $save_btn.click(function() {

//drawn elements
var d_elements = IterateDrawnElements();
var d_conns = IterateConnections();
var d_name =$('#id_diagram_name').val();

$.ajax({
    url : ".",
    type : "POST",
    dataType: "json",
    data : {
        drawn_elements: JSON.stringify(d_elements),
        conns: JSON.stringify(d_conns),
        diagram_name: d_name,
        csrfmiddlewaretoken: '{{ csrf_token }}'
    },
    success: function (result) {

        if (result.success == true){
            save_status.html(result.message)
        }
        //console.log(JSON.stringify(result));
        $save_btn.attr('disabled','disabled');
        if (result.old_name != false){
            //alert()
            $('#id_diagram_name').val(result.old_name)
        }
    },
    error: function(xhr, textStatus, errorThrown) {
        alert("Please report this error: "+errorThrown+xhr.status+xhr.responseText);
    }
});
//return false; // always return error?

});

To load all this up is even easier and there are many ways you can do this. In Django you can just generate the html straight in your template as well as the js for the connections or you can create a JSON object in javascript for everything and then have javascript draw it all based on the array. I used jquery for this.

//js & connections load

var asset_conns = [
    {% for conn in diagram_conns  %}
    [ {{ conn.source.id }}, {{ conn.target.id }}, '{{ conn.name }}' ],
    {% endfor %}
]


// Takes loaded connections and connects them
for (var i = 0; i< asset_conns.length; i++){
    var source = asset_conns[i][0].toString();
    var target = asset_conns[i][1].toString();
    var label = asset_conns[i][2];
    var c = jsPlumb.connect({source: source, target: target, detachable:true, reattach: true });  //on init already know what kind of anchor to use!
    if (label != null && label != 'None'){
        c.addOverlay([ "Label", { label: label,  id:"label-overlay"} ]);
    }
}

//html right into django template to draw elements, asset element interchangeable terms

{% for element in drawn_elements %}
    <div id="{{ element.asset.id }}" class="window" style="left:{{ element.left }}px;top:{{ element.top }}px;background-image: url('{% static element.asset.asset_mold.image.url %}'); width: {{ element.asset.asset_mold.image.width }}px;height: {{ element.asset.asset_mold.image.height }}px;">
        <div class="asset-label" id="label-{{ element.asset.id }}">
            {#{{ element.asset }}#}<a class="lbl-link" id="lbl-link-{{ element.asset.id }}" href="{{ element.asset.get_absolute_url }}">{{ element.asset }}</a>
            <div class='asset-diagram-label' id="lbl-{{ element.asset.id }}">{% if element.asset.diagram_label  %}{{ element.asset.diagram_label }}{% endif %}</div>
        </div>
        <div class='ep' id="ep-{{ element.asset.id }}"></div>
    </div>
{% endfor %}

You can greatly simplify this but mine also gets a background for the element, as well as label and the shape of the element to use with perimeter anchors. This solution works and is tested. I'll release an open source Djago application for this soon on PyPi.

Choreograph answered 20/5, 2014 at 23:46 Comment(0)
D
0

I'm using YUI with it. I'm saving the position of each box item being connected in a table. I them have a separate table the stores a parent to child relationship between the items, which is used to determine the lines jsPlumb should draw. I determine this using a selection process in which the first item selected is the parent, and all other items are children. When the "connect" button is clicked, the parent/child selection of the items is cleared. I also toggle this if you click the selected parent - it clear the child selections as well.

Diminished answered 16/9, 2011 at 20:3 Comment(0)
C
0

I recently wrote this blog post about why jsPlumb doesn't have a save function (and what I recommend you do):

http://jsplumb.tumblr.com/post/11297005239/why-doesnt-jsplumb-offer-a-save-function

...maybe someone will find it useful.

Caplin answered 8/11, 2011 at 8:12 Comment(1)
What people are looking for is a simple way to say: persist this diagram to xml/json, or save it in some other way that can be easily parsed and mapped to update the data model... It seems like that's an obvious usability thing. It seems like what you outlined here will cause me to take a lot of annoying extra steps to get there the way I want to get there.Tetrastichous

© 2022 - 2024 — McMap. All rights reserved.