Предыстория

Начну с небольшой предыстории. Во время новогодних праздников мне нечем было особо заняться и я решил написать мобильное приложение, что-то вроде Zenly (социальная сеть, в которой в real-time можно увидеть, где сейчас находятся твои друзья), которое сейчас закрывает Snapchat. Решил делать это мобильное приложение на фреймворке js - React Native - для меня это казалось идеальным решением, так как такие языки как Kotlin или Swift я не особо уважаю, в силу того, что с ними ни разу не взаимодействовал. Первая задача с которой я столкнулся - это отображение карты в приложении и как на ней оставлять маркеры (в моём случае маркеры - это друзья в социальной сети). Эта тема на самом деле очень глубокая и копать в ней можно вплоть до написания своего картографического движка, но я решил воспользоваться чем-то из уже готовых решений. Из готовых решений с первым с чем я столкнулся - это интеграция Google Maps в приложение с помощью react-native-maps, однако, в современных реалиях Google не хочет предоставлять в Россию свои средства для разработчиков. Следующий вариант, который я рассматривал, это интеграция Mapbox в React Native. У Mapbox Maps SDK инструментарий мне понравился, там можно и стиль карты кастомизировать очень удобно, и весь нужный мне функционал присутствует. Однако, я всё же решил пойти дальше и наткнулся на Яндекс Карты для React Native. Они мне показались гораздо удобнее и легче в использовании в конкретно моём случае и я остановился на Яндекс Картах. В этой статье расскажу про начало работы с Яндекс Картами для React Native и базовые примеры того, что можно сделать с этой библиотекой.

Установка и инициализация Яндекс Карт для React Native

Установить библиотеку в проект можно с помощью менеджеров пакетов:

npm i react-native-yamap --save
yarn add react-native-yamap

Также, если у вас версия React Native ниже 0.60 необходима линковка библиотеки:

react-native link react-native-yamap

Далее переходим к инициализации библиотеки в наш проект. Для этого необходимо библиотеку импортировать и записать функцию инициализации, и передать в функцию строку с API-ключом, который можно получить на сайте кабинета Яндекс Разработчика.

import { YaMap, Marker } from 'react-native-yamap';


YaMap.init('ВАШ_API_КЛЮЧ');

И если вы пишете приложение для iOS, документация подсказывает, что необходимо инициализировать библиотеку в didFinishLaunchingWithOptions - функцию, которая находится в AppDelegate.m/AppDelegate.mm

#import <YandexMapsMobile/YMKMapKitFactory.h>

...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  ...

  [YMKMapKit setLocale:@"ru_RU"];
  [YMKMapKit setApiKey:@"API_KEY"];

  return YES;
}

Добавляем карту в приложение

Библиотеку мы инициализировали, теперь можно добавлять карту в приложение. Для этого воспользуемся компонентом карты. При добавлении карты наш компонент будет выглядеть как-то так:

export default function Habr() {
  
    return (
      <>
  
        <YaMap/>
        
      </>
    );
}

И что мы увидим, когда добавим компонент карты? Да вобщем-то ничего, он добавился, но для корректного отображения ему следует задать размеры. Для примера я сделал это как-то так. Наш компонент:

import MapStyles from './HabrStyles';
...
export default function Habr() {
  
    return (
      <>
  
        <YaMap
          style={MapStyles.map}
        >           

        </YaMap>
        
      </>
    );
}

Стили выглядят так:

import {StyleSheet} from 'react-native';
import { vw, vh } from 'react-native-expo-viewport-units';

export default MapStyles = StyleSheet.create({

    map: {

        width: vw(100),
        height: vh(100),

    },

})

Я для указания размеров использую viewport по старой привычке с css, однако, размеры там можно задавать как угодно.

Теперь у нас карта отобразилась и теперь наше приложение выглядит вот так:

Для компонента YaMap доступно использование пропсов, которые позволят настроить карту, как нам необходимо. Например, давайте сделаем, карту, на которой будет выключен показ текущей позиции пользователя, карта будет отображаться векторным изображением в ночном режиме и также я хочу отключить поворот камеры на карте. Также хочу, чтобы при открытии карты, камера находилась на координатах 30 по широте, 30 по долготе, уровень зума был выставлен на 7, а поворот по азимуту был выставлен на 0 градусов. Это будет выглядеть так:

export default function Habr() {
  
    return (
      <>
  
        <YaMap
          showUserPosition={false}
          rotateGesturesEnabled={false}
          nightMode={true}
          mapType={'vector'}
          initialRegion={{
              lat: 30,
              lon: 30,
              zoom: 7,
              azimuth: 0,
              }}
          style={MapStyles.map}>           

        </YaMap>
        
      </>
    );
}

Тогда при открытии карты мы видим следующее:

Добавляем примитивы на карту

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

Конкретно для своей задачи я воспользовался компонентом Marker, который поместил в компонент YaMap. Давайте для примера на координатах 30 по широте и 30 по долготе установим маркер на нашей карте. Это будет выглядеть так:

export default function Habr() {
  
    return (
      <>
  
        <YaMap
        showUserPosition={false}
        rotateGesturesEnabled={false}
        nightMode={true}
        mapType={'vector'}
        initialRegion={{
            lat: 30,
            lon: 30,
            zoom: 7,
            azimuth: 0,
            }}
        style={MapStyles.map}
        >           

            <Marker 
              point={{ lat: 30, lon: 30 }}
            />  

        </YaMap>
        
      </>
    );
}

И тогда на экране мы увидим следующее:

Мы добавили совсем маленький, практически незаметный маркер, с помощью пропса увеличим его:

export default function Habr() {
  
    return (
      <>
  
        <YaMap
        showUserPosition={false}
        rotateGesturesEnabled={false}
        nightMode={true}
        mapType={'vector'}
        initialRegion={{
            lat: 30,
            lon: 30,
            zoom: 7,
            azimuth: 0,
            }}
        style={MapStyles.map}
        >           

            <Marker 
              point={{ lat: 30, lon: 30 }}
              scale={5}
            />  

        </YaMap>
        
      </>
    );
}

Вот так уже лучше. Но я хочу маркер как-то кастомизировать. Для этого можно с помощью пропса souce передать изображение в маркер, но мне интереснее другое, с помощью пропса children можно передать в маркер компонент, который собственно говоря у нас и будет отображаться на заданных координатах. Именно компонентом я хочу передавать изображение в маркер, потому что в случае если мы передаём ссылку на изображение без компонента, то если изображение имеет разрешение 100x100 пикселей, оно так и отображаться будет. Масштабировать можно при помощью scale, однако, тогда если мы отрисовываем много маркеров, у каждого из которого своё изображение и их надо как-то унифицировать, придётся задавать-подбирать scale для каждого отдельного маркера. Также я хочу добавить изображению обводку и сгладить углы.

export default function Habr() {
  
    return (
      <>
  
        <YaMap
        showUserPosition={false}
        rotateGesturesEnabled={false}
        nightMode={true}
        mapType={'vector'}
        initialRegion={{
            lat: 30,
            lon: 30,
            zoom: 7,
            azimuth: 0,
            }}
        style={MapStyles.map}
        >           

            <Marker 
                children={<Image
                    style={MapStyles.marker} 
                    source={{uri: 'ВАШЕ_ИЗОБРАЖЕНИЕ'}} />}
                point={{ lat: 30, lon: 30 }}
            /> 

        </YaMap>
        
      </>
    );
}

Рассмотрим следующий примитив - Circle. Тут, я думаю, всё понятно из названия. Принимает он координаты центра окружности и её радиус. Также можно передавать другие параметры. Давайте допустим сделаем синий круг с тёмно-синей обводкой. Стоит также обратить внимание, что все примитивы принимают пропсом параметр zIndex, от которого будет завить, как они будут друг на друга накладываться.

export default function Habr() {
  
    return (
      <>
  
        <YaMap
        showUserPosition={false}
        rotateGesturesEnabled={false}
        nightMode={true}
        mapType={'vector'}
        initialRegion={{
            lat: 30,
            lon: 30,
            zoom: 7,
            azimuth: 0,
            }}
        style={MapStyles.map}
        >           

            <Marker 
                children={<Image
                    style={MapStyles.marker} 
                    source={{uri: 'ВАШЕ_ИЗОБРАЖЕНИЕ'}} />}
                point={{ lat: 30, lon: 30 }}
                zIndex={4}
            /> 

            <Circle
                center={{lat: 30, lon: 30}}
                radius={60000}
                fillColor='#5789d9'
                strokeColor='#154ca3'
                strokeWidth={4}
                zIndex={5} />

        </YaMap>
        
      </>
    );
}

Также существуют примитивы Polygon и Polyline, которые позволяют по точкам строить фигуры и линии соответственно. Стиль для этих примитивов задаётся также, как и для круга. Для примера давайте закрасим фигурой город Каир на карте, а также обозначим реку Нил линией.

export default function Habr() {
  
    return (
      <>
  
        <YaMap
        showUserPosition={false}
        rotateGesturesEnabled={false}
        nightMode={true}
        mapType={'vector'}
        initialRegion={{
            lat: 30,
            lon: 30,
            zoom: 7,
            azimuth: 0,
            }}
        style={MapStyles.map}
        >           

            <Marker 
                children={<Image
                    style={MapStyles.marker} 
                    source={{uri: 'ВАШЕ_ИЗОБРАЖЕНИЕ'}} />}
                point={{ lat: 30, lon: 30 }}
                zIndex={4}
            /> 

            <Circle
                center={{lat: 30, lon: 30}}
                radius={60000}
                fillColor='#5789d9'
                strokeColor='#154ca3'
                strokeWidth={4}
                zIndex={5} />

            <Polygon
                points={[
                    { lat: 30.540273, lon: 31.182331 },
                    { lat: 30.070791, lon: 31.928108 },
                    { lat: 29.233658, lon: 31.228942 },
                    { lat: 29.983355, lon: 30.622998 },
                ]}
                fillColor='#5789d9'
                strokeColor='#154ca3'
                strokeWidth={4}
                zIndex={5}
            />

            <Polyline
                points={[
                    { lat: 29.988660, lon: 31.207694 },
                    { lat: 29.364817, lon: 31.176281 },
                    { lat: 28.634771, lon: 30.862143 },
                    { lat: 27.490336, lon: 30.839704},
                ]}
                fillColor='#5789d9'
                strokeColor='#154ca3'
                strokeWidth={4}
                zIndex={4}
            />

        </YaMap>
        
      </>
    );
}

Думаю, общая концепция работы с примитивами на Яндекс Картах понятна. Также стоит отметить, что все они принимают в пропс onPress функцию, которая будет выполняться по нажатию на них и все эти примитивы необходимо импортировать перед использованием:

import { YaMap, Marker, Circle, Polygon, Polyline } from 'react-native-yamap';

Итог

В конце хочу сказать, что выше приведенные примеры, это совсем базовая работая с Yandex Maps SDK. Библиотека позволяет простраивать маршруты, использовать геокодер, в ней также можно настраивать стили для карты. Мне на эту тему есть что ещё сказать, как про Yandex Maps SDK, так и про Mapbox Maps SDK. Интересно было бы почитать комментарии, услышать, интересно это кому-то или нет, стоит дальше рассказывать про этот инструментарий или что-нибудь другое.

Читать следующую часть

Комментарии (3)


  1. vkompaniec
    27.01.2023 22:11

    Хорошая библиотека, но она какое-то время не обновлялась. Сейчас последнее обновление от сентября прошлого года. Уже появились новые ишьюс и еще много старых. Из интересных глюков - первый показ карты. Сетка есть, кнопки яндекса и лейбл есть, карты нет. Если приложение свернуть/развернуть, появляется.


  1. UserHome
    27.01.2023 22:11
    +1

    Никита, раскажите про ВАШ_API_КЛЮЧ, а также расценки на пользование картографическим фреймворком: столько то запросов в год - столькото рублей в год, еще чуть поболее - еще чутка подбавить и сравни с аналогом Google Maps и другими. Интересно какая фирма окажется более экономически выгодной в плане разработки, тестирования и работы вашего приложения с сервисом картографии. Вам же не бесплатно предоставили право использования чужой инфраструктуры и технологических наработок в вашем приложении?


  1. Avadon
    28.01.2023 18:24

    Также можно поставить либу MapBox и использовать тайлы СтарЛайн Карт. Там есть все: векторные тайлы, дизайнер карт, геокодер, роутинг и куча полезных API.