Ruby on Rails
GoogleMaps gebruiken met rails
Zoeken…
Voeg de javascript-tag van Google maps toe aan de layoutkop
Om Google Maps goed te laten werken met turbolinks , voegt u de JavaScript-tag rechtstreeks toe aan de lay- outkop in plaats van deze op te nemen in een weergave.
# app/views/layouts/my_layout.html.haml
!!!
%html{:lang => 'en'}
%head
- # ...
= google_maps_api_script_tag
De google_maps_api_script_tag
kan het beste in een helper worden gedefinieerd.
# 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
U kunt uw toepassing registreren bij Google en uw API-sleutel ophalen in de Google API-console . Google heeft een korte handleiding voor het aanvragen van een API-sleutel voor de JavaScript-API van Google Maps .
De api-sleutel wordt opgeslagen in het bestand secrets.yml
:
# config/secrets.yml
development:
google_maps_api_key: '...'
# ...
production:
google_maps_api_key: '...'
# ...
Vergeet niet om config/secrets.yml
.gitignore
toe te voegen aan uw .gitignore
bestand en zorg ervoor dat u de api-sleutel niet in de repository vastlegt.
Geocode het model
Stel dat uw gebruikers en / of groepen profielen hebben en dat u adresprofielvelden op een google map wilt weergeven.
# 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
Een geweldige manier om de adressen te geocoderen, dwz longitude
en latitude
is de geocoder-parel .
Voeg geocoder toe aan uw Gemfile
en voer de bundle
uit om deze te installeren.
# Gemfile
gem 'geocoder', '~> 1.3'
Voeg databasekolommen voor latitude
en longitude
toe om de locatie in de database op te slaan. Dit is efficiënter dan elke keer dat u de locatie nodig hebt, vragen naar de geocoderingsservice. Het is sneller en u bereikt de vraaglimiet niet zo snel.
➜ 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
Voeg het geocodeermechanisme toe aan uw model. In dit voorbeeld wordt de adresstring opgeslagen in het value
. Configureer de geocodering om uit te voeren wanneer het record is gewijzigd en alleen wanneer een waarde aanwezig is:
# 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
Standaard gebruikt geocoder Google als opzoekservice. Het heeft veel interessante functies zoals afstandsberekeningen of nabijheid zoeken. Kijk voor meer informatie op de geocoder README .
Toon adressen op een google map in de profielweergave
Geef in de profielweergave de profielvelden van een gebruiker of groep in een lijst weer, evenals de adresvelden op een google map.
- # app/views/profiles/show.html.haml
%h1 Contact Information
.profile_fields
= render @profile_fields
.google_map{data: address_fields: @address_fields.to_json }
De juiste @profile_fields
en @address_fields
worden ingesteld in de 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
Initialiseer de kaart, plaats de markeringen, stel de zoom en andere kaartinstellingen in met javascript.
Plaats de markeringen op de kaart met JavaScript
Stel dat er een .google_map
div is, die de kaart wordt en die de adresvelden heeft om als markeringen als data
worden weergegeven.
Bijvoorbeeld:
<!-- 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>
Gebruik de jquery.turbolinks-edelsteen om gebruik te maken van het $(document).ready
evenement met turbolinks zonder de turbolinks-gebeurtenissen handmatig te beheren.
Als u later nog andere bewerkingen met de kaart wilt uitvoeren, bijvoorbeeld filteren of informatievensters, is het handig om de kaart te laten beheren door een koffiescriptklasse .
# 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
Wanneer u meerdere koffie-scriptbestanden gebruikt, die standaard een naamruimte hebben, is het handig om een algemene App
naamruimte te definiëren die wordt gedeeld door alle koffie-scriptbestanden.
Loop vervolgens (mogelijk meerdere) .google_map
divs door en maak voor elk een exemplaar van de klasse 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
Initialiseer de kaart met een koffiescriptklasse.
Mits een App.GoogleMap
koffie- App.GoogleMap
, kan de google map als volgt worden geïnitialiseerd:
# 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
}
Voor meer informatie over de mogelijk te leren map_configuration
opties, eens een kijkje op google MapOptions documentatie en hun gids voor het toevoegen van bedieningselementen .
Ter referentie wordt de klasse google.maps.Map
hier uitgebreid gedocumenteerd .
Initialiseer de kaartmarkeringen met behulp van een koffiescriptklasse
Op voorwaarde dat een App.GoogleMap
koffie- App.GoogleMap
en de markeringsinformatie wordt opgeslagen in het kenmerk data-address-fields
van de .google_map
div, kunnen de .google_map
als volgt op de kaart worden geïnitialiseerd:
# 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
Raadpleeg de documentatie van MarkerOptions van Google en hun gids voor markeringen voor meer informatie over opties voor markeringen .
Zoom automatisch op een kaart met een koffiescriptklasse
Mits een App.GoogleMap
koffie- App.GoogleMap
met de google.maps.Map
opgeslagen als @map
en de google.maps.Marker
opgeslagen als @markers
, kan op de kaart automatisch worden ingezoomd, dwz aangepast dat alle markers zichtbaar zijn, zoals deze : op de kaart als volgt:
# 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
Bekijk de LatLngBounds-documentatie van Google voor meer informatie over grenzen.
De modeleigenschappen blootstellen als json
Om adresprofielvelden weer te geven als markeringen op een google map, moeten de adresveldobjecten als json-objecten worden doorgegeven aan javascript.
Reguliere database-attributen
Wanneer u to_json
op een ApplicationRecord
object, worden de database-kenmerken automatisch weergegeven.
Gegeven een ProfileFields::Address
met kenmerken voor label
, value
, longitude
en latitude
, resulteert address_field.as_json
in een Hash
, bijvoorbeeld representatie,
address_field.as_json # =>
{label: "Work address", value: "Willy-Brandt-Straße 1\n10557 Berlin",
longitude: ..., latitude: ...}
die wordt omgezet in een json-string door to_json
:
address_field.to_json # =>
"{\"label\":\"Work address\",\"value\":\"Willy-Brandt-Straße 1\\n
10557 Berlin\",\"longitude\":...,\"latitude\":...}"
Dit is handig omdat het mogelijk is om label
en value
later in javascript te gebruiken, bijvoorbeeld om tooltips voor de kaartmarkeringen weer te geven.
Overige attributen
Andere virtuele kenmerken kunnen worden weergegeven door de as_json
methode te overschrijven.
Bijvoorbeeld, om een bloot title
attribuut, opnemen in het samengevoegde 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
In het bovenstaande voorbeeld wordt super
gebruikt om de oorspronkelijke methode as_json
aan te roepen, die de oorspronkelijke attribuuthash van het object retourneert en deze samenvoegt met de vereiste positiehash.
Bekijk het blogbericht van jjulian om het verschil tussen as_json
en to_json
te begrijpen.
Positie
Om markeringen weer te geven, vereist de API van Google Maps standaard een position
hash waarin lengte- en breedtegraad is opgeslagen als respectievelijk lng
en lat
.
Deze positie-hash kan worden gemaakt in javascript, later of hier bij het definiëren van de json-weergave van het adresveld:
Om deze position
als json-kenmerk van het adresveld op te geven, overschrijft u gewoon de as_json
methode op het model.
# 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