能否通过CSS或jQuery事件的属性来线性渐变填充SVG中的分组路径?

24

如何为SVG图像中的一个

在这种情况下,我想展示非洲,只填充一个从黄色到红色的渐变,但由于子组的存在,填充会产生许多渐变。

Javascript代码:

<script type="text/javascript">
function svgOver() { 
    var what = $(this).attr("id");
    $("#world #"+what, svg.root()).attr("fill", "url(#red_black)"); 
} 
function svgOut() { 
    $(this).attr("fill", "");
}

...

$("#map").svg({ 
    loadURL: 'http://teszt.privilegetours.hu/skins/privilege/svg/worldmap.svg',
        onLoad: function(svg) { 
        $("#world > g", svg.root()).bind('mouseover', svgOver).bind('mouseout', svgOut).bind('click', svgZoom);
        },
    settings: {}
});

SVG图像:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" mlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="570px" height="300px" viewBox="146.605 71.42 570 300" enable-background="new 146.605 71.42 570 300" xml:space="preserve">

<defs>
    <linearGradient id="red_black" x1="0%" y1="0%" x2="0%" y2="100%">
        <stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1"/>
        <stop offset="100%" style="stop-color:rgb(255,255,0);stop-opacity:1"/>
    </linearGradient>
</defs>

<g id="world" transform="scale(1)" fill="#AAAAAA" stroke="#FFFFFF" stroke-width="0.1">
    <g id="africa" name="africa"> // < i want to fill this
        <g id="er" transform="translate(-29.9017, -45.0745)"> // < instead of theese
            <path d="..."/>
        </g>
        <g id="yt"> // < instead of theese
            <path d="..."/>
        </g> 
        ...

这是非洲

如何解决这个问题?
如何在不向原始图像添加另一个<g>标签的情况下解决这个问题?


你能提供一个在线示例链接吗?我认为问题可能出在你的CSS而不是SVG上,我只想查看整个内容。 - robertc
所以你不能链接到在线示例吗?你应用样式于 #africa 的代码在哪里? - robertc
$("#world #"+what, svg.root()).attr("fill", "url(#red_black)"); 第4行,第一个框中的程序代码。 - Répás
但你只是在鼠标悬停时这样做:$(“#world> g”,svg.root())。bind('mouseover',svgOver)。 你真的不能在线链接整个东西吗? - robertc
好的,正如您所看到的,当$(“#world> g”,svg.root()).bind('mouseover',svgOver)绑定mouseover事件时,将元素的ID传递给svgOver()函数。因此,svgOver将等于$(“#world#africa”,svg.root())。attr(“fill”,“url(#red_black)”);url(#red_black)将从svg(<defs>)中选择。实际上,我没有分享整个网站的权限。稍后我会复制它并分享它。 - Répás
在你的 svgOver 函数中,你是否尝试过使用 console.log 打印 id 属性,以确保你没有收到任何意外的元素? - RussellUresti
4个回答

53

你的问题可以通过将渐变坐标系设置为用户空间(而不是默认的对象边界框)来解决。

你可以尝试:

<defs>
    <linearGradient id="red_black" x1="0%" y1="0%" x2="0%" y2="100%" gradientUnits="userSpaceOnUse">
        <stop offset="0%" style="stop-color:rgb(255,0,0);stop-opacity:1"/>
        <stop offset="100%" style="stop-color:rgb(255,255,0);stop-opacity:1"/>
    </linearGradient>
</defs>

该解决方案并不违背e.nelson的评论 - 这里发生的是每个代表国家的子组仍然应用其各自的渐变实例,同时所有这些实例共享相同的坐标原点和相对于用户空间的相同变换 - 因此在最终呈现的任何点上,可见哪个渐变实例并不重要。

需要进行两个调整:

  1. [轻微]

    必须调整渐变定义中的y1/y2偏移量(或停止偏移量)- 因为它们与整个地图的用户坐标空间相关,非洲只覆盖了定义的停止之间渐变的一部分。尝试使用y1="50%"y2="100%"

  2. [中等]

    如果你查看SVG的g元素定义国家形状,你会注意到其中一些经受了额外的平移,它们有效地移动了用户坐标系,因此也适用于渐变,这导致受影响的国家形状看起来像地图上的斑点。

    这种虚假变换可能是创建地图所用的生成器中的工件。可以通过将平移偏移量添加到各个

我编写了一个临时perl脚本来规范表示国家边界的SVG代码结构,实现了上述修改。请注意,这些修改也可以在JS中很方便地完成。 这是结果

希望这有所帮助,如果您需要有关执行所提到的调整的其他信息,请给我留言。

PS:

我刚刚注意到生成的输出仍然缺少莫桑比克 - 对于该单个国家的形状,另一种平移已经被指定。但这只是一个小细节,今天稍后会添加进去...

result


2
嗯,我感到非常惊讶。正在处理中。你有什么程序可以用来制作一个没有M和翻译的版本的地图吗?谢谢,Répás。 - Répás
2
我有一个Perl脚本。顺便说一下,今天我的日程很紧,所以我可能要到明天才能上StackOverflow。再见,Carsten - collapsar
2
赞和+1,解决方案很棒。 - Elliot Nelson
3
@repas:抱歉回复晚了,上周我比预计的要忙得多... 脚本的网址为http://collapsar.co.ohost.de/data/astcko.03.cleanse.pl; 您需要在第64行及其后面的内容中调整路径以适应您的本地文件系统。$fclone是原始文件名,$fres是目标文件名,$workdir...呃...;-)(由于历史原因而拥有别致的标识符名称...)。最好的问候,卡斯滕。 - collapsar
6
嗨,@collapsar。链接失效了。 - GottZ
显示剩余2条评论

2
如果您想使用一个渐变填充整个非洲,那么您需要合并该填充的路径。也许您应该使用另一张地图?一张只有大陆的地图?
无论如何,修复它的一种方法是:
  1. 在Inkscape中打开文件
  2. 选择要填充的所有路径
  3. 从“Path”菜单中选择“Union”
  4. 保存文件(或复制并粘贴联合路径)
另一种方法:
  1. 寻找另一张地图,参见 http://d-maps.com/http://commons.wikimedia.org。 这里有一份只有大陆和非洲标记的地图。
完成后,您可以将渐变应用于新路径。
您也可以用其他方法完成它,但出于性能原因,它们可能不如此方法好。其中一种(不建议使用)方法是在剪辑路径中填充渐变的矩形,该剪辑路径由组中的路径组成。大致如下所示:
<clipPath id="clip">
  <use xlink:href="#africa"/>
</clipPath>
<rect width="100" height="100" fill="url(#grad)" clip-path="url(#clip)"/>
<g id="africa">...</g>

这个地图有一些其他的JavaScript... :D 移动,选择等等。所以我不能选择另一种方式,第一种也不行,因为。现在我有了一个关于无形联合路径的想法。 :) 你以后会看到我的。 - Répás
请注意,clip-path中的SVG组没有任何效果。 clip-path只能包含基本形状、文本或路径元素或直接指向这些元素的use引用。 - Simon

2
“然而,绘画总是在每个图形元素上单独完成的,从不在容器元素(例如‘g’)级别上完成。因此,在以下SVG中,即使渐变填充是在‘g’上指定的,渐变也只是通过‘g’元素向下继承到每个矩形中,每个矩形都被渲染为其内部用渐变填充。”

http://www.w3.org/TR/SVGTiny12/painting.html#InheritanceOfPaintingProperties

您所要求的,根据规范来说是不可能的。如果这是一个要求,你可以考虑以下方案之一:让SVG创建者为你添加鼠标悬停路径;在服务器上通过代码合并路径(可能有些棘手);选择纯色而非渐变色,这样问题就不会那么明显了。

0

我认为你的问题可能是fill 被继承了, 根据SVG中CSS的标准规则。所以你需要在子元素g上设置一个明确的透明fill。如果不是这个问题,等你提供在线示例后我会再来看一下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接