В Compass мы используем API Карт Google для поиска и отображения данных о недвижимости. Ключевым преимуществом Google Maps перед другими API-интерфейсами карт является просмотр улиц, что особенно важно в сфере недвижимости.
Поскольку мы уже несколько лет используем Карты Google в Интернете и на iOS, мы хотели бы поделиться некоторыми передовыми практиками использования этого API, которые помогут вашей команде создавать более эффективные приложения, использующие карты. Типы проблем, с которыми мы столкнулись, применимы ко многим объектам, связанным с путешествиями и недвижимостью, а также к другим, требующим высокоинтерактивных карт.
Исследовать
Нашим первым подходом к использованию Google Maps было посмотреть, не создал ли кто-нибудь Angular компоненты, которые обертывают Maps API, поскольку мы не хотим изобретать все заново. К сожалению, Google не выпустил собственную оболочку для Google Maps с Angular, поэтому мы рассмотрели варианты с открытым исходным кодом. Основными соперниками здесь являются angular-google-maps и ng-map, и существуют варианты этих библиотек для большинства основных интерфейсных фреймворков (React, Angular 2 и т. Д.).
После изучения двух упомянутых библиотек и рассмотрения других вариантов использования карт, общий набор функций, предлагаемых существующими библиотеками, следующий:
- Асинхронный способ загрузки скрипта Google Maps API
- Компонент для визуализации карты с масштабированием, центром и стилем.
- Способ визуализации одного или нескольких маркеров на карте, обычно в состоянии щелчка.
- Некоторые дополнительные функции, обычно включающие дополнительные библиотеки Карт, такие как предложения мест, геокодирование и т. Д.
В общем, мы обнаружили, что сбивает с толку то, что каждая из этих библиотек оборачивает Google API в свой собственный набор API, который отличается от того, что говорится в документации Google, а это означает, что вам нужно изучить оба API. На самом деле это не упрощает вашу работу с картами, поэтому мы не рекомендуем использовать библиотеку-оболочку для Google Maps.
Даже если дизайн этих библиотек был правильным, мы не могли использовать оболочку, потому что нам также необходимы:
- Пользовательские кнопки в верхней части карты
- Просмотр улиц
- Наложения карт с привязками Angular
- Рисование и редактирование фигур на карте
- Использование на стороне клиента других сервисов Google, таких как геокодирование и предложения мест
Поэтому на основе всего этого мы решили написать свои собственные обертки и рекомендуем вам тоже.
Создание повторно используемых компонентов для каждого типа карты
В Compass мы используем множество видов карт, и каждая из них создается как отдельный компонент, который можно использовать по-разному. Так, например, у нас есть:
- Стилизованные карты с одним стилизованным маркером
- Карты с кластерными данными листинга
- Статическая карта с множеством маркеров
- Просмотр улиц
У каждого компонента есть API, подходящий для конкретного случая использования, с максимально возможным общим внутренним кодом. Мы обнаружили, что это правильный уровень абстракции, потому что он позволяет нам повторно использовать карты и связанные с ними инструменты в разных частях нашего приложения, а также позволяет нам быстро разрабатывать новые способы использования географической информации.
Асинхронная загрузка Google Maps API
Это функция, которую предлагают многие библиотеки, и мы также сочли ее полезной. Мы загружаем API Карт только тогда, когда вы переходите на экран, который его использует, а это не везде в нашем приложении. Это сначала делает наше приложение более отзывчивым и делает его пригодным для модульного тестирования.
Асинхронная загрузка может добавить много шаблонного кода, ожидающего загрузки скрипта. Чтобы избежать этого шаблона, мы используем наш маршрутизатор (ui-router) для управления загрузкой асинхронных сценариев. Для нас это выглядит так:
resolve: { googleMaps: (ucGoogleMapsApiService) => { return ucGoogleMapsApiService.load(); }, },
Два способа добавления кнопок на карту
Использование элемента с абсолютным позиционированием поверх карты
Это вариант, который проще всего интегрировать в ваше приложение, где вы пишете свой пользовательский интерфейс, используя те же инструменты, которые обычно используете, и визуализируете элементы поверх карты. Мы выбрали эту опцию для простых кнопок «закрыть», а также для нашей самой сложной функции карты - поиска пользовательских границ. Мы выбираем этот вариант в большинстве случаев.
Pro:
- Совершенно не использует API карт
- Легко добавить условную логику и стили
Против:
- Не интегрирован напрямую в карту
Интеграция кнопок в карту
Иногда мы хотим расположить наш пользовательский интерфейс так, как если бы он был частью самой карты, например, рядом с элементами управления масштабированием или элементами управления спутниковым обзором. Требуется больше работы, чтобы подключить всю логику обработки событий и рендеринга, которая требуется API, но она хороша для замены пользовательского интерфейса по умолчанию вашим собственным. Это можно сделать с помощью настраиваемых элементов управления:
Pro:
- Взаимодействует со встроенными элементами управления картой, такими как масштабирование
Против:
- Сложнее стилизовать
- Сложнее добавить условную логику
Просмотр улиц
Когда мы думаем о просмотре улиц, обычно мы думаем о том, что происходит на Google Maps, когда вы вводите адрес в их строку поиска. Вы получаете предварительный просмотр просмотра улиц, указывающий прямо на введенный вами адрес. К сожалению, API просмотра улиц не позволяет легко получить аналогичный тип просмотра улиц, который вы получаете в собственных приложениях Google.
Используя параметры по умолчанию для просмотра улиц в определенном месте, вы получаете панораму, которая будет обращена на север (а не на ваше местоположение) и иногда будет внутренней панорамой. Из-за этих значений по умолчанию мы рекомендуем:
- никогда не используйте запрос просмотра улиц по умолчанию, и
- всегда направляйте камеру в желаемое место из центра панорамы
Этот пример кода найдет панораму, используя наши лучшие практики, и наведет камеру в нужное нам место. Это не делает просмотр улиц видимым, это зависит от вашего приложения. Вы можете использовать этот образец кода для изображений улиц или для интерактивных панорам.
// Assumption: you have a map already const streetView = map.getStreetView(); // Set location to be the lat/lng you want a street view for, more accurate is better const location = map.getCenter(); const streetViewService = new maps.StreetViewService(); streetViewService.getPanorama({ // Set location to whatever you want location, // Usually the NEAREST panorama matches Google Maps better than the BEST panorama, aka we // are looking for a straight-on view of a building, and BEST often returns a steeper // angle than NEAREST preference: maps.StreetViewPreference.NEAREST, // We do not want indoor street view source: maps.StreetViewSource.OUTDOOR, }, (pano, status) => { if (status === 'OK') { // Pano ID is a session-stable reference to the queried street view, used for the static // and dynamic street view lookup const panoId = pano.location.pano; // The default heading of street view is north, we point it to the actual location const heading = maps.geometry.spherical.computeHeading(pano.location.latLng, location); streetView.setPano(panoId); streetView.setPov({ heading, pitch: 0, }); } else { // Failure case, this is where you could show an error or hide street view } });
Пользовательские наложения внутри карты с привязками Angular
API Карт имеет ограниченные способы создания интерактивных маркеров карты, которые используются на большинстве веб-сайтов о недвижимости и путешествиях. К счастью, есть способ создавать Пользовательские наложения в любом месте на карте, и таким образом мы можем получить полный контроль над маркерами карты.
API JavaScript Карт Google предоставляет класс OverlayView для создания ваших собственных наложений. OverlayView - это базовый класс, который предоставляет несколько методов, которые необходимо реализовать при создании наложений. Класс также предоставляет несколько методов, которые позволяют переводить координаты экрана и местоположения на карте.
Как мы уже говорили выше, наша практика при разработке компонентов карты заключается в том, чтобы начинать с API:
<uc-map-with-clusters source-function="$ctrl.getMapData()"> <!-- Map clusters are repeated for each item from the source data --> <uc-map-cluster item="item"> <uc-map-cluster-hover>{{item.title}}</uc-map-cluster-hover> <uc-map-cluster-active>{{item.title}} Active state</uc-map-cluster-active> </uc-map-cluster> </uc-map-with-clusters>
На основе этого API у нас есть uc-map-with-clusterters, который создает элемент карты, а затем создает каждый экземпляр uc-map-cluster, который будет настраиваемым OverlayView. В Angular этот API требует использования $ compile для привязки данных к этим элементам DOM.
Самая важная часть этого API заключается в том, что нам нужно использовать директиву для отсоединения и повторения HTML, аналогично ng-repeat, но повторяя, как выберет наше приложение. Каждый маркер будет создан путем вызова $ compile для HTML и необходимой области.
export default function clustersDirective() { return { controller, scope: true, bindToController: { // App-maker must configure a data loader callback sourceFunction: '&', }, compile(tElement) { // Templates are detached at compile time, then cleared. // They are rendered dynamically. Cloning them for IE-11; otherwise // template child elements get lost. const clusterTemplate = tElement.find('uc-map-cluster').clone(); tElement.html(''); return { post(scope, element, attrs, [clustersCtrl]) { clustersCtrl.template = clusterTemplate; }, }; }, }; }
Собрав все части вместе, мы получим пример JSFiddle с маркерами карты, скомпилированными с помощью angular:
Https://jsfiddle.net/wylieconlon/7Lsp5ckz/
Вы хотите работать над интересными картографическими приложениями?
Обратитесь в Компас для работы над нашей технологией в сфере недвижимости!