Buscar..


Agregue la etiqueta javascript de google maps al encabezado de diseño

Para que Google Maps funcione correctamente con turbolinks , agregue la etiqueta javascript directamente al encabezado del diseño en lugar de incluirla en una vista.

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

El google_maps_api_script_tag se define mejor en un ayudante.

# 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

Puede registrar su aplicación en google y obtener su clave de api en la consola de google api . Google tiene una breve guía sobre cómo solicitar una clave de API para la API de Google Maps javascript .

La clave api se almacena en el archivo secrets.yml :

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

No se olvide de añadir config/secrets.yml a su .gitignore archivo y makre asegurarse de que no se compromete la clave de API en el repositorio.

Geocodificar el modelo

Supongamos que sus usuarios y / o grupos tienen perfiles y desea mostrar los campos de perfil de dirección en un mapa de 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

Una gran manera de geocodificar las direcciones, es decir, proporcionar longitude y latitude es la gema del geocodificador .

Agregue geocodificador a su Gemfile y ejecute bundle para instalarlo.

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

Agregue columnas de la base de datos para latitude y longitude para guardar la ubicación en la base de datos. Esto es más eficiente que consultar el servicio de geocodificación cada vez que necesita la ubicación. Es más rápido y no alcanzas el límite de consulta tan rápido.

➜ 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

Agregue el mecanismo de geocodificación a su modelo. En este ejemplo, la cadena de dirección se almacena en el atributo de value . Configure la geocodificación para que se realice cuando el registro haya cambiado, y solo cuando esté presente un valor:

# 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

Por defecto, el geocodificador usa google como servicio de búsqueda. Tiene muchas características interesantes como cálculos de distancia o búsqueda de proximidad. Para más información, eche un vistazo al README del geocodificador .

Mostrar direcciones en un mapa de Google en la vista de perfil

En la vista de perfil, muestre los campos de perfil de un usuario o grupo en una lista, así como los campos de dirección en un mapa de Google.

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

Los @profile_fields y @address_fields apropiados se configuran en el controlador:

# 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

Inicialice el mapa, coloque los marcadores, configure el zoom y otras configuraciones del mapa con javascript.

Ejemplo de vista de perfil

Establecer los marcadores en el mapa con javascript

Supongamos que hay un div .google_map , que se convertirá en el mapa, y que tiene los campos de dirección para mostrar como marcadores como atributo de data .

Por ejemplo:

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

Para utilizar el evento $(document).ready con turbolinks sin gestionar los eventos turbolinks a mano, use la gema jquery.turbolinks .

Si desea realizar otras operaciones con el mapa, más adelante, por ejemplo, mediante el filtrado o las ventanas de información, es conveniente que el mapa sea administrado por una clase de script de 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

Cuando se usan varios archivos de script de café, que tienen espacios de nombre por defecto, es conveniente definir un espacio de nombres de App global, que sea compartido por todos los archivos de script de café.

Luego, .google_map (posiblemente varios) divs .google_map y cree una instancia de la clase App.GoogleMap para cada uno de ellos.

# 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

Inicialice el mapa usando una clase de script de café.

Siempre que haya una clase de script de café App.GoogleMap , el mapa de google se puede inicializar así:

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

Para aprender más acerca de los posibles map_configuration opciones, echar un vistazo a Google de documentación MapOptions y su guía a la adición de elementos de control .

Para referencia, la clase google.maps.Map está ampliamente documentada aquí .

Inicialice los marcadores de mapa usando una clase de script de café

Si se proporciona una clase de script de café App.GoogleMap y la información del marcador se almacena en el atributo data-address-fields de la div .google_map , los marcadores del mapa se pueden inicializar en el mapa de la siguiente manera:

# 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

Para obtener más información sobre las opciones de marcadores, consulte la documentación de MarkerOptions y su guía de marcadores .

Zoom automático de un mapa usando una clase de script de café

Se proporcionó una clase de script de café App.GoogleMap con google.maps.Map almacenado como @map y google.maps.Marker s almacenado como @markers , el mapa puede @markers automáticamente, es decir, ajustado para que todos los marcadores sean visibles, de esta manera : en el mapa como este:

# 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

Para obtener más información sobre los límites, eche un vistazo a la documentación de LatLngBounds de Google .

Exponiendo las propiedades del modelo como json.

Para mostrar los campos de perfil de dirección como marcadores en un mapa de Google, los objetos del campo de dirección deben pasarse como objetos json a javascript.

Atributos regulares de la base de datos

Al llamar a to_json en un objeto ApplicationRecord , los atributos de la base de datos se exponen automáticamente.

Dado un ProfileFields::Address Modelo de ProfileFields::Address con atributos de label , value , longitude y latitude , address_field.as_json da address_field.as_json resultado un Hash , por ejemplo, representación,

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

que se convierte en una cadena json por to_json :

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

Esto es útil porque permite usar label y value más adelante en javascript, por ejemplo, para mostrar sugerencias de herramientas para los marcadores de mapa.

Otros atributos

Otros atributos virtuales se pueden exponer anulando el método as_json .

Por ejemplo, para exponer un atributo de title , as_json hash as_json combinado:

# 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

El ejemplo anterior usa super para llamar al método as_json original, que devuelve el hash del atributo original del objeto, y lo combina con el hash de posición requerido.

Para comprender la diferencia entre as_json y to_json , to_json un vistazo a esta publicación del blog de jjulian .

Posición

Para representar marcadores, la API de google maps, de forma predeterminada, requiere un hash de position que tiene la longitud y la latitud almacenadas como lng y lat respectivamente.

Este hash de posición se puede crear en javascript, más tarde, o aquí cuando se define la representación json del campo de dirección:

Para proporcionar esta position como atributo json del campo de dirección, simplemente anule el método as_json en el modelo.

# 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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow