В моей практике накопилось некоторое количество приёмов для стилевого оформления слоёв GeoServer, чем и спешу поделиться. Я планирую написать 3 статьи: символизация точек, линий и полигонов. Первая из них перед вами.
Предполагается, что все примеры кода, описанные в этой статье, находятся внутри следующей XML:
<?xml version="1.0" encoding="UTF-8"?>
<StyledLayerDescriptor version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd"
xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<NamedLayer>
<Name></Name>
<UserStyle>
<Title>Basic point style</Title>
<FeatureTypeStyle>
<Rule>
<Title>Здесь идёт заголовок легенды</Title>
<PointSymbolizer>
<!-- ТЕЛО СТИЛЯ ИДЁТ ЗДЕСЬ -->
</PointSymbolizer>
</Rule>
</FeatureTypeStyle>
</UserStyle>
</NamedLayer>
</StyledLayerDescriptor>
Все примеры написаны в соответствии с форматом SLD версии 1.0.0. На данном этапе достаточно понимать, что Rule
— это правило, которое задаёт стилевое оформление. У правила может быть условие, правил может быть несколько. Всё, что находится вне тэга Rule
, практически не будет меняться на протяжении цикла статей и поэтому мало нас интересует — можно воспринимать всё остальное, как заготовку. Правило задаёт символизацию для точек, линий, полигонов — за это отвечает соответствующий Symbolizer
. В данном посте будут затронут только PointSymbolizer
— символизация точек.
PointSymbolizer
По умолчанию GeoServer отображает точки в виде красных квадратов.

Ему соответствует следующий стиль (точнее, тело стиля):
<Graphic>
<Mark>
<WellKnownName>square</WellKnownName>
<Fill>
<CssParameter name="fill">#FF0000</CssParameter>
</Fill>
</Mark>
<Size>6</Size>
</Graphic>
Разберём каждый тэг по порядку. PointSymbolizer
может содержать внутри себя тэг Geometry
(необязательный) или тэг Graphic
(должен присутствовать всегда). Geometry
используется в более продвинутых случаях, когда из объекта (линии, полигона) нужно выделить одну или несколько точек и применить к ним символизацию, а поэтому сейчас рассматриваться не будет. Graphic
может содержать в себе либо Mark
, либо ExternalGraphic
, и определяет таким образом символизацию точки. ExternalGraphic
— это изображение (в роли него может выступать, например, файл png), которое будет подставляться в каждую точку. Mark
сам определяет форму отображения точки — в нём содержится описание, какой формы, цвета и с какой границей будет точка. Тэг Size
применим и к ExternalGraphic
, и к Mark
и определяет размер значка в пикселях.
Mark
Рассмотрим Mark
более подробно. WellKnownName
определяет форму значка. В примере выше использовалось значение square
— квадрат. Вместе с этой фигурой допустимы следующие стандартные символы:
square
— квадратcircle
— кругtriangle
— треугольник острым краем вверхstar
— пятиконечная звездаcross
— знак «плюс» с отступом вокругx
— буква «x» с отступом вокруг
Кроме того допустимы расширенные символы, начинающиеся с shape://
:
shape://vertline
— вертикальная линияshape://horline
— горизонтальная линияshape://slash
— слэшshape://backslash
— обратный слэшshape://dot
— очень маленький кружок с отступом вокругshape://plus
— знак «плюс» без отступаshape://times
— буква «x» без отступаshape://oarrow
— незакрытая стрелка (треугольник без одной стороны)shape://carrow
— закрытая стрелка
В чём разница значков с отступом и без него? Для точек — никакой. Это пригодится в следующей статье, когда будем рассматривать заливку полигонов. Помимо символа на одном уровне с WellKnownName
задаются заливка Fill
и граница Stroke
. Оба они задаются через тэги CssParameter
с отличием в атрибуте name
. В примере выше CssParameter
указывает, что заливка выполняется красным цветом. Теперь разберём разные варианты на примерах.
Предположим, что нам нужна символизация в виде большого зелёного полупрозрачного треугольника с красной толстой границей:

Соответствующий ему стиль будет выглядеть следующим образом:
<Graphic>
<Mark>
<WellKnownName>triangle</WellKnownName>
<Fill>
<CssParameter name="fill">#00FF00</CssParameter>
<CssParameter name="fill-opacity">0.2</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#FF0000</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
</Stroke>
</Mark>
<Size>20</Size>
</Graphic>
В роли фигуры здесь выступает triangle
, размер увеличен до 20 пикселей, задана заливка и граница. Для заливки можно использовать следующие значения атрибута name
тэга CssParameter
:
fill
— цвет заливки в формате#RRGGBB
(по умолчанию#808080
)fill-opacity
— непрозрачность, значение от 0 (полностью прозрачный) до 1 (полностью непрозрачный). Значение по умолчанию — 1
Для границы допустимы следующие значения атрибута name
тэга CssParameter
:
stroke
— цвет заливки в формате#RRGGBB
(по умолчанию#000000
)stroke-width
— толщина в пикселях. Значение по умолчанию — 1stroke-opacity
— непрозрачность, значение от 0 (полностью прозрачный) до 1 (полностью непрозрачный). Значение по умолчанию — 1
Кроме ExternalGraphic
, Mark
и Size
в тэге Graphic
могут присутствовать Opacity
и Rotation
. Opacity
действует на весь символ (как на ExternalGraphic
, так и на Mark
), значения от 0 до 1. Rotation
задаёт поворот знака в десятичных градусах, положительно значение поворачивает знак по часовой стрелке, отрицательное — против. Рассмотрим эти значения на примере использования ExternalGraphic
.
ExternalGraphic
ExternalGraphic
использует изображения для символизации точек. Содержит два обязательных тэга:
OnlineResource
— URL до картинки, либо путь относительно директорииdata/styles
Format
— формат картинки (например, image/png)
Например, можно отметить аэродромы на карте:

Стиль для аэродромов:
<Graphic>
<ExternalGraphic>
<OnlineResource xlink:type="simple" xlink:href="fly.png" />
<Format>image/png</Format>
</ExternalGraphic>
<Size>32</Size>
</Graphic>
Предварительно я скачал картинку fly.png 32×32 (Size
установлен соответствующим образом) и положил её в папку со стилями. Можно сразу завести папку images, чтобы картинки не перемешивались с файлами *.sld. Тогда путь будет выглядеть так — images/fly.png
. Теперь предположим, что нужно указать URL картинки (а заодно повернуть её на 20 градусов против часовой стрелки и сделать полупрозрачной):

Соответствующий стиль:
<Graphic>
<ExternalGraphic>
<OnlineResource xlink:type="simple" xlink:href="http://localhost/fly.png" />
<Format>image/png</Format>
</ExternalGraphic>
<Size>32</Size>
<Rotation>-20</Rotation>
<Opacity>0.5</Opacity>
</Graphic>
Менее распространённые (но не менее значимые) возможности
Пожалуй, рассмотренные выше возможности покроют большую часть задач. Однако, есть ещё несколько вещей, мимо которых нельзя пройти — это использование символов из шрифта системы и задание фигуры с помощью WKT.
Использование символов шрифта
Для символизации через символ шрифта в WellKnownName
необходимо указать строку следующего вида: ttf://<ИМЯ_ШРИФТА>#0x<ШЕСТНАДЦАТЕРИЧНЫЙ_КОД_СИМВОЛА>. Например, возьмём символ Ubuntu из одноимённого шрифта:

Соответствующий стиль:
<Graphic>
<Mark>
<WellKnownName>ttf://Ubuntu#0xE0FF</WellKnownName>
<Fill>
<CssParameter name="fill">#8a434b</CssParameter>
</Fill>
</Mark>
<Size>20</Size>
</Graphic>
При использовании символа шрифта обязательно указывайте Fill
и(или) Stroke
, иначе символ не отобразится. Символы удобно просматривать в редакторе пакета офиса (MS Word или LibreOffice Writer) через вставку специального символа. Там же будет шестнадцатеричное представление.
Well-known text
И на закуску у нас остался самый интересный и самый сложный способ символизации — через WKT. Здесь мы сами задаём форму символа, что открывает широкий простор для творчества (однако, всегда стоит помнить, что за эту гибкость мы платим дополнительной работой процессора). Например, отметим точки на карте в виде значков заземления:

Соответствующий стиль:
<Graphic>
<Mark>
<WellKnownName>
wkt://MULTILINESTRING(
(0 0, 0 3),
(-2 0, 2 0),
(-1.3 -1, 1.3 -1),
(-0.8 -2, 0.8 -2)
)
</WellKnownName>
<Stroke>
<CssParameter name="stroke">#0000ff</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
</Stroke>
</Mark>
<Size>20</Size>
</Graphic>
Multilinestring
— это объект, состоящий из нескольких линий. Точки задаются координатами — x и y соответственно, которые разделены пробелом. Точки отделяются друг от друга запятыми. Точка (0 0) — это место, где находится объект слоя (то есть та координата, для которой мы настраиваем символизацию). В примере выше создаются четыре линии, каждая из которых задаётся двумя точками. Первой создаётся вертикальная линия, далее самая длинная, средняя и короткая горизонтальная линия. Здесь координаты — это некоторая условность, они задают лишь пропорции объекта, и если все координаты умножить на 10 — на выходе ничего не изменится, так как размер всё равно будет определяться тэгом Size
. Толщина линий задаётся тэгом Stroke
, он работает так же, как и везде.
Кроме линий можно задавать и мультиполигоны с заливкой:

В примере выше для каждой точки создаётся квадрат слева от координаты (0 0) и треугольник справа от нулевой координаты. Для этого использовался следующий стиль:
<Graphic>
<Mark>
<WellKnownName>
wkt://MULTIPOLYGON(
((-5 2, -1 2, -1 -2, -5 -2, -5 2)),
((3 2, 1 -2, 5 -2, 3 2))
)
</WellKnownName>
<Fill>
<CssParameter name="fill">#0b9fca</CssParameter>
<CssParameter name="fill-opacity">0.5</CssParameter>
</Fill>
<Stroke>
<CssParameter name="stroke">#0b9fca</CssParameter>
<CssParameter name="stroke-width">2</CssParameter>
</Stroke>
</Mark>
<Size>10</Size>
</Graphic>
Это лишь базовые примеры. Можно создавать куда более сложные контуры, включая кривые линии (CompoundCurve и CircularString). Однако, всегда помните про производительность — на определённом этапе правильней будет перейти на картинку.
Если статья не отвечает на ваши вопросы, если что-то осталось непонятным или же вы по-прежнему не знаете, как настроить символизацию для какого-то случая — напишите в комментариях.
Здраствуйте! Вопрос: если название шрифта — два слова (содержит пробел)
ttf://Ubuntuitalic#0xE0FF
что вставляем вмето пробела? %20?
Добрый день.
Пробел не нужно чем-то заменять, геосервер его нормально распознаёт. Во всяком случае сейчас проверил символизацию «ttf://Times New Roman#0x0021» на геосервере под управлением Windows — стиль нормально работает и выводит ожидаемые восклицательные знаки.
День добрый, помогите в следующем.
Борюсь с подписями…:
есть точечный слой, в котором помимо графики, есть поля «наименование» для отображения на экране , а также задается угол для поворота. В целом добился решения вопроса, но есть проблема, что геосервер текст не всегда отображает (зависит от масштаба, шрифта, длины текста, поворота, самой точки или еще чего не понятно)
прилагаю скриптик
5-26000
5
26000
circle
#FF0000
7
name
Times new roman
18.0
normal
bold
1
#FFFFFF
#000000
0
0
360
angle
От чего все-таки зависит отображение, есть ли смысл пользовать для этих задач css?
Для понимания, цель: нужно осуществлять пометки вдоль улиц в нужных местах (и их печать в последствии)
Здравствуйте.
Лично для меня CSS не подходит, потому что это лишь обёртка поверх SLD (в итоге при сохранении стиля происходит конвертация CSS в XML), и иногда в этой обёртке просто нет нужного функционала — например, нельзя использовать VendorOption или какие-нибудь продвинутые функции. Плюс я не использую CSS ещё и потому, что порой приходится переносить стили между геосерверами, а плагин CSS практически нигде не установлен.
Причин того, почему подписи не показываются, может быть несколько:
1. Если слой приходит тайлами, то может случиться так, что точка находится на левом тайле, а её подпись — на соседнем правом. Эта проблема обнаруживается по обрезанным подписям — это и будет граница между тайлами. При приближении подпись может показаться целиком, а может быть обрезана ещё больше, в зависимости от границы тайлов. Один из вариантов решения — получать слой подписей одним тайлом.
2. Подписи не выводятся из-за пересечения друг с другом. Геосервер не выведет подпись, если она перекроет другую подпись. Для проверки этой проблемы нужно приближаться к точке, где подпись не выведена. На определённом масштабе другие точки вокруг неё разъедутся и для подписи будет достаточно места, чтобы она не перекрывала подписи других точек. Для решения проблемы можно принудительно отключить контроль пересечений, добавив в конце тега строчку false.
3. Некоторые подписи слишком длинные. В этом случае над некоторыми точками отсутствуют подписи, несмотря на решение первых двух пунктов. Для решения проблемы необходимо добавить тег 150 в конце тега . 150 в данном примере — количество пикселей для вывода подписей.