I came accross a strange behaviour when using SVG with AngularJS. I'm using the $routeProvider
service to configure my routes. When I put this simple SVG in my templates, everything is fine:
<div id="my-template">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect fill="red" height="200" width="300" />
</svg>
// ...
</div>
But when I add a filter, with this code for instance:
<div id="my-template">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="blurred">
<feGaussianBlur stdDeviation="5"/>
</filter>
</defs>
<rect style="filter:url(#blurred)" fill="red" height="200" width="300" />
</svg>
</div>
Then:
filter
style.Here is the routes configuration:
$routeProvider
.when('/site/other-page/', {
templateUrl : 'view/Site/OtherPage.html',
controller : 'Site.OtherPage'
})
.when('/', {
templateUrl : 'view/Site/Home.html',
controller : 'Site.Home'
})
.otherwise({
redirectTo : '/'
})
;
Fiddle
Please notice that I've failed to reproduce the problem with Chrome in a Fiddle, although it "works" with Firefox.
I've tried to no avail to create my whole SVG with document.createElementNS()
.
Does someone has an idea of what is happening?
The problem is that there is a <base>
tag in my HTML page. Therefore, the IRI used to identify the filter is not anymore relative to the current page, but to the URL indicated in the <base>
tag.
This URL was also the URL of my home page, http://example.com/my-folder/
for instance.
For the pages other than the home page, http://example.com/my-folder/site/other-page/
for example, #blurred
was computed to the absolute URL http://example.com/my-folder/#blurred
. But for a simple GET request, without JavaScript, and therefore without AngularJS, this is simply my base page, with no template loaded. Thus, the #blurred
filter doesn't exist on this pages.
In such cases, Firefox doesn't render the <rect>
(which is the normal behaviour, see the W3C recommandation). Chrome simply doesn't apply the filter.
For the home page, #blurred
is also computed to the absolute URL http://example.com/my-folder/#blurred
. But this time, this is also the current URL. There is no need to send a GET request, and thus the #blurred
filter exists.
I should have seen the additional request to http://example.com/my-folder/
, but in my defense, it was lost in a plethora of other requests to JavaScript files.
If the <base>
tag is mandatory, the solution is to use an absolute IRI to identify the filter. With the help of AngularJS, this is pretty simple. In the controller or in the directive that is linked to the SVG, inject the $location
service and use the absUrl()
getter:
$scope.absUrl = $location.absUrl();
Now, in the SVG, just use this property:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<filter id="blurred">
<feGaussianBlur stdDeviation="5"/>
</filter>
</defs>
<rect style="filter:url({{absUrl}}#blurred)" fill="red" height="200" width="300" />
</svg>
Related: SVG Gradient turns black when there is a BASE tag in HTML page?
It looks like a behaviour I observed before. The root cause is that you end up having multiple elements (filters) with the same id (blurred). Different browsers handle it differently...
Here is what I did to reproduce your case: http://jsfiddle.net/z5cwZ/ It has two svg and one is hidden, firefox shows none.
There are two possibilities to avoid conflicting ids. First you can generate unique ids from your template (I can't help in doing it with angularjs tough). Here is an example: http://jsfiddle.net/KbCLB/1/
Second possibility, and it may be easier with angularjs, is to put the filter outside of the individual svgs (http://jsfiddle.net/zAbgr/1/):
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0">
<defs>
<filter id="blurred">
<feGaussianBlur stdDeviation="10" />
</filter>
</defs>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="display:none">
<rect style="filter:url(#blurred)" fill="red" height="200" width="300" />
</svg>
<br/>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect style="filter:url(#blurred)" fill="red" height="200" width="300" />
</svg>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With