Search code examples
javascriptcsssvgraphael

Controlling the fill of a rect through CSS in Raphael


I am using Raphael and I want to create a rect and control the fill property through a CSS.

Everything works fine when I set the fill attr in the classical way:

    space = paper.rect(0,0,1000,500).attr({fill: "url('img/cell_background.png')"});

In fact, with this approach I get the correct filling. If inspect the elements I can see that in the rect element the fill attribute is specified and it refers to a pattern defined in the svg's defs.

<svg>
   ...
   <defs style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); ">
        <pattern style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); " 
         id="E6992022-9B75-4D1E-9D44-6EC45CE420A1" x="0" y="0" 
         patternUnits="userSpaceOnUse" height="5" width="9" 
         patternTransform="matrix(1,0,0,1,0,0) translate(0,0)">
           <image style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); " 
                      x="0" y="0" 
                  href="img/cell_background.png" width="9" height="5">
               </image>
        
            </pattern>
      </defs>
      <rect style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); " 
        x="0" y="0" width="1000" height="500" r="0" rx="0" ry="0" 
    fill="url(#E6992022-9B75-4D1E-9D44-6EC45CE420A1)" stroke="#000" 
    class="space">
      </rect>
    ...
</svg>

If I instead create the rect with the following code:

space = paper.rect(0,0,1000,500);
space.node.setAttribute("class","space");

And then in the .css I define:

.space {
fill: url('img/cell_background.png');
stroke: #ff0000;
}

Then the inspected html shows a fill='none' as rect attribute, the rectangle is correctly rendered with a red border, but it is filled with a solid black.

Some further observations:

  1. js are in the js/ folder, css in css/ folder, and images in img/ folder. I tried with '../img', './img' and 'img' but I have the same behaviour;
  2. if I don't put fill I obtain a white filling as expected;
  3. if I put fill: foobar I obtain a white background;
  4. if I put fill: #ff0000 I get the expected red background;
  5. I obtain the same black background if I use a fake filename;
  6. the behaviour is consistent with Chrome and with Firefox.

From the fourth and fifth point it looks like the file cannot be found, but I think to have exhausted the combination of paths that I should have checked (the css finds other images in the same folder using the '../img' path). I reckon that the problem is somewhere else.

Does anybody had a similar experience?


Solution

  • In SVG you can't just specify a bitmap background url for an element as you do with HTML elements. The standard way of doing this in SVG is through pattern definitions. Raphael abstracts this messiness from you with a simple fill: url(...).

    You could load the pattern with your CSS stylesheet with something like...

    .space {
      fill: url('img/cell_background.svg#bitmap');
      stroke: #ff0000;
    }
    

    But of course, cell_background.svg#bitmap still needs to look like...

    <svg xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink">
       <defs>
            <pattern id="bitmap" x="0" y="0" patternUnits="userSpaceOnUse" height="5" width="9">
               <image x="0" y="0" xlink:href="img/cell_background.png" width="9" height="5">
               </image>
             </pattern>
        </defs>
    </svg>
    

    But of course this only makes matters more complex.

    The reason why your rect is showing up black is because the engine is trying to load a missing fill definition (gradient or pattern), which defaults to black.