cytoscape / cytoscape.js

Graph theory (network) library for visualisation and analysis
https://js.cytoscape.org
MIT License
10.11k stars 1.64k forks source link

SVG not rendering under IE (tested under IE 11) #782

Closed ktei closed 9 years ago

ktei commented 9 years ago

Hi, Max: Could this potentially be a bug? So here's my html. Note that

              .selector('#bird')
                  .css({
                    'background-image': 'circle.svg'
                  })

You can see the bird image references to 'circle.svg', a very simple svg:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 312 312" enable-background="new 0 0 312 312" xml:space="preserve">
 <circle cx="100" cy="100" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
<!DOCTYPE html>
<html>
<head>
    <meta charset=utf-8 />
    <title>Cytoscape.js initialisation</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
    <script src="http://cytoscape.github.io/cytoscape.js/api/cytoscape.js-latest/cytoscape.min.js"></script>
    <script>
        $(function(){ // on dom ready

            var cy = cytoscape({
              container: document.getElementById('cy'),

              style: cytoscape.stylesheet()
                .selector('node')
                  .css({
                    'height': 80,
                    'width': 80,
                    'background-fit': 'cover',
                    'border-color': '#000',
                    'border-width': 3,
                    'border-opacity': 0.5
                  })
                .selector('.eating')
                  .css({
                    'border-color': 'red'
                  })
                .selector('.eater')
                  .css({
                    'border-width': 9
                  })
                .selector('edge')
                  .css({
                    'width': 6,
                    'target-arrow-shape': 'triangle',
                    'line-color': '#ffaaaa',
                    'target-arrow-color': '#ffaaaa'
                  })
                .selector('#bird')
                  .css({
                    'background-image': 'circle.svg'
                  })
                .selector('#cat')
                  .css({
                    'background-image': 'https://farm2.staticflickr.com/1261/1413379559_412a540d29_b.jpg'
                  })
                .selector('#ladybug')
                  .css({
                    'background-image': 'https://farm4.staticflickr.com/3063/2751740612_af11fb090b_b.jpg'
                  })
              .selector('#aphid')
                  .css({
                    'background-image': 'https://farm9.staticflickr.com/8316/8003798443_32d01257c8_b.jpg'
                  })
              .selector('#rose')
                  .css({
                    'background-image': 'https://farm6.staticflickr.com/5109/5817854163_eaccd688f5_b.jpg'
                  })
              .selector('#grasshopper')
                  .css({
                    'background-image': 'https://farm7.staticflickr.com/6098/6224655456_f4c3c98589_b.jpg'
                  })
              .selector('#plant')
                  .css({
                    'background-image': 'https://farm1.staticflickr.com/231/524893064_f49a4d1d10_z.jpg'
                  })
              .selector('#wheat')
                  .css({
                    'background-image': 'https://farm3.staticflickr.com/2660/3715569167_7e978e8319_b.jpg'
                  }),

              elements: {
                nodes: [
                  { data: { id: 'cat' } },
                  { data: { id: 'bird' } },
                  { data: { id: 'ladybug' } },
                  { data: { id: 'aphid' } },
                  { data: { id: 'rose' } },
                  { data: { id: 'grasshopper' } },
                  { data: { id: 'plant' } },
                  { data: { id: 'wheat' } }
                ],
                edges: [
                  { data: { source: 'cat', target: 'bird' } },
                  { data: { source: 'bird', target: 'ladybug' } },
                  { data: { source: 'bird', target: 'grasshopper' } },
                  { data: { source: 'grasshopper', target: 'plant' } },
                  { data: { source: 'grasshopper', target: 'wheat' } },
                  { data: { source: 'ladybug', target: 'aphid' } },
                  { data: { source: 'aphid', target: 'rose' } }
                ]
              },

              layout: {
                name: 'breadthfirst',
                directed: true,
                padding: 10
              }
            }); // cy init
        }); // on dom ready
    </script>
</head>
    <body>
        <div id="cy" style="width:800px;height:600px"></div>
    </body>
</html>

Under Chrome, it renders like this: capture1

Under IE, it renders like this: capture2

You can see that under IE, the SVG is not rendered at all.

maxkfranz commented 9 years ago

I strongly suspect this is an issue with IE itself. I'll take a look, but it may just be that IE is unable to render certain types of SVG images.

ktei commented 9 years ago

@maxkfranz The issue I found is that: if I simply use SVG in html, for example <img src="circle.svg" /> This will work under IE; the image shows up. However, this doesn't show up for nodes in cytoscape. Maybe this is an issue of IE itself (I'm actually surprised even IE11 doesn't work), and if that is the case then I guess I'll need to detect browser and use different formats of images.

maxkfranz commented 9 years ago

SVG rendering is different under the DOM compared to a canvas. I'll test this out relatively soon, but I often do not have high hopes for anything IE-related.

ktei commented 9 years ago

@maxkfranz I think you're right. I actually just checked Firefox, which doesn't work as well (SVG node not rendered properly). Now it appears to me that perhaps only Chrome works in this case. I realize that I'll just use SVG for chrome, but PNG for other browsers then.

If you happen to find something, please let me know, otherwise I think we can close this issue?

maxkfranz commented 9 years ago

It may be possible to work around the issues, but some of the issues are actually tradeoffs that the browser designers have made -- like for performance. It's probably best to just use PNG for now if you have crossbrowser consistency as a higher priority.

rockshandy commented 9 years ago

I was doing some digging into this recently, it seems IE (at least 10 and 11) does not get a width/height for a SVG created with new Image() without appending that image to the DOM. I believe the canvas renderer depends on this working, and it does in other browsers. Using some suggested code from a related question on stack overflow, it seems you could get the width without having to display the SVG image at least.

Without modifying cytoscape itself, I found a redraw could work with manual imageCache manipulation, but that is not ideal. Each image element is cached by it's 'src' attribute. Getting the image cache after loading nodes for example:

cy.renderer('canvas').imageCache["circle.svg"].image.width = 20;
cy.renderer('canvas').imageCache["circle.svg"].image.height = 20;

I'm not sure what the best overall solution for IE may be in this case though. I've seen some people suggests certain SVGs work, but in my case I have a width,height, and viewBox set for all my intended background icons.

melborp commented 9 years ago

Hi, I really like the library.I also hit this issue in IE.

The fix committed will still not work because IE reports img.width and img.height as 0, not as undefined. Even with appendChild and removeChild, the size will remain 0 (as far as i played with IE11, works nicely on Chrome, FF and MS EDGE, ... ). The workaround i have right now is to tweek the function that was changed to make sure that when imgW and imgH are 0, then either take the nodeW / nodeH or take the background-width, background-height as an override value. Works in IE then and everything renders.

something like this in drawInscribedImage:

var w = imgW;
var h = imgH;

//COMMENTED OUT, too early to check //if( w === 0 || h === 0 ){ // return; // no point in drawing empty image (and chrome is broken in this case) //}

var bgW = style['background-width'];
if( bgW.value !== 'auto' ){
  if( bgW.units === '%' ){
    w = bgW.value/100 * nodeW;
  } else {
    w = bgW.pxValue;
  }
}

var bgH = style['background-height'];
if( bgH.value !== 'auto' ){
  if( bgH.units === '%' ){
    h = bgH.value/100 * nodeH;
  } else {
    h = bgH.pxValue;
  }
}

if( w === 0 || h === 0 ){
  return; // no point in drawing empty image (and chrome is broken in this case)
}

if (img.width === 0 || img.height === 0) {
    imgW = w;
    imgH = h;
}

Also, i think there is a bug in the workaround itself that was attempted: if ((img.width === undefined || img.height === undefined)) { document.body.appendChild( img );

    imgW = img.cachedW = img.width;  
  //IN SOURCE THIS IS: 
  //imgW = img.cachedH = img.height;  
   //SHOULD BE
    imgH = img.cachedH = img.height;  

    document.body.removeChild( img );  
}  
melborp commented 9 years ago

I've done the change here https://github.com/melborp/cytoscape.js/commit/cb2e0f910112d1b4e5602afffc56c76ed59bc9b3

maxkfranz commented 9 years ago

Thanks!

The change I pushed allows for specifying the dimensions manually. It also gets the correct image dimensions automatically from IE. However, IE just doesn't seem to be able to render (maybe just particular?) SVGs in canvas.

I tested in a Windows 10 VM with IE11 latest and Edge latest. Edge seems OK. IE doesn't render the SVG. I tried with gnu.svg in the debug page.