Yer Otomatik Tamamlama ve Routes API ile rota planlayıcı oluşturma

1. Genel Bakış

İster uzun bir yolculuğa çıkın, ister günlük işe gidip gelme yolculuğunuzu planlayın, ister kalabalık bir şehirde yolunuzu bulun, A noktasından B noktasına gitmek istediğiniz yeri bilmekten daha fazlasını gerektirir. Güvenilir bir rota oluşturma aracı olmazsa olmazdır.

Google Haritalar Platformu ile uygulamanıza dinamik bir harita ekleyebilir, kullanıcıların otomatik tamamlama özelliğiyle konumları hızlıca girmesine olanak tanıyabilir ve rotaları haritada gösterebilirsiniz.

Bu Codelab, geliştiricilere Maps JavaScript API, Otomatik Yer Tamamlama ve Routes API'yi kullanarak bir web uygulaması oluşturma konusunda rehberlik eder. Özelleştirilebilir bir eğitimle birden fazla Google Haritalar Platformu API'sini nasıl entegre edeceğinizi öğreneceksiniz.

Ne oluşturacaksınız?

Bu Codelab'de HTML, CSS, JavaScript ve Node.js arka ucu kullanarak bir web uygulaması oluşturma konusunda size yol gösterilecektir.

Rota planlayıcı web uygulaması mimarisi

Rota planlayıcı web uygulaması

Neler öğreneceksiniz?

  • Google Haritalar Platformu API'lerini etkinleştirme
  • Dinamik haritayı web uygulamasına entegre etme
  • Yer Otomatik Tamamlama hizmetini entegre etme
  • Routes API ile rota isteğinde bulunma
  • Rotayı dinamik haritada görüntüleme
  • Harita kimliği oluşturma
  • Dinamik haritaya gelişmiş işaretçiler ekleme

İhtiyacınız olanlar

Örnek kod

Çözümün tamamı ve adım adım kod GitHub'da mevcuttur. Kod, gerekli Node paketlerini içermiyor. Kodu yürütmeden önce gerekli bağımlılıkları yükleyin. Gerekli paketlerin ayrıntılarını package.json dosyasında(3. adımda açıklanmıştır) bulabilirsiniz.

2. Projeyi ayarlama ve API'leri etkinleştirme

Etkinleştirme adımında Maps JavaScript API, Otomatik Yer Tamamlama ve Routes API'yi etkinleştirmeniz gerekir.

Google Haritalar Platformu'nu ayarlama

Henüz bir Google Cloud Platform hesabınız ve faturalandırmanın etkinleştirildiği bir projeniz yoksa lütfen faturalandırma hesabı ve proje oluşturmak için Google Haritalar Platformu'nu Kullanmaya Başlama kılavuzuna bakın.

  1. Cloud Console'da proje açılır menüsünü tıklayın ve bu codelab için kullanmak istediğiniz projeyi seçin. Proje seçin
  2. Bu codelab için gereken Google Haritalar Platformu API'lerini Haritalar API Kitaplığı sayfasında etkinleştirin. Bunun için bu videodaki veya bu dokümandaki adımları uygulayın.
  3. Cloud Console'un Kimlik Bilgileri sayfasında bir API anahtarı oluşturun. Bu videodaki veya bu dokümandaki adımları uygulayabilirsiniz. Google Haritalar Platformu'na yapılan tüm istekler için API anahtarı gerekir.

3. Node.js projesi oluşturma

Bu laboratuvarda, web'den başlangıç ve hedef noktalarını toplamak ve Routes API aracılığıyla rota isteğinde bulunmak için Node.js'yi kullanacağız.

Node.js'yi yüklediğinizi varsayarak bu projeyi çalıştırmak için kullanacağınız bir dizin oluşturun:

$ mkdir ac_routes
$ cd ac_routes

Uygulamanızın dizininde yeni bir Node.js paketi başlatın:

$ npm init

Bu komut, uygulamanızın adı ve sürümü gibi çeşitli bilgiler ister. Şimdilik çoğu için varsayılan ayarları kabul etmek üzere RETURN tuşuna basmanız yeterlidir. Varsayılan giriş noktası index.js'dir. Bunu ana dosyanızla değiştirebilirsiniz. Bu laboratuvarda ana dosya function/server.js'dir(6. adımda daha fazla bilgi verilmektedir).

Ayrıca, tercih ettiğiniz çerçeveyi ve modülleri yükleyebilirsiniz. Bu laboratuvarda web çerçevesi(Express) ve gövde ayrıştırıcı(body-parser) kullanılır. Daha fazla bilgiyi package.json dosyasında bulabilirsiniz.

4. Dinamik harita oluşturma

Node.js arka ucumuzu oluşturduğumuza göre şimdi de istemci tarafı için gerekli adımları inceleyelim.

  • Uygulama için bir HTML sayfası oluşturun
  • Stil oluşturmak için CSS dosyası oluşturma
  • Google Maps JavaScript API'yi HTML sayfasına yükleme
  • Uygulamanızın kimliğini doğrulamak için API anahtarınızı komut dosyası etiketine yapıştırın.
  • Uygulama işlevselliğini işlemek için bir JavaScript dosyası oluşturun.

HTML sayfası oluşturma

  1. Proje klasörünüzde yeni bir dizin oluşturun(bu örnekte ac_routes)
     $ mkdir public
     $ cd public
    
  2. Herkese açık dizinde index.html dosyasını oluşturun.
  3. Aşağıdaki kodu index.html dosyasına kopyalayın.
     <!DOCTYPE html>
     <html>
     <head>
       <title>GMP Autocomplete + Routes</title>
       <meta charset="utf-8">
       <link rel="stylesheet" type="text/css" href="style.css">
     </head>
     <body>
       <div class="container">
         <!-- Start of the container for map -->
         <div class="main">
           <div id="map"></div>
         </div>
         <!-- End of the container for map -->
       </div>
       </body>
     </html>
    

CSS dosyası oluşturma

  1. Herkese açık dizinde style.css dosyasını oluşturun
  2. Aşağıdaki kodu style.css dosyasına kopyalayın:
     html, body {height: 100%;}
     body {
       background: #fff;
       font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif;
       font-style: normal;
       font-weight: normal;
       font-size:16px;
       line-height: 1.5;
       margin: 0;
       padding: 0;
     }
     .container {display:flex; width:90%; padding:100px 0; margin:0 auto;}
     .main {width:70%; height:800px;}
      #map {height:100%; border-radius:20px;}
    

Maps JavaScript API'yi yükleme

Bu laboratuvarda, Maps JavaScript API'yi yüklemek için dinamik kitaplık içe aktarma özelliğini kullanacağız. Buradan daha ayrıntılı bilgi edinebilirsiniz.

index.html dosyasında, kapanış gövde etiketinden önce aşağıdaki kodu kopyalayın. "YOUR_API_KEY" kısmını kendi API anahtarınızla değiştirin.

<script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({key: "YOUR_API_KEY", v: "weekly"});</script>

JavaScript dosyası oluşturma

  1. Herkese açık dizinde app.js dosyasını oluşturun.
  2. Aşağıdaki kodu app.js dosyasına kopyalayın.
     (function(){
       let map;
    
       async function initMap() {
           const { Map } = await google.maps.importLibrary('maps');
           map = new Map(document.getElementById('map'), {
               center: { lat: -34.397, lng: 150.644 },
               zoom: 8,
               mapId: 'DEMO_MAP_ID'
           });
       }
    
       initMap();
     }());
    

DEMO_MAP_ID, Haritalar kimliği gerektiren kod örneklerinde kullanılabilen bir kimliktir. Bu kimlik, üretim uygulamalarında kullanılmak üzere tasarlanmamıştır ve bulut stilini gerektiren özellikler için kullanılamaz. Bu laboratuvarda, sonraki aşamada gelişmiş işaretçiler için bir harita kimliği gereklidir. Uygulamanız için harita kimliği oluşturma hakkında daha fazla bilgi edinin.

index.html dosyasında, app.js dosyasını kapanış body etiketinden önce ve Haritalar JavaScript API'sini yükleyen komut dosyası etiketinden sonra bağlayın.

<script type="text/JavaScript" src="app.js"></script>

Tam örnek kod

Bu noktaya kadar olan kodun tamamını GitHub:step1_createDynamicMap adresinde bulabilirsiniz.

5. Başlangıç ve varış noktası adreslerini girme

  • index.html dosyasına kaynak ve hedef girişi için iki metin alanı ekleyin.
  • Autocomplete kitaplığını içe aktarma
  • Otomatik Tamamlama hizmetini kaynak ve hedef metin alanlarına bağlayın

Metin alanları ekleme

index.html dosyasında, div öğesinin ilk alt öğesi olarak aşağıdaki kodu ekleyin.container

<div class="aside">
  <div class="inputgroup">
    <label for="origin">Start</label>
    <input type="text" id="origin" name="origin" class="input-location" placeholder="Enter an address">
  </div>
  <div class="inputgroup">
    <label for="origin">End</label>
    <input type="text" id="destination" name="destination" class="input-location" placeholder="Enter an address">
  </div>
</div>

Otomatik Tamamlama'yı içe aktarma ve etkinleştirme

google.maps.places.Autocomplete sınıfı, kullanıcının metin girişine göre yer tahminleri sağlayan bir widget'tır. Bu işlev, türü metin olan bir giriş öğesine eklenir ve bu alana girilen metinleri dinler. Tahmin listesi, açılır liste olarak sunulur ve metin girildikçe güncellenir.

app.js dosyasında, harita başlatma işleminden sonra aşağıdaki kodu ekleyin:

let placeIds = [];
async function initPlace() {
  const { Autocomplete } = await google.maps.importLibrary('places');
  let autocomplete = [];
  let locationFields = Array.from(document.getElementsByClassName('input-location'));
  //Enable autocomplete for input fields
  locationFields.forEach((elem,i) => {
      autocomplete[i] = new Autocomplete(elem);
      google.maps.event.addListener(autocomplete[i],"place_changed", () => {
          let place = autocomplete[i].getPlace();
          if(Object.keys(place).length > 0){
              if (place.place_id){
                  placeIds[i] = place.place_id; //We use Place Id in this example
              } else {
                  placeIds.splice(i,1); //If no place is selected or no place is found, remove the previous value from the placeIds.
                  window.alert(`No details available for input: ${place.name}`);
                  return;
              }
          }
      });
  });
}
initPlace();

Kullanıcı, otomatik tamamlama tahmini listesinden bir yer seçtikten sonra getPlace() yöntemi kullanılarak bir yer sonucu ayrıntısı alınabilir. Yer sonucu, bir yer hakkında çok fazla bilgi içerir. Bu laboratuvarda, seçilen yeri tanımlamak için place_id kullanacağız. Yer kimlikleri, Google Places veritabanında ve Google Haritalar'da bir yeri benzersiz şekilde tanımlar. Yer kimlikleri hakkında daha fazla bilgi edinin.

İlgili stilleri ekleme

style.css dosyasına aşağıdaki kodu ekleyin:

.aside {width:30%; padding:20px;}
.inputgroup {margin-bottom:30px;}
.aside label {display:block; padding:0 10px; margin-bottom:10px; font-size:18px; color:#666565;}
.aside input[type=text] {width:90%;padding:10px; font-size:16px; border:1px solid #e6e8e6; border-radius:10px;}

Tam örnek kod

Bu noktaya kadar olan kodun tamamı GitHub:step2_inputAddress adresinde mevcuttur.

6. Rotayı isteyin

  • Rota isteğini başlatmak için index.html dosyasına "Rota al" düğmesi ekleyin.
  • Bu düğme, kaynak ve hedef verilerinin Node.js hizmetine gönderilmesini tetikler.
  • Node.js hizmeti, Routes API'ye istek gönderir.
  • API yanıtı, görüntülenmek üzere istemci tarafına döndürülür.

Başlangıç ve varış noktası ayarlanıp dinamik harita hazır olduğunda rotayı alabilirsiniz. Yeni nesil, performans açısından optimize edilmiş yol tarifi ve mesafe matrisi hizmeti olan Routes API bu sorunu çözmenize yardımcı olur. Bu laboratuvarda, web'den başlangıç ve hedef noktalarını toplamak ve Routes API aracılığıyla rota isteğinde bulunmak için Node.js'yi kullanacağız.

index.html dosyasında, aside sınıfına sahip div kapanış etiketinden önce "Rota al" düğmesi ekleyin :

<div class="inputgroup">
  <button id="btn-getroute">Get a route</button>
</div>

style.css dosyasına aşağıdaki satırı ekleyin:

.aside button {padding:20px 30px; font-size:16px; border:none; border-radius:50px; background-color:#1a73e8; color:#fff;}

app.js dosyasında, kaynak ve hedef verilerini Node.js hizmetine göndermek için aşağıdaki kodu ekleyin:

function requestRoute(){
  let btn = document.getElementById('btn-getroute');
  btn.addEventListener('click', () => {
    //In this example, we will extract the Place IDs from the Autocomplete response
    //and use the Place ID for origin and destination
    if(placeIds.length == 2){
        let reqBody = {
            "origin": {
                "placeId": placeIds[0]
            },
            "destination": {
                "placeId": placeIds[1]
            }
        }

        fetch("/request-route", {
            method: 'POST',
            body: JSON.stringify(reqBody),
            headers: {
                "Content-Type": "application/json"
            }
        }).then((response) => {
            return response.json();
        }).then((data) => {
            //Draw the route on the map
            //Details will be covered in next step
            renderRoutes(data);
        }).catch((error) => {
            console.log(error);
        });
    } else {
        window.alert('Location must be set');
        return;
    }
  });
}

requestRoute();

renderRoutes(), rotayı haritada çizmek için kullanacağımız işlevdir. Ayrıntıları sonraki adımda ele alacağız.

Sunucuyu oluşturma

Proje dizininde(bu örnekte ac_routes) function adlı yeni bir klasör oluşturun. Bu klasörün içinde server.js adlı bir dosya oluşturun. Dosya, Node.js projenizi oluştururken yapılandırılan ve üç temel işlevi yerine getiren projenizin giriş noktası olarak işlev görür:

  1. Web istemcisinden veri toplama
  2. Routes API'ye istek gönderme
  3. API yanıtını istemci tarafına döndürme

Aşağıdaki kodu server.js dosyasına kopyalayın. "YOUR_API_KEY" kısmını kendi API anahtarınızla değiştirin. API anahtarı güvenliğini artırmak için arka uçta farklı bir anahtar kullanmanızı önemle tavsiye ederiz. Güvenlik rehberliğine göz atın.

const express = require('express');
const app = express();
const bodyParser = require('body-parser');

const port  = 8080;
const urlencodedParser = bodyParser.urlencoded({extended:true}); 

function main() {
  app.use('/', express.static('public'));
  app.use(urlencodedParser);
  app.use(express.json());

  app.post('/request-route', (req,res) => {    
    fetch("https://routes.googleapis.com/directions/v2:computeRoutes", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Goog-Api-Key": "YOUR_API_KEY",
        "X-Goog-FieldMask": "*"
      },
      body: JSON.stringify(req.body)
    }).then((response) => {
      return response.json();
    }).then((data) => {
      if('error' in data){
        console.log(data.error);
      } else if(!data.hasOwnProperty("routes")){
        console.log("No route round");
      } else {
        res.end(JSON.stringify(data));
      }
    }).catch((error) => {
      console.log(error)
    });
  });

  app.listen(port, () => {
      console.log('App listening on port ${port}: ' + port);
      console.log('Press Ctrl+C to quit.');
  });
}

main();

Routes API ile rota alma hakkında daha fazla bilgi edinin.

Kodu çalıştırma

Komut satırında aşağıdaki kodu çalıştırın:

$ node function/server.js

Tarayıcıyı açıp http://127.0.0.1:8080/index.html adresini ziyaret edin. Uygulama sayfasını görürsünüz. Bu aşamaya kadar API yanıtı web istemcisine döndürülür. Bir sonraki adımda rotayı haritada nasıl göstereceğimize bakalım.

Tam örnek kod

Bu noktaya kadar olan kodun tamamı GitHub:step3_requestRoute adresinde mevcuttur.

7. Rotayı haritada görüntüleme

Önceki adımda, Node.js hizmetinden yanıtı başarıyla aldığımızda renderRoutes() olarak adlandırıyoruz. Şimdi de rotayı haritada göstermek için kodu ekleyelim.

app.js dosyasına aşağıdaki kodu ekleyin:

let paths = [];
async function renderRoutes(data) {
  const { encoding } = await google.maps.importLibrary("geometry");
  let routes = data.routes;
  let decodedPaths = [];

  ///Display routes and markers
  routes.forEach((route,i) => {
      if(route.hasOwnProperty('polyline')){
        //Decode the encoded polyline
        decodedPaths.push(encoding.decodePath(route.polyline.encodedPolyline));

        //Draw polyline on the map
        for(let i = decodedPaths.length - 1; i >= 0; i--){
            let polyline = new google.maps.Polyline({
                map: map,
                path: decodedPaths[i],
                strokeColor: "#4285f4",
                strokeOpacity: 1,
                strokeWeight: 5
            });
            paths.push(polyline);
        }
        
        //Add markers for origin/destination
        addMarker(route.legs[0].startLocation.latLng,"A");
        addMarker(route.legs[0].endLocation.latLng,"B");
        //Set the viewport
        setViewport(route.viewport);
      } else {
        console.log("Route cannot be found");
      }
  });
}

Routes API, polyline'ı encodedPolyline(varsayılan) veya geoJsonLinestring biçiminde döndürür. Bu laboratuvarda, encodedPolyline biçimini kullanıp Maps JavaScript geometry kitaplığını kullanarak kodunu çözeceğiz.

Başlangıç ve hedef için gelişmiş işaretçiler eklemek üzere addMarker() simgesini kullanacağız. app.js dosyasına aşağıdaki kodu ekleyin:

let markers = [];
async function addMarker(pos,label){
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
  const { PinElement } = await google.maps.importLibrary("marker");
  const { LatLng } = await google.maps.importLibrary("core");
  let pinGlyph = new PinElement({
      glyphColor: "#fff",
      glyph: label
  });
  let marker = new AdvancedMarkerElement({
      position: new LatLng({lat:pos.latitude,lng:pos.longitude}),
      gmpDraggable: false,
      content: pinGlyph.element,
      map: map
  });
  markers.push(marker);
}

Burada iki gelişmiş işaretçi oluşturuyoruz: A, başlangıç noktası için; B ise hedef için. Gelişmiş işaretçiler hakkında daha fazla bilgi edinin.

Ardından, Routes API tarafından sağlanan kullanışlı viewport bilgilerini kullanarak harita görüntü alanını alınan rotanın ortasına yerleştiririz. app.js dosyasına aşağıdaki kodu ekleyin:

async function setViewport(viewPort) {
  const { LatLng } = await google.maps.importLibrary("core");
  const { LatLngBounds } = await google.maps.importLibrary("core");
  let sw = new LatLng({lat:viewPort.low.latitude,lng:viewPort.low.longitude});
  let ne = new LatLng({lat:viewPort.high.latitude,lng:viewPort.high.longitude});
  map.fitBounds(new LatLngBounds(sw,ne));
}

Tam örnek kod Bu noktaya kadar olan kodun tamamı GitHub:step4_displayRoute adresinde mevcuttur.

8. Haritadan öğe kaldırma

Bu noktada bir adım daha ileri gitmek istiyoruz. Yeni işaretçiler ve rotalar çizmeden önce haritayı temizleyelim. Böylece harita karışık görünmez.

app.js dosyasına bir işlev daha ekleyelim:

function clearUIElem(obj,type) {
  if(obj.length > 0){
      if(type == 'advMarker'){
          obj.forEach(function(item){
              item.map = null;
          });
      } else {
          obj.forEach(function(item){
              item.setMap(null);
          });
      }
  }
}

renderRoutes() dosyasının başına aşağıdaki satırı ekleyin:

clearUIElem(paths,'polyline');

addMarker() dosyasının başına aşağıdaki satırı ekleyin:

clearUIElem(markers,'advMarker');

Tam örnek kod

Bu noktaya kadar olan kodun tamamı GitHub:step5_removeElements adresinde mevcuttur.

9. Tebrikler

Şeyi başarıyla oluşturdunuz.

Öğrendikleriniz

  • Google Haritalar Platformu API'lerini etkinleştirme
  • Google Maps JavaScript API'yi HTML sayfasına yükleme
  • Yerleri içe aktarma kitaplığı, Maps JavaScript API
  • Yer Otomatik Tamamlama hizmetini metin alanlarına bağlama
  • Routes API aracılığıyla rota isteğinde bulunma
  • Rotayı dinamik bir haritada görüntüleme
  • Harita kimliği oluşturma
  • Gelişmiş İşaretler Oluşturma

Daha fazla bilgi

Başka hangi codelab'leri görmek istersiniz?

Haritalarda veri görselleştirme Haritalarımın stilini özelleştirme hakkında daha fazla bilgi Haritalarda 3D etkileşimler için geliştirme

İstediğiniz codelab yukarıda listelenmiyor mu? Buradan yeni bir sorunla ilgili istekte bulunun.