Leaflet - Wstęp do map

Open-source biblioteka JavaScript do obsługi interaktywnych map

Jestem z powrotem! Tym razem chciałabym pokazać Wam trochę map. Dzisiejszym tematem będzie: Jak w prosty sposób można obsłużyć mapy na własnej stronie internetowej. Do tego potrzebne nam będzie:

  1. Leaflet - biblioteka JavaScript do obsługi map
  2. Fragmenty mapy (Maps tiles)
  3. Ruby on Rails (nie jest wymagany, na początek wystarczy strona html)

Zacznijmy od początku. Co to są map tiles? Prostymi słowami, są to małe kwadratowe obrazki zawierające wygląd naszej mapy. Są one przygotowywane w postaci paczek, by można było na stronie wyświetlić większy fragment mapy.

Skąd możemy dostać takie fragmenty mapy?

Można zarejestrować się na stronie Mapbox i skorzystać z ich darmowego pakietu do obsługi map lub użyć OpenStreetMap. Jest wiele serwisów, które dostarczają map tiles, na końcu tego artykułu postaram się wymienić kilka z nich.

Przygotowania

Gdy w naszym projekcie mamy już dołączoną bibliotekę Leaflet i wybraliśmy z jakich talii będziemy korzystać możemy zacząć.

W naszym pliku index.html dodajemy następująca linijkę:

<div id='map'></div>

Po stronie JavaScript potrzebujemy jeszcze ustawić wybranego dostawcę map tiles. W tym przykładzie będę używać CoffeeScript ale każda z prezentowanych funkcjonalności jest też możliwa do osiągnięcia w czystym JavaScript.

jQuery ->
  map = L.map('map').setView([50.301, 18.654], 13)

Mapbox tiles

  L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
      attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>',
      maxZoom: 18,
      id: 'your id',
      accessToken: 'your token'
  }).addTo(map)

OpenStreetMap tiles

  L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
      attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
      maxZoom: 18
  }).addTo(map)

Toner tiles

  L.tileLayer('http://tile.stamen.com/toner/{z}/{x}/{y}.png', {
      attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://www.openstreetmap.org/copyright">ODbL</a>.',
      maxZoom: 18
  }).addTo(map)

WaterColor tiles

  L.tileLayer('http://tile.stamen.com/watercolor/{z}/{x}/{y}.png', {
      attribution: 'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.',
      maxZoom: 18
  }).addTo(map)

I to wszystko, po odświeżeniu przeglądarki powinniśmy widzieć już mapę.

Dodawanie obiektów na mapę

Teraz zaczyna się prawdziwa zabawa! Możemy zacząć dodawać różne obiekty na mapę. Jedną ważną rzecz watro tu zaznaczyć. Każdy obiekt, który będzie pojawiał się na mapie posiada swoje współrzędne (tak jak w układnie współrzędnych na Matematyce). Leaflet używa dwóch układów współrzędnych. Układu Kartezjańskiego i układu typu Szerokość-długość geograficzna. Pierwszy z nich podaje współrzędne punktu jako [długość, szerokość] a drugi jako [szerokość, długość]. Zapamiętanie, gdzie którego z tych systemów używamy jest bardzo proste. Dla obiektu GeoJSON używamy układu Kartezjańskiego dla pozostałych elementów układu Geograficznego.

Marker

marker = L.marker([50.28895538456755, 18.681907653808594]).addTo(map)

Custom marker

customIcon = L.icon(
  iconUrl: 'assets/womanonrails.jpg'
  iconSize:     [50, 50]
  iconAnchor:   [25, 25]
  className: 'round'
)

customMarker = L.marker(
  [50.29391802001304, 18.665471076965332],
  icon: customIcon
).addTo(map)

HTML marker

divIcon = L.divIcon(
  className: 'div-icon'
  html: '<div>This is my custom html</div>'
  iconSize: [100, 20]
)

L.marker([50.2845132498121, 18.668603897094727], icon: divIcon).addTo(map)

Okrąg

circle = L.circle(
  [50.290024725454515, 18.640880584716797], 500,
  color: 'red',
  fillColor: '#f03',
  fillOpacity: 0.5
).addTo(map)

Wielokąt

polygon = L.polygon([
  [50.29830444909283, 18.61384391784668],
  [50.29619353058144, 18.620710372924805],
  [50.29084727901576, 18.616890907287598],
  [50.29125855046426, 18.61354351043701],
  [50.2941373510724,  18.611998558044434],
  [50.29830444909283, 18.61384391784668]
]).addTo(map)

Popups

marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup()
circle.bindPopup("I am a circle.")
polygon.bindPopup("I am a polygon.")
popup = L.popup()
  .setLatLng([51.5, -0.09])
  .setContent("I am a standalone popup.")
  .openOn(map)

Zdarzenia

onMapClick = (e) -> console.log "Coordinate: #{e.latlng}"
map.on('click', onMapClick)
onMapClick = (e) ->
  popup = L.popup()
  popup.setLatLng(e.latlng)
  popup.setContent("You clicked the map at #{e.latlng}")
  popup.openOn(map);
  console.log "Coordinate: #{e.latlng}"

map.on('click', onMapClick)

GeoJSON

Myślę, że geoJson jest jedną z najbardziej wszechstronnych opcji biblioteki Leaflet. Dzięki niej można wyświetlać wszystkie dotychczas poznane obiekty. Dodatkowo można w łatwy sposób zmienić style obiektów, podpinać do nich zdarzenia a także wyświetlać na mapie dane GIS bezpośrednio z bazy danych takiej jak PostgreSQL.

geoData = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [[
      [18.613758087158203, 50.298386690775416],
      [18.618135452270508, 50.3022518894775],
      [18.619508743286133, 50.302279301112605],
      [18.62457275390625, 50.30570563109659],
      [18.62959384918213, 50.30510261491786],
      [18.624873161315918, 50.3016488295082],
      [18.627877235412598, 50.3005797498622],
      [18.622384071350098, 50.29600162425392],
      [18.613758087158203, 50.298386690775416]
    ]]
  }
}

style = {
  "color": "#ff7800",
  "weight": 5,
  "opacity": 0.65
}

L.geoJson(geoData, style: style).addTo(map)

Na koniec

To co pokazałam to tylko mały wycinek tego co można zrobić dzięki bibliotece Leaflet. Jeżeli szukasz bardziej zaawansowanych funkcji (jak na przykład rysowanie kształtów) zapraszam do zapoznania się z poniższymi linkami: