Можно ли линейно-градиентно-заполнить сгруппированный путь в SVG (css или attr для события jQuery) - PullRequest
11 голосов
/ 27 марта 2011

Как я могу заполнить один градиент для <g> в SVG-изображении вместо заполнения всех <g> в выбранном <g>?

В этом случае я хотел бы показать Африку, заполненную всего одним градиентом от желтого до красного, но из-за подгрупп заливка создает много градиентов.

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

this is the africa

Как я могу решить эту проблему?
Какможно исправить эту проблему, не добавляя еще один тег <g> к исходному изображению?

Ответы [ 4 ]

30 голосов
/ 02 апреля 2011

Ваша проблема может быть решена путем установки системы координат градиентов в пространстве пользователя (вместо стандартного ограничивающего прямоугольника).

вы можете попробовать

<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-elements, определяющие формы страны, вы заметите, что некоторые из них подвергаются дополнительному переводу. они эффективно смещают пользовательскую систему координат и, следовательно, также применяются к градиенту, который заставляет фигуры затронутой страны выглядеть как пятна на карте. это преобразование spurios, вероятно, является артефактом действий в генераторе, используемом для создания карты. это можно исправить, добавив сдвиги перевода к каждой абсолютной координате в элементах пути внутри соответствующих g-элементов. поскольку эти пути определены с использованием относительных координат для сшиваемых частей, это сводится к изменению координат начальной и конечной команд «С» в атрибуте «d» пути.

Я подготовил специальный perl-скрипт для нормализации структуры кода svg, представляющего границы страны, который реализует вышеупомянутые модификации. Обратите внимание, что эти изменения могут быть сделаны довольно удобно и в JS. Это результат .

надеюсь, что это поможет, и напишите мне, если вам нужна дополнительная информация о том, как выполнить упомянутые корректировки.

PS: я только заметил, что Мозамбик все еще отсутствует в сгенерированном результате - для формы этой отдельной страны был задан еще один перевод. эта незначительная деталь должна быть добавлена ​​позже сегодня, однако ...

результат http://collapsar.co.ohost.de/data/astcko.03.png

2 голосов
/ 30 марта 2011

"Рисование, однако, всегда выполняется для каждого графического элемента отдельно, никогда не на уровне элемента контейнера (например, 'g'). Таким образом, для следующего SVG, даже если градиентная заливка указана на 'g', градиент просто наследуется через элемент' g 'вниз в каждый прямоугольник, каждый из которых отображается так, что его внутренняя часть закрашена градиентом. "

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

ЧтоВы просите, не возможно, согласно спецификации.Если это требование, вы можете изучить одну из следующих задач: сделать так, чтобы создатель SVG добавил для вас указатель мыши;объединить пути в коде на сервере (потенциально сложно);выберите сплошной цвет вместо градиента, чтобы проблема не была столь очевидной.

2 голосов
/ 30 марта 2011

Если вы хотите заполнить всю Африку одним градиентом, то вы хотите объединить пути для этого заполнения.Может быть, вы должны использовать другую карту?Один только с континентами?

В любом случае, один из способов исправить это было бы:

  1. открыть его в Inkscape
  2. выбрать все пути, которые вы хотитезаполните
  3. выберите «Объединение» в меню «Путь»
  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>
0 голосов
/ 30 марта 2011

Я думаю, что ваша проблема может быть в том, что fill наследуется в соответствии со стандартными правилами CSS в SVG . Таким образом, вам нужно установить явное fill прозрачного для дочерних g элементов. Если это не так, я вернусь и посмотрю еще раз после того, как у вас есть онлайн-пример.

...