Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome doesn't cache images inside SVG

I just discovered that Chrome doesn't cache images which are placed inside SVGs if their cache-control header is set to no-cache. Firefox & IE10 seem to ignore this setting.

I've created a little test page with a static SVG:

HTML:

<div style="width: 500px; text-align: center;">
    <input id="move-left-btn" type="button" value="&lt;&lt;">
    <input id="move-right-btn" type="button" value="&gt;&gt;">
</div>

<div class="svgwrapper" style="width: 500px; height: 250px; background-color: lightgrey;">
    <svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" width="500" height="250">
        <g id="svggroup" class="transition-on" transform="matrix(0.2,0,0,0.2,80,35)">
            <image width="1672" height="887" opacity="1" xlink:href="https://dl.dropboxusercontent.com/sh/q7htlj5h8qqfhjf/SVDuynM7R3/car.png"></image>
        </g>
    </svg>
</div>

Javascript:

$(document).ready(function() {
    var curXPos = 80;

    // Local test function which represent some server calls in my "real life" scenario
    // Just updates the x-position in the transform matrix in this test case
    function updateSvgText(svgText, posXDelta) {
        curXPos += posXDelta;
        if (curXPos < 0) {
            curXPos = 160;
        } else if (curXPos > 160) {
            curXPos = 0;
        }

        return svgText.replace(/matrix\(.*\)/, 'matrix(0.2,0,0,0.2,' + curXPos + ',35)');
    }

    // Fetch the new SVG (in real life from server) and rerender it
    function moveSvg(posXDelta) {
        var svg = $('#svg'),
            svgText = updateSvgText($('.svgwrapper').html(), posXDelta);

        svg.empty();
        svg.append($(svgText).children());
    }

    $('#move-left-btn').click($.proxy(moveSvg, this, -20));
    $('#move-right-btn').click($.proxy(moveSvg, this, 20));
});
  • Working example with cache-control header of source image set to no-cache (flickers in chrome after every press on the "move" buttons):
    http://jsfiddle.net/zF6NF/4/

  • Same example with different source image with cache-control header set to max-age=315360000,public (no flickering):
    http://jsfiddle.net/zF6NF/5/

In Chrome you can see the reloading of the images on each button click in the first example ("flickering" of the image & visible in the network tab of the dev tools) whereas Firefox rerenders the SVG in both examples smoothly without any reloading.

Some additional information:

  1. This is just an example. In my "real-life-scenario" I receive a new SVG from the server (instead of the updateSvgText method call) which means that I can't just perform partial updates of the SVG by changing the value of the transform matrix attribute but have to rerender the whole SVG every time (at least by now...).

  2. I can't control where the images come from which means 2 things:

    • I can't change the cache-control header
    • I can't create Base64 encoded data-uris, save them locally and just replace the images inside the SVG with those data-uris before rendering (can't create Base64 encoded data-uri because of "Same resource origin" policies...)

Is there any way to either...

  • Overwrite/overrule the cache-control header locally even if the image is from an uncontrolled remote location?
  • Create the Base64 encoded data-uri from an Image that is loaded from a different domain I don't have any control over client sided?
  • Somehow tell Chrome to always cache images inside my SVGs?

Needless to say that other solutions are also very welcome!

Thanks

like image 984
suamikim Avatar asked Oct 17 '13 08:10

suamikim


1 Answers

Unfortunately, when it comes to caching, it's 99% the server's job.

In-dept guide : here

Browsers will always look for more recent versions of the file based on certain conditions:

  • The cached entry has no expiration date and the content is being accessed for the first time in a browser session
  • The cached entry has an expiration date but it has expired
  • Cache-Control/Pragma tells the browser not to cache
  • Etag in header is a pain.

In terms of solutions you have:

  • Be very insistent to your server guys that you need caching (remove etag, Cache-Control: public,max-age=31536000, Pragma: public)
  • Create a proxy on your domain that requires the image from the site, (optionally convert to base64) then send to your client (with the proper headers). Here's an example for PHP : here
like image 176
NodeNodeNode Avatar answered Sep 18 '22 12:09

NodeNodeNode