Accessor-функции представляют собой один из ключевых механизмов преобразования данных в визуальные атрибуты слоёв. Они позволяют отделить источник данных от логики их отображения, обеспечивая гибкость, переиспользуемость и декларативность описания визуализации.
В основе большинства слоёв deck.gl лежит идея: каждый визуальный примитив (точка, линия, полигон, инстанс) получает набор атрибутов, которые затем передаются в WebGL-шейдеры. Accessor-функции определяют, как именно из входного объекта данных получить значение этих атрибутов.
При построении слоя deck.gl проходит несколько этапов:
data)Accessor-функции участвуют на втором этапе, формируя промежуточное представление данных.
Каждый слой может принимать параметры вида:
getPosition: d => d.coordinates,
getColor: d => [255, 0, 0],
getWidth: d => d.size
Эти функции вызываются для каждого элемента массива
data.
Accessor в deck.gl — это функция вида:
(d, {index, data, target}) => any
Где:
d — текущий объект данныхindex — индекс элементаdata — весь массив данныхtarget — предварительно выделенный массив (оптимизация
памяти)Пример использования:
getPosition: (d, {index}) => {
return [d.lon, d.lat];
}
Accessor-функции могут возвращать разные типы данных в зависимости от атрибута слоя.
Используются для координат и цветов:
getPosition: d => [d.x, d.y, d.z],
getColor: d => [255, d.intensity, 0, 255]
Важно, что размер массива должен соответствовать ожиданиям слоя (например, 2D или 3D координаты).
Используются для ширины, высоты, радиуса:
getRadius: d => d.value * 10,
getWidth: d => Math.sqrt(d.weight)
Accessor может включать произвольную логику:
getColor: d => {
if (d.type === 'A') return [255, 0, 0];
if (d.type === 'B') return [0, 255, 0];
return [0, 0, 255];
}
Для больших датасетов важно избегать лишних аллокаций массивов.
deck.gl предоставляет target:
getPosition: (d, {target}) => {
target[0] = d.x;
target[1] = d.y;
target[2] = d.z;
return target;
}
Это снижает нагрузку на GC и ускоряет рендеринг.
Если accessor не указан как функция, можно использовать строку:
getPosition: 'coordinates'
В этом случае deck.gl автоматически извлекает значение из объекта:
d['coordinates']
Это упрощённая форма, которая особенно полезна при работе с плоскими структурами данных.
Accessor-функции могут использовать индекс и внешний контекст:
getColor: (d, {index, data}) => {
return index % 2 === 0 ? [255, 0, 0] : [0, 0, 255];
}
Это позволяет создавать визуальные паттерны, зависящие не только от данных, но и от их положения в массиве.
Внутри deck.gl accessor-функции компилируются в атрибуты через
AttributeManager. Процесс выглядит следующим образом:
getPosition)Таким образом accessor — это мост между JavaScript-данными и GPU-атрибутами.
Для повышения производительности deck.gl может кэшировать результаты accessor-функций, если:
Это особенно важно для сложных вычислений:
getElevation: d => Math.sin(d.value) * 1000
Без кэширования такие вычисления на больших массивах становятся узким местом.
Accessor-функции в deck.gl должны быть синхронными. Недопустимы конструкции вида:
getColor: async d => {
const res = await fetch(...);
return res.color;
}
Все данные должны быть подготовлены заранее до рендеринга. Асинхронная логика выносится на уровень загрузки данных.
Accessor может работать с вложенными объектами:
getPosition: d => d.geometry.coordinates,
getColor: d => d.properties.style.color
При этом важно учитывать стоимость доступа к глубоким структурам при больших объёмах данных.
Accessor часто используется вместе с преобразованием данных перед передачей в слой:
const data = rawData.map(d => ({
position: [d.x, d.y],
color: d.value > 10 ? [255, 0, 0] : [0, 0, 255]
}));
new ScatterplotLayer({
data,
getPosition: d => d.position,
getColor: d => d.color
});
Такой подход снижает вычислительную нагрузку внутри accessor.
Accessor-функции могут выноситься в отдельные модули:
export const getDefaultColor = d =>
d.active ? [0, 200, 0] : [200, 0, 0];
И использоваться в разных слоях:
getColor: getDefaultColor
Это повышает консистентность визуализации между слоями.
Наиболее распространённые проблемы:
Оптимизация обычно сводится к минимизации работы внутри accessor и переносу вычислений на этап подготовки данных.
При изменении data accessor-функции пересчитываются. При
этом deck.gl старается минимизировать перерасчёт:
Accessor-функции усиливают декларативный характер deck.gl. Вместо императивного описания рендеринга задаётся правило трансформации данных:
Это делает слой независимым от структуры данных и упрощает композицию визуализаций.