Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding SVG query-string parameters

I created an SVG file that I intend to use as a background image in CSS. I want to be able to change the fill color in the SVG using a query-string parameter, like so:

#rect     { background-image: url( 'rect.svg' ); }
#rect.red { background-image: url( 'rect.svg?color=red' ); }

As I understand, using a script tag in the SVG, I am able to get the color parameter and update the fill color. Here is an example SVG:

<!DOCTYPE svg PUBLIC "-//W3C//DDTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
    <rect width="100%" height="100%" />

    <script>
    <![CDATA[
        var params = { };
        location.href.split( '?' )[1].split( '&' ).forEach(
            function( i )
            {
                params[ i.split( '=' )[0] ] = i.split( '=' )[1];
            }
        );

        if( params.color )
        {
            var rect = document.getElementsByTagName( "rect" )[0];
            rect.setAttribute( "fill", params.color );
        }
    ]]>
    </script>
</svg>

Going to the file directly, or using an object tag seems to work, but for CSS background images or img tags, the color parameter is ignored.

I'm not exactly sure what is going on here, and I was hoping that there would be an explanation or alternative solution to what I'm trying to accomplish (preferably without resorting to server-side processing).

Here is a jsFiddle showing the different render methods: http://jsfiddle.net/ehb7S/

like image 743
Jeff Jenkins Avatar asked Apr 12 '13 17:04

Jeff Jenkins


2 Answers

You can use an inline SVG that is hidden, change that and dynamically encode it as a data URL that you put into the background-image property. Your HTML could look like:

<div id="backgroundContainer" style="display:none">
    <svg width="100px" height="100px" id="backgroundSvg" xmlns="http://www.w3.org/2000/svg">
        <circle cx="50" cy="50" r="50" fill="green"/>
    </svg>
</div>

<div id="divWithBackground" onclick="changeBackground(event)">
    Click to change background SVG to random color
</div>

and your JavaScript like

changeBackground = function(event) {
  var backgroundSvg = document.getElementById("backgroundSvg");
  var backgroundContainer = document.getElementById("backgroundContainer");
  backgroundSvg.getElementsByTagName("circle")[0].setAttribute(
    "fill",
    ["red","green","blue","black"][Math.floor(4*Math.random())]
  );
  event.target.setAttribute(
    "style",
    "background-image:url(data:image/svg+xml,"
    + encodeURI(backgroundContainer.innerHTML)
    + ")"
  );
}

See the proof of concept on jsFiddle.

like image 51
Thomas W Avatar answered Sep 23 '22 12:09

Thomas W


I ended up created a server-side solution that allows me to inject the color fill into the SVG file. Essentially, I redirect all SVG requests to a PHP file that does the following on them:

$filename = $_SERVER['SCRIPT_FILENAME'];

$svg = simplexml_load_file( $filename );
if( isset( $_GET['color'] ) )
{
    $svg->path->addAttribute( 'fill', '#' . $_GET['color'] );
}

header( "Content-type: image/svg+xml" );
echo $svg->asXML( );

Obviously, there's a little more to it than that, what with handling caching and such, but that's the meat-n-potatoes. Might want to check if the fill attribute already exists, as well.

like image 25
Jeff Jenkins Avatar answered Sep 23 '22 12:09

Jeff Jenkins