Градиенты и эффекты

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


В HERE Maps API основа визуального представления строится на объекте карты:

const platform = new H.service.Platform({
  apikey: 'YOUR_API_KEY'
});

const layers = platform.createDefaultLayers();

const map = new H.Map(
  document.getElementById('mapContainer'),
  layers.vector.normal.map,
  {
    center: { lat: 50.4501, lng: 30.5234 },
    zoom: 10,
    pixelRatio: window.devicePixelRatio
  }
);

Система рендеринга разделяет:

  • базовые тайлы (векторные или растровые),
  • динамические объекты (маршруты, маркеры),
  • пользовательские слои (Canvas, DOM, WebGL).

Именно пользовательские слои позволяют реализовывать градиенты и эффекты, выходящие за рамки стандартного стиля.


Цветовые градиенты в векторной стилизации

Векторные тайлы HERE поддерживают стилевые выражения, где цвет может задаваться через интерполяцию значений.

Типичный подход — использование шкалы значений:

const style = {
  layers: {
    'water': {
      fillColor: '#a0d8ef'
    },
    'road': {
      color: [
        'interpolate',
        ['linear'],
        ['zoom'],
        5, '#cccccc',
        10, '#888888',
        15, '#444444'
      ]
    }
  }
};

Ключевой механизм — интерполяция:

  • линейная (linear) — плавный переход,
  • ступенчатая (step) — резкие переходы.

Градиент здесь применяется не как CSS-градиент, а как функция зависимости цвета от масштаба или атрибутов объекта.


Линейные градиенты через Canvas Overlay

Для более гибких эффектов используется слой Canvas:

const canvasLayer = new H.map.layer.CanvasLayer(function (ctx, renderParams) {
  const canvas = ctx.canvas;
  const width = canvas.width;
  const height = canvas.height;

  const gradient = ctx.createLinearGradient(0, 0, width, 0);

  gradient.addColorStop(0, 'rgba(0, 150, 255, 0.2)');
  gradient.addColorStop(1, 'rgba(0, 50, 200, 0.6)');

  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, width, height);
});

map.addLayer(canvasLayer);

Характерные сценарии:

  • затемнение части карты,
  • визуальное выделение зон интереса,
  • наложение климатических или аналитических слоёв.

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


Радиальные градиенты и фокусные зоны

Радиальные градиенты используются для выделения центральных точек интереса:

const radialLayer = new H.map.layer.CanvasLayer(function (ctx) {
  const centerX = ctx.canvas.width / 2;
  const centerY = ctx.canvas.height / 2;

  const gradient = ctx.createRadialGradient(
    centerX, centerY, 10,
    centerX, centerY, 300
  );

  gradient.addColorStop(0, 'rgba(255, 200, 0, 0.5)');
  gradient.addColorStop(1, 'rgba(255, 200, 0, 0)');

  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
});

map.addLayer(radialLayer);

Такие эффекты используются для:

  • визуализации радиуса влияния,
  • подсветки событий,
  • отображения плотности вокруг центра.

Градиентные линии маршрутов

Полилинии в HERE Maps стандартно имеют один цвет, но градиент реализуется через разбиение линии на сегменты.

const points = [
  { lat: 50.45, lng: 30.52 },
  { lat: 50.46, lng: 30.53 },
  { lat: 50.47, lng: 30.55 }
];

for (let i = 0; i < points.length - 1; i++) {
  const segment = new H.map.Polyline(
    new H.geo.LineString().pushPoint(points[i]).pushPoint(points[i + 1]),
    {
      style: {
        strokeColor: `rgba(0, 100, 255, ${i / points.length})`,
        lineWidth: 5
      }
    }
  );

  map.addObject(segment);
}

Более сложный вариант — вычисление цветовой шкалы по скорости, высоте или времени.


Тепловые карты (Heatmap) как градиент плотности

Heatmap — один из наиболее прямых способов отображения градиента плотности данных.

const dataPoints = [
  { lat: 50.45, lng: 30.52, value: 10 },
  { lat: 50.46, lng: 30.53, value: 30 },
  { lat: 50.47, lng: 30.55, value: 80 }
];

const heatmapProvider = new H.data.heatmap.Provider({
  colors: new H.data.heatmap.Colors({
    '0': 'blue',
    '0.5': 'yellow',
    '1': 'red'
  })
});

dataPoints.forEach(p => {
  heatmapProvider.addDataPoint(p.lat, p.lng, p.value);
});

const heatmapLayer = new H.map.layer.TileLayer(heatmapProvider);

map.addLayer(heatmapLayer);

Ключевые параметры:

  • плотность точек,
  • радиус влияния,
  • цветовая шкала.

Heatmap фактически является динамическим радиальным градиентом, наложенным на множество точек.


Градиенты в маркерах и иконках

Маркерные эффекты часто реализуются через SVG или Canvas-иконки.

const svg = `
<svg width="40" height="40">
  <defs>
    <radialGradient id="grad">
      <stop offset="0%" stop-color="red"/>
      <stop offset="100%" stop-color="transparent"/>
    </radialGradient>
  </defs>
  <circle cx="20" cy="20" r="15" fill="url(#grad)"/>
</svg>
`;

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

const marker = new H.map.Marker(
  { lat: 50.45, lng: 30.52 },
  { icon }
);

map.addObject(marker);

Такие маркеры применяются для:

  • событий в реальном времени,
  • визуализации сигналов,
  • динамических индикаторов активности.

Динамические эффекты прозрачности и наложения

Эффекты часто строятся на изменении alpha-канала:

const circle = new H.map.Circle(
  { lat: 50.45, lng: 30.52 },
  1000,
  {
    style: {
      fillColor: 'rgba(0, 150, 255, 0.2)',
      strokeColor: 'rgba(0, 150, 255, 0.8)',
      lineWidth: 2
    }
  }
);

map.addObject(circle);

Комбинация прозрачностей позволяет:

  • создавать слои глубины,
  • накладывать несколько аналитических зон,
  • избегать визуального перегруза.

Анимационные градиенты

Динамика достигается через перерисовку Canvas слоя:

let alpha = 0;
let direction = 1;

const animatedLayer = new H.map.layer.CanvasLayer(function (ctx) {
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

  const gradient = ctx.createRadialGradient(
    200, 200, 10,
    200, 200, 150
  );

  gradient.addColorStop(0, `rgba(0, 200, 255, ${alpha})`);
  gradient.addColorStop(1, 'rgba(0, 200, 255, 0)');

  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
});

setInterval(() => {
  alpha += 0.02 * direction;

  if (alpha >= 0.6 || alpha <= 0.1) {
    direction *= -1;
  }

  animatedLayer.getProvider().refresh();
}, 50);

map.addLayer(animatedLayer);

Анимационные градиенты применяются для:

  • пульсации событий,
  • обозначения активности,
  • визуализации сигналов GPS или IoT.

Комбинирование эффектов слоёв

Сложные визуализации строятся как стек слоёв:

  • базовая карта,
  • heatmap слой,
  • canvas overlay с градиентом,
  • маркеры событий,
  • анимированные эффекты.

Порядок наложения критичен, так как влияет на читаемость данных.


Производственные ограничения и оптимизация

Градиентные эффекты чувствительны к нагрузке GPU и CPU:

  • частая перерисовка Canvas снижает FPS,
  • большое количество сегментов линий увеличивает стоимость рендера,
  • heatmap с высокой плотностью требует оптимизации радиуса влияния,
  • SVG-маркеры тяжелее растровых иконок.

Практика оптимизации:

  • минимизация перерисовок (requestAnimationFrame вместо setInterval),
  • кэширование Canvas-слоёв,
  • агрегация точек перед heatmap,
  • ограничение количества одновременно активных эффектов.