Работа с несколькими слоями deck.gl
Вы можете отрисовывать на карте MapGL JS API несколько слоёв deck.gl одновременно и управлять ими:
- Добавлять слои на карту и удалять их.
- Изменять порядок отрисовки слоёв и отображать слои так, чтобы они не перекрывали друг друга. Чтобы изменить порядок слоёв, укажите индекс слоя в массиве.
- Скрывать и показывать слои.
Чтобы работать с несколькими слоями в проекте на React:
- Настройте провайдер карты.
- Создайте провайдер Deck.
- Инициализируйте провайдеры.
- Создайте контекст для управления слоями.
1. Настройте провайдер карты
-
Инициализируйте карту MapGL JS API по инструкции Работа с React.
-
Перед добавлением слоя на карту стиль карты должен быть загружен, иначе он перезапишет предыдущий стиль и удалит добавленные слои. Используйте обработчик события
styleload, который срабатывает каждый раз после установки нового стиля: подробнее см. в инструкции Дополнение текущего стиля карты «на лету». Добавьте в провайдер картыMapProviderфлаг готовности стиля карты:const MapContext = React.createContext({
mapInstance: undefined,
setMapInstance: () => {},
styleLoaded: false
});
const MapProvider = (props) => {
const [mapInstance, setMapInstance] = React.useState(undefined);
// Добавление флага готовности стиля карты
const [styleLoaded, setStyleLoaded] = React.useState(false);
// Подписка на событие готовности стиля при загрузке карты
React.useEffect(() => {
if (!mapInstance) {
return;
}
// Callback для обработки события готовности стиля
const onStyleHasLoaded = () => {
setStyleLoaded(true);
};
mapInstance.on('styleload', onStyleHasLoaded);
return () => {
mapInstance.off('styleload', onStyleHasLoaded);
};
}, [mapInstance]);
// Добавление флага styleLoaded в контекст
return (
<MapContext.Provider value={{ mapInstance, setMapInstance, styleLoaded }}>
{props.children}
</MapContext.Provider>
);
};
Для повышения производительности вы можете вынести флаг загрузки стиля в отдельный контекст.
2. Создайте провайдер Deck
Создайте отдельный провайдер для экземпляра Deck, чтобы иметь к нему доступ и управлять слоями из любой точки приложения:
const DeckContext = React.createContext({ deckInstance: undefined });
let deckGLInstance = undefined;
const DeckProvider: FC<PropsWithChildren> = ({ children }) => {
const [deckInstance, setDeckInstance] = React.useState(undefined);
useMapEffect(({ mapInstance }) => {
if (deckGLInstance) {
return;
}
// Инициализация Deck при загрузке карты
const deckGLInstance = Deck2gisLayer.initDeck(mapInstance, DeckGL, { antialiasing: 'msaa' });
deckGLInstance = deckGLInstance;
setDeckInstance(deckGLInstance);
}, []);
return <DeckContext.Provider value={{ deckInstance }}>{children}</DeckContext.Provider>;
};
3. Инициализируйте провайдеры
Инициализируйте провайдеры в корневом компоненте приложения:
const App = () => {
return (
<MapProvider>
<DeckProvider>
{/* Остальная часть приложения */}
</DeckProvider>
</MapProvider>
);
};
Провайдер DeckProvider вложен в MapProvider, чтобы экземпляр Deck имел доступ к карте.
4. Создайте контекст для управления слоями
Для управления слоями deck.gl создайте контекст, который хранит список слоёв и предоставляет функции для управления слоями.
Алгоритм работы со слоями состоит из следующих шагов:
- Добавление слоёв в контекст с указанием порядка отрисовки.
- Добавление слоёв на карту после загрузки стиля.
- Изменение набора слоёв с помощью функций
addLayer()иremoveLayer(). - Удаление предыдущего набора слоёв с карты (очистка в
useMapEffect) и отрисовка нового. Экземпляр слоя не удаляется, и вы можете использовать его повторно. - Повторение цикла при каждом изменении набора слоёв или их порядка.
Пример контекста:
const deck2GisLayerContext = React.createContext({
addLayer: () => {},
removeLayer: () => {},
});
const Deck2gisLayerContextProvider = ({ children }) => {
// Массив хранит слой и его индекс, который определяет порядок отрисовки слоя на карте
// Слой с большим индексом отрисовывается выше слоя с меньшим
const [deck2gisLayers, setDeck2gisLayers] = React.useState([]);
const addLayer = React.useCallback((deck2gisLayer, layerIndex) => {
// Массив слоёв сортируется по их индексам
setDeck2gisLayers((layers) =>
[...layers, { layerIndex, layer: deck2gisLayer }].sort(
(a, b) => b.layerIndex - a.layerIndex,
),
);
}, []);
const removeLayer = React.useCallback((layer) => {
setDeck2gisLayers((layers) => layers.filter((l) => l.layer !== layer));
}, []);
const { styleLoaded } = useMapContext();
useMapEffect(
({ mapInstance }) => {
if (!styleLoaded) {
return;
}
deck2gisLayers.forEach(({ layer }) => {
if (!mapInstance.hasLayer(layer.id)) {
mapInstance.addLayer(layer);
}
});
return () => {
deck2gisLayers.forEach(({ layer }) => {
mapInstance.removeLayer(layer.id);
});
};
},
[deck2gisLayers, styleLoaded],
);
const value = React.useMemo(() => ({ addLayer, removeLayer }), [addLayer, removeLayer]);
return <deck2GisLayerContext.Provider value={value}>{children}</deck2GisLayerContext.Provider>;
};
Пример использования
Пример содержит дополнительный код, который имитирует работу с серверной частью приложения. Способ получения данных для слоёв зависит от вашей реализации.