Filtros angulares e SVG

Eu vi um comportamento estranho ao usar o SVG com o AngularJS. Estou usando o serviço $routeProvider para configurar minhas rotas. Quando eu coloco este SVG simples em meus templates, está tudo bem:

 
// ...

Mas quando eu adiciono um filtro, com este código por exemplo:

 

Então:

  • Funciona na minha homepage .
  • Com o Firefox , o SVG não é mais visível nas outras páginas , mas ainda deixa espaço onde estaria. Com o Chrome , o SVG fica visível, mas não fica desfocado.
  • O SVG fica visível novamente quando eu removo manualmente (com o Firebug) o estilo do filter .

Aqui está a configuração das rotas:

 $routeProvider .when('/site/other-page/', { templateUrl : 'view/Site/OtherPage.html', controller : 'Site.OtherPage' }) .when('/', { templateUrl : 'view/Site/Home.html', controller : 'Site.Home' }) .otherwise({ redirectTo : '/' }) ; 

Violino

Por favor note que eu não consegui reproduzir o problema com o Chrome in the Fiddle, embora “funcione” com o Firefox.

Eu tentei sem sucesso para criar todo o meu SVG com document.createElementNS() .

Alguém tem uma ideia do que está acontecendo?

O problema

O problema é que existe uma tag na minha página HTML. Portanto, o IRI usado para identificar o filtro não é mais relativo à página atual, mas ao URL indicado na tag .

Esse URL também era o URL da minha página inicial, http://example.com/my-folder/ , por exemplo.

Para as páginas que não sejam a página inicial, http://example.com/my-folder/site/other-page/ , por exemplo, #blurred foi calculado para o URL absoluto http://example.com/my-folder/#blurred Mas, para uma solicitação GET simples, sem JavaScript e, portanto, sem AngularJS, essa é simplesmente minha página base, sem nenhum modelo carregado. Assim, o filtro #blurred não existe nessas páginas.

Nesses casos, o Firefox não renderiza o (que é o comportamento normal , consulte a recomendação do W3C ). O Chrome simplesmente não aplica o filtro.

Para a página inicial, #blurred também é calculado para o URL absoluto http://example.com/my-folder/#blurred . Mas desta vez, este também é o URL atual. Não há necessidade de enviar uma solicitação GET e, portanto, o filtro #blurred existe .

Eu deveria ter visto a solicitação adicional para http://example.com/my-folder/ , mas, em minha defesa, ela foi perdida em uma infinidade de outras solicitações para arquivos JavaScript.

A solução

Se a tag for obrigatória, a solução é usar um IRI absoluto para identificar o filtro. Com a ajuda do AngularJS, isso é bem simples. No controlador ou na diretiva que está vinculada ao SVG, injete o serviço de $location e use o getter absUrl() :

 $scope.absUrl = $location.absUrl(); 

Agora, no SVG, basta usar essa propriedade:

         

Relacionado: O Gradiente SVG fica preto quando há uma tag BASE na página HTML?

Parece um comportamento que eu observei antes. A causa raiz é que você acaba tendo vários elementos (filtros) com o mesmo id (desfocado). Navegadores diferentes lidam com isso de forma diferente …

Aqui está o que eu fiz para reproduzir o seu caso: http://jsfiddle.net/z5cwZ/ Ele tem dois svg e um é oculto, o firefox não mostra nenhum.

Existem duas possibilidades para evitar ids conflitantes. Primeiro você pode gerar ids únicos a partir do seu template (eu não posso ajudar fazendo isso com o angularjs tough). Aqui está um exemplo: http://jsfiddle.net/KbCLB/1/

Segunda possibilidade, e pode ser mais fácil com o angularjs, é colocar o filtro fora do svgs individual ( http://jsfiddle.net/zAbgr/1/ ):

           

Apenas corri para esse problema. Expandindo da resposta do @Blackhole, minha solução foi adicionar uma diretiva que altera o valor de cada atributo de preenchimento.

 angular.module('myApp').directive('fill', function( $location ) { 'use strict'; var absUrl = 'url(' + $location.absUrl() + '#'; return { restrict: 'A', link: function($scope, $element, $attrs) { $attrs.$set('fill', $attrs.fill.replace(/url\(#/g, absUrl)); } }; }); 

Eu recentemente me deparo com esse problema, se o svg é usado em rotas diferentes, você terá que adicionar o $ location a cada caminho. Uma maneira melhor de implementar isso é apenas usar um window.location.href em vez do serviço $ location.

Também tive problemas com o svg link: hrefs, e sim o problema é por causa do – eu tinha erros sendo lançados ao concatenar o url absoluto por causa das restrições do Strict Contextual Escaping .

Minha solução foi escrever um filtro que adicionasse o URL absoluto e também confiasse na concatenação.

 angular.module('myApp').filter('absUrl', ['$location', '$sce', function ($location, $sce) { return function (id) { return $sce.trustAsResourceUrl($location.absUrl() + id); }; }]); 

E então use assim: {{'#SVGID_67_' | absUrl} {{'#SVGID_67_' | absUrl}

Resultado: http://www.example.com/deep/url/to/page#SVGID_67_ e nenhum erro de $ sce