Save and load a flowchart on jsPlumb
What's the best approach to save and load an flowchart on jsPlum开发者_如何学JAVAb?
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.
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
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.
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.
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.
精彩评论