34

AngularJS で SVG を使用すると、奇妙な動作に遭遇しました。この$routeProviderサービスを使用してルートを構成しています。この単純な SVG をテンプレートに入れると、すべて問題ありません。

<div id="my-template">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
        <rect fill="red" height="200" width="300" />
    </svg>
    // ...
</div>

しかし、たとえば次のコードを使用してフィルターを追加すると、次のようになります。

<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>

それで:

  • それは私のホームページで動作します。
  • Firefoxでは、SVG は他のページでは表示されなくなりましたが、本来あったはずのスペースが残っています。Chromeでは、SVG は表示されますが、まったくぼやけていません。
  • スタイルを手動で (Firebug を使用して) 削除すると、SVG が再び表示されfilterます。

ルート構成は次のとおりです。

$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

Firefox では「動作」しますが、Fiddle で Chrome で問題を再現できなかったことに注意してください。

で SVG 全体を作成しようとしましたが、無駄でしたdocument.createElementNS()

誰かが何が起こっているのか考えていますか?

4

5 に答える 5

72

問題

問題は<base>、HTML ページにタグがあることです。したがって、フィルタを識別するために使用されるIRIは、現在のページに対してではなく、<base>タグで示される URL に対して相対的になります。

http://example.com/my-folder/この URL は、たとえば私のホームページの URL でもありました。

http://example.com/my-folder/site/other-page/たとえば、ホームページ以外のページの場合は#blurred、絶対 URL に計算されますhttp://example.com/my-folder/#blurred。しかし、JavaScript を使用せず、したがって AngularJS を使用しない単純な GET 要求の場合、これは単に私のベース ページであり、テンプレートは読み込まれません。したがって、#blurredフィルタはこのページには存在しません。

そのような場合、Firefoxは をレンダリングしません<rect>(これは通常の動作です。W3Cの推奨事項を参照してください)。Chromeは単純にフィルターを適用しません。

ホームページの場合、#blurredも絶対 URL に計算されますhttp://example.com/my-folder/#blurred。しかし、今回はこれも現在の URL です。GET リクエストを送信する必要がないため、#blurredフィルタが存在します。

への追加のリクエストを確認する必要がありhttp://example.com/my-folder/ましたが、私の弁護では、JavaScript ファイルへの他の多くのリクエストで失われました。

ソリューション

タグが必須の場合<base>、解決策は絶対 IRI を使用してフィルターを識別することです。AngularJS の助けを借りて、これは非常に簡単です。SVG にリンクされているコントローラーまたはディレクティブで、$locationサービスを挿入し、absUrl()getterを使用します。

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

SVG では、次のプロパティを使用します。

<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>

関連: HTMLページにBASEタグがあるとSVGグラデーションが黒くなる?

于 2013-11-03T13:26:00.507 に答える
1

以前に観察した動作のようです。根本的な原因は、同じ ID (ぼやけた) を持つ複数の要素 (フィルター) を持つことになることです。ブラウザによって処理が異なります...

あなたのケースを再現するために私がしたことは次のとおりです: http://jsfiddle.net/z5cwZ/ 2つのsvgがあり、1つは隠されています.

ID の競合を回避する方法は 2 つあります。最初に、テンプレートから一意の ID を生成できます (angularjs でそれを行うのは大変です)。以下に例を示します: http://jsfiddle.net/KbCLB/1/

2番目の可能性は、angularjsの方が簡単かもしれませんが、フィルターを個々のsvgの外に置くことです( 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>
于 2013-11-02T15:26:35.943 に答える
0

この問題に遭遇しました。@Blackholeの回答から拡張した私の解決策は、すべての塗りつぶし属性の値を変更するディレクティブを追加することでした。

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));
        }
    };
});
于 2015-09-03T06:35:26.223 に答える