vis.js library – Rendering a network of nodes with svg and custom html

I’m working with the vis.js library, and rendering nodes with custom HTML via the svg tag.

My online project is at: https://stackblitz.com/edit/visjs-with-angular

The problem I’m having is when I attempt to add an image to the div, which is inside an svg.

You can see the vis.component.ts in the ‘appappvis’ folder of my project, and its associated HTML view file.

In the drawSvgNetwork() function you will see where I build out the SVG. I figured I’d be able to add a <i> tag with a background-image url, but it doesn’t seem to be rendering when vis.js renders the nodes:

var svg = '<svg xmlns="http://www.w3.org/2000/svg" width="390" height="65">' +
          '<rect x="0" y="0" width="100%" height="100%" fill="#7890A7" stroke-width="20" stroke="#ffffff" ></rect>' +
          '<foreignObject x="15" y="10" width="100%" height="100%">' +
          '<div xmlns="http://www.w3.org/1999/xhtml" style="font-family:Arial; font-size:30px">' +
          ' <em>I</em> am' +
          '<span style="color:white; text-shadow:0 0 20px #000000;">' +            
            ' HTML in SVG!</span>' +

          // * THIS IMAGE IS NOT RENDERING * 
          '<i style="background-image: url(https://openclipart.org/download/280615/July-4th-v2B.svg);"></i>' +

          '</div>' +
          '</foreignObject>' +
          '</svg>';

i.e. Here is what you will see when running my online project.

visjs network of nodes.

*For reference:

The full online examples are at: https://visjs.github.io/vis-network/examples/ And the specific demo page is here (view source to see js code): https://visjs.github.io/vis-network/examples/network/nodeStyles/HTMLInNodes.html

Answer

Looks like with visjs it’s not possible to load an external image inside an SVG, nor in <foreignObject>, neither in <Image> tag. Here is an open issue for the problem on github: Image tag is not loading inside the svg

The maintainer of the repository answered that it was not possible.

A workaround can be found in the same thread (but it may not be suitable for you): the idea is to load the image separately and render it as dataUrl

Loading the svg image and converting it to dataUrl:

  loadImage(url) {
    const img = new Image();

    img.crossOrigin = "anonymous";
    img.src = url;

    return Observable.fromEvent(img, 'load')
        .map((e: Event) => {
            const canvas = document.createElement('canvas');
            canvas.getContext('2d').drawImage(e.target as HTMLImageElement, 0, 0);
            const dataURL = canvas.toDataURL();
            return dataURL;
        })
  }

Using the acquired dataUrl as background instead of the direct svg file url:

  '<i style="background-image: url(' + dataUrl + '); display: inline-block; width: 40px; height: 20px; background-size: contain;"></i>' +

Here is the corrected project https://stackblitz.com/edit/visjs-with-angular-m63jme (I also replaced the svg file, which was used in the original project and contained a US flag, with another arbitrary svg to avoid issues in FF, see below)

FF issues with rendering svg on canvas

Firefox has some issues with rendering an svg file on canvas, when the file contains width and height attributes specified as percentages. See the SO questions for more details: 1, 2. So be sure to use an svg with width and height attributes that are not percentages.