javascriptcytoscape.jsrdkit

Problem with automatically-generated SVG display using Cytoscape.js


I'm trying to use Cytoscape.js to create a diagram of chemical reactions generated from student input, but I can't seem to get the images of the molecules to display on each of the nodes.

The images I need are automatically generated with RDKit.js.

These images can be displayed outside of cytoscape just fine (when embedded in a plain HTML document, for example), but I can't get the images to display properly on the cytoscape diagram nodes. Specifically, when I try to use the RDKit svg as the node's background-image, it won't display it.

Here's a live example of what I've tried so far, modified from some other guides about using svg images with cytoscape. Here's what it looks like:

Example diagram image

And here's the code for the node data:

[
  {
    "data": {
      "id": "id0"
    },
    "position": {
      "x": 44,
      "y": 93
    },
    "style": {
      "background-image": "data:image/svg+xml;utf-8,%3Csvg%20width=%2224%22%20height=%2224%22%20viewBox=%220%200%2024%2024%22%20version=%221.1%22%20xmlns=%22http://www.w3.org/2000/svg%22%3E%3Cpath%20d=%22M12,11.5A2.5,2.5%200%200,1%209.5,9A2.5,2.5%200%200,1%2012,6.5A2.5,2.5%200%200,1%2014.5,9A2.5,2.5%200%200,1%2012,11.5M12,2A7,7%200%200,0%205,9C5,14.25%2012,22%2012,22C12,22%2019,14.25%2019,9A7,7%200%200,0%2012,2Z%22%20fill=%22yellow%22%3E%3C/path%3E%3C/svg%3E",
      "background-fit": "cover cover",
      "background-image-opacity": 1
    }
  },
  {
    "data": {
      "id": "id1"
    },
    "position": {
      "x": 77,
      "y": 93
    },
    "style": {
      "background-image": "benzene.svg",
      "background-fit": "cover cover",
      "background-image-opacity": 1
    }
  },
  {
    "data": {
      "id": "id2"
    },
    "position": {
      "x": 77,
      "y": 150
    },
    "style": {
      "background-image": "data:image/svg+xml;utf-8,data:image/svg+xml;utf-8,%3C%3Fxml version='1.0' encoding='iso-8859-1'%3F%3E%3Csvg version='1.1' baseProfile='full' xmlns='http://www.w3.org/2000/svg' xmlns:rdkit='http://www.rdkit.org/xml' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' width='250px' height='200px' viewBox='0 0 250 200'%3E%3C!-- END OF HEADER --%3E%3Crect style='opacity:1.0;fill:%23FFFFFF;stroke:none' width='250.0' height='200.0' x='0.0' y='0.0'%3E%3C/rect%3E%3Cpath class='bond-0 atom-0 atom-1' d='M 230.0,100.0 L 177.5,190.9' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath class='bond-0 atom-0 atom-1' d='M 211.8,100.0 L 168.4,175.2' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath class='bond-1 atom-1 atom-2' d='M 177.5,190.9 L 72.5,190.9' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath class='bond-2 atom-2 atom-3' d='M 72.5,190.9 L 20.0,100.0' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath class='bond-2 atom-2 atom-3' d='M 81.6,175.2 L 38.2,100.0' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath class='bond-3 atom-3 atom-4' d='M 20.0,100.0 L 72.5,9.1' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath class='bond-4 atom-4 atom-5' d='M 72.5,9.1 L 177.5,9.1' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath class='bond-4 atom-4 atom-5' d='M 81.6,24.8 L 168.4,24.8' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath class='bond-5 atom-5 atom-0' d='M 177.5,9.1 L 230.0,100.0' style='fill:none;fill-rule:evenodd;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1' /%3E%3Cpath d='M 227.3,104.5 L 230.0,100.0 L 227.3,95.5' style='fill:none;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;' /%3E%3Cpath d='M 180.1,186.4 L 177.5,190.9 L 172.2,190.9' style='fill:none;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;' /%3E%3Cpath d='M 77.8,190.9 L 72.5,190.9 L 69.9,186.4' style='fill:none;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;' /%3E%3Cpath d='M 22.7,104.5 L 20.0,100.0 L 22.7,95.5' style='fill:none;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;' /%3E%3Cpath d='M 69.9,13.6 L 72.5,9.1 L 77.8,9.1' style='fill:none;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;' /%3E%3Cpath d='M 172.2,9.1 L 177.5,9.1 L 180.1,13.6' style='fill:none;stroke:%23000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;' /%3E%3C/svg%3E",
      "background-fit": "cover cover",
      "background-image-opacity": 1
    }
  }
]

There are three nodes in this diagram; the first node ("id0", top left) uses an example SVG from another tutorial, and it displays as expected.

The second node ("id1", top right) displays a chemical structure generated by RDKit. This structure's image was saved as a separate svg file. This works as expected, but I can't use this method for my desired application.

Finally, for the third node ("id2", bottom right), I've tried encoding and embedding the svg and using it directly, as in the first example. The second and third node should be identical! Instead there is no image on the third node at all.

I've tried trimming out the excess header information from the svg (leaving just the width, height, version, and xmlns). I've tried changing the width and height in the header to match the example svg. I've even tried running the svg through various optimizers, all to no avail. How can I fix this?


Solution

  • Just in case this comes up in the future for anyone else: I solved the problem by encoding the svg to base64 and using that. So, if you have something like this:

    var svg = "<svg>[svg content here]</svg>";
    

    Encode it like this:

    var svgBase64 = btoa(svg);
    

    And then use that as the Cytoscape background-image instead.