Перейти к основному содержимому

Работа с несколькими слоями deck.gl

Вы можете отрисовывать на карте MapGL JS API несколько слоёв deck.gl одновременно и управлять ими:

  • Добавлять слои на карту и удалять их.
  • Изменять порядок отрисовки слоёв и отображать слои так, чтобы они не перекрывали друг друга. Чтобы изменить порядок слоёв, укажите индекс слоя в массиве.
  • Скрывать и показывать слои.

Чтобы работать с несколькими слоями в проекте на React:

  1. Настройте провайдер карты.
  2. Создайте провайдер Deck.
  3. Инициализируйте провайдеры.
  4. Создайте контекст для управления слоями.

1. Настройте провайдер карты

  1. Инициализируйте карту MapGL JS API по инструкции Работа с React.

  2. Перед добавлением слоя на карту стиль карты должен быть загружен, иначе он перезапишет предыдущий стиль и удалит добавленные слои. Используйте обработчик события 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 создайте контекст, который хранит список слоёв и предоставляет функции для управления слоями.

Алгоритм работы со слоями состоит из следующих шагов:

  1. Добавление слоёв в контекст с указанием порядка отрисовки.
  2. Добавление слоёв на карту после загрузки стиля.
  3. Изменение набора слоёв с помощью функций addLayer() и removeLayer().
  4. Удаление предыдущего набора слоёв с карты (очистка в useMapEffect) и отрисовка нового. Экземпляр слоя не удаляется, и вы можете использовать его повторно.
  5. Повторение цикла при каждом изменении набора слоёв или их порядка.

Пример контекста:

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>;
};

Пример использования

Пример содержит дополнительный код, который имитирует работу с серверной частью приложения. Способ получения данных для слоёв зависит от вашей реализации.