javascriptsvginternet-explorer-11polyfillsrappid

IE11 - Object doesn't support property or method 'contains'


Working with Rappid I encountered an error in IE11 console:

Object doesn't support property or method 'contains'

This error is from an SVGElement not having that method. Same code in Chrome works.

Seems like I need to polyfill for this missing method, but according to MDN docs on contains it is supported from IE9 and up, but is not supported on SVGElement.

Edit: Here is a snippet - try to run in Chrome and in IE11

const joint = window.joint;

let graph = new joint.dia.Graph;

let paper = new joint.dia.Paper({
    width: 1500,   /*200,*/
    height: 1500,  /*200,*/
    el: $('.paper-container'),
    gridSize: 1,
    drawGrid: true,
    model: graph,
    //defaultLink: new joint.shapes.app.Link,
    //defaultConnectionPoint: joint.shapes.app.Link.connectionPoint,
    interactive: { linkMove: false }
});

$('.paper-container').append(paper.el);
paper.render();
    
var member = function(x, y, rank, name, background, textColor) {

    textColor = textColor || "#000";

    var cell = new joint.shapes.org.Member({
        position: { x: x, y: y },
        attrs: {
            '.card': { fill: background, stroke: 'none'},
            '.rank': { text: rank, fill: textColor, 'word-spacing': '-5px', 'letter-spacing': 0},
            '.name': { text: name, fill: textColor, 'font-size': 13, 'font-family': 'Arial', 'letter-spacing': 0 }
        }
    });
    graph.addCell(cell);
    return cell;
};

function link(source, target, breakpoints) {

    var cell = new joint.shapes.org.Arrow({
        source: { id: source.id },
        target: { id: target.id },
        vertices: breakpoints,
        attrs: {
            '.connection': {
                'fill': 'none',
                'stroke-linejoin': 'round',
                'stroke-width': '2',
                'stroke': '#4b4a67'
            }
        }

    });
    graph.addCell(cell);
    return cell;
}

var bart = member(300, 70, 'CEO', 'Bart Simpson', '#30d0c6');
var homer = member(90, 200, 'VP Marketing', 'Homer Simpson', '#7c68fd', '#f1f1f1');
var marge = member(300, 200, 'VP Sales', 'Marge Simpson', '#7c68fd', '#f1f1f1');
var lisa = member(500, 200, 'VP Production' , 'Lisa Simpson', '#7c68fd', '#f1f1f1');
var maggie = member(400, 350, 'Manager', 'Maggie Simpson', '#feb563');
var lenny = member(190, 350, 'Manager', 'Lenny Leonard', '#feb563');
var carl = member(190, 500, 'Manager', 'Carl Carlson', '#feb563');


link(bart, marge, [{x: 385, y: 180}]);
link(bart, homer, [{x: 385, y: 180}, {x: 175, y: 180}]);
link(bart, lisa, [{x: 385, y: 180}, {x: 585, y: 180}]);
link(homer, lenny, [{x:175 , y: 380}]);
link(homer, carl, [{x:175 , y: 530}]);
link(marge, maggie, [{x:385 , y: 380}]);

var rootNode = paper.el.querySelector('.joint-type-org-member');
var card = paper.el.querySelector('.joint-type-org-member .card');
console.log("rootNode.contains = ", rootNode.contains);
console.log("rootNode.contains(card) = ", rootNode.contains(card));
<script src="https://unpkg.com/@babel/polyfill@7.4.4/dist/polyfill.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/lodash/lodash.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/backbone/backbone.js"></script>

<link href="https://resources.jointjs.com/demos/joint/build/joint.css" rel="stylesheet"/>
<script src="https://resources.jointjs.com/demos/joint/build/joint.js"></script>



<div class="paper-container"></div>


Solution

  • Looking for a proper Polyfill I found this one

    In case the link doesn't work, here is the code:

    SVGElement.prototype.contains = function contains(node) {
        if (!(0 in arguments)) {
            throw new TypeError('1 argument is required');
        }
    
        do {
            if (this === node) {
                return true;
            }
        } while (node = node && node.parentNode);
    
        return false;
    };
    

    Edit
    Here is the snippet from the question along with the polyfill suggested

    const joint = window.joint;
    
    let graph = new joint.dia.Graph;
    
    let paper = new joint.dia.Paper({
        width: 1500,   /*200,*/
        height: 1500,  /*200,*/
        el: $('.paper-container'),
        gridSize: 1,
        drawGrid: true,
        model: graph,
        //defaultLink: new joint.shapes.app.Link,
        //defaultConnectionPoint: joint.shapes.app.Link.connectionPoint,
        interactive: { linkMove: false }
    });
    
    $('.paper-container').append(paper.el);
    paper.render();
        
    var member = function(x, y, rank, name, background, textColor) {
    
        textColor = textColor || "#000";
    
        var cell = new joint.shapes.org.Member({
            position: { x: x, y: y },
            attrs: {
                '.card': { fill: background, stroke: 'none'},
                '.rank': { text: rank, fill: textColor, 'word-spacing': '-5px', 'letter-spacing': 0},
                '.name': { text: name, fill: textColor, 'font-size': 13, 'font-family': 'Arial', 'letter-spacing': 0 }
            }
        });
        graph.addCell(cell);
        return cell;
    };
    
    function link(source, target, breakpoints) {
    
        var cell = new joint.shapes.org.Arrow({
            source: { id: source.id },
            target: { id: target.id },
            vertices: breakpoints,
            attrs: {
                '.connection': {
                    'fill': 'none',
                    'stroke-linejoin': 'round',
                    'stroke-width': '2',
                    'stroke': '#4b4a67'
                }
            }
    
        });
        graph.addCell(cell);
        return cell;
    }
    
    var bart = member(300, 70, 'CEO', 'Bart Simpson', '#30d0c6');
    var homer = member(90, 200, 'VP Marketing', 'Homer Simpson', '#7c68fd', '#f1f1f1');
    var marge = member(300, 200, 'VP Sales', 'Marge Simpson', '#7c68fd', '#f1f1f1');
    var lisa = member(500, 200, 'VP Production' , 'Lisa Simpson', '#7c68fd', '#f1f1f1');
    var maggie = member(400, 350, 'Manager', 'Maggie Simpson', '#feb563');
    var lenny = member(190, 350, 'Manager', 'Lenny Leonard', '#feb563');
    var carl = member(190, 500, 'Manager', 'Carl Carlson', '#feb563');
    
    
    
    link(bart, marge, [{x: 385, y: 180}]);
    link(bart, homer, [{x: 385, y: 180}, {x: 175, y: 180}]);
    link(bart, lisa, [{x: 385, y: 180}, {x: 585, y: 180}]);
    link(homer, lenny, [{x:175 , y: 380}]);
    link(homer, carl, [{x:175 , y: 530}]);
    link(marge, maggie, [{x:385 , y: 380}]);
    
    
    if (window.SVGElement && !SVGElement.prototype.contains) {
      SVGElement.prototype.contains = function (node) {
        if (!(0 in arguments)) {
          throw new TypeError('1 argument is required');
        }
    
        do {
          if (this === node) {
            return true;
          }
        } while (node = node && node.parentNode);
    
        return false;
      };
    }
    
    var rootNode = paper.el.querySelector('.joint-type-org-member');
    var card = paper.el.querySelector('.joint-type-org-member .card');
    console.log("rootNode.contains = ", rootNode.contains);
    console.log("rootNode.contains(card) = ", rootNode.contains(card));
    <script src="https://unpkg.com/@babel/polyfill@7.4.4/dist/polyfill.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://resources.jointjs.com/demos/joint/node_modules/lodash/lodash.js"></script>
    <script src="https://resources.jointjs.com/demos/joint/node_modules/backbone/backbone.js"></script>
    
    <link href="https://resources.jointjs.com/demos/joint/build/joint.css" rel="stylesheet"/>
    <script src="https://resources.jointjs.com/demos/joint/build/joint.js"></script>
    
    
    
    <div class="paper-container"></div>