在包含SVG标记元素的页面上使用基本标记无法呈现标记

时间:2013-08-15 18:16:21

标签: html google-chrome firefox svg base-url

尝试在基于SVG的可视化中使用SVG标记元素时遇到了问题。我正在将我的更改添加到Web应用程序中,该应用程序恰好在每个页面上都包含一个基本标记,因此对CSS文件,javascript文件等的任何引用都可以是相对的。

下面有一些示例代码可以重现问题。有一个line元素,并定义了一个标记元素。标记元素由其“marker-end”属性中的行引用,通过uri和id of marker。没有基本标签,箭头显示正常。使用基本标记时,未显示。原因是因为基本标记改变了浏览器解析URL的方式..即使是在行的marker-end属性中指定的基于简单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>

8 个答案:

答案 0 :(得分:43)

HTML <base> element用于表示“解析所有相对网址,而不是相对于此网页,而是指向新位置”。在您的情况下,您已告诉它使用HTML页面解析相对于该目录。

SVG marker-mid="url(…)"属性为FuncIRI Reference。当您使用类似url(#foo)的值时,通常相对于当前页面解析相对IRI,找到具有foo id的元素。但是,当您使用<base>时,您会更改其外观。

要解决此问题,请使用更好的值。由于您的基本引用是当前目录,因此您只需使用当前文件的名称:

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

如果你有一个不同的<base> href,而不是你所展示的,如:

<base href="http://other.site.com/whee/" />

然后你需要使用一个绝对的href,例如

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

答案 1 :(得分:5)

在像Angular一样构建的富Web应用程序的上下文中,您需要设置<base>标记以使HTML5样式的导航工作,尝试以永久方式修复它会变得混乱

在我的情况下,我正在处理的应用程序显示SVG-based interactive diagram builder,当我在其中选择元素时,它会更改应用程序网址。

我所做的是添加一个全局事件处理程序,该处理程序将修复页面中找到的任何url(#...)元素中的所有<path>内联样式:

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

然后在关键位置触发此处理程序,例如应用程序状态更改时(我正在使用ui-router

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

以及我所知道的任何地方都会有新的/更新过的路径。在这里,$timeout是为了解释在触发$stateChangeSuccess事件后,DOM节点确实异步更改的事实。

答案 2 :(得分:4)

尝试使用javascript:

<line id="something" />

使用原生:

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

使用jQuery:

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

它只是有效。

答案 3 :(得分:4)

在Angular 2+中,您可以在app模块中注入基本路径,而不是使用&lt; base&gt;标签。这为我解决了Edge和Firefox中的问题。

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

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

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

答案 4 :(得分:1)

Ember 2.7会将<base>标记替换为rootURL,以解决此问题。

与此同时,在我的d3渐变中,我使用了以下内容:

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

如果您不这样做,那么您定位的项目似乎是透明的。

答案 5 :(得分:1)

在Windows上(04-2017),所有浏览器都按预期运行( mask = url(“#svgmask”))。 Chrome,Firefox,甚至IE 11 !! - 但Edge出现错误。

因此,对于Microsoft Edge,您仍然需要为您的掩码ID提供绝对路径( mask =“url(path / 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>

答案 6 :(得分:0)

如果您不想修改/动画svg,则有一个比更改url()参数更简单的解决方案。

将svg包含为图像:

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

答案 7 :(得分:0)

您可以使用以下方式对其进行存档:

$("[marker-mid]").attr("marker-mid", function () {
    return $(this).attr("marker-mid").replace("url(", "url(" + location.href); 
});