2013-08-15 7 views
42

SVGベースの視覚化でSVGマーカー要素を使用しようとしているときに問題が発生しました。私はWebアプリケーションに自分の変更を追加しています。これは、CSSファイルやJavaScriptファイルなどの参照が相対的なものになるように、すべてのページにベースタグを含めることになります。SVGマーカー要素を含むページでベースタグを使用するとマーカーのレンダリングに失敗する

私はこの問題を再現するいくつかのサンプルコードを用意しています。線要素とマーカー要素が定義されています。 marker要素は、マーカーのuriとidを介して、その 'marker-end'属性の行によって参照されます。ベースタグがなければ、矢印は正常に表示されます。ベースタグは表示されません。理由は、ベースタグがブラウザのURLを解決する方法を変更するためです。ラインのマーカー終了属性で指定された単純なIDベースのURLの場合でもです。

ベースタグを削除せずにこの問題を回避する方法はありますか?

私が取り組んでいる製品では、その使用がかなり蔓延しているため、実際には削除できません。私は私のwebappのためにFirefox、Chrome、IE9 +をサポートする必要があります。 FirefoxとChromeの両方でこの問題が発生します。 IEは正常に動作します(つまり、矢印マーカーが表示されます)。

<html> 
    <head> 
    <base href="."> 
    <style> 
    .link { stroke: #999; stroke-opacity: .6; } 
    marker#arrow { fill: black; } 
    </style> 
</head> 
<body> 
    <svg width="100%" height="100%"> 
     <defs> 
      <marker id="arrow" viewBox="0 -5 10 10" refX="0" refY="0" markerWidth="20" markerHeight="20" orient="auto"> 
       <path d="M0,-5L10,0L0,5"></path> 
      </marker> 
     </defs> 
     <line x1="100" y1="100" x2="333" y2="333" marker-start="url(#arrow)" class="link"></line> 
    </svg> 
</body> 
</html> 
+1

基本的な要素を使って再考することができます。何年も前、私はあまり書かれていないクローラに問題があり、私のサイトを通過して何千もの404を生成しました。 – cimmanon

+3

AngularJSユーザーが苦痛の一日を救うためにここに残しておきます:https://github.com/angular/angular.js/issues/8934#issuecomment-56568466 – Bungle

答えて

35

HTML <base> elementは「ありませんこのページへのが、新しい場所への相対すべての相対URLを解決する」と言うために使用されます。あなたの場合は、HTMLページでディレクトリに関連する解決を指示しました。

SVG marker-mid="url(…)"の属性はFuncIRI Referenceです。 url(#foo)のような値を使用すると、現在のページに対して相対IRIが通常解決されるため、foo idを持つ要素を見つけることができます。しかし、<base>を使用すると、見た目が変わります。

この問題を解決するには、より良い値を使用してください。あなたが別の<base>のhrefを持っている場合は、同様に、示されてきたものよりも、

<line … marker-mid="url(this_page_name.html#arrow)" /> 

<base href="http://other.site.com/whee/" /> 
あなたのベース基準は、現在のディレクトリであるので、あなたは、単に現在のファイルの名前を使用することができます

次に絶対hrefを使用する必要があります。

<line … marker-mid="url(http://my.site.com/this_page_name.html#arrow)" /> 
+6

返事Phrogzのための非常に寛大な。私は昨日の終わりにこれを実際に分かった。 imはjavascript経由でマーカーを追加しているので、marker-start、marker-endなどの属性値を設定するためには次のようにしてください: "url(" + window.location + "#arrow") marker属性を絶対URLと一緒に使用すると、FirefoxとChromeの問題を修正しましたが、IEでは動作しません。しかしこれは大きな問題ではありません。私はちょうど使用中のブラウザに応じて異なる動作を使用することができます。もう一度ありがとう。 -Dave – DaViS

+0

私たちのケースでは、私に戻ったレポートは「すべてのグラジエントが機能しなくなりました」でした!もちろん、 "url(#gradientName)"はベースタグで飛んでいません。これは、Cloudfrontディストリビューションに移動したときに発生したので、完全に動作するコードは、Cloudタグでベースタグ経由でプロダクションに移行されたときに役に立たなくなっていました。 –

+0

@DaViS私もこれに遭遇しました。 FWIWでは、マーカーURLを指定するための「外部」ファイル参照を使用するとブラウザのサポートが不足しています。これはIEの問題を説明するものです(ただし、Chromeでうまくいきましたが)。参照:http://stackoverflow.com/questions/27752494/why-cant-i-reference-an-svg-linear-gradient-defined-in-an-external-file-paint/27752594#27752594 – Bungle

2

あなたがurl()パラメータを変更するよりも簡単な解決策があるSVGをアニメーション/変更する必要がない場合。

は画像としてSVGを含める:

<img src="yourpath/image.svg"> 
4

はJavaScriptを使用して試してみてください:ネイティブで

<line id="something" /> 

:jQueryを使って

document.getElementById('something').setAttribute('marker-mid', 'url(' + location.href + '#arrow)'); 

$('#something').attr('marker-mid', 'url(' + location.href + '#arrow)'); 

これは機能します。

+1

素晴らしいアイデア、またはさらに良い... '$(..タグあなたたいターゲット...)。各(関数(){ \t \t \tするvar clip_path = $(この).ATTR( 'クリップパス') \t \t \t VAR clip_path.indexOf( ')')); \t \t \t $(this).attr( 'clip-path'、 'url(' + location.href + actual_id + ')'); \t \t}); ' – user151496

+0

これもうまくいく可能性があります:) – nikoloza

5

<base>タグをHTML5スタイルのナビゲーション作業を行うように設定する必要がある、Angular上に構築されたようなリッチなWebアプリケーションのコンテキストでは、永続的な方法で問題を解決しようとするのが面倒です。

私のケースでは、私が働いていたアプリは、要素を選択したときにアプリのURLを変更するSVG-based interactive diagram builderを表示していました。そして、時にアプリケーションの状態のように、キーの場所でこのハンドラをトリガ

$rootScope.$on 'fixSVGReference', -> 
    $('path').each -> 
     $path = $ this 
     if (style = $path.attr 'style')? 
      $path.attr 'style', style.replace /url\([^)#]*#/g, "url(#{location.href}\#" 

:私は何

は、ページ内に見つかった<path>要素内のすべての​​インラインスタイルを修正するだろうグローバルイベントハンドラを追加しました変更(私はui-routerを使用しています)

$rootScope.$on '$stateChangeSuccess', -> 
    $timeout (-> $rootScope.$emit 'fixSVGReference'), 5 

としてだけでなく、どこにでも、私はこれらのような新しい/更新パスがあると思います知っています。ここで、$timeoutは、$stateChangeSuccessイベントがトリガーされた後、いつもDOMノードが非同期に変更されるという事実を説明することです。

1

Ember 2.7は<base>タグをこの問題を修正するrootURLに置き換えます。私は、次を使用してい勾配のための私のD3で一方

.attr('fill', `url(${Ember.$(location).attr('href')}#my-gradient)`);

これを行わない場合は、あなたがターゲットとしている項目は、透明であるように思われます。

2

角2+では、<ベースの>タグを使用する代わりに、ベースモジュールのパスをアプリモジュールに注入できます。これでEdgeとFirefoxの問題が解決されました。 (マスク= URL( "#のsvgmask"))予想通り

import { APP_BASE_HREF } from '@angular/common'; 

@NgModule({ 
    providers: [{ 
    provide: APP_BASE_HREF, 
    useValue: '/' 
    }] 
}) 
export class AppModule { } 
Windows上

https://angular.io/docs/ts/latest/api/common/index/APP_BASE_HREF-let.html

0

は、現在(04から2017)すべてのブラウザで動作します。 Chrome、Firefox、さらにIE 11! - しかし、エッジはエラーを伴います。

Microsoft Edgeの場合、ベースを使用しているときにマスクIDの絶対パス(マスク= "url(パス/ to/this-document.htm#svgmask)")タグ:

<svg viewBox="0 0 600 600" > 
    <defs> 
    <mask id="svgmask"> 
     <image width="100%" height="100%" xlink:href="path/to/mask.svg" ></image> 
    </mask> 
    </defs> 
    <image mask="url(path/to/this-document.htm#svgmask)" width="600" height="600" xlink:href="path/to/image.jpg"></image> 
</svg> 
関連する問題