رسم مسیر بر روی نقشه با استفاده از کتابخانه mapboxgl

رسم مسیر بر روی نقشه با استفاده از کتابخانه mapbox-gl نشان

برای استفاده از کیت توسعه‌ی نقشه وب ابتدا بایستی از طریق ثبت نام رایگان در پنل توسعه‌دهندگان نشان، اقدام به دریافت کلید دسترسی برای (API Key) برای وب‌سایت یا اپلیکیشن تحت وب خود نمایید.

در اینجا با استفاده از کتابخانه mapbox-gl نشان یک نقشه را پیاده سازی می‌کنیم و سپس بر روی نقشه بر اساس نمونه پاسخ بازگشتی از ارسال درخواست به سرویس مسیریابی نشان خطوط مسیر را رسم می‌کنیم.

1- راه اندازی نقشه

ابتدا یک فایل HTML  با محتوای زیر ایجاد می‌کنیم. توجه داشته باشید برای نمایش نقشه ما نیازمند این هستیم که نقشه را با یک Id شناسایی کنیم.

            <!DOCTYPE html>
<html lang="fa">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport"
    content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Mapbox Neshan Map (Draw route Example)</title>

  <link rel="stylesheet" href="https://static.neshan.org/sdk/mapboxgl/v1.13.2/neshan-sdk/v1.1.1/index.css" />
  <script src="https://static.neshan.org/sdk/mapboxgl/v1.13.2/neshan-sdk/v1.1.1/index.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mapbox-polyline/1.2.1/polyline.js"></script>

  <style>

    body {
      height: 100vh;
      width: 100vw;
      margin: 0;
    }

    #map {
      height: 100%;
      width: 100%;
    }

  </style>
</head>

<body>
  <div id="map"></div>
  <script type="text/javascript">


    const neshanMap = new nmp_mapboxgl.Map({
      mapType: nmp_mapboxgl.Map.mapTypes.neshanVector,
      container: "map",
      zoom: 15,
      pitch: 0,
      center: [51.391165,35.700956],
      minZoom: 2,
      maxZoom: 21,
      trackResize: true,
      mapKey: "YOUR_WEB_API_KEY", // Get your own API Key on https://platform.neshan.org/panel
      poi: false,
      traffic: false,
      mapTypeControllerOptions: {
        show: true,
        position: 'bottom-left'
      }
    });


  </script>
</body>

</html>
        

2- افزودن نمونه پاسخ بازگشتی

به منظور رسم مسیر نیاز داریم تا اطلاعات مسیر را داشته باشیم در این جا نمونه پاسخی از ارسال درخواست به سرویس مسیریابی نشان را به فایل خود اضافه می‌کنیم. در این پاسخ به منظور رسم مسیر فیلد polyline را از حالت انکد شده خارج کنیم.

            // example of response data from direction-API v4
        // request URL : https://api.neshan.org/v4/direction?type=car&origin=35.700785062128666,51.38881156907395&destination=35.703189177622946,51.3908984545814&alternative=false

        var exampleResponse = {
            "routes": [
                {
                    "overview_polyline": {
                        "points": "cy{xEa{sxHCyEr@}FIi@MWi@Um@L[l@A^{Jr@"
                    },
                    "legs": [
                        {
                            "summary": "میدان انقلاب اسلامی - کارگر شمالی",
                            "distance": {
                                "value": 555.0,
                                "text": "۵۷۵ متر"
                            },
                            "duration": {
                                "value": 99.0,
                                "text": "۲ دقیقه"
                            },
                            "steps": [
                                {
                                    "name": "آزادی",
                                    "instruction": "در جهت شرق در آزادی قرار بگیرید",
                                    "bearing_after": 88,
                                    "type": "depart",
                                    "distance": {
                                        "value": 197.0,
                                        "text": "۲۰۰ متر"
                                    },
                                    "duration": {
                                        "value": 35.0,
                                        "text": "۱ دقیقه"
                                    },
                                    "polyline": "cy{xEa{sxHAkBAmBDa@BKHs@BWD]J{@",
                                    "start_location": [
                                        51.388811,
                                        35.70082
                                    ]
                                },
                                {
                                    "name": "کارگر شمالی",
                                    "instruction": "در میدان انقلاب اسلامی، از خروجی سوم، خارج شوید",
                                    "rotaryName": "میدان انقلاب اسلامی",
                                    "bearing_after": 111,
                                    "type": "rotary",
                                    "modifier": "straight",
                                    "exit": 3,
                                    "distance": {
                                        "value": 146.0,
                                        "text": "۱۵۰ متر"
                                    },
                                    "duration": {
                                        "value": 38.0,
                                        "text": "۱ دقیقه"
                                    },
                                    "polyline": "}w{xEohtxHDSBUCUESEKGKSOUEW@UJORKXAN?N",
                                    "start_location": [
                                        51.390956,
                                        35.700632
                                    ]
                                },
                                {
                                    "name": "",
                                    "instruction": "به مسیر خود ادامه دهید",
                                    "bearing_after": 354,
                                    "type": "exit rotary",
                                    "modifier": "right",
                                    "exit": 3,
                                    "distance": {
                                        "value": 212.0,
                                        "text": "۲۲۵ متر"
                                    },
                                    "duration": {
                                        "value": 39.0,
                                        "text": "۱ دقیقه"
                                    },
                                    "polyline": "a|{xEuitxH_ADaBLO@{BRmAH",
                                    "start_location": [
                                        51.391154,
                                        35.701293
                                    ]
                                },
                                {
                                    "name": "کارگر شمالی",
                                    "instruction": "در مقصد قرار دارید",
                                    "bearing_after": 0,
                                    "type": "arrive",
                                    "distance": {
                                        "value": 0.0,
                                        "text": ""
                                    },
                                    "duration": {
                                        "value": 0.0,
                                        "text": ""
                                    },
                                    "polyline": "}g|xEahtxH",
                                    "start_location": [
                                        51.390885,
                                        35.703188
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        }
        

به منظور رسم مسیر بر روی نقشه لازم است تا فیلد های Polyline در پاسخ بازگشتی را از حالت کد شده خارج نمائیم. در اینجا برای برای decode مسیر از این کتابخانه به صورت cdn استفاده شده است.

مطالعه مستندات الگوریتم encode مسیر گوگل

3- استخراج مسیر و نقاط هر گام مسیر

حال با پیمایش پاسخ بازگشتی از سرویس مسیر یابی را پیمایش می‌کنیم تا اطلاعات مربوط به مسیر و نقاط شروع هر گام را استخراج کنیم و براساس آن ها geoJson های لازم برای رسم مسیر را ایجاد نمائیم.

             var routes = [];
    var points = [];

    for (let k = 0; k < exampleResponse.routes.length; k++) {
      for (let j = 0; j < exampleResponse.routes[k].legs.length; j++) {
        for (let i = 0; i < exampleResponse.routes[k].legs[j].steps.length; i++) {

          var step = exampleResponse.routes[k].legs[j].steps[i]["polyline"];
          var point = exampleResponse.routes[k].legs[j].steps[i]["start_location"];

          var route = polyline.decode(step, 5);

          route.map(item => { item.reverse() })

          routes.push(route);
          points.push(point);

        }
      }
    }

 var routeObj = {
    type: 'FeatureCollection',
    features: [
      {
        type: 'Feature',
        geometry: {
          type: 'MultiLineString',
          coordinates: routes 
        }
      }
    ]
};

 var pointsObj = {
    type: 'FeatureCollection',
    features: [
    {
      type:"Feature",
      geometry:
          {
              "type": "MultiPoint",
              "coordinates": points
          }
    }
  ]
};
        

4- افزودن لایه مسیر و نقاط شروع گام به نقشه

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

            neshanMap.on('load', function () {

    neshanMap.addSource('route', {
      type: 'geojson',
      data: routeObj 
    });
    neshanMap.addSource('points1', {
      type: 'geojson',
      data: pointsObj 
    });

    neshanMap.addLayer({
      id: 'route-line',
      type: 'line',
      source: 'route',
      layout: {
        'line-join': 'round',
        'line-cap': 'round'
      },
      paint: {
        'line-color': '#250ECD',
        'line-width': 9
      }
    });

    neshanMap.addLayer({
      id: 'points1',
      type: 'circle',
      source: 'points1',
      paint: {
        "circle-color" : "#9fbef9",
        "circle-stroke-color":"#FFFFFF",
        "circle-stroke-width": 2,
        "circle-radius" : 5
      }
    });
  });
        

پس از افزودن تکه کد بالا محتویات صفحه به شکل زیر در می‌آید:

            <!DOCTYPE html>
<html lang="fa">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport"
    content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Mapbox Neshan Map (Draw route Example)</title>

  <link rel="stylesheet" href="https://static.neshan.org/sdk/mapboxgl/v1.13.2/neshan-sdk/v1.1.1/index.css" />
  <script src="https://static.neshan.org/sdk/mapboxgl/v1.13.2/neshan-sdk/v1.1.1/index.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mapbox-polyline/1.2.1/polyline.js"></script>

  <style>

    body {
      height: 100vh;
      width: 100vw;
      margin: 0;
    }

    #map {
      height: 100%;
      width: 100%;
    }

  </style>
</head>

<body>
  <div id="map"></div>
  <script type="text/javascript">

    // example of response data from direction-API v4
    // request URL : https://api.neshan.org/v4/direction?type=car&origin=35.700785062128666,51.38881156907395&destination=35.703189177622946,51.3908984545814&alternative=false

    var exampleResponse = {
      "routes": [
        {
          "overview_polyline": {
            "points": "cy{xEa{sxHCyEr@}FIi@MWi@Um@L[l@A^{Jr@"
          },
          "legs": [
            {
              "summary": "میدان انقلاب اسلامی - کارگر شمالی",
              "distance": {
                "value": 555.0,
                "text": "۵۷۵ متر"
              },
              "duration": {
                "value": 99.0,
                "text": "۲ دقیقه"
              },
              "steps": [
                {
                  "name": "آزادی",
                  "instruction": "در جهت شرق در آزادی قرار بگیرید",
                  "bearing_after": 88,
                  "type": "depart",
                  "distance": {
                    "value": 197.0,
                    "text": "۲۰۰ متر"
                  },
                  "duration": {
                    "value": 35.0,
                    "text": "۱ دقیقه"
                  },
                  "polyline": "cy{xEa{sxHAkBAmBDa@BKHs@BWD]J{@",
                  "start_location": [
                    51.388811,
                    35.70082
                  ]
                },
                {
                  "name": "کارگر شمالی",
                  "instruction": "در میدان انقلاب اسلامی، از خروجی سوم، خارج شوید",
                  "rotaryName": "میدان انقلاب اسلامی",
                  "bearing_after": 111,
                  "type": "rotary",
                  "modifier": "straight",
                  "exit": 3,
                  "distance": {
                    "value": 146.0,
                    "text": "۱۵۰ متر"
                  },
                  "duration": {
                    "value": 38.0,
                    "text": "۱ دقیقه"
                  },
                  "polyline": "}w{xEohtxHDSBUCUESEKGKSOUEW@UJORKXAN?N",
                  "start_location": [
                    51.390956,
                    35.700632
                  ]
                },
                {
                  "name": "",
                  "instruction": "به مسیر خود ادامه دهید",
                  "bearing_after": 354,
                  "type": "exit rotary",
                  "modifier": "right",
                  "exit": 3,
                  "distance": {
                    "value": 212.0,
                    "text": "۲۲۵ متر"
                  },
                  "duration": {
                    "value": 39.0,
                    "text": "۱ دقیقه"
                  },
                  "polyline": "a|{xEuitxH_ADaBLO@{BRmAH",
                  "start_location": [
                    51.391154,
                    35.701293
                  ]
                },
                {
                  "name": "کارگر شمالی",
                  "instruction": "در مقصد قرار دارید",
                  "bearing_after": 0,
                  "type": "arrive",
                  "distance": {
                    "value": 0.0,
                    "text": ""
                  },
                  "duration": {
                    "value": 0.0,
                    "text": ""
                  },
                  "polyline": "}g|xEahtxH",
                  "start_location": [
                    51.390885,
                    35.703188
                  ]
                }
              ]
            }
          ]
        }
      ]
    }

    const neshanMap = new nmp_mapboxgl.Map({
      mapType: nmp_mapboxgl.Map.mapTypes.neshanVector,
      container: "map",
      zoom: 15,
      pitch: 0,
      center: [51.391165,35.700956],
      minZoom: 2,
      maxZoom: 21,
      trackResize: true,
      mapKey: "YOUR_WEB_API_KEY", // Get your own API Key on https://platform.neshan.org/panel
      poi: false,
      traffic: false,
      mapTypeControllerOptions: {
        show: true,
        position: 'bottom-left'
      }
    });

  var routes = [];
    var points = [];

    for (let k = 0; k < exampleResponse.routes.length; k++) {
      for (let j = 0; j < exampleResponse.routes[k].legs.length; j++) {
        for (let i = 0; i < exampleResponse.routes[k].legs[j].steps.length; i++) {

          var step = exampleResponse.routes[k].legs[j].steps[i]["polyline"];
          var point = exampleResponse.routes[k].legs[j].steps[i]["start_location"];

          var route = polyline.decode(step, 5);

          route.map(item => { item.reverse() })

          routes.push(route);
          points.push(point);

        }
      }
    }

 var routeObj = {
    type: 'FeatureCollection',
    features: [
      {
        type: 'Feature',
        geometry: {
          type: 'MultiLineString',
          coordinates: routes 
        }
      }
    ]
};

 var pointsObj = {
    type: 'FeatureCollection',
    features: [
    {
      type:"Feature",
      geometry:
          {
              "type": "MultiPoint",
              "coordinates": points
          }
    }
  ]
};

  neshanMap.on('load', function () {

    neshanMap.addSource('route', {
      type: 'geojson',
      data: routeObj 
    });
    neshanMap.addSource('points1', {
      type: 'geojson',
      data: pointsObj 
    });

    neshanMap.addLayer({
      id: 'route-line',
      type: 'line',
      source: 'route',
      layout: {
        'line-join': 'round',
        'line-cap': 'round'
      },
      paint: {
        'line-color': '#250ECD',
        'line-width': 9
      }
    });

    neshanMap.addLayer({
      id: 'points1',
      type: 'circle',
      source: 'points1',
      paint: {
        "circle-color" : "#9fbef9",
        "circle-stroke-color":"#FFFFFF",
        "circle-stroke-width": 2,
        "circle-radius" : 5
      }
    });
  });

  </script>
</body>

</html>