Joint.js add custom ports with path class. for custom elements
Asked Answered
D

1

11

What I am trying to do is make a element with custom class for ports and path so that I can add an element with custom path and my own markup for ports.This way when I create an element I will pass dynamic path for its shape just like elements of path class behave and as I have also extended from PortsModelInterface I will also have my own markup for ports. This whole effort is to make svg scalable for zomming. Previously I was using html custom element with my custom ports which was working fine but html of custom elements wasn't scaling on zooming

var graph = new joint.dia.
var paper = new joint.dia.Paper({
    el: $('#paper'),
    width: 800,
    height: 600,
    gridSize: 1,
    model: graph,
    snapLinks: true,
    embeddingMode: true
});
joint.shapes.custom1={};
 joint.shapes.custom1.Element = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
        markup: '<g class="rotatable"><g class="scalable"><rect class = "myrect"/></g><g class="inPorts"/><g class="outPorts"/></g>',
        portMarkup: '<g class="port<%= id %>"><circle class="port-body"/></g>',
        defaults: joint.util.deepSupplement({
            type: 'html.Element',
            size: { width: 200, height: 110 },
            inPorts: [],
            outPorts: [],
            attrs: {
                '.': { magnet: true},
                rect: {
                    stroke: 'none', 'fill-opacity': 0, width: 300, height: 210,
                },
                circle: {
                    r: 6, //circle radius
                    magnet: true,
          left:0,
                    stroke: 'gray'
                },

                '.inPorts circle': { fill: 'gray', magnet: 'passive', type: 'input', y: 0},
                '.outPorts circle': { fill: 'gray', type: 'output' }
            }
        }, joint.shapes.basic.Generic.prototype.defaults),
        getPortAttrs: function (portName, index, total, selector, type) {

            var attrs = {};
            var portClass = 'port' + index;
            var portSelector = selector + '>.' + portClass;
            var portCircleSelector = portSelector + '>circle';
            attrs[portCircleSelector] = { port: { id: portName || _.uniqueId(type), type: type } };
            attrs[portSelector] = { ref: 'rect', 'ref-x': (index + 1) * (0.55 / total)};
            if (selector === '.outPorts') { 
          attrs[portSelector]['ref-dy'] = 15; 
      }
            return attrs;
        }
    }));
joint.shapes.custom1.Atomic = joint.shapes.custom1.Element.extend({

    markup: '<g class="rotatable"><g class="scalable"><path/></g><text/></g>',

    defaults: joint.util.deepSupplement({

        type: 'basic.Path',
        size: { width: 60, height: 60 },
        attrs: {
            'path': { fill: '#FFFFFF', stroke: 'black' },
            'text': { 'font-size': 14, text: '', 'text-anchor': 'middle', 'ref-x': .5, 'ref-dy': 20, ref: 'path', 'y-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
        }
    }, joint.shapes.basic.Generic.prototype.defaults)

});

var a2 = new joint.shapes.custom1.Atomic({
    position: { x: 50, y: 260 },
    size: { width: 100, height: 100 },
    attrs: {
        path: { d: 'M 30 0 L 60 30 30 60 0 30 z' },
        text: {
            text: 'Diamond',
            'ref-y': .5 // basic.Path text is originally positioned under the element
        }
    },
     inPorts: ['in'],
     outPorts: ['out']
});
graph.addCells([a2])

The element is added in graph but some how the ports don't show up. I don't have proper concept of adding classes so please any help will be greatly appreciated. Thanks. Fiddle example

Distrust answered 12/7, 2015 at 13:15 Comment(9)
What does this have to do with backbone.js?Mclane
Joint.js is built over backbone.js, this whole mechanism of extending classes is derived from backbone. Should'nt I add this tag??Distrust
Is there anyway you could make a fiddle or something so we can run the code and see it fail, and then try things to see if we can make it work? I'm not sure you're going to find someone with joint.js, but if you give us a chance to play, we may figure it out.Hypolimnion
Just made a fiddle of it. link is in post.Distrust
Here's a JSFiddle of a working demo of a custom element with custom ports.Diatomite
Thanks for helping but I want to give element custom path. So that I can draw elements of my choice like in a fiddle of diamond shape it can be of any shape. In your fiddle where can I give path.Distrust
with custom markup for ports I also want to give custom markup for my element. I am not going to draw same element always.Distrust
Did you try modifying the example in the jsfiddle I posted? Making custom shapes in jointjs is not the easiest or most intuitive thing to do right now. And working with ports is even trickier. Improving the API and usability of jointjs is on the development roadmap.Diatomite
Yes I tried. In markup for element instead of <rect/> I added '<path d=""/>', so that I can give custom d value for my variable shape element. But when I applied paper.scale function to zoom in . I was not able to draw link properly from port. tweaked fiddleDistrust
M
6

I suggest to define an element with custom markup for the shape and ports. Both markups should contain an SVG path, so you can set an arbitrary path data d via model.attr() on them.

joint.shapes.devs.GenericModel = joint.shapes.devs.Model.extend({

    markup: '<g class="rotatable"><g class="scalable"><path class="body"/></g><text class="label"/><g class="inPorts"/><g class="outPorts"/></g>',
    portMarkup: '<g class="port port<%= id %>"><path class="port-body"/><text class="port-label"/></g>',

    defaults: joint.util.deepSupplement({
        type: 'devs.GenericModel'
    }, joint.shapes.devs.Model.prototype.defaults)
});

Tell the paper to use devs.ModelView for rendering.

joint.shapes.devs.GenericModelView = joint.shapes.devs.ModelView;

Now you can set or change d attribute for the shape and ports anytime you wish.

var model = new joint.shapes.devs.GenericModel({
    attrs: {
        '.body': { d: 'M 0 0 0 50 50 50 z'},
        '.port-body': { d: 'M 0 0 10 0 10 10 0 10 z'}
    } 
});

model.attr('.body/d', 'M 25 0 50 50 0 50 z');

JS Fiddle: http://jsfiddle.net/kumilingus/kge023bc/

Mycenaean answered 27/7, 2015 at 10:9 Comment(1)
That is exactly what I was craving for. Thanks .Distrust

© 2022 - 2024 — McMap. All rights reserved.