Recherche…


Ajouter la balise javascript google maps à l'en-tête de la mise en page

Pour que Google Maps fonctionne correctement avec turbolinks , ajoutez le tag javascript directement dans l’en-tête de la présentation plutôt que de l’inclure dans une vue.

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

google_maps_api_script_tag est mieux défini dans un assistant.

# 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

Vous pouvez enregistrer votre application avec google et obtenir votre clé API dans la console google api . Google a un petit guide sur la façon de demander une clé d'API pour l'API JavaScript de Google Maps .

La clé api est stockée dans le fichier secrets.yml :

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

N'oubliez pas d'ajouter config/secrets.yml à votre fichier .gitignore et assurez-vous de ne pas valider la clé api dans le dépôt.

Géocoder le modèle

Supposons que vos utilisateurs et / ou groupes ont des profils et que vous souhaitez afficher les champs de profil d'adresse sur une carte 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

Le géocodeur est un excellent moyen de géocoder les adresses, c’est-à-dire de fournir la longitude et la latitude .

Ajoutez le géocodeur à votre Gemfile et exécutez le bundle pour l'installer.

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

Ajouter des colonnes de base de données pour la latitude et la longitude afin de sauvegarder l'emplacement dans la base de données. C'est plus efficace que d'interroger le service de géocodage chaque fois que vous avez besoin de l'emplacement. C'est plus rapide et la limite de requête n'est pas atteinte si rapidement.

➜ 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

Ajoutez le mécanisme de géocodage à votre modèle. Dans cet exemple, la chaîne d'adresse est stockée dans l'attribut value . Configurez le géocodage pour qu'il fonctionne lorsque l'enregistrement a changé et que seule une valeur est présente:

# 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

Par défaut, geocoder utilise google comme service de recherche. Il a beaucoup de fonctionnalités intéressantes comme les calculs de distance ou la recherche de proximité. Pour plus d'informations, consultez le fichier README du géocodeur .

Afficher les adresses sur une carte google dans la vue de profil

Dans la vue de profil, affichez les champs de profil d'un utilisateur ou d'un groupe dans une liste, ainsi que les champs d'adresse sur une carte Google.

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

Les @profile_fields et @address_fields appropriés sont définis dans le contrôleur:

# 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

Initialisez la carte, placez les marqueurs, définissez le zoom et les autres paramètres de la carte avec JavaScript.

Exemple de vue de profil

Définir les marqueurs sur la carte avec javascript

Supposons qu'il y ait un div .google_map , qui deviendra la carte, et qui comporte les champs d'adresse à afficher en tant que marqueurs en tant qu'attribut de data .

Par exemple:

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

Pour utiliser l'événement $(document).ready avec turbolinks sans gérer les événements turbolinks à la main, utilisez la gem jquery.turbolinks .

Si vous souhaitez effectuer d'autres opérations avec la carte, ultérieurement, par exemple, des fenêtres de filtrage ou des fenêtres d'informations, il est pratique de faire gérer la carte par une classe de script café .

# 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

Lorsque vous utilisez plusieurs fichiers de script de café, qui sont placés par nom par défaut, il est pratique de définir un espace de noms App global, partagé par tous les fichiers de script de café.

Ensuite, parcourez (éventuellement plusieurs) div .google_map et créez une instance de la classe App.GoogleMap pour chacun d'eux.

# 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

Initialisez la carte en utilisant une classe de script café.

Si vous App.GoogleMap une classe de script App.GoogleMap , la carte Google peut être initialisée comme App.GoogleMap :

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

Pour en savoir plus sur les options possibles de map_configuration , consultez la documentation de Google MapOptions et leur guide sur l'ajout d'éléments de contrôle .

Pour référence, la classe google.maps.Map est largement documentée ici .

Initialiser les marqueurs de carte à l'aide d'une classe de script café

Si une classe de script App.GoogleMap Coffee et les informations de marqueur sont stockées dans l'attribut data-address-fields du .google_map div, les marqueurs de carte peuvent être initialisés sur la carte comme .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

Pour en savoir plus sur les options de marqueur, consultez la documentation MarkerOptions de Google et son guide des marqueurs .

Zoom automatique sur une carte en utilisant une classe de script café

Avec une classe de script App.GoogleMap Coffee avec google.maps.Map stockée en tant que @map et google.maps.Marker stockée en tant que @markers , la carte peut être agrandie automatiquement, c'est-à-dire ajustée pour que tous les marqueurs soient visibles, comme ceci: : sur la carte comme ceci:

# 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

Pour en savoir plus sur les limites, consultez la documentation de Google LatLngBounds .

Exposition des propriétés du modèle en json

Pour afficher les champs de profil d'adresse sous forme de marqueurs sur une carte google, les objets du champ d'adresse doivent être transmis en tant qu'objets json à JavaScript.

Attributs de base de données réguliers

Lors de l'appel à to_json sur un objet ApplicationRecord , les attributs de la base de données sont automatiquement exposés.

Étant donné un modèle ProfileFields::Address avec des attributs label , value , longitude et latitude , address_field.as_json produit un Hash , par exemple une représentation,

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

qui est converti en chaîne json par to_json :

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

Ceci est utile car il permet d'utiliser plus tard l' label et la value en javascript, par exemple pour afficher des info-bulles pour les marqueurs de carte.

Autres attributs

D'autres attributs virtuels peuvent être exposés en as_json méthode as_json .

Par exemple, pour exposer un attribut title , incluez-le dans le hachage as_json fusionné:

# 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

L'exemple ci-dessus utilise super pour appeler la méthode as_json origine, qui renvoie l'attribut d'origine de l'objet et le fusionne avec la position requise.

Pour comprendre la différence entre as_json et to_json , consultez cet article de jjulian .

Position

Pour rendre les marqueurs, Google Maps api nécessite, par défaut, une position hachée qui contient respectivement la longitude et la latitude lng et lat .

Ce hachage de position peut être créé dans JavaScript, plus tard, ou ici lors de la définition de la représentation json du champ d'adresse:

Pour fournir cette position tant qu'attribut json du champ d'adresse, remplacez simplement la méthode as_json sur le modèle.

# 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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow