Ricerca…


Aggiungi il tag javascript di google maps all'intestazione del layout

Per fare in modo che google maps funzioni correttamente con i turbolinks , aggiungi il tag javascript direttamente all'intestazione del layout piuttosto che includerlo in una vista.

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

google_maps_api_script_tag è meglio definito in un helper.

# 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

Puoi registrare la tua domanda con google e ottenere la tua chiave API nella console di Google API . Google ha una breve guida su come richiedere una chiave API per le API di javascript di google maps .

La chiave API è memorizzata nel file secrets.yml :

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

Non dimenticate di aggiungere config/secrets.yml al .gitignore di file e makre sicuri di non commettere la chiave API al repository.

Geocodifica il modello

Supponiamo che i tuoi utenti e / o gruppi abbiano profili e che tu voglia visualizzare i campi del profilo dell'indirizzo su una mappa di 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

Un ottimo modo per geocodificare gli indirizzi, ovvero fornire longitude e latitude è la gemma del geocoder .

Aggiungi geocoder al tuo Gemfile ed esegui bundle per installarlo.

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

Aggiungi colonne di database per latitude e longitude per salvare la posizione nel database. Questo è più efficiente dell'interrogazione del servizio di geocoding ogni volta che è necessario il percorso. È più veloce e non stai raggiungendo il limite della query così velocemente.

➜ 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

Aggiungi il meccanismo di geocoding al tuo modello. In questo esempio, la stringa di indirizzo è memorizzata nell'attributo value . Configura la geocodifica da eseguire quando il record è cambiato e solo se è presente un valore:

# 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

Per impostazione predefinita, geocoder utilizza google come servizio di ricerca. Ha molte caratteristiche interessanti come i calcoli della distanza o la ricerca di prossimità. Per maggiori informazioni, date un'occhiata al README del geocoder .

Mostra indirizzi su una mappa di google nella vista profilo

Nella vista profilo, mostra i campi del profilo di un utente o di un gruppo in un elenco, nonché i campi degli indirizzi su una mappa di google.

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

I @profile_fields e @address_fields appropriati sono impostati nel controller:

# 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

Inizializza la mappa, posiziona i marcatori, imposta lo zoom e altre impostazioni della mappa con javascript.

Esempio di vista del profilo

Imposta i marcatori sulla mappa con javascript

Supponiamo che esista un div .google_map , che diventerà la mappa e che abbia i campi degli indirizzi da mostrare come marcatori come attributo dei data .

Per esempio:

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

Per utilizzare l'evento $(document).ready con i turbolinks senza gestire manualmente gli eventi turbolinks, utilizzare la gem jquery.turbolinks .

Se si desidera eseguire altre operazioni con la mappa, in seguito, ad esempio il filtro o le finestre informative, è conveniente che la mappa sia gestita da una classe di script caffè .

# 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

Quando si utilizzano diversi file di script caffè, che sono assegnati in modo predefinito per nome, è conveniente definire uno spazio dei nomi di App globale, condiviso da tutti i file di script caffè.

Quindi, passa attraverso (possibilmente diversi) .google_map div e crea un'istanza della classe App.GoogleMap per ognuno di essi.

# 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

Inizializza la mappa utilizzando una classe di script caffè.

Fornita una classe di script per caffè App.GoogleMap , la mappa di google può essere inizializzata in questo modo:

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

Per ulteriori informazioni sulle possibili opzioni map_configuration , dai un'occhiata alla documentazione di MapOptions di google e alla loro guida per aggiungere elementi di controllo .

Per riferimento, la classe google.maps.Map è ampiamente documentata qui .

Inizializza gli indicatori di mappa utilizzando una classe di script caffè

A condizione che una classe di script caffè App.GoogleMap e le informazioni sul marker vengano memorizzate nell'attributo data-address-fields del div .google_map , gli indicatori di mappa possono essere inizializzati sulla mappa in questo modo:

# 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

Per ulteriori informazioni sulle opzioni dei marker, dai un'occhiata alla documentazione di MarkerOptions di google e alla loro guida ai marcatori .

Zoom automatico di una mappa utilizzando una classe di script caffè

Fornita una classe di script per caffè App.GoogleMap con la google.maps.Map memorizzata come @map e i google.maps.Marker s memorizzati come @markers , la mappa può essere ingrandita automaticamente, ovvero regolata affinché tutti i marcatori siano visibili, come questo : sulla mappa in questo modo:

# 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

Per saperne di più sui limiti, dai un'occhiata alla documentazione di LatLngBounds di google.

Esporre le proprietà del modello come json

Per visualizzare i campi del profilo dell'indirizzo come marcatori su una mappa di google, gli oggetti del campo indirizzo devono essere passati come oggetti json a javascript.

Attributi regolari del database

Quando si chiama to_json su un oggetto ApplicationRecord , gli attributi del database vengono automaticamente esposti.

Dato un modello ProfileFields::Address con gli attributi label , value , longitude e latitude , address_field.as_json risulta in un Hash , ad es. Rappresentazione,

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

che viene convertito in una stringa json di to_json :

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

Ciò è utile perché consente di utilizzare l' label e il value seguito in javascript, ad esempio per mostrare suggerimenti sugli strumenti per gli indicatori di mappa.

Altri attributi

Altri attributi virtuali possono essere esposti sovrascrivendo il metodo as_json .

Ad esempio, per esporre un attributo title , as_json nell'hash unito 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

L'esempio precedente utilizza super per chiamare il metodo as_json originale, che restituisce l'hash dell'attributo originale dell'oggetto e lo unisce con l'hash della posizione richiesta.

Per capire la differenza tra as_json e to_json , dai un'occhiata a questo post sul blog di jjulian .

Posizione

Per rendere i marcatori, l'API di google maps, per impostazione predefinita, richiede un hash di position che ha la longitudine e la latitudine memorizzate come lng e lat rispettivamente.

Questo hash di posizione può essere creato in javascript, in seguito, o qui quando si definisce la rappresentazione json del campo dell'indirizzo:

Per fornire questa position come attributo json del campo dell'indirizzo, basta sovrascrivere il metodo as_json sul modello.

# 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow