Sök…


Lägg till Google Maps-javascript-taggen i layouthuvudet

Lägg till javascript-taggen direkt i layouthuvudet i stället för att inkludera den i en vy för att google maps ska fungera korrekt med turbolinks .

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

google_maps_api_script_tag definieras bäst i en hjälpare.

# 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

Du kan registrera din ansökan på google och få din api-nyckel i google api-konsolen . Google har en kort guide för att begära en api-nyckel för Google Maps javascript api .

Api-nyckeln lagras i filen secrets.yml :

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

Glöm inte att lägga till config/secrets.yml i din .gitignore fil och se till att du inte begår api-nyckeln till förvaret.

Geocode modellen

Anta att dina användare och / eller grupper har profiler och du vill visa adressprofilfält på en Google-karta.

# 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

Geocoder-pärlan är ett bra sätt att geokodera adresserna, dvs ge longitude och latitude .

Lägg till geocoder i din Gemfile och kör bundle att installera den.

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

Lägg till databaskolumner för latitude och longitude för att spara platsen i databasen. Detta är mer effektivt än att fråga efter geokodningstjänsten varje gång du behöver platsen. Det är snabbare och du träffar inte frågegränsen så snabbt.

➜ 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

Lägg till geokodningsmekanismen till din modell. I det här exemplet lagras value värdeattributet. Konfigurera geokodningen för att utföra när posten har ändrats, och endast när ett värde är närvarande:

# 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

Som standard använder geocoder Google som uppslagstjänst. Det har många intressanta funktioner som avståndsberäkningar eller närhetssökning. För mer information, titta på geocodern README .

Visa adresser på en Google-karta i profilvyn

Visa profilfälten för en användare eller grupp i en lista samt adressfält på en Google-karta.

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

De lämpliga @profile_fields och @address_fields ställs in i regulatorn:

# 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

Initiera kartan, placera markörerna, ställ in zoom och andra kartinställningar med javascript.

Exempel på profilvy

Ställ markörerna på kartan med javascript

Antag finns en .google_map div, som kommer att bli kartan och som har adressfälten för att visa som markörer som data attribut.

Till exempel:

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

För att använda $(document).ready med turbolinks utan att hantera turbolinkshändelserna för hand, använd jquery.turbolinks-pärla .

Om du vill utföra andra operationer med kartan senare, till exempel filtrering eller infofönster, är det bekvämt att kartan hanteras av en kaffeskriptklass .

# 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

Vid användning av flera kaffe skriptfiler, som namnområde som standard, är det lämpligt att definiera en global App namespace, som delas av alla kaffe skriptfiler.

Gå sedan igenom (eventuellt flera) .google_map divs och skapa en instans av klassen App.GoogleMap för var och en av dem.

# 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

Initiera kartan med en kaffeskriptklass.

Förutsatt en App.GoogleMap kaffe script klass kan google map initieras så här:

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

För att lära dig mer om de möjliga alternativen för map_configuration , titta på Googles MapOptions-dokumentation och deras guide för att lägga till kontrollelement .

Som referens dokumenteras klassen google.maps.Map här i stort .

Initiera kartmarkörerna med en kaffeskriptklass

Förutsatt en App.GoogleMap kaffe script klass och markören informationen lagras i data-address-fields attribut .google_map div kan kartmarkörer initieras på kartan så här:

# 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

För att lära dig mer om marköralternativ, ta en titt på Googles dokumentation om MarkerOptions och deras guide till markörer .

Zooma automatiskt en karta med en kaffeskriptklass

Förutsatt en App.GoogleMap kaffe script klass med google.maps.Map lagras som @map och google.maps.Marker s lagras som @markers , kartan kan vara automatiskt zoomas, det vill säga justerat att alla markörer är synliga, så här : på kartan så här:

# 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

För att lära dig mer om gränser, titta på Googles LatLngBounds-dokumentation .

Att exponera modellegenskaperna som json

För att visa adressprofilfält som markörer på en Google-karta måste adressfältobjekten skickas som json-objekt till javascript.

Vanliga databasattribut

När du ringer to_json på ett ApplicationRecord objekt exponeras databasattributen automatiskt.

Med tanke på en ProfileFields::Address med label , value , longitude och latitude resulterar address_field.as_json i en Hash , t.ex. representation,

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

som konverteras till en json-sträng av to_json :

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

Detta är användbart eftersom det gör det möjligt att använda label och value senare i javascript, till exempel för att visa verktygstips för kartmarkörerna.

Andra attribut

Andra virtuella attribut kan exponeras genom att åsidosätta metoden as_json .

Till exempel, för att exponera en title attribut inkludera den i det sammanslagna 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

Exemplet ovan använder super att kalla den ursprungliga as_json metoden, som returnerar objektets ursprungliga attribut hash och sammanfogar det med den önskade position hash.

För att förstå skillnaden mellan as_json och to_json , titta på detta blogginlägg av jjulian .

Placera

För att göra markörer kräver Google Maps api som standard en position som har longitud och latitud lagrad som lng respektive lat .

Denna position hash kan skapas i javascript, senare eller här när du definierar json-representationen av adressfältet:

För att tillhandahålla denna position som json-attribut för adressfältet, åsidosätter du bara as_json metoden på modellen.

# 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow