clientIO / joint

A proven SVG-based JavaScript diagramming library powering exceptional UIs
https://jointjs.com
Mozilla Public License 2.0
4.48k stars 839 forks source link

toJSON -> fromJSON port attrs not restored (bug) #594

Closed mahald closed 7 years ago

mahald commented 7 years ago

i use paper.toJSON to save a flowchart. then i use paper.fromJSON to restore it again. The restored Ports are missing the color and the label:

(TypeScript Code):

var m1 = joint_extend.createModel(joint, 'MyImageModel',mydata) as joint.shapes.devs.Model; m1.portProp('makecall.ok', 'attrs/.port-body/fill', '#00FF00'); m1.portProp('makecall.ok', 'attrs/.port-label/text', 'Ok'); m1.addTo(this.graph);

The toJSON is correctly saving the port attrs:

{ "id":"makecall.ok", "group":"out", "attrs":{ ".port-label":{ "text":"Ok" }, ".port-body":{ "fill":"#00FF00" } } },

if i do paper.fromJSON with the obove attrs the colors are not restored.

if i then do paper.toJSON again u see why. because the port attrs were not restored:

{ "id":"makecall.ok", "group":"out", "attrs":{ ".port-label":{ "text":"makecall.ok" } } },

looks to me like a missing feature in fromJSON to resorte port attrs.

vtalas commented 7 years ago

hi, there shouldn't be any magic, it's weird your ports are not "reconstructed" correctly. I tried it on this code and it worked fine:

m.addPort({ id: "xxx.x", attrs: { circle: { magnet: true, stroke: '#31d0c6', 'stroke-width': 2 } } });
m.addPort({ attrs: { circle: { magnet: true, stroke: '#31d0c6', 'stroke-width': 2, fill: '#ffffff' } } });
m.addPort({ attrs: { circle: { magnet: true, stroke: '#31d0c6', 'stroke-width': 2, fill: '#ffffff' } } });

m.portProp('xxx.x', 'attrs/circle/fill', 'red');

graph.addCell(m);

var json = graph.toJSON();
graph.clear();
setTimeout(function() {
    graph.fromJSON(json)
}, 1000);
mahald commented 7 years ago

ok im puzzled now. none of them get restored:

    m1.portProp('test123', 'attrs/.port-body/fill', '#00FF00');
    m1.addPort({ id: 'test', group:'out'});

my (totaly) stripped down test-code looks as follows:

 <!DOCTYPE html>
<html>
<head>
<title>joint test</title>
    <link rel="stylesheet" type="text/css" href="/lib/css/joint.min.css" />
    <script src="/lib/jquery.3.1.1.min.js"></script>
    <script src="/lib/lodash3.10.1.min.js"></script>
    <script src="/lib/backbone1.3.3.min.js"></script>
    <script src="/lib/joint1.1.0.min.js"></script>
  <style>
    .available-magnet { fill: yellow;  }
    .available-cell rect { stroke-dasharray: 5, 2; }
  </style>
</head>

<body>
    <div id="paper"></div>
<script>
joint.shapes.devs.MyImageModel = joint.shapes.devs.Model.extend({
    markup: '<g class="rotatable"><g class="scalable"><rect class="body"/></g><image/><text class="label"/><text class="label2"/><g class="inPorts"/><g class="outPorts"/></g>',
    defaults: joint.util.deepSupplement({ type: 'devs.MyImageModel' },
    joint.shapes.devs.Model.prototype.defaults)
  });
joint.shapes.devs.MyImageModelView = joint.shapes.devs.ModelView;

    var graph = new joint.dia.Graph;
    var paper = new joint.dia.Paper({
        el: $('#paper'),
        width: 1000, height: 1000, gridSize: 10,
        model: graph
    });

    var m1 = new joint.shapes.devs.MyImageModel({
        position: { x: 50, y: 50 },
        size: { width: 90, height: 90 },
        outPorts: ['test123']
    });
    m1.portProp('test123', 'attrs/.port-body/fill', '#00FF00');
    m1.addPort({ id: 'test', group:'out'});
    //m1.addTo(graph);
    graph.addCell(m1);

    var json = graph.toJSON();

    setTimeout(function() { graph.clear(); }, 1000);
    setTimeout(function() { graph.fromJSON(json); }, 2000);

    </script>
</body>
</html>

any ideas what im doing wrong then ?

vtalas commented 7 years ago

the thing is the devs.Model is quite special. It has an extra API to be compatible with the new implementation of ports. You either use the devs.Model api - instead of the m1.addPort use the m1.addOutPort('label') / m1.addInPort('label') or don't use the devs.Model at all (recommended). Ports can be added to any shape, e.g.:

var m = new joint.shapes.basic.Rect({
    position: { x: 20, y: 100 },
    size: { width: 100, height: 100 }
})

m.addPort({ id: "xxx.x", attrs: { circle: { magnet: true, stroke: '#31d0c6', 'stroke-width': 2 } } });
m.addPort({ attrs: { circle: { magnet: true, stroke: '#31d0c6', 'stroke-width': 2, fill: '#ffffff' } } });
m.addPort({ attrs: { circle: { magnet: true, stroke: '#31d0c6', 'stroke-width': 2, fill: '#ffffff' } } });

m.portProp('xxx.x', 'attrs/circle/fill', 'red');

graph.addCell(m);

var json = graph.toJSON();
graph.clear();
setTimeout(function() {
    graph.fromJSON(json)
}, 1000);
Marais commented 7 years ago

I also have this problem with devs.Model. The port is not populated when i fetch it.

kumilingus commented 7 years ago

Please do not use devs.Model if you do not want to use addInPort() and addOutPort() API. We keep devs.Model here to maintain the backwards compatibility, where ports are controlled via inPorts and outPorts attributes. Note that any joint.dia.Element (e.g. joint.shapes.basic.Rect) can have ports.

mahald commented 7 years ago

thank you all very mutch, i was able to use joint.shapes.basic.Rect instead and was able to do anything i previously did with devs.Model.

mahald commented 7 years ago

PS: Updating the Tutorials, 'Working with Ports' http://resources.jointjs.com/tutorial/ports would be a good idea then, to prevent newbies from using it.

vtalas commented 7 years ago

Yes, updating tutorials is on the schedule. Thank you to pointing this out.

IRooc commented 5 years ago

Could you please update the docs? I fell into the same trap because http://resources.jointjs.com/tutorial/ports still uses devs.Model....