با Place Autocomplete and Routes API یک برنامه ریز مسیر بسازید

1. بررسی اجمالی

چه در حال شروع یک سفر جاده ای، برنامه ریزی رفت و آمد روزانه یا پیمایش در یک شهر شلوغ باشید، رسیدن از نقطه A به نقطه B فراتر از دانستن اینکه به کجا می خواهید بروید است. یک ابزار تولید مسیر قابل اعتماد ضروری است.

با استفاده از پلتفرم نقشه های گوگل، می توانید یک نقشه پویا به برنامه خود اضافه کنید، به کاربران اجازه دهید به سرعت مکان ها را با تکمیل خودکار وارد کنند و مسیرها را روی نقشه نمایش دهند.

این Codelab توسعه دهندگان را از طریق ایجاد یک برنامه وب با استفاده از Maps JavaScript API ، Place Autocomplete و Routes API راهنمایی می کند. نحوه ادغام چندین API پلتفرم Google Maps را از طریق یک آموزش قابل تنظیم خواهید آموخت.

چیزی که خواهی ساخت

این Codelab شما را در ساخت یک برنامه وب با استفاده از HTML، CSS، جاوا اسکریپت و یک Backend Node.js راهنمایی می کند.

معماری برنامه وب برنامه ریز مسیر

برنامه وب برنامه ریز مسیر

چیزی که یاد خواهید گرفت

  • چگونه API های پلتفرم Google Maps را فعال کنیم
  • نحوه ادغام یک نقشه پویا در یک برنامه وب
  • نحوه ادغام سرویس تکمیل خودکار Places
  • نحوه درخواست مسیر از طریق Routes API
  • نحوه نمایش مسیر بر روی نقشه پویا
  • نحوه ایجاد شناسه نقشه
  • نحوه اضافه کردن نشانگرهای پیشرفته به یک نقشه پویا

آنچه شما نیاز دارید

کد نمونه

راه حل کامل و کد گام به گام در GitHub موجود است. کد شامل بسته های Node مورد نیاز نیست. قبل از اجرای کد، وابستگی های لازم را نصب کنید. جزئیات بسته های مورد نیاز را می توانید در فایل package.json (در مرحله 3 توضیح داده شده) بیابید.

2. پروژه را راه اندازی کنید و API ها را فعال کنید

برای مرحله فعال سازی، باید Maps JavaScript API ، Place Autocomplete و Routes API را فعال کنید.

پلتفرم نقشه های گوگل را راه اندازی کنید

اگر قبلاً یک حساب Google Cloud Platform و پروژه‌ای با صورت‌حساب فعال ندارید، لطفاً راهنمای شروع به کار با Google Maps Platform را برای ایجاد یک حساب صورت‌حساب و یک پروژه ببینید.

  1. در Cloud Console ، روی منوی کشویی پروژه کلیک کنید و پروژه ای را که می خواهید برای این کد لبه استفاده کنید انتخاب کنید. پروژه را انتخاب کنید
  2. APIهای پلتفرم Google Maps مورد نیاز برای این کد لبه را در صفحه کتابخانه Maps API فعال کنید. برای انجام این کار، مراحل این ویدیو یا این مستند را دنبال کنید.
  3. یک کلید API در صفحه Credentials در Cloud Console ایجاد کنید. می توانید مراحل این ویدئو یا این مستند را دنبال کنید. همه درخواست‌ها به پلتفرم Google Maps به یک کلید API نیاز دارند.

3. یک پروژه Node.js راه اندازی کنید

در این آزمایشگاه از Node.js برای جمع آوری مبدا و مقصد از وب و درخواست مسیر از طریق Routes API استفاده می کنیم.

با فرض اینکه قبلا Node.js را نصب کرده اید، یک دایرکتوری ایجاد کنید که از آن برای اجرای این پروژه استفاده می کنید:

$ mkdir ac_routes
$ cd ac_routes

یک بسته Node.js جدید را در دایرکتوری برنامه خود راه اندازی کنید:

$ npm init

این دستور چندین مورد مانند نام و نسخه برنامه را از شما می خواهد. در حال حاضر، می‌توانید به سادگی RETURN را بزنید تا پیش‌فرض‌های بیشتر آنها را بپذیرید. نقطه ورودی پیش فرض index.js است، می توانید آن را به فایل اصلی خود تغییر دهید. در این آزمایشگاه، فایل اصلی function/server.js است (جزئیات بیشتر در مرحله 6).

علاوه بر این، با خیال راحت چارچوب و ماژول های دلخواه خود را نصب کنید. این آزمایشگاه از چارچوب وب ( اکسپرس ) و تجزیه کننده بدن ( تجزیه کننده بدن ) استفاده می کند. جزئیات بیشتر را در فایل package.json بیابید.

4. یک نقشه پویا ایجاد کنید

اکنون که باطن Node.js خود را آماده کرده ایم، بیایید مراحل لازم را برای سمت کلاینت بررسی کنیم.

  • یک صفحه HTML برای برنامه ایجاد کنید
  • یک فایل CSS برای استایل ایجاد کنید
  • Google Maps JavaScript API را در صفحه HTML بارگیری کنید
  • کلید API خود را در تگ اسکریپت بچسبانید تا برنامه خود را احراز هویت کنید
  • یک فایل جاوا اسکریپت برای مدیریت عملکرد برنامه ایجاد کنید

یک صفحه HTML ایجاد کنید

  1. یک دایرکتوری جدید در پوشه پروژه خود ایجاد کنید (در این مورد ac_routes)
     $ mkdir public
     $ cd public
    
  2. در فهرست عمومی، index.html را ایجاد کنید
  3. کد زیر را در index.html کپی کنید
     <!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 ایجاد کنید

  1. style.css را در فهرست عمومی ایجاد کنید
  2. کد زیر را در style.css کپی کنید:
     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;}
    

API جاوا اسکریپت Maps را بارگیری کنید

در این آزمایشگاه، ما از واردات کتابخانه پویا برای بارگیری Maps JavaScript API استفاده خواهیم کرد. جزئیات بیشتر را اینجا بیابید.

در index.html کد زیر را قبل از بسته شدن تگ بدنه کپی کنید. «YOUR_API_KEY» را با کلید API خود جایگزین کنید.

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

یک فایل جاوا اسکریپت ایجاد کنید

  1. در فهرست عمومی، app.js را ایجاد کنید
  2. کد زیر را در app.js کپی کنید
     (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 شناسه ای است که می تواند برای نمونه کدهایی که به شناسه Maps نیاز دارند استفاده شود. این شناسه برای استفاده در برنامه‌های تولیدی در نظر گرفته نشده است و نمی‌تواند برای ویژگی‌هایی که نیاز به استایل ابری دارند استفاده شود. در این آزمایشگاه، ما به یک Map ID برای نشانگرهای پیشرفته در مرحله بعد نیاز داریم. جزئیات بیشتری درباره ایجاد شناسه نقشه برای برنامه خود بیابید.

در index.html، app.js را قبل از بسته شدن تگ بدنه و بعد از تگ اسکریپت بارگیری Maps JavaScript API پیوند دهید.

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

کد نمونه کامل

کد کامل تا این مرحله در GitHub:step1_createDynamicMap موجود است

5. آدرس های ورودی برای مبدا و مقصد

  • دو فیلد متنی در index.html برای ورودی مبدا و مقصد اضافه کنید
  • وارد کردن کتابخانه تکمیل خودکار
  • سرویس تکمیل خودکار را به قسمت های متن مبدا و مقصد متصل کنید

فیلدهای متنی را اضافه کنید

در index.html، کد زیر را به عنوان فرزند اول div با کلاس 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>

تکمیل خودکار را وارد و فعال کنید

کلاس google.maps.places.Autocomplete ویجتی است که پیش بینی مکان را بر اساس ورودی متنی کاربر ارائه می دهد. به یک عنصر ورودی از نوع متن متصل می شود و به ورودی متن در آن قسمت گوش می دهد. فهرست پیش‌بینی‌ها به‌عنوان یک فهرست کشویی ارائه می‌شود و با وارد کردن متن به‌روزرسانی می‌شود.

در app.js، کد زیر را پس از مقداردهی اولیه نقشه اضافه کنید:

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();

هنگامی که کاربر مکانی را از لیست پیش بینی تکمیل خودکار انتخاب می کند، جزئیات نتیجه مکان را می توان با استفاده از متد getPlace() بازیابی کرد. نتیجه مکان حاوی اطلاعات زیادی در مورد یک مکان است. در این آزمایشگاه قصد داریم از place_id برای شناسایی مکان انتخاب شده استفاده کنیم. شناسه‌های مکان به طور منحصربه‌فردی یک مکان را در پایگاه داده Google Places و در Google Maps شناسایی می‌کنند. جزئیات بیشتری درباره شناسه‌های مکان پیدا کنید.

اضافه کردن سبک های مرتبط

در style.css کد زیر را اضافه کنید:

.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;}

کد نمونه کامل

کد کامل تا این لحظه در GitHub:step2_inputAddress موجود است

6. درخواست مسیر

  • برای شروع درخواست مسیر، دکمه «دریافت مسیر» را به index.html اضافه کنید
  • این دکمه باعث ارسال اطلاعات مبدا و مقصد به سرویس Node.js می شود
  • سرویس Node.js درخواستی را به Routes API ارسال می کند
  • پاسخ API برای نمایش به سمت کلاینت بازگردانده می شود

با تنظیم مبدا و مقصد و نقشه پویا، زمان رسیدن به مسیر است. Routes API ، نسل بعدی، نسخه بهینه‌سازی عملکرد جهت‌ها و سرویس ماتریس فاصله به کمک می‌آید. در این آزمایشگاه از Node.js برای جمع آوری مبدا و مقصد از وب و درخواست مسیر از طریق Routes API استفاده می کنیم.

در index.html، دکمه «دریافت مسیر» را قبل از تگ بسته شدن div با کلاس aside اضافه کنید:

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

در style.css، خط زیر را اضافه کنید:

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

در app.js، کد زیر را برای ارسال اطلاعات مبدا و مقصد به سرویس Node.js اضافه کنید:

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() تابعی است که برای ترسیم مسیر روی نقشه از آن استفاده می کنیم. در مرحله بعد به جزئیات خواهیم پرداخت.

ایجاد سرور

در دایرکتوری پروژه (در این مورد ac_routes)، یک پوشه جدید به نام تابع ایجاد کنید. در داخل این پوشه فایلی به نام server.js ایجاد کنید. فایل به عنوان نقطه ورودی پروژه شما عمل می کند که در راه اندازی پروژه Node.js پیکربندی شده است و سه عملکرد کلیدی را انجام می دهد:

  1. جمع آوری داده ها از سرویس گیرنده وب
  2. ارسال درخواست به Routes API
  3. بازگرداندن پاسخ API به سمت مشتری

کد زیر را در server.js کپی کنید. «YOUR_API_KEY» را با کلید API خود جایگزین کنید. برای افزایش امنیت کلید API، ما قویاً توصیه می کنیم از یک کلید متمایز برای backend استفاده کنید. به راهنمای امنیتی مراجعه کنید.

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 را در مورد دریافت مسیر با Routes API بیابید.

کد را اجرا کنید

کد زیر را در خط فرمان اجرا کنید:

$ node function/server.js

مرورگر را باز کنید و به http://127.0.0.1:8080/index.html مراجعه کنید. شما باید صفحه برنامه را ببینید. تا این مرحله، پاسخ API به سرویس گیرنده وب برگردانده می شود. بیایید در مرحله بعد نحوه نمایش مسیر را روی نقشه ببینیم.

کد نمونه کامل

کد کامل تا این مرحله در GitHub:step3_requestRoute موجود است

7. مسیر را روی نقشه نمایش دهید

در مرحله قبل، زمانی که پاسخ سرویس Node.js را با موفقیت دریافت کردیم، به renderRoutes() اشاره می کنیم. حالا بیایید کد واقعی را اضافه کنیم تا مسیر روی نقشه نمایش داده شود.

در app.js، کد زیر را اضافه کنید:

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 چند خط را در قالب encodedPolyline (پیش‌فرض) یا geoJsonLinestring برمی‌گرداند. در این آزمایشگاه از فرمت encodedPolyline استفاده می کنیم و با استفاده از کتابخانه هندسی Maps JavaScript آن را رمزگشایی می کنیم .

ما از addMarker() برای اضافه کردن نشانگرهای پیشرفته برای مبدا و مقصد استفاده خواهیم کرد. در app.js، کد زیر را اضافه کنید:

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);
}

در اینجا ما دو نشانگر پیشرفته ایجاد می کنیم - A برای مبدا و B برای مقصد. جزئیات بیشتری در مورد نشانگرهای پیشرفته بیابید.

در مرحله بعد، با استفاده از اطلاعات نمای مناسب ارائه شده توسط Routes API، نمای نقشه را روی مسیر بازیابی شده متمرکز می کنیم. در app.js، کد زیر را اضافه کنید:

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));
}

کد نمونه کامل کد کامل تا این مرحله در GitHub:step4_displayRoute موجود است

8. عناصر را از نقشه حذف کنید

در اینجا می خواهیم قدمی فراتر برداریم. بیایید قبل از ترسیم نشانگرها و مسیرهای جدید نقشه را پاک کنیم تا از شلوغی جلوگیری کنیم.

در app.js، بیایید یک تابع دیگر اضافه کنیم:

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() اضافه کنید:

clearUIElem(paths,'polyline');

خط زیر را در ابتدای addMarker() اضافه کنید:

clearUIElem(markers,'advMarker');

کد نمونه کامل

کد کامل تا این مرحله در GitHub:step5_removeElements موجود است

9. تبریک می گویم

شما با موفقیت آن را ساخته اید.

چیزی که یاد گرفتی

  • API های پلتفرم نقشه های گوگل را فعال کنید
  • Google Maps JavaScript API را در صفحه HTML بارگیری کنید
  • وارد کردن کتابخانه مکان‌ها، Maps JavaScript API
  • سرویس تکمیل خودکار مکان را به فیلدهای متنی متصل کنید
  • درخواست یک مسیر از طریق Routes API
  • نمایش مسیر بر روی نقشه پویا
  • یک شناسه نقشه ایجاد کنید
  • نشانگرهای پیشرفته ایجاد کنید

بیشتر بدانید

دوست دارید چه کدهای دیگری را ببینید؟

تجسم داده ها بر روی نقشه ها بیشتر در مورد سفارشی کردن سبک نقشه های من ساختمان برای تعاملات سه بعدی در نقشه ها

آیا کد لبه مورد نظر شما در بالا فهرست نشده است؟ آن را با یک شماره جدید در اینجا درخواست کنید .