В библиотеке deck.gl всплывающие подсказки (tooltips) реализуются как слой взаимодействия между системой рендеринга и механизмом picking-событий WebGL. Основная задача tooltip-логики заключается в отображении контекстной информации о визуальных объектах без нарушения производительности и без необходимости дополнительного DOM-рендеринга для каждого кадра.
В основе лежит процесс picking — определение объекта сцены под курсором. Deck.gl выполняет его на уровне GPU, используя специальный буфер идентификаторов, сопоставляемых с объектами слоёв.
Механизм всплывающих подсказок опирается на три ключевых компонента:
1. Picking engine
object picking colorsinfo структуру с данными слоя и объекта2. Event pipeline
hover, click,
drag3. Tooltip renderer
При наведении курсора Deck.gl формирует объект info,
который является основой для tooltip-логики:
{
object: {}, // данные объекта слоя
index: 12, // индекс элемента
picked: true, // был ли объект найден
x: 350, // координата курсора X
y: 220, // координата курсора Y
layer: {}, // слой, который вернул объект
viewport: {} // текущая вьюпорт-конфигурация
}
На основе этих данных формируется содержимое всплывающей подсказки.
В React-интеграции через react deck.gl tooltip чаще всего
определяется через функцию getTooltip.
import DeckGL from '@deck.gl/react';
import {ScatterplotLayer} from '@deck.gl/layers';
const layer = new ScatterplotLayer({
id: 'scatter',
data: points,
getPosition: d => d.position,
getRadius: 100,
getFillColor: [255, 0, 0]
});
function getTooltip({object}) {
if (!object) return null;
return {
html: `<div><b>${object.name}</b><br/>Value: ${object.value}</div>`,
style: {
backgroundColor: 'white',
color: 'black',
fontSize: '12px'
}
};
}
export default function App() {
return (
<DeckGL
initialViewState={{longitude: 0, latitude: 0, zoom: 2}}
controller={true}
layers={[layer]}
getTooltip={getTooltip}
/>
);
}
Функция getTooltip вызывается при каждом движении мыши и
получает актуальный pickingInfo.
Tooltip может возвращать различные форматы:
HTML-строка
return {
html: `<div>${object.label}</div>`
};
Текстовый формат
return object.label;
DOM-стилизация
return {
html: `<div>${object.label}</div>`,
style: {
background: 'rgba(0,0,0,0.7)',
color: '#fff',
padding: '8px'
}
};
В низкоуровневом API через класс Deck tooltip реализуется через
callback getTooltip или обработчик событий.
import {Deck} from '@deck.gl/core';
import {ScatterplotLayer} from '@deck.gl/layers';
const deckgl = new Deck({
initialViewState: {
longitude: 10,
latitude: 50,
zoom: 4
},
controller: true,
layers: [
new ScatterplotLayer({
id: 'points',
data: points,
getPosition: d => d.position,
getRadius: 5000,
pickable: true
})
],
getTooltip: ({object}) =>
object && {
text: `${object.name}: ${object.value}`
}
});
Ключевое требование — pickable: true в слое, иначе
picking не активируется.
Низкоуровневый контроль достигается через обработчик
onHover, где tooltip полностью выносится в пользовательский
DOM.
const deckgl = new Deck({
layers: [layer],
onHover: info => {
const tooltip = document.getElementById('tooltip');
if (info.object) {
tooltip.style.display = 'block';
tooltip.style.left = info.x + 'px';
tooltip.style.top = info.y + 'px';
tooltip.innerHTML = info.object.name;
} else {
tooltip.style.display = 'none';
}
}
});
Этот подход позволяет:
Deck.gl не управляет абсолютным позиционированием tooltip автоматически в низкоуровневом режиме. Обычно используются экранные координаты:
info.xinfo.yПример CSS:
.tooltip {
position: absolute;
pointer-events: none;
transform: translate(10px, 10px);
}
При наличии нескольких слоёв поведение определяется:
pickableПервый подходящий объект возвращается как info.object,
даже если под курсором находится несколько слоёв.
При необходимости tooltip можно формировать на основе нескольких объектов:
getTooltip: (info) => {
if (!info.picked) return null;
return {
html: `
<div>
Layer: ${info.layer.id}<br/>
Index: ${info.index}<br/>
Value: ${info.object.value}
</div>
`
};
};
При движении мыши callback может вызываться десятки раз в секунду. Для снижения нагрузки применяются:
info.indexlet lastId = null;
function getTooltip(info) {
if (!info.object || info.index === lastId) return null;
lastId = info.index;
return {
text: info.object.name
};
}
В отличие от DOM-ориентированных библиотек, Deck.gl работает поверх WebGL, поэтому:
Это позволяет сохранять производительность даже при десятках тысяч объектов.
Tooltip часто используется совместно с внешними UI-фреймворками:
Пример через portal:
function Tooltip({info}) {
if (!info.object) return null;
return createPortal(
<div className="tooltip">
{info.object.name}
</div>,
document.body
);
}
Когда курсор не попадает на объект:
info.object === nullЭто важно для предотвращения мерцания интерфейса при движении курсора по пустым областям карты или сцены.
Tooltip в Deck.gl применяется не только для отображения данных, но и для:
В сложных сценах tooltip становится инструментом интроспекции слоя, предоставляя доступ к внутренним данным визуализации без изменения рендера сцены.