Szukaj…


Dodaj tag javascript Google Maps do nagłówka układu

Aby mapy Google działały poprawnie z turbolinkami , dodaj tag javascript bezpośrednio do nagłówka układu, zamiast umieszczać go w widoku.

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

google_maps_api_script_tag najlepiej zdefiniować w pomocniku.

# 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

Możesz zarejestrować swoją aplikację w Google i uzyskać klucz API w konsoli Google API . Google ma krótki przewodnik, jak poprosić o klucz API dla Google Maps Java API .

Klucz API jest przechowywany w pliku secrets.yml :

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

Nie zapomnij dodać config/secrets.yml do .gitignore pliku i makre pewno nie popełnić klucz API do repozytorium.

Geokoduj model

Załóżmy, że twoi użytkownicy i / lub grupy mają profile i chcesz wyświetlić pola profilu adresu na mapie 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

Świetnym sposobem na geokodowanie adresów, tj. Podanie longitude i latitude jest klejnot geokodera .

Dodaj Gemfile do Gemfile i uruchom bundle aby go zainstalować.

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

Dodaj kolumny bazy danych dla latitude i longitude , aby zapisać lokalizację w bazie danych. Jest to bardziej wydajne niż odpytywanie usługi geokodowania za każdym razem, gdy potrzebujesz lokalizacji. Jest szybszy i nie wyczerpujesz tak szybko limitu zapytań.

➜ 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

Dodaj mechanizm geokodowania do swojego modelu. W tym przykładzie ciąg adresu jest przechowywany w atrybucie value . Skonfiguruj geokodowanie, aby działało, gdy rekord się zmieni, i tylko wtedy, gdy wartość jest obecna:

# 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

Domyślnie geocoder używa Google jako usługi wyszukiwania. Ma wiele interesujących funkcji, takich jak obliczanie odległości lub wyszukiwanie bliskości. Aby uzyskać więcej informacji, zapoznaj się z geokoderem README .

Pokaż adresy na mapie Google w widoku profilu

W widoku profilu pokaż pola profilu użytkownika lub grupy na liście, a także pola adresu na mapie Google.

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

Odpowiednie @profile_fields i @address_fields są ustawione w kontrolerze:

# 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

Zainicjuj mapę, umieść znaczniki, ustaw powiększenie i inne ustawienia mapy za pomocą javascript.

Przykładowy widok profilu

Ustaw znaczniki na mapie za pomocą javascript

Załóżmy, że istnieje div .google_map , która stanie się mapą i która będzie miała pola adresu, które będą wyświetlane jako znaczniki jako atrybut data .

Na przykład:

<!-- 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>

Aby skorzystać ze zdarzenia $(document).ready z turbolinkami bez ręcznego zarządzania zdarzeniami turbolinks, użyj klejnotu jquery.turbolinks .

Jeśli chcesz wykonać inne operacje na mapie, później, na przykład filtrowanie lub okna informacyjne, wygodnie jest zarządzać mapą za pomocą klasy skryptu kawowego .

# 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

Podczas korzystania z kilku plików skryptów kawy, które są domyślnie z przestrzenią nazw, wygodnie jest zdefiniować globalną przestrzeń nazw App , która jest współdzielona przez wszystkie pliki skryptów kawy.

Następnie .google_map przez (ewentualnie kilka) .google_map div .google_map i utwórz dla każdej z nich jedną instancję klasy 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

Zainicjuj mapę za pomocą klasy skryptu kawowego.

Pod warunkiem App.GoogleMap kawy App.GoogleMap mapę Google można zainicjować w następujący sposób:

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

Aby dowiedzieć się więcej o możliwych opcjach map_configuration , zapoznaj się z dokumentacją MapOptions Google i ich przewodnikiem po dodawaniu elementów sterujących .

Dla porównania klasa google.maps.Map jest tutaj obszernie udokumentowana .

Zainicjuj znaczniki mapy za pomocą klasy skryptu kawy

Pod warunkiem, że App.GoogleMap skryptu kawy App.GoogleMap i informacje o znaczniku są przechowywane w atrybucie data-address-fields div .google_map , znaczniki mapy można zainicjować na mapie w następujący sposób:

# 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

Aby dowiedzieć się więcej o opcjach znaczników, zapoznaj się z dokumentacją MarkerOptions firmy Google i ich przewodnikiem po znacznikach .

Automatyczne powiększanie mapy za pomocą klasy skryptu kawowego

Pod warunkiem, że App.GoogleMap skryptów do kawy google.maps.Map przechowywana jako @map jako @map i google.maps.Marker jako @markers , mapa może być automatycznie powiększana, tzn. Dostosowywana tak, aby wszystkie markery były widoczne, tak jak to : na mapie w ten sposób:

# 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

Aby dowiedzieć się więcej na temat granic, zapoznaj się z dokumentacją Google LatLngBounds .

Ujawnianie właściwości modelu jako json

Aby wyświetlić pola profilu adresu jako znaczniki na mapie Google, obiekty pola adresu należy przekazać jako obiekty JSON do javascript.

Regularne atrybuty bazy danych

Podczas wywoływania funkcji to_json na obiekcie ApplicationRecord atrybuty bazy danych są automatycznie ujawniane.

Biorąc pod uwagę ProfileFields::Address Model ProfileFields::Address z atrybutami label , value , longitude i latitude , pole address_field.as_json powoduje Hash , np. Reprezentację,

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

który jest konwertowany na ciąg json przez to_json :

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

Jest to przydatne, ponieważ pozwala na użycie label i value później w javascript, na przykład w celu wyświetlenia podpowiedzi do znaczników mapy.

Inne atrybuty

Inne atrybuty wirtualne można wyświetlić, zastępując metodę as_json .

Na przykład, aby odsłonić atrybut title , as_json go do scalonego as_json hash:

# 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

W powyższym przykładzie użyto super do wywołania oryginalnej metody as_json , która zwraca oryginalny skrót wartości obiektu i łączy go z wymaganym as_json pozycji.

Aby zrozumieć różnicę między as_json i to_json , spójrz na ten post na blogu autorstwa jjulian .

Pozycja

Aby renderować znaczniki, interfejs Google Maps domyślnie wymaga skrótu position który ma długość i szerokość geograficzną przechowywane odpowiednio jako lng i lat .

Ten skrót pozycji można utworzyć w javascript, później lub tutaj podczas definiowania reprezentacji json pola adresu:

Aby podać tę position jako atrybut json pola adresu, po prostu zastąp metodę as_json w modelu.

# 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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow