Основы стилизации в OpenLayers

Стилизация определяет внешний вид пространственных объектов на карте. От правильно настроенных стилей зависит читаемость данных, визуальная иерархия, удобство анализа информации и производительность отображения.

В OpenLayers стили применяются к объектам векторных слоёв и позволяют управлять:

  • цветами объектов;
  • толщиной и типом линий;
  • отображением точек;
  • подписями;
  • иконками;
  • заливками полигонов;
  • масштабно-зависимым оформлением;
  • динамическим изменением внешнего вида на основе атрибутов объектов.

Основные классы стилизации располагаются в модуле ol/style.


Архитектура системы стилей

Система оформления OpenLayers построена вокруг объекта Style.

Типичная структура выглядит следующим образом:

import Style from 'ol/style/Style.js';
import Fill from 'ol/style/Fill.js';
import Stroke from 'ol/style/Stroke.js';

const style = new Style({
    fill: new Fill({
        color: 'rgba(0, 0, 255, 0.3)'
    }),
    stroke: new Stroke({
        color: '#0000ff',
        width: 2
    })
});

Стиль объединяет несколько компонентов:

Компонент Назначение
Fill Заливка полигонов
Stroke Контур линий и полигонов
Circle Отображение точек окружностями
Icon Использование изображений
Text Подписи объектов
RegularShape Геометрические фигуры
Style Контейнер всех элементов оформления

Применение стиля к слою

Наиболее распространённый способ оформления — назначение одного стиля всему векторному слою.

import VectorLayer from 'ol/layer/Vector.js';

const vectorLayer = new VectorLayer({
    source: vectorSource,
    style: style
});

Все объекты слоя будут отображаться одинаково.

Такой подход подходит для:

  • административных границ;
  • дорожных сетей;
  • тематических слоёв с единым оформлением;
  • небольших картографических проектов.

Заливка полигонов

Для отображения площадных объектов используется класс Fill.

import Fill from 'ol/style/Fill.js';

const fill = new Fill({
    color: 'rgba(255, 0, 0, 0.4)'
});

Пример полигона:

const polygonStyle = new Style({
    fill: new Fill({
        color: 'rgba(255, 100, 100, 0.5)'
    })
});

Поддерживаются различные форматы цветов:

HEX

color: '#ff0000'

RGB

color: 'rgb(255,0,0)'

RGBA

color: 'rgba(255,0,0,0.5)'

Именованные цвета

color: 'red'

На практике чаще используются RGBA-значения, поскольку они позволяют задавать прозрачность.


Настройка контуров

Контур объекта создаётся классом Stroke.

import Stroke from 'ol/style/Stroke.js';

const stroke = new Stroke({
    color: '#000000',
    width: 3
});

Пример:

const style = new Style({
    stroke: new Stroke({
        color: '#2c3e50',
        width: 4
    })
});

Пунктирные линии

Для создания пунктирных линий применяется свойство lineDash.

const style = new Style({
    stroke: new Stroke({
        color: '#e74c3c',
        width: 3,
        lineDash: [10, 5]
    })
});

Параметры массива:

lineDash: [длина_штриха, длина_пробела]

Примеры:

lineDash: [5, 5]
lineDash: [15, 10]
lineDash: [20, 5, 5, 5]

Подобное оформление часто используется для:

  • проектируемых объектов;
  • временных маршрутов;
  • инженерных коммуникаций;
  • тематических карт.

Отображение точек

Для точечных объектов обычно используется класс Circle.

import CircleStyle from 'ol/style/Circle.js';

Пример:

const pointStyle = new Style({
    image: new CircleStyle({
        radius: 8,
        fill: new Fill({
            color: '#3498db'
        }),
        stroke: new Stroke({
            color: '#ffffff',
            width: 2
        })
    })
});

Результат:

  • синий круг;
  • белая обводка;
  • радиус 8 пикселей.

Размер точечных символов

Размер определяется параметром radius.

radius: 4
radius: 10
radius: 20

Увеличение радиуса повышает заметность объекта, однако чрезмерно крупные символы могут перекрывать соседние элементы карты.


Использование иконок

Вместо окружностей можно применять изображения.

import Icon from 'ol/style/Icon.js';

Пример:

const style = new Style({
    image: new Icon({
        src: 'images/marker.png'
    })
});

Масштабирование иконок

Размер изображения можно изменять независимо от исходного файла.

image: new Icon({
    src: 'images/marker.png',
    scale: 0.5
})

Увеличение:

scale: 2

Уменьшение:

scale: 0.3

Это особенно удобно при использовании одного набора иконок для различных уровней масштабирования.


Смещение иконок

Положение значка относительно координаты объекта настраивается через параметры привязки.

image: new Icon({
    src: 'images/marker.png',
    anchor: [0.5, 1]
})

Значение:

[0.5, 1]

означает:

  • центр по горизонтали;
  • нижняя часть изображения по вертикали.

Такой вариант часто используется для маркеров местоположения.


Поворот символов

Иконки могут вращаться.

image: new Icon({
    src: 'images/arrow.png',
    rotation: Math.PI / 4
})

Угол задаётся в радианах.

Примеры:

Math.PI / 2

90°

Math.PI

180°

Math.PI * 2

360°

Поворот активно используется при визуализации:

  • транспортных средств;
  • судов;
  • самолётов;
  • направлений движения.

Создание подписей

Текст отображается через класс Text.

import Text from 'ol/style/Text.js';

Пример:

const style = new Style({
    text: new Text({
        text: 'Город'
    })
});

Настройка шрифта

Размер и параметры текста определяются свойством font.

text: new Text({
    text: 'Алматы',
    font: '14px Arial'
})

Более сложный вариант:

font: 'bold 16px Verdana'

Возможности:

  • размер;
  • семейство шрифтов;
  • жирность;
  • курсив.

Цвет текста

text: new Text({
    text: 'Объект',
    fill: new Fill({
        color: '#000000'
    })
})

Белая подпись:

fill: new Fill({
    color: '#ffffff'
})

Контур текста

Для повышения читаемости часто добавляют обводку.

text: new Text({
    text: 'Река',
    fill: new Fill({
        color: '#ffffff'
    }),
    stroke: new Stroke({
        color: '#000000',
        width: 3
    })
})

Такой приём широко применяется в веб-картографии.


Смещение подписей

Текст можно перемещать относительно объекта.

text: new Text({
    text: 'Город',
    offsetY: -20
})

Подпись будет расположена над маркером.

Горизонтальное смещение:

offsetX: 15

Вертикальное:

offsetY: 10

Получение текста из атрибутов

Наиболее распространённый вариант — отображение значений полей объекта.

const styleFunction = function(feature) {
    return new Style({
        text: new Text({
            text: feature.get('name')
        })
    });
};

Если объект содержит поле:

{
    name: 'Караганда'
}

то на карте появится соответствующая подпись.


Функции стилей

OpenLayers позволяет динамически формировать стиль для каждого объекта.

layer.setStyle(function(feature) {
    return style;
});

Функция вызывается для каждого отображаемого объекта.

Это один из важнейших механизмов оформления.


Стилизация по атрибутам

Предположим, объекты содержат поле населения:

{
    population: 500000
}

Можно изменять цвет в зависимости от значения.

const styleFunction = function(feature) {

    const population = feature.get('population');

    let color;

    if (population > 1000000) {
        color = 'red';
    } else {
        color = 'orange';
    }

    return new Style({
        fill: new Fill({
            color: color
        })
    });
};

Такой подход лежит в основе тематических карт.


Категориальная стилизация

Часто используется классификация по типам объектов.

const type = feature.get('type');

Далее:

switch(type) {

    case 'city':
        color = 'red';
        break;

    case 'village':
        color = 'green';
        break;

    case 'capital':
        color = 'blue';
        break;
}

Каждая категория получает собственное оформление.


Масштабно-зависимые стили

Функция стиля получает текущее разрешение карты.

function(feature, resolution) {

}

Можно скрывать подписи при сильном уменьшении масштаба.

function(feature, resolution) {

    if (resolution > 100) {
        return simpleStyle;
    }

    return detailedStyle;
}

Подобный механизм предотвращает перегрузку карты.


Переиспользование объектов стилей

Создание новых стилей для каждого объекта может отрицательно влиять на производительность.

Неэффективный вариант:

function(feature) {
    return new Style({
        ...
    });
}

Более эффективный подход:

const cityStyle = new Style({
    ...
});

function(feature) {
    return cityStyle;
}

Стиль создаётся один раз и используется многократно.


Кэширование стилей

При большом количестве объектов полезно хранить стили в кэше.

const styleCache = {};

Пример:

function(feature) {

    const category = feature.get('category');

    if (!styleCache[category]) {

        styleCache[category] = new Style({
            image: new CircleStyle({
                radius: 6
            })
        });

    }

    return styleCache[category];
}

Подход существенно снижает нагрузку на браузер.


Несколько стилей для одного объекта

OpenLayers позволяет возвращать массив стилей.

return [
    style1,
    style2
];

Пример:

return [
    polygonStyle,
    labelStyle
];

Или:

return [
    shadowStyle,
    markerStyle
];

Стили будут отрисованы последовательно.


Создание эффекта ореола

Часто используется двойная линия.

const outerStyle = new Style({
    stroke: new Stroke({
        color: 'white',
        width: 8
    })
});

const innerStyle = new Style({
    stroke: new Stroke({
        color: 'blue',
        width: 4
    })
});

Возврат:

return [
    outerStyle,
    innerStyle
];

В результате получается контур с эффектом свечения или выделения.


Класс RegularShape

Для создания геометрических символов применяется RegularShape.

import RegularShape from 'ol/style/RegularShape.js';

Треугольник:

image: new RegularShape({
    points: 3,
    radius: 10,
    fill: new Fill({
        color: 'red'
    })
})

Квадрат:

points: 4

Пятиугольник:

points: 5

Звёздчатые символы

Регулярные фигуры позволяют создавать звёзды.

image: new RegularShape({
    points: 5,
    radius: 12,
    radius2: 5,
    fill: new Fill({
        color: 'gold'
    })
})

Такое оформление часто используется для специальных объектов или тематических обозначений.


Управление прозрачностью

Практически любой элемент поддерживает альфа-канал.

Пример полигона:

fill: new Fill({
    color: 'rgba(52,152,219,0.25)'
})

Пример линии:

stroke: new Stroke({
    color: 'rgba(231,76,60,0.6)'
})

Прозрачность позволяет отображать несколько перекрывающихся слоёв без потери информации.


Стилизация различных типов геометрий

Для разных типов объектов обычно создаются отдельные наборы стилей.

Точки

CircleStyle

Линии

Stroke

Полигоны

Fill + Stroke

Универсальная функция:

function(feature) {

    const type = feature.getGeometry().getType();

    switch(type) {

        case 'Point':
            return pointStyle;

        case 'LineString':
            return lineStyle;

        case 'Polygon':
            return polygonStyle;
    }
}

Подобный подход особенно полезен при работе со смешанными наборами геометрий.


Лучшие практики стилизации

Использование кэширования стилей

  • уменьшает нагрузку на память;
  • ускоряет отрисовку.

Ограничение количества подписей

  • повышает читаемость карты;
  • улучшает производительность.

Применение прозрачности

  • делает многослойные карты более информативными.

Единая визуальная система

  • обеспечивает понятную картографическую символику;
  • упрощает восприятие данных.

Использование масштабно-зависимого оформления

  • предотвращает визуальную перегрузку;
  • улучшает пользовательский опыт.

Разделение логики и оформления

  • облегчает сопровождение проекта;
  • упрощает развитие картографического приложения.

Система стилизации OpenLayers предоставляет полный набор инструментов для построения профессионального картографического интерфейса: от простого изменения цвета объектов до сложной динамической символизации, основанной на атрибутах, масштабе отображения и пользовательской логике визуализации данных.