TextLayer — специализированный слой библиотеки Deck.gl, предназначенный для отображения текстовых подписей в геопространственных визуализациях. Слой позволяет размещать отдельные строки текста над картой, поверх объектов других слоёв и в произвольных координатах.
TextLayer используется для отображения:
Внутри TextLayer применяется технология рендеринга символов через текстурный атлас (glyph atlas), что позволяет эффективно отображать тысячи подписей одновременно с использованием GPU.
import {Deck} from '@deck.gl/core';
import {TextLayer} from '@deck.gl/layers';
Простейший пример:
const data = [
{
position: [37.6176, 55.7558],
name: 'Москва'
}
];
const textLayer = new TextLayer({
id: 'cities',
data,
getPosition: d => d.position,
getText: d => d.name
});
new Deck({
initialViewState: {
longitude: 37.6176,
latitude: 55.7558,
zoom: 5
},
controller: true,
layers: [textLayer]
});
В результате над указанными координатами появится текстовая подпись.
Обычно каждый элемент массива содержит:
{
position: [37.6176, 55.7558],
name: 'Москва'
}
Либо более сложный набор данных:
{
id: 1,
city: 'Москва',
population: 13000000,
coordinates: [37.6176, 55.7558]
}
Настройка доступа к данным:
new TextLayer({
data,
getPosition: d => d.coordinates,
getText: d => d.city
});
Функция getText определяет текст, который будет отображён для каждого объекта.
Пример:
getText: d => d.name
Формирование строки из нескольких полей:
getText: d =>
`${d.city} (${d.population})`
Использование вычисляемого значения:
getText: d =>
`${d.temperature}°C`
Многострочный текст:
getText: d =>
`${d.city}\n${d.population}`
Результат:
Москва
13000000
Deck.gl автоматически поддерживает перенос строк через символ
\n.
Положение подписи задаётся через accessor getPosition.
getPosition: d => d.position
Формат координат:
[longitude, latitude]
Пример:
[30.3158, 59.9391]
Для работы в трёхмерном пространстве можно использовать высоту:
getPosition: d => [
d.lng,
d.lat,
d.altitude
]
Например:
getPosition: d => [
37.6176,
55.7558,
1000
]
Текст будет поднят на высоту 1000 метров относительно поверхности.
Размер текста определяется свойством getSize.
getSize: 18
Или динамически:
getSize: d => d.population / 1000000
Пример:
new TextLayer({
data,
getText: d => d.city,
getPosition: d => d.position,
getSize: d =>
Math.sqrt(d.population)
});
Крупные города будут отображаться более заметно.
Для управления цветом используется getColor.
Формат:
[r, g, b]
или
[r, g, b, a]
Примеры:
getColor: [255, 255, 255]
Белый цвет.
getColor: [255, 0, 0]
Красный цвет.
Полупрозрачный текст:
getColor: [255, 255, 255, 150]
Динамический выбор:
getColor: d =>
d.population > 5000000
? [255, 0, 0]
: [0, 200, 255]
Свойство fontFamily определяет используемый шрифт.
fontFamily: 'Arial'
Другие варианты:
fontFamily: 'Roboto'
fontFamily: 'Verdana'
fontFamily: 'Helvetica'
Пример:
new TextLayer({
fontFamily: 'Roboto'
});
При смене шрифта Deck.gl автоматически пересоздаёт текстурный атлас символов.
Свойство fontWeight управляет насыщенностью.
fontWeight: 'normal'
Жирный вариант:
fontWeight: 'bold'
Числовые значения:
fontWeight: 300
fontWeight: 600
fontWeight: 700
Пример:
new TextLayer({
fontWeight: 700
});
По умолчанию размер текста зависит от масштаба карты.
Контроль осуществляется через sizeUnits.
sizeUnits: 'meters'
Размер будет измеряться в реальных метрах.
new TextLayer({
getSize: 200,
sizeUnits: 'meters'
});
Подходит для пространственных объектов.
sizeUnits: 'pixels'
Размер сохраняется визуально постоянным.
new TextLayer({
getSize: 16,
sizeUnits: 'pixels'
});
Наиболее распространённый режим для подписей городов.
sizeUnits: 'common'
Используется реже и зависит от системы координат слоя.
sizeMinPixels: 10
Даже при сильном уменьшении карты текст останется читаемым.
sizeMaxPixels: 48
Предотвращает чрезмерное увеличение подписей.
Полный пример:
new TextLayer({
getSize: d => d.population / 500000,
sizeMinPixels: 10,
sizeMaxPixels: 40
});
Свойство getTextAnchor.
Возможные значения:
'start'
'middle'
'end'
Пример:
getTextAnchor: 'middle'
Точка координат будет располагаться в центре текста.
Схематично:
start
X Москва
middle
Москва
X
end
Москва X
Используется свойство getAlignmentBaseline.
Возможные варианты:
'top'
'center'
'bottom'
Пример:
getAlignmentBaseline: 'center'
Координата будет соответствовать центру текстового блока.
Для смещения используется getPixelOffset.
Пример:
getPixelOffset: [20, -10]
Где:
[xOffset, yOffset]
Например, подпись можно вынести выше точки:
new TextLayer({
getPosition: d => d.position,
getPixelOffset: [0, -15]
});
Типичная комбинация с IconLayer:
layers: [
iconLayer,
textLayer
]
Текст располагается над иконкой.
Свойство getAngle задаёт угол поворота.
getAngle: 0
getAngle: 45
getAngle: 90
Динамический вариант:
getAngle: d => d.direction
Пример:
new TextLayer({
getAngle: d => d.rotation
});
Угол измеряется в градусах.
Прозрачность задаётся альфа-каналом.
getColor: [255, 255, 255, 100]
Полностью непрозрачный текст:
getColor: [255, 255, 255, 255]
Полностью скрытый:
getColor: [255, 255, 255, 0]
Часто применяется для анимаций появления и исчезновения.
TextLayer поддерживает механизм picking.
Включение:
pickable: true
Обработка события:
new TextLayer({
pickable: true,
onClick: info => {
console.log(info.object);
}
});
Получение объекта:
{
city: 'Москва',
population: 13000000
}
Совместное использование с Deck Tooltip:
new Deck({
getTooltip: ({object}) =>
object && {
text: `${object.city}`
}
});
Слой:
new TextLayer({
pickable: true
});
При наведении появляется информационная подсказка.
TextLayer оптимизирован для отображения большого объёма данных.
Пример:
const cities = new Array(10000)
.fill(null)
.map((_, i) => ({
name: `City ${i}`,
position: [
Math.random() * 360 - 180,
Math.random() * 180 - 90
]
}));
Отображение:
new TextLayer({
data: cities,
getPosition: d => d.position,
getText: d => d.name
});
Рендеринг остаётся быстрым благодаря:
Изменение массива автоматически приводит к обновлению слоя.
textLayer = new TextLayer({
id: 'cities',
data: updatedData,
getPosition: d => d.position,
getText: d => d.name
});
В React:
const layer = new TextLayer({
data,
getPosition: d => d.position,
getText: d => d.name
});
После изменения состояния компонент перерисует слой.
layers: [
new ScatterplotLayer({
data,
getPosition: d => d.position,
getRadius: 5000
}),
new TextLayer({
data,
getPosition: d => d.position,
getText: d => d.name,
getPixelOffset: [0, -15]
})
]
Точки получают подписи.
layers: [
iconLayer,
new TextLayer({
data,
getPosition: d => d.position,
getText: d => d.label,
getPixelOffset: [0, -25]
})
]
Подходит для отображения маркеров и названий объектов.
layers: [
columnLayer,
new TextLayer({
data,
getPosition: d => [
d.lng,
d.lat,
d.height
],
getText: d => d.value.toString()
})
]
Текст размещается над трёхмерными колонками.
Deck.gl может заранее определить набор символов.
characterSet: 'auto'
Автоматический режим.
Явный список:
characterSet:
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Поддержка кириллицы:
characterSet:
'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'
Полезно для оптимизации памяти.
Настройки создания текстурного атласа.
Пример:
fontSettings: {
fontSize: 64,
buffer: 4
}
Параметры:
| Параметр | Назначение |
|---|---|
| fontSize | Размер символов в атласе |
| buffer | Отступ между символами |
| sdf | Использование Signed Distance Field |
| radius | Радиус генерации SDF |
Технология SDF позволяет сохранять высокую чёткость текста при масштабировании.
Включение:
fontSettings: {
sdf: true
}
Преимущества:
Особенно полезно для крупных картографических приложений и систем мониторинга.
Причины:
getText: d => d.title
при отсутствии поля:
{
name: 'Москва'
}
Необходимо проверить структуру данных.
Ошибочный порядок:
[latitude, longitude]
Правильно:
[longitude, latitude]
Следует увеличить:
getSize
или установить:
sizeMinPixels
Используется смещение:
getPixelOffset: [0, -20]
Рекомендуется включить SDF:
fontSettings: {
sdf: true
}
или увеличить размер атласа:
fontSettings: {
fontSize: 64
}
import {TextLayer} from '@deck.gl/layers';
const layer = new TextLayer({
id: 'cities',
data: [
{
city: 'Москва',
population: 13000000,
position: [37.6176, 55.7558]
},
{
city: 'Санкт-Петербург',
population: 5600000,
position: [30.3158, 59.9391]
}
],
pickable: true,
getPosition: d => d.position,
getText: d =>
`${d.city}\n${d.population.toLocaleString()}`,
getSize: d =>
Math.sqrt(d.population) / 150,
getColor: [255, 255, 255],
getTextAnchor: 'middle',
getAlignmentBaseline: 'bottom',
getPixelOffset: [0, -10],
sizeUnits: 'pixels',
sizeMinPixels: 12,
sizeMaxPixels: 40,
fontFamily: 'Roboto',
fontWeight: 600,
fontSettings: {
sdf: true
}
});
Данный пример демонстрирует большинство возможностей TextLayer: динамический текст, масштабирование размера, поддержку кириллицы, взаимодействие с пользователем, выравнивание, настройку шрифта и качественный рендеринг текста при любых уровнях масштабирования карты.