Search code examples
backbone.jssvgjointjsdiagramming

JointJS Element with ports and tool items (delete, settings etc.)


I managed to enhance my SVG-shape with ports via:

joint.shapes.devs.Element = joint.shapes.basic.Generic.extend(_.extend({},     
joint.shapes.basic.PortsModelInterface, {
    // SVG markup with ports
});

With this I get the output:

SVG shape with ports

I want to enhance this shape with a delete button. For that I have:

joint.shapes.devs.toolElement = joint.shapes.basic.Generic.extend({
    // markup for delete button
});

based on Mike Goodwin´s solution in How to give JointJS elements a remove tool?

My question: How can I combine the PortModelInterface with the delete tool? The solution should look like this:

delete action and ports combined

Thanks for helping me out.


Solution

  • Solution

    The key was this plugin. The author extended the PortsModelInterface with own code for a move-, resize- and ports-tool. I extended it further by implementing the delete functionality. This way the devs-model is open to any extension in case of functionality.

    How it´s done

    In tooledViewPlugin.js there is joint.plugins.TooledModelInterface = {}. In there I added:

    deleteToolMarkup: '<circle fill="red" r="11"/><path transform="scale(.8) translate(-16, -16)" d="M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z"/><title>Remove this element from the model</title>',
    

    Below in joint.plugins.TooledViewInterface = {} I wrote

    renderDeleteTool: function () {
        var deleteContainer = this.$('.deleteTool').empty();
        var markup = V(this.model.deleteToolMarkup);
        for(var id in markup)
            deleteContainer.append(markup[id].node);
    }
    

    An example shape with special SVG markup other than a simple rectangle. Note the <g class="deleteTool"/> in the markup:

    joint.shapes.devs.UnspecifiedProcess = joint.shapes.devs.Model.extend(_.extend({}, joint.plugins.TooledModelInterface, {
    
    markup: ['<g class="rotatable">',
                '<g class="scalable">',
                    '<rect class="body"/>',
                    '<g xmlns="http://www.w3.org/2000/svg" transform="translate(-549.49953,-824.87393)" id="layer1">',
                        '<g transform="matrix(0.933025,0,0,-0.2986125,549.49953,846.37362)" id="g3553">',
                          '<g transform="scale(0.98976,3.0047)" id="g3555">',
                            '<g clip-path="url(#clipPath3559)" id="g3557">',
                              '<path d="m 57.805,0.90155 -57.805,0 0,23.06045 57.805,0 L 72.244,12.432 57.805,0.90155 z" id="path3563" style="fill:#b8cde8;fill-opacity:1;fill-rule:evenodd;stroke:none"/>',
                            '</g>',
                          '</g>',
                        '</g>',
                    '</g>',
                '</g>',
                '<g class="inPorts"/>',
                '<g class="outPorts"/>',
                '<g class="moveTool"/>',
                '<g class="resizeTool"/>',
                '<g class="portsTool"/>',
                '<g class="deleteTool"/>',
                '<title class="tooltip"/>',
            '</g>'].join(''),
    
    defaults: joint.util.deepSupplement({
        type: 'devs.UnspecifiedProcess',
        inPorts: [''],
        outPorts: [''],
        moveTool: true,
        resizeTool: true,
        size: { width: 100, height: 31},
        attrs: {
            '.inPorts circle': { fill: '#fff' },
            '.outPorts circle': { fill: '#fff' },
            '.body': {
                width: 67, height: 21,
                stroke: 'none'
            },
        }
    }, joint.shapes.devs.Model.prototype.defaults),
    }));
    joint.shapes.devs.UnspecifiedProcessView = joint.shapes.devs.ModelView.extend(joint.plugins.TooledViewInterface);
    

    The final part is instantiating the element with new joint.shapes.devs.UnspecifiedProcess. I present it to you with my drag and drop logic as it might be useful for you too:

    //Drag and drop shapes
    if (Modernizr.draganddrop) {
        // Mouse position
        var posX = 0,
            posY = 0;
        // Selected Element with start of dragging
        var selectedEl = "";
        var selectedObj = null;
        var oldObj = null;
        //
        $(".draggable-svg").on("dragstart", function(e) {
            selectedEl = this.id;
            console.log(selectedEl);
        }); 
        $("#drawing-area").on("dragover", function(e) {
            e.preventDefault();
            posX = e.originalEvent.pageX - sideBarW;
            posY = e.originalEvent.pageY - topBarH;
        }); 
        $("#drawing-area").on("drop", function(e) {
            e.preventDefault();
            var element = new joint.shapes.devs[selectedEl]({
                position: { x: posX, y: posY }
            });
            graph.addCell(element);
            selectedEl = "";
            oldObj = selectedObj;
            selectedObj = element;
    
        }); 
    } else {
        alert("Your browser is very old. Please update.");
    }