Паттерны и градиенты

В HERE Maps JavaScript API базовая стилизация пространственных объектов ограничивается сплошными цветами, прозрачностью, толщиной линий и простыми штриховками. При необходимости более сложного визуального языка применяются паттерны, реализуемые через несколько подходов: тайловые стили, повторяющиеся иконки и канвасные текстуры.

Повторяющиеся паттерны в линиях через иконки

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

const lineString = new H.geo.LineString();
lineString.pushPoint({ lat: 52.5, lng: 13.4 });
lineString.pushPoint({ lat: 52.51, lng: 13.45 });

const polyline = new H.map.Polyline(lineString, {
  style: {
    lineWidth: 6,
    strokeColor: '#3366FF'
  }
});

map.addObject(polyline);

Для имитации паттерна поверх линии используется серия маркеров с одинаковой иконкой, распределённых по геометрии:

const icon = new H.map.Icon('dot.svg');

const strip = new H.geo.LineString([
  { lat: 52.5, lng: 13.4 },
  { lat: 52.51, lng: 13.45 }
]);

const points = strip.getLatLngAltArray();

for (let i = 0; i < points.length; i += 3) {
  const marker = new H.map.Marker(
    { lat: points[i], lng: points[i + 1] },
    { icon }
  );
  map.addObject(marker);
}

Такой подход создаёт эффект пунктирного или символического паттерна, особенно полезного для отображения трасс, потоков или маршрутов.

Тайловые паттерны через Vector Tile Styling

Более системный способ работы с паттернами реализуется через векторные тайлы HERE. В стиле слоёв поддерживаются свойства fill-pattern и line-pattern, позволяющие задавать повторяющиеся изображения.

Пример фрагмента стиля:

{
  "layers": {
    "water": {
      "draw": {
        "polygons": {
          "fill": "#a0c8f0",
          "fill-pattern": "wave_texture"
        }
      }
    }
  }
}

Иконка wave_texture заранее определяется в стиле и может ссылаться на изображение или спрайт. Такой подход используется для больших данных, где ручная отрисовка через маркеры становится неэффективной.

Canvas-паттерны для полигонов

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

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

canvas.width = 20;
canvas.height = 20;

ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, 20, 20);

ctx.strokeStyle = '#cccccc';
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(20, 20);
ctx.stroke();

const pattern = ctx.createPattern(canvas, 'repeat');

Далее такой паттерн используется в кастомном рендерере или при отрисовке поверх карты через overlay-слой. В чистом API HERE это требует интеграции с DOM/Canvas слоями.


Градиенты в линейной и площадной геометрии

Градиентная заливка в картографических системах представляет собой более сложную задачу, так как геометрические примитивы HERE Maps по умолчанию не поддерживают плавные переходы цветов внутри одного объекта.

Линейные градиенты через сегментацию

Наиболее распространённый метод — разбиение линии на множество сегментов с постепенным изменением цвета.

function interpolateColor(color1, color2, factor) {
  const c1 = parseInt(color1.slice(1), 16);
  const c2 = parseInt(color2.slice(1), 16);

  const r1 = (c1 >> 16) & 255;
  const g1 = (c1 >> 8) & 255;
  const b1 = c1 & 255;

  const r2 = (c2 >> 16) & 255;
  const g2 = (c2 >> 8) & 255;
  const b2 = c2 & 255;

  const r = Math.round(r1 + factor * (r2 - r1));
  const g = Math.round(g1 + factor * (g2 - g1));
  const b = Math.round(b1 + factor * (b2 - b1));

  return `rgb(${r},${g},${b})`;
}

Далее линия строится как серия коротких полилиний:

const coords = [
  { lat: 52.5, lng: 13.4 },
  { lat: 52.505, lng: 13.41 },
  { lat: 52.51, lng: 13.42 }
];

for (let i = 0; i < coords.length - 1; i++) {
  const factor = i / (coords.length - 1);

  const segment = new H.map.Polyline(
    new H.geo.LineString([
      coords[i],
      coords[i + 1]
    ]),
    {
      style: {
        strokeColor: interpolateColor('#00ff00', '#ff0000', factor),
        lineWidth: 5
      }
    }
  );

  map.addObject(segment);
}

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

Радиальные и площадные градиенты через Canvas

Для полигонов более гибким решением является использование Canvas с радиальными или линейными градиентами.

const canvas = document.createElement('canvas');
canvas.width = 200;
canvas.height = 200;

const ctx = canvas.getContext('2d');

const gradient = ctx.createRadialGradient(100, 100, 10, 100, 100, 100);
gradient.addColorStop(0, 'rgba(0, 150, 255, 0.8)');
gradient.addColorStop(1, 'rgba(0, 150, 255, 0)');

ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 200, 200);

Далее такой canvas используется как текстура или накладывается через DOM-иконку:

const icon = new H.map.DomIcon(canvas.toDataURL());

const marker = new H.map.DomMarker(
  { lat: 52.5, lng: 13.4 },
  { icon }
);

map.addObject(marker);

Этот подход особенно эффективен для тепловых зон, радиусов влияния и визуализации плотности.

Аппроксимация градиентов в полигонах

Для полигональных областей градиенты часто имитируются через вложенные полигоны с разной прозрачностью:

const outer = new H.map.Polygon(outerShape, {
  style: {
    fillColor: 'rgba(255,0,0,0.1)'
  }
});

const inner = new H.map.Polygon(innerShape, {
  style: {
    fillColor: 'rgba(255,0,0,0.4)'
  }
});

map.addObjects([outer, inner]);

Так создаётся эффект концентрации цвета без прямой поддержки градиентной заливки.


Комбинированные визуальные эффекты

Паттерн + градиент в одном слое

Сложные визуализации часто комбинируют текстуры и цветовые переходы. Например, вода может иметь базовый градиент и поверх него — повторяющийся шумовой паттерн.

const base = new H.map.Polygon(shape, {
  style: {
    fillColor: 'rgba(0, 100, 200, 0.5)'
  }
});

const overlay = new H.map.Polygon(shape, {
  style: {
    fillColor: 'rgba(0, 0, 0, 0.1)'
  }
});

Перекрытие объектов формирует визуальную глубину.

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

При необходимости высокой производительности и сложных визуальных эффектов применяется WebGL-слой поверх карты. Он позволяет реализовать:

  • плавные цветовые переходы вдоль геометрии
  • процедурные текстуры
  • динамические паттерны
  • шумовые функции (Perlin noise, simplex noise)

Такая реализация выходит за пределы стандартного API объектов карты и требует отдельного рендеринга поверх canvas WebGL контекста, синхронизированного с камерой карты.


Особенности производительности при работе с визуальными стилями

Избыточное количество объектов для имитации паттернов или градиентов приводит к росту нагрузки на слой отрисовки. Основные ограничения проявляются в следующих сценариях:

  • большое число сегментированных полилиний
  • массовое использование DOM-иконок
  • пересчёт градиентов при каждом движении карты

Оптимизация достигается через:

  • агрегацию геометрии
  • перенос визуальных эффектов в тайловые стили
  • использование canvas-кеширования
  • минимизацию количества независимых объектов на карте

Практика выбора подхода

  • Тайловые стили (fill-pattern, line-pattern) применяются при работе с большими наборами данных и векторными слоями
  • Canvas-паттерны используются для кастомных локальных эффектов
  • Сегментация линий подходит для динамических данных с изменяемыми значениями
  • DOM-иконки эффективны для точечных визуальных акцентов
  • WebGL-слои применяются для сложных визуализаций высокой плотности