Preferred way to display SVG icons?

I’m adding a feature to our app where I use phantomjs to capture a screenshot of our GoJS canvas so users can display a static image on a page. Our nodes use a TextBlock and font icon for the different node types using this code which works just fine:

                make('TextBlock',
                {
                    name: 'icon',
                    alignment: go.Spot.Center,
                    font: me.iconSize + 'px workpoint',
                    width: me.iconSize + 2,
                    height: me.iconSize + 2,
                    stroke: '#fff'
                },
                new go.Binding('text', 'iconText'),
                new go.Binding('visible', 'iconVisible')
            ),

Now the users have the option to override our icons by attaching an SVG to the node. When this is done we use a Picture and set the source to the base64 encoded SVG and again GoJS displays it just fine.

                make('Picture',
                {
                    name: 'templateIcon',
                    background: null,
                    alignment: go.Spot.Center,
                    width: me.iconSize,
                    height: me.iconSize,
                    visible: false
                },
                new go.Binding('source', 'templateSource'),
                new go.Binding('visible', 'templateVisible')
            )

The image below shows both of the above methods working just fine in our app.

On to doing the screen capture using phantomjs. We use diagram.makeImageData() to render a PNG or JPEG of the diagram. phantomjs runs our app and captures the output of diagram.makeImageData(). It works just fine for the font icons but doesn’t display the SVG icon.

Doing some searches there are some people having problems with phantomjs not rendering SVG’s and adding a polyfill fixed the problem for some. I applied this polyfill and it didn’t work - maybe because the SVG is in canvas?

After some more playing around I ran phantomjs against the SVG Icons example and it worked!

I was encouraged and starting playing around with Shape and realized it uses Geometry and not a pure SVG. I tried feeding it my base64 SVG but couldn’t get it to work.

So my questions are:

  1. Can Shape use an SVG (base64 or not)? These icons are used in other parts of our app so we can’t convert store geometry string in our database that Shape appears to want. Does GoJS have a util to convert SVG to Geometry? I tried go.Geometry.parse() on my base64 SVG and also on window.atob(image) but it didn’t like either one. Since phantomjs renders Shape correctly according to my test I hope there is a way to do it this way.

  2. If the above isn’t possibly, are there any other options other than Picture to use SVG icons?

Shape cannot use Base64 SVG. Shapes can display SVG-like path strings only because you can convert an SVG-like path string into a Geometry, and shapes display a Geometry.

Pictures can display SVG as images, but I’m not clear on what the caveats are when using PhantomJS. Be sure to see the very end of this page, which contains some important pointers on using SVG as an image source.

My SVG images have the size in them and my Picture currently uses height & width and I added preferredSize but still no luck with PhantomJS.

Back to Shape - can it use SVG images that aren’t base64 encoded? When you say you can convert an SVG-like path into a Geometry, does that mean an SVG file, and if so, does GoJS have a utility (or example) of how do do this?

I found the example below and used it to create a utility to convert an SVG to a Shape and it’s working. Now both my app and PhantomJS screen capture are happy. My question is - do you think for larger diagrams that it might slow down the performance converting every SVG to a Shape? Maybe the JavaScript processing is always minimal compared to the time it takes to draw on the canvas?

As long as you only parse the SVG and build the GraphObjects once for each SVG file, I think you’ll be fine.