В 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);
}
Такой подход создаёт эффект пунктирного или символического паттерна, особенно полезного для отображения трасс, потоков или маршрутов.
Более системный способ работы с паттернами реализуется через
векторные тайлы HERE. В стиле слоёв поддерживаются свойства
fill-pattern и line-pattern, позволяющие
задавать повторяющиеся изображения.
Пример фрагмента стиля:
{
"layers": {
"water": {
"draw": {
"polygons": {
"fill": "#a0c8f0",
"fill-pattern": "wave_texture"
}
}
}
}
}
Иконка wave_texture заранее определяется в стиле и может
ссылаться на изображение или спрайт. Такой подход используется для
больших данных, где ручная отрисовка через маркеры становится
неэффективной.
При необходимости локальной кастомизации применяется 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 с радиальными или линейными градиентами.
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-слой поверх карты. Он позволяет реализовать:
Такая реализация выходит за пределы стандартного API объектов карты и требует отдельного рендеринга поверх canvas WebGL контекста, синхронизированного с камерой карты.
Избыточное количество объектов для имитации паттернов или градиентов приводит к росту нагрузки на слой отрисовки. Основные ограничения проявляются в следующих сценариях:
Оптимизация достигается через:
fill-pattern,
line-pattern) применяются при работе с большими наборами
данных и векторными слоями