Стилизация точек

OpenLayers использует объектную модель стилей, в которой визуальное представление точечных объектов определяется через комбинацию классов ol.style.Style, ol.style.Circle, ol.style.Fill, ol.style.Stroke, а также функций динамической стилизации. Такой подход позволяет управлять отображением геометрий на основе свойств объектов, масштаба карты и внешних условий.

Точечные объекты векторного слоя отображаются через стиль, связанный либо с самим слоем, либо с отдельной геометрией. Основной класс, определяющий внешний вид, — ol.style.Style. Он инкапсулирует визуальные параметры для различных типов геометрий, включая точки.

Типичный минимальный стиль точки задаётся через image, внутри которого используется ol.style.Circle:

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

const pointStyle = new Style({
  image: new CircleStyle({
    radius: 6,
    fill: new Fill({
      color: 'rgba(30, 144, 255, 0.8)'
    }),
    stroke: new Stroke({
      color: '#1e90ff',
      width: 2
    })
  })
});

Такой стиль определяет точку как круг с заливкой и обводкой. Параметр radius задаёт размер в пикселях в экранной системе координат.

CircleStyle как основной инструмент отображения точек

ol.style.Circle представляет собой один из наиболее часто используемых способов рендеринга точечных данных. Его свойства:

  • radius — радиус в пикселях
  • fill — заливка (ol.style.Fill)
  • stroke — обводка (ol.style.Stroke)

При этом визуальный результат не зависит от географической системы координат, так как отрисовка выполняется в экранных единицах.

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

const largePoint = new Style({
  image: new CircleStyle({
    radius: 12,
    fill: new Fill({ color: 'rgba(255, 0, 0, 0.6)' }),
    stroke: new Stroke({ color: '#ff0000', width: 3 })
  })
});

Fill и Stroke в контексте точек

Fill определяет внутреннюю часть символа точки, тогда как Stroke управляет границей.

Fill

new Fill({
  color: 'rgba(0, 200, 0, 0.5)'
})

Поддерживаются форматы:

  • rgba
  • rgb
  • hex
  • named colors

Stroke

new Stroke({
  color: '#333333',
  width: 1.5,
  lineCap: 'round',
  lineJoin: 'round'
})

Параметры lineCap и lineJoin особенно заметны при использовании сложных символов или при увеличенных радиусах.

Динамическая стилизация через функцию

На практике статические стили применяются редко. Основной механизм гибкости — функция стиля, возвращающая Style или массив стилей на основе объекта feature и текущего масштаба.

const dynamicStyle = function(feature, resolution) {
  const type = feature.get('type');

  if (type === 'city') {
    return new Style({
      image: new CircleStyle({
        radius: 10,
        fill: new Fill({ color: 'blue' })
      })
    });
  }

  if (type === 'village') {
    return new Style({
      image: new CircleStyle({
        radius: 5,
        fill: new Fill({ color: 'green' })
      })
    });
  }
};

Функция принимает:

  • feature — объект слоя
  • resolution — текущее разрешение карты

Учет масштаба через resolution

Параметр resolution позволяет изменять визуализацию в зависимости от уровня масштабирования карты. Чем больше значение resolution, тем менее детализированная карта.

Пример адаптивного изменения размера точки:

const scaleDependentStyle = function(feature, resolution) {
  const baseRadius = 10;
  const radius = Math.max(baseRadius / resolution, 2);

  return new Style({
    image: new CircleStyle({
      radius: radius,
      fill: new Fill({ color: 'rgba(0, 0, 255, 0.6)' })
    })
  });
};

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

Использование текста в точечных стилях

Текст добавляется через свойство text объекта Style. Он применяется поверх или рядом с точкой.

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

const labeledStyle = new Style({
  image: new CircleStyle({
    radius: 6,
    fill: new Fill({ color: '#ffcc00' })
  }),
  text: new Text({
    text: 'Объект',
    offsetY: -15,
    fill: new Fill({
      color: '#000'
    }),
    stroke: new Stroke({
      color: '#fff',
      width: 3
    })
  })
});

Параметры текста:

  • font — шрифт CSS
  • text — содержимое
  • offsetX, offsetY — смещение
  • rotation — поворот текста
  • scale — масштабирование

Стилевые функции с учетом свойств feature

Стили часто зависят от атрибутов объекта:

const propertyBasedStyle = function(feature) {
  const population = feature.get('population');

  let radius = 5;

  if (population > 1000000) radius = 15;
  else if (population > 100000) radius = 10;

  return new Style({
    image: new CircleStyle({
      radius: radius,
      fill: new Fill({ color: 'rgba(200, 0, 0, 0.6)' })
    })
  });
};

Такой подход обеспечивает визуальную иерархию точек.

Множественные стили для одной точки

Feature может возвращать массив стилей, что позволяет накладывать эффекты:

const multiStyle = function(feature) {
  return [
    new Style({
      image: new CircleStyle({
        radius: 8,
        fill: new Fill({ color: 'blue' })
      })
    }),
    new Style({
      image: new CircleStyle({
        radius: 14,
        stroke: new Stroke({
          color: 'rgba(0, 0, 255, 0.3)',
          width: 6
        })
      })
    })
  ];
};

Это используется для создания эффекта свечения или внешнего ореола.

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

При большом количестве точек критически важно учитывать стоимость вычисления стиля. Основные принципы:

  • избегание создания новых объектов стиля при каждом вызове функции
  • переиспользование экземпляров Style
  • кэширование по типу feature
  • минимизация вычислений внутри style function

Пример кэширования:

const cache = {};

function getStyle(type) {
  if (!cache[type]) {
    cache[type] = new Style({
      image: new CircleStyle({
        radius: 6,
        fill: new Fill({
          color: type === 'A' ? 'red' : 'green'
        })
      })
    });
  }
  return cache[type];
}

Влияние кластеризации на стили точек

При работе с плотными наборами данных применяется кластеризация. В этом случае стиль определяется не отдельной точкой, а группой объектов.

const clusterStyle = function(feature) {
  const size = feature.get('features').length;

  return new Style({
    image: new CircleStyle({
      radius: 10 + size,
      fill: new Fill({
        color: 'rgba(0, 150, 136, 0.6)'
      })
    }),
    text: new Text({
      text: size.toString(),
      fill: new Fill({ color: '#fff' })
    })
  });
};

Размер и текст визуально отражают количество объектов в кластере.

Цветовые схемы и семантическое кодирование

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

function getColor(status) {
  switch (status) {
    case 'active': return 'green';
    case 'inactive': return 'gray';
    case 'error': return 'red';
    default: return 'blue';
  }
}

const statusStyle = function(feature) {
  return new Style({
    image: new CircleStyle({
      radius: 7,
      fill: new Fill({
        color: getColor(feature.get('status'))
      })
    })
  });
};

Такой подход упрощает визуальную интерпретацию данных.

Комбинация геометрических и визуальных слоев

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