Поиск…


Добавьте тег javascript Google Maps в заголовок макета

Чтобы карты Google корректно работали с turbolinks , добавьте тег javascript непосредственно в заголовок макета, а не включите его в представление.

# app/views/layouts/my_layout.html.haml
!!!
%html{:lang => 'en'}
  %head
    - # ...
    = google_maps_api_script_tag

Значение google_maps_api_script_tag лучше всего определено в помощнике.

# app/helpers/google_maps_helper.rb
module GoogleMapsHelper
  def google_maps_api_script_tag
    javascript_include_tag google_maps_api_source
  end

  def google_maps_api_source
    "https://maps.googleapis.com/maps/api/js?key=#{google_maps_api_key}"
  end

  def google_maps_api_key
    Rails.application.secrets.google_maps_api_key
  end
end

Вы можете зарегистрировать свое приложение в Google и получить свой ключ api в консоли google api . В Google есть краткое руководство о том, как запросить ключ api для javascript api .

Ключ api хранится в файле secrets.yml :

# config/secrets.yml
development:
  google_maps_api_key: '...'
  # ...
production:
  google_maps_api_key: '...'
  # ...

Не забудьте добавить config/secrets.yml в ваш .gitignore файл и убедитесь, что вы не передаете ключ api в репозиторий.

Геокодировать модель

Предположим, что у ваших пользователей и / или групп есть профили, и вы хотите отображать поля профиля адреса на карте Google.

# app/models/profile_fields/address.rb
class ProfileFields::Address < ProfileFields::Base
  # Attributes: 
  # label, e.g. "Work address"
  # value, e.g. "Willy-Brandt-Straße 1\n10557 Berlin"
end

Отличный способ геокодирования адресов, то есть обеспечить longitude и latitude - это драгоценный камень геокодирования .

Добавьте геокодер в свой Gemfile и запустите bundle чтобы установить его.

# Gemfile
gem 'geocoder', '~> 1.3'

Добавьте столбцы базы данных для latitude и longitude , чтобы сохранить местоположение в базе данных. Это более эффективно, чем запрос службы геокодирования каждый раз, когда вам нужно место. Это быстрее, и вы не так быстро достигаете предела запроса.

➜ bin/rails generate migration add_latitude_and_longitude_to_profile_fields \
    latitude:float longitude:float
➜ bin/rails db:migrate  # Rails 5, or:
➜ rake db:migrate       # Rails 3, 4

Добавьте механизм геокодирования к вашей модели. В этом примере строка адреса хранится в атрибуте value . Настройте геокодирование для выполнения, когда запись изменилась, и только то, что имеет значение:

# app/models/profile_fields/address.rb
class ProfileFields::Address < ProfileFields::Base
  geocoded_by :value
  after_validation :geocode, if: ->(address_field){ 
    address_field.value.present? and address_field.value_changed? 
  }

end

По умолчанию геокодер использует google как службу поиска. Он имеет множество интересных функций, таких как дистанционные вычисления или поиск близости. За дополнительной информацией обратитесь к геокодированию README .

Показывать адреса на карте google в профиле

В представлении профиля отобразите поля профиля пользователя или группы в списке, а также поля адреса на карте google.

- # app/views/profiles/show.html.haml
%h1 Contact Information
.profile_fields
  = render @profile_fields
.google_map{data: address_fields: @address_fields.to_json }

Соответствующие @profile_fields и @address_fields задаются в контроллере:

# app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
  def show
    # ...
    @profile_fields = @user_or_group.profile_fields
    @address_fields = @profile_fields.where(type: 'ProfileFields::Address')
  end
end

Инициализируйте карту, поместите маркеры, установите масштаб и другие настройки карты с помощью javascript.

Пример просмотра профиля

Установите маркеры на карте с помощью javascript

Предположим, что есть div .google_map , который станет картой и который имеет поля адреса, которые будут отображаться как маркеры как атрибут data .

Например:

<!-- http://localhost:3000/profiles/123 -->
<div class="google_map" data-address-fields="[
  {label: 'Work address', value: 'Willy-Brandt-Straße 1\n10557 Berlin', 
  position: {lng: ..., lat: ...}},
  ...
]"></div>

Чтобы использовать событие $(document).ready с turbolinks без управления событиями turbolinks вручную, используйте jquery.turbolinks gem .

Если вы хотите выполнить некоторые другие операции с картой, позже, например, для фильтрации или инфо-окна, удобно иметь карту, управляемую классом сценария кофе .

# app/assets/javascripts/google_maps.js.coffee
window.App = {} unless App?
class App.GoogleMap
  constructor: (map_div)->
    # TODO: initialize the map
    # TODO: set the markers

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

Затем .google_map (возможно, несколько) .google_map и создайте один экземпляр класса App.GoogleMap для каждого из них.

# app/assets/javascripts/google_maps.js.coffee
# ...
$(document).ready ->
  App.google_maps = []
  $('.google_map').each ->
    map_div = $(this)
    map = new App.GoogleMap map_div
    App.google_maps.push map

Инициализируйте карту, используя класс сценария кофе.

При условии класса сценария кофе-скрипта App.GoogleMap карту google можно инициализировать следующим образом:

# app/assets/javascripts/google_maps.js.coffee
# ...
class App.GoogleMap
  map_div: {}
  map: {}
  
  constructor: (map_div)->
    @map_div = map_div
    @init_map()
    @reference_the_map_as_data_attribute

  # To access the GoogleMap object or the map object itself
  # later via the DOM, for example 
  # 
  #     $('.google_map').data('GoogleMap')
  #
  # store references as data attribute of the map_div.
  #
  reference_the_map_as_data_attribute: ->
    @map_div.data 'GoogleMap', this
    @map_div.data 'map', @map

  init_map: ->
    @map = new google.maps.Map(@dom_element, @map_configuration) if google?

  # `@map_div` is the jquery object. But google maps needs
  # the real DOM element.
  #
  dom_element: ->
    @map_div.get(0)

  map_configuration: -> {
    scrollWheel: true
  }

Чтобы узнать больше о возможных параметрах map_configuration , просмотрите документацию MapOptions Google и их руководство по добавлению элементов управления .

Для справки, класс google.maps.Map широко документирован здесь .

Инициализация маркеров карты с использованием класса сценария кофе

При условии, что App.GoogleMap сценария кофе App.GoogleMap и информация о маркере, хранящаяся в атрибуте data-address-fields в div .google_map , маркеры карт могут быть инициализированы на карте следующим образом:

# app/assets/javascripts/google_maps.js.coffee
# ...
class App.GoogleMap
  # ...
  markers: []

  constructor: (map_div)->
    # ...
    @init_markers()

  address_fields: ->
    @map_div.data('address-fields')

  init_markers: ->
    self = this  # to reference the instance as `self` when `this` is redefined.
    self.markers = []
    for address_field in self.address_fields()
      marker = new google.maps.Marker {
        map: self.map,
        position: {
          lng: address_field.longitude,
          lat: address_field.latitude
        },
        # # or, if `position` is defined in `ProfileFields::Address#as_json`:
        # position: address_field.position,
        title: address_field.value
      }
      self.markers.push marker

Чтобы узнать больше о параметрах маркера, ознакомьтесь с документацией Google MarkerOptions и их руководством к маркерам .

Автоматическое масштабирование карты с использованием класса сценария кофе

При условии, что App.GoogleMap сценария кофе-класса App.GoogleMap содержит App.GoogleMap google.maps.Map хранящуюся как @map а @map google.maps.Marker хранится как @markers , карта может быть автоматически увеличена, то есть отрегулирована, чтобы все маркеры были видны, например : на карте:

# app/assets/javascripts/google_maps.js.coffee
# ...
class App.GoogleMap
  # ...
  bounds: {}

  constructor: (map_div)->
    # ...
    @auto_zoom()

  auto_zoom: ->
    @init_bounds()
    # TODO: Maybe, adjust the zoom to have a maximum or 
    # minimum zoom level, here.

  init_bounds: ->
    @bounds = new google.maps.LatLngBounds()
    for marker in @markers
      @bounds.extend marker.position
    @map.fitBounds @bounds

Чтобы узнать больше о границах, просмотрите документацию Google LatLngBounds .

Отображение свойств модели как json

Чтобы отображать поля профиля адреса в качестве маркеров на карте google, объекты поля адреса должны передаваться как json-объекты в javascript.

Обычные атрибуты базы данных

При вызове to_json объекта ApplicationRecord автоматически отображаются атрибуты базы данных.

Учитывая модель ProfileFields::Address с атрибутами label , value , longitude и latitude , address_field.as_json приводит к Hash , например, представлению,

address_field.as_json  # =>
  {label: "Work address", value: "Willy-Brandt-Straße 1\n10557 Berlin",
    longitude: ..., latitude: ...}

который преобразуется в строку json to_json :

address_field.to_json  # =>
  "{\"label\":\"Work address\",\"value\":\"Willy-Brandt-Straße 1\\n
    10557 Berlin\",\"longitude\":...,\"latitude\":...}"

Это полезно, потому что позволяет использовать label и value позже в javascript, например, чтобы показать подсказки инструментов для маркеров карты.

Другие атрибуты

Другие виртуальные атрибуты могут быть раскрыты путем переопределения метода as_json .

Например, чтобы открыть атрибут title , as_json его в объединенный хэш as_json :

# app/models/profile_fields/address.rb
class ProfileFields::Address < ProfileFields::Base
  # ...

  # For example: "John Doe, Work address"
  def title
    "#{self.parent.name}, #{self.label}"
  end

  def as_json
    super.merge {
      title: self.title
    }
  end
end

В приведенном выше примере super используется для вызова исходного метода as_json , который возвращает исходный хэш атрибута объекта и объединяет его с требуемым хэш- as_json позиции.

Чтобы понять разницу между as_json и to_json , посмотрите на это сообщение в блоге jjulian .

Позиция

Для рендеринга маркеров google maps api по умолчанию требует хеш position который имеет долготу и широту, хранящиеся как lng и lat соответственно.

Эта позиция hash может быть создана в javascript, позже или здесь при определении json-представления поля адреса:

Чтобы обеспечить эту position как json-атрибут поля адреса, просто переопределите метод as_json на модели.

# app/models/profile_fields/address.rb
class ProfileFields::Address < ProfileFields::Base
  # ...

  def as_json
    super.merge {
      # ...
      position: {
        lng: self.longitude,
        lat: self.latitude
      }
    }
  end
end


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow