JointJS - Dashed Line Between Vertices (Custom Attribute)

by Roman Bruckner

HTML

<html>
<head>
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.5.5/joint.css" />
</head>
<body>
      <!-- content -->
      <div id="paper"></div>         

      <!-- dependencies -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.4.0/backbone.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/3.5.5/joint.js"></script>
    
    </body>
</html>

CSS

.joint-paper {
  display: inline-block;
  border: 1px solid gray;
}

JavaScript

class Link extends joint.dia.Link {

    defaults() {
        return {
            ...super.defaults,
            type: 'Link',
            attrs: {
                line: {
                    connectionPart: 'outer',
                    stroke: '#333333',
                    strokeWidth: 2,
                    strokeLinejoin: 'round',
                    targetMarker: {
                        'type': 'path',
                        'd': 'M 10 -5 0 0 10 5 z'
                    }
                },
                dashedLine: {
                    connectionPart: 'inner',
                    stroke: '#999999',
                    strokeWidth: 2,
                    strokeDasharray: '5 5',
                    strokeLinejoin: 'round',
                },
                wrapper: {
                    connection: true,
                    strokeWidth: 10,
                    strokeLinejoin: 'round'
                }
            }
        };
    }

    preinitialize() {
        this.markup = [{
            tagName: 'path',
            selector: 'wrapper',
            attributes: {
                'fill': 'none',
                'cursor': 'pointer',
                'stroke': 'transparent',
                'stroke-linecap': 'round'
            }
        }, {
            tagName: 'path',
            selector: 'line',
            attributes: {
                'fill': 'none',
                'pointer-events': 'none'
            }
        }, {
            tagName: 'path',
            selector: 'dashedLine',
            attributes: {
                'fill': 'none',
                'pointer-events': 'none'
            }
        }];
    }

    static attributes = {
        connectionPart: {
            set: function(type) {
                const vertices = this.model.vertices();
                if (type === 'inner') {
                    const path = new g.Path(new g.Polyline(vertices));
                    return { d: path.serialize() };
                } else {
            ...