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

1. قبل از شروع

یکی از رایج‌ترین ویژگی‌های یک وب‌سایت، نمایش نقشه گوگل است که یک یا چند مکان را برای یک کسب‌وکار، مؤسسه یا نهاد دیگری با حضور فیزیکی برجسته می‌کند. نحوه پیاده سازی این نقشه ها بسته به نیازها، مانند تعداد مکان ها و فرکانس تغییر آنها، می تواند بسیار متفاوت باشد.

در این کد لبه، شما به ساده‌ترین مورد استفاده نگاه می‌کنید—تعداد کمی از مکان‌ها که به ندرت تغییر می‌کنند، مانند مکان یاب فروشگاه برای یک کسب‌وکار با فروشگاه‌های زنجیره‌ای. در این مورد، می توانید از رویکرد نسبتاً کم فناوری بدون برنامه نویسی سمت سرور استفاده کنید. اما این بدان معنا نیست که نمی توانید خلاق باشید و این کار را با استفاده از قالب داده GeoJSON برای ذخیره و ارائه اطلاعات دلخواه در مورد هر فروشگاه روی نقشه خود و همچنین سفارشی کردن نشانگرها و سبک کلی خود نقشه انجام می دهید.

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

489628918395c3d0.png

پیش نیازها

  • دانش اولیه HTML و جاوا اسکریپت

کاری که خواهی کرد

  • نمایش یک نقشه با مجموعه ای از مکان های فروشگاه و اطلاعات ذخیره شده در قالب GeoJSON.
  • نشانگرها و خود نقشه را سفارشی کنید.
  • نمایش اطلاعات اضافی در مورد فروشگاه زمانی که نشانگر آن کلیک می شود.
  • نوار جستجوی تکمیل خودکار مکان را به صفحه وب اضافه کنید.
  • نزدیک ترین مکان فروشگاه به نقطه شروع ارائه شده توسط کاربر را شناسایی کنید.

2. راه اندازی شوید

در مرحله 3 از بخش زیر، سه API زیر را برای این Codelab فعال کنید:

  • Maps JavaScript API
  • Places API
  • Distance Matrix API

با پلتفرم Google Maps شروع کنید

اگر قبلاً از Google Maps Platform استفاده نکرده‌اید، راهنمای Get Started with Google Maps Platform را دنبال کنید یا لیست پخش Started with Google Maps Platform را برای تکمیل مراحل زیر تماشا کنید:

  1. یک حساب صورتحساب ایجاد کنید.
  2. یک پروژه ایجاد کنید.
  3. APIها و SDKهای پلتفرم Google Maps را فعال کنید (در قسمت قبل فهرست شده است).
  4. یک کلید API ایجاد کنید.

Cloud Shell را فعال کنید

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

برای فعال کردن Cloud Shell از Cloud Console، روی Activate Cloud Shell کلیک کنید 89665d8d348105cd.png (تهیه و اتصال به محیط فقط چند لحظه طول می کشد).

5f504766b9b3be17.png

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

d3bb67d514893d1f.png

پس از اتصال به Cloud Shell، باید ببینید که قبلاً احراز هویت شده اید و پروژه قبلاً روی ID پروژه ای که در هنگام راه اندازی انتخاب کرده اید تنظیم شده است.

$ gcloud auth list
Credentialed Accounts:
ACTIVE  ACCOUNT
  *     <myaccount>@<mydomain>.com
$ gcloud config list project
[core]
project = <YOUR_PROJECT_ID>

اگر به دلایلی پروژه تنظیم نشد، دستور زیر را اجرا کنید:

$ gcloud config set project <YOUR_PROJECT_ID>

3. "سلام، جهان!" با یک نقشه

توسعه را با نقشه شروع کنید

در Cloud Shell، شما با ایجاد یک صفحه HTML شروع می‌کنید که به عنوان پایه‌ای برای بقیه قسمت‌های Codelab عمل می‌کند.

  1. در نوار ابزار Cloud Shell، روی Launch Editor کلیک کنید 996514928389de40.png برای باز کردن یک ویرایشگر کد در یک تب جدید.

این ویرایشگر کد مبتنی بر وب به شما این امکان را می دهد که به راحتی فایل ها را در Cloud Shell ویرایش کنید.

اسکرین شات 19/04/2017 در ساعت 10.22.48.png

  1. با کلیک کردن روی File > New Folder ، یک فهرست store-locator جدید برای برنامه خود در ویرایشگر کد ایجاد کنید.

NewFolder.png

  1. پوشه جدید store-locator کنید.

بعد، یک صفحه وب با نقشه ایجاد می کنید.

  1. یک فایل در دایرکتوری store-locator نام index.html ایجاد کنید.

3c257603da5ab524.png

  1. محتوای زیر را در فایل index.html قرار دهید:

index.html

<html>

<head>
    <title>Store Locator</title>
    <style>
        #map {
            height: 100%;
        }
        
        html,
        body {
            height: 100%;
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <!-- The div to hold the map -->
    <div id="map"></div>

    <script src="app.js"></script>
    <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap&solution_channel=GMP_codelabs_simplestorelocator_v1_a">
    </script>
</body>

</html>

این صفحه HTML است که نقشه را نمایش می دهد. این شامل مقداری CSS برای اطمینان از اینکه نقشه به صورت بصری کل صفحه را می گیرد، یک <div> برای نگهداری نقشه، و یک جفت تگ <script> است. اولین تگ اسکریپت یک فایل جاوا اسکریپت به نام app.js را بارگیری می کند که حاوی تمام کدهای جاوا اسکریپت است. دومین تگ اسکریپت کلید API را بارگیری می‌کند، شامل استفاده از کتابخانه مکان‌ها برای عملکرد تکمیل خودکار است که بعداً اضافه می‌کنید، و نام تابع جاوا اسکریپت را که پس از بارگیری Maps JavaScript API اجرا می‌شود، مشخص می‌کند، یعنی initMap .

  1. متن YOUR_API_KEY را در قطعه کد با کلید API که قبلاً در این لبه کد ایجاد کردید جایگزین کنید.
  2. در نهایت فایل دیگری به نام app.js با کد زیر ایجاد کنید:

app.js

function initMap() {
   // Create the map.
    const map = new google.maps.Map(document.getElementById('map'), {
        zoom: 7,
        center: { lat: 52.632469, lng: -1.689423 },
    });

}

این حداقل کد مورد نیاز برای ایجاد نقشه است. برای نگه داشتن نقشه، یک مرجع به <div> خود ارسال می کنید و مرکز و سطح بزرگنمایی را مشخص می کنید.

برای آزمایش این برنامه، می توانید سرور ساده Python HTTP را در Cloud Shell اجرا کنید.

  1. به Cloud Shell رفته و عبارت زیر را تایپ کنید:
$ cd store-locator
$ python3 -m http.server 8080

برخی از خطوط خروجی گزارش را مشاهده می کنید که به شما نشان می دهد که در واقع سرور HTTP ساده را در Cloud Shell با برنامه وب در حال گوش دادن به پورت لوکال هاست 8080 اجرا می کنید.

  1. با کلیک بر روی پیش نمایش وب ، یک برگه مرورگر وب را در این برنامه باز کنید 95e419ae763a1d48.png در نوار ابزار Cloud Console و انتخاب Preview در پورت 8080 .

47b06e5169eb5add.png

bdab1f021a3b91d5.png

با کلیک بر روی این آیتم منو، یک تب جدید در مرورگر وب شما با محتوای HTML ارائه شده از سرور ساده Python HTTP باز می شود. اگر همه چیز خوب پیش رفت، باید نقشه ای را با مرکز لندن، انگلستان ببینید.

برای متوقف کردن سرور ساده HTTP، Control+C را در Cloud Shell فشار دهید.

4. نقشه را با GeoJSON پر کنید

اکنون به داده های فروشگاه ها نگاهی بیندازید. GeoJSON فرمت داده ای است که ویژگی های جغرافیایی ساده ای مانند نقاط، خطوط یا چند ضلعی ها را بر روی نقشه نشان می دهد. ویژگی ها همچنین می توانند حاوی داده های دلخواه باشند. این باعث می‌شود که GeoJSON کاندیدای عالی برای نمایندگی فروشگاه‌ها باشد، که اساساً نقاطی روی نقشه با کمی داده‌های اضافی مانند نام فروشگاه، ساعات کاری و شماره تلفن هستند. مهمتر از همه، GeoJSON از پشتیبانی درجه یک در Google Maps برخوردار است، به این معنی که می توانید یک سند GeoJSON را به نقشه Google ارسال کنید و آن را به طور مناسب بر روی نقشه نمایش دهد.

  1. یک فایل جدید به نام stores.json ایجاد کنید و در کد زیر قرار دهید:

stores.json

{
    "type": "FeatureCollection",
    "features": [{
            "geometry": {
                "type": "Point",
                "coordinates": [-0.1428115,
                    51.5125168
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "patisserie",
                "hours": "10am - 6pm",
                "description": "Modern twists on classic pastries. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Patisserie Mayfair",
                "phone": "+44 20 1234 5678",
                "storeid": "01"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-2.579623,
                    51.452251
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "patisserie",
                "hours": "10am - 6pm",
                "description": "Come and try our award-winning cakes and pastries. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Patisserie Bristol",
                "phone": "+44 117 121 2121",
                "storeid": "02"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [
                    1.273459,
                    52.638072
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "patisserie",
                "hours": "10am - 6pm",
                "description": "Whatever the occasion, whether it's a birthday or a wedding, Josie's Patisserie has the perfect treat for you. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Patisserie Norwich",
                "phone": "+44 1603 123456",
                "storeid": "03"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-1.9912838,
                    50.8000418
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "patisserie",
                "hours": "10am - 6pm",
                "description": "A gourmet patisserie that will delight your senses. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Patisserie Wimborne",
                "phone": "+44 1202 343434",
                "storeid": "04"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-2.985933,
                    53.408899
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "patisserie",
                "hours": "10am - 6pm",
                "description": "Spoil yourself or someone special with our classic pastries. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Patisserie Liverpool",
                "phone": "+44 151 444 4444",
                "storeid": "05"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-1.689423,
                    52.632469
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "patisserie",
                "hours": "10am - 6pm",
                "description": "Come and feast your eyes and tastebuds on our delicious pastries and cakes. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Patisserie Tamworth",
                "phone": "+44 5555 55555",
                "storeid": "06"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-3.155305,
                    51.479756
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "patisserie",
                "hours": "10am - 6pm",
                "description": "Josie's Patisserie is family-owned, and our delectable pastries, cakes, and great coffee are renowed. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Patisserie Cardiff",
                "phone": "+44 29 6666 6666",
                "storeid": "07"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-0.725019,
                    52.668891
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "cafe",
                "hours": "8am - 9:30pm",
                "description": "Oakham's favorite spot for fresh coffee and delicious cakes. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Cafe Oakham",
                "phone": "+44 7777 777777",
                "storeid": "08"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-2.477653,
                    53.735405
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "cafe",
                "hours": "8am - 9:30pm",
                "description": "Enjoy freshly brewed coffe, and home baked cakes in our homely cafe. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Cafe Blackburn",
                "phone": "+44 8888 88888",
                "storeid": "09"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-0.211363,
                    51.108966
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "cafe",
                "hours": "8am - 9:30pm",
                "description": "A delicious array of pastries with many flavours, and fresh coffee in an snug cafe. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Cafe Crawley",
                "phone": "+44 1010 101010",
                "storeid": "10"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-0.123559,
                    50.832679
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "cafe",
                "hours": "8am - 9:30pm",
                "description": "Grab a freshly brewed coffee, a decadent cake and relax in our idyllic cafe. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Cafe Brighton",
                "phone": "+44 1313 131313",
                "storeid": "11"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [-3.319575,
                    52.517827
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "cafe",
                "hours": "8am - 9:30pm",
                "description": "Come in and unwind at this idyllic cafe with fresh coffee and home made cakes. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Cafe Newtown",
                "phone": "+44 1414 141414",
                "storeid": "12"
            }
        },
        {
            "geometry": {
                "type": "Point",
                "coordinates": [
                    1.158167,
                    52.071634
                ]
            },
            "type": "Feature",
            "properties": {
                "category": "cafe",
                "hours": "8am - 9:30pm",
                "description": "Fresh coffee and delicious cakes in an snug cafe. We're part of a larger chain of patisseries and cafes.",
                "name": "Josie's Cafe Ipswich",
                "phone": "+44 1717 17171",
                "storeid": "13"
            }
        }
    ]
}

این داده‌های زیادی است، اما وقتی آن‌ها را مطالعه کنید، می‌بینید که ساختار مشابهی برای هر فروشگاه تکرار می‌شود. هر فروشگاه به عنوان یک Point GeoJSON همراه با مختصات آن و داده های اضافی موجود در زیر کلید properties داده می شود. جالب اینجاست که GeoJSON اجازه می دهد تا کلیدهایی را که به دلخواه نامگذاری شده اند، در زیر کلید properties قرار دهند. در این کد لبه، این کلیدها category ، hours ، description ، name و phone هستند.

  1. اکنون app.js را ویرایش کنید تا GeoJSON در stores.js را روی نقشه شما بارگیری کند.

app.js

function initMap() {
  // Create the map.
  const map = new google.maps.Map(document.getElementById('map'), {
    zoom: 7,
    center: {lat: 52.632469, lng: -1.689423},
  });

  // Load the stores GeoJSON onto the map.
  map.data.loadGeoJson('stores.json', {idPropertyName: 'storeid'});

  const apiKey = 'YOUR_API_KEY';
  const infoWindow = new google.maps.InfoWindow();

  // Show the information for a store when its marker is clicked.
  map.data.addListener('click', (event) => {
    const category = event.feature.getProperty('category');
    const name = event.feature.getProperty('name');
    const description = event.feature.getProperty('description');
    const hours = event.feature.getProperty('hours');
    const phone = event.feature.getProperty('phone');
    const position = event.feature.getGeometry().get();
    const content = `
      <h2>${name}</h2><p>${description}</p>
      <p><b>Open:</b> ${hours}<br/><b>Phone:</b> ${phone}</p>
    `;

    infoWindow.setContent(content);
    infoWindow.setPosition(position);
    infoWindow.setOptions({pixelOffset: new google.maps.Size(0, -30)});
    infoWindow.open(map);
  });
}

در مثال کد، شما GeoJSON خود را با فراخوانی loadGeoJson و ارسال نام فایل JSON روی نقشه بارگذاری کرده اید. شما همچنین یک تابع را تعریف کرده اید که هر بار که روی یک نشانگر کلیک می شود اجرا شود. سپس این تابع می تواند به داده های اضافی برای فروشگاهی که نشانگر آن کلیک شده است دسترسی داشته باشد و از اطلاعات در پنجره اطلاعاتی که نمایش داده می شود استفاده کند. برای آزمایش این برنامه، می‌توانید سرور ساده پایتون HTTP را با استفاده از دستور قبلی اجرا کنید.

  1. به Cloud Shell برگردید و عبارت زیر را تایپ کنید:
$ python3 -m http.server 8080
  1. پیش نمایش وب را کلیک کنید 95e419ae763a1d48.png > دوباره روی پورت 8080 پیش‌نمایش کنید و باید نقشه‌ای پر از نشانگرها را ببینید که می‌توانید روی آن کلیک کنید تا جزئیات مربوط به هر فروشگاه را مشاهده کنید، مانند مثال زیر. پیش رفتن!

c4507f7d3ea18439.png

5. نقشه را سفارشی کنید

شما تقریباً آنجا هستید. شما یک نقشه با تمام نشانگرهای فروشگاه و اطلاعات اضافی دارید که با کلیک روی آن نمایش داده می شود. اما به نظر می رسد مانند سایر نقشه های گوگل وجود دارد. چقدر کسل کننده! آن را با یک سبک نقشه سفارشی، نشانگرها، نشان‌واره‌ها و تصاویر نمای خیابان تحسین کنید.

در اینجا نسخه جدیدی از app.js با استایل سفارشی اضافه شده است:

app.js

const mapStyle = [{
  'featureType': 'administrative',
  'elementType': 'all',
  'stylers': [{
    'visibility': 'on',
  },
  {
    'lightness': 33,
  },
  ],
},
{
  'featureType': 'landscape',
  'elementType': 'all',
  'stylers': [{
    'color': '#f2e5d4',
  }],
},
{
  'featureType': 'poi.park',
  'elementType': 'geometry',
  'stylers': [{
    'color': '#c5dac6',
  }],
},
{
  'featureType': 'poi.park',
  'elementType': 'labels',
  'stylers': [{
    'visibility': 'on',
  },
  {
    'lightness': 20,
  },
  ],
},
{
  'featureType': 'road',
  'elementType': 'all',
  'stylers': [{
    'lightness': 20,
  }],
},
{
  'featureType': 'road.highway',
  'elementType': 'geometry',
  'stylers': [{
    'color': '#c5c6c6',
  }],
},
{
  'featureType': 'road.arterial',
  'elementType': 'geometry',
  'stylers': [{
    'color': '#e4d7c6',
  }],
},
{
  'featureType': 'road.local',
  'elementType': 'geometry',
  'stylers': [{
    'color': '#fbfaf7',
  }],
},
{
  'featureType': 'water',
  'elementType': 'all',
  'stylers': [{
    'visibility': 'on',
  },
  {
    'color': '#acbcc9',
  },
  ],
},
];

function initMap() {
  // Create the map.
  const map = new google.maps.Map(document.getElementById('map'), {
    zoom: 7,
    center: {lat: 52.632469, lng: -1.689423},
    styles: mapStyle,
  });

  // Load the stores GeoJSON onto the map.
  map.data.loadGeoJson('stores.json', {idPropertyName: 'storeid'});

  // Define the custom marker icons, using the store's "category".
  map.data.setStyle((feature) => {
    return {
      icon: {
        url: `img/icon_${feature.getProperty('category')}.png`,
        scaledSize: new google.maps.Size(64, 64),
      },
    };
  });

  const apiKey = 'YOUR_API_KEY';
  const infoWindow = new google.maps.InfoWindow();

  // Show the information for a store when its marker is clicked.
  map.data.addListener('click', (event) => {
    const category = event.feature.getProperty('category');
    const name = event.feature.getProperty('name');
    const description = event.feature.getProperty('description');
    const hours = event.feature.getProperty('hours');
    const phone = event.feature.getProperty('phone');
    const position = event.feature.getGeometry().get();
    const content = `
      <img style="float:left; width:200px; margin-top:30px" src="img/logo_${category}.png">
      <div style="margin-left:220px; margin-bottom:20px;">
        <h2>${name}</h2><p>${description}</p>
        <p><b>Open:</b> ${hours}<br/><b>Phone:</b> ${phone}</p>
        <p><img src="https://maps.googleapis.com/maps/api/streetview?size=350x120&location=${position.lat()},${position.lng()}&key=${apiKey}&solution_channel=GMP_codelabs_simplestorelocator_v1_a"></p>
      </div>
      `;

    infoWindow.setContent(content);
    infoWindow.setPosition(position);
    infoWindow.setOptions({pixelOffset: new google.maps.Size(0, -30)});
    infoWindow.open(map);
  });

}

این چیزی است که شما اضافه کردید:

  • متغیر mapStyle شامل تمام اطلاعات برای استایل دادن به نقشه است. (به عنوان یک امتیاز اضافی، حتی می توانید سبک خود را در صورت تمایل ایجاد کنید.)
  • با استفاده از روش map.data.setStyle ، نشانگرهای سفارشی را اعمال کردید—یک نشانگر متفاوت برای هر category از GeoJSON.
  • شما متغیر content را طوری تغییر دادید که یک نشان‌واره (دوباره با استفاده از category GeoJSON) و یک تصویر نمای خیابان برای مکان فروشگاه در آن گنجانده شود.

قبل از اجرای این، باید چند مرحله را انجام دهید:

  1. مقدار صحیح متغیر apiKey را با جایگزین کردن رشته 'YOUR_API_KEY' در app.js با کلید API قبلی خود (همان چیزی که در index.html جای‌گذاری کرده‌اید و نقل قول‌ها دست نخورده باقی می‌ماند) تنظیم کنید.
  2. برای دانلود نشانگر و گرافیک لوگو، دستورات زیر را در Cloud Shell اجرا کنید. مطمئن شوید که در دایرکتوری store-locator هستید. از Control+C برای متوقف کردن سرور HTTP ساده در صورت اجرا استفاده کنید.
$ mkdir -p img; cd img
$ wget https://github.com/googlecodelabs/google-maps-simple-store-locator/raw/master/src/img/icon_cafe.png
$ wget https://github.com/googlecodelabs/google-maps-simple-store-locator/raw/master/src/img/icon_patisserie.png
$ wget https://github.com/googlecodelabs/google-maps-simple-store-locator/raw/master/src/img/logo_cafe.png
$ wget https://github.com/googlecodelabs/google-maps-simple-store-locator/raw/master/src/img/logo_patisserie.png
  1. با اجرای دستور زیر، پیش نمایش یاب فروشگاه تمام شده را مشاهده کنید:
$ python3 -m http.server 8080

وقتی پیش‌نمایش را مجدداً بارگیری می‌کنید، باید چیزی شبیه این نقشه را با استایل سفارشی، تصاویر نشانگر سفارشی، قالب‌بندی پنجره اطلاعات بهبودیافته و یک تصویر نمای خیابان برای هر مکان ببینید:

3d8d13da126021dd.png

6. ورودی کاربر را دریافت کنید

کاربران مکان یاب فروشگاه معمولاً می خواهند بدانند کدام فروشگاه به آنها نزدیکتر است یا آدرسی که قصد دارند سفر خود را از آنجا شروع کنند. یک نوار جستجوی تکمیل خودکار مکان اضافه کنید تا کاربر بتواند به راحتی آدرس شروع را وارد کند. «تکمیل خودکار مکان» عملکردی شبیه به روش «تکمیل خودکار» در سایر نوارهای جستجوی Google ارائه می‌کند، اما پیش‌بینی‌ها همه مکان‌ها در پلتفرم نقشه‌های Google هستند.

  1. برای افزودن یک ظاهر به نوار جستجوی تکمیل خودکار و پانل جانبی مرتبط نتایج، به ویرایش index.html برگردید. فراموش نکنید که اگر کد قدیمی خود را چسبانده اید، کلید API خود را جایگزین کنید.

index.html

<html>

<head>
  <title>Store Locator</title>
  <style>
    #map {
      height: 100%;
    }
    
    html,
    body {
      height: 100%;
      margin: 0;
      padding: 0;
    }

    /* Styling for Autocomplete search bar */
    #pac-card {
      background-color: #fff;
      border-radius: 2px 0 0 2px;
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
      box-sizing: border-box;
      font-family: Roboto;
      margin: 10px 10px 0 0;
      -moz-box-sizing: border-box;
      outline: none;
    }
    
    #pac-container {
      padding-top: 12px;
      padding-bottom: 12px;
      margin-right: 12px;
    }
    
    #pac-input {
      background-color: #fff;
      font-family: Roboto;
      font-size: 15px;
      font-weight: 300;
      margin-left: 12px;
      padding: 0 11px 0 13px;
      text-overflow: ellipsis;
      width: 400px;
    }
    
    #pac-input:focus {
      border-color: #4d90fe;
    }
    
    #title {
      color: #fff;
      background-color: #acbcc9;
      font-size: 18px;
      font-weight: 400;
      padding: 6px 12px;
    }
    
    .hidden {
      display: none;
    }

    /* Styling for an info pane that slides out from the left. 
     * Hidden by default. */
    #panel {
      height: 100%;
      width: null;
      background-color: white;
      position: fixed;
      z-index: 1;
      overflow-x: hidden;
      transition: all .2s ease-out;
    }
    
    .open {
      width: 250px;
    }
    
    .place {
      font-family: 'open sans', arial, sans-serif;
      font-size: 1.2em;
      font-weight: 500;
      margin-block-end: 0px;
      padding-left: 18px;
      padding-right: 18px;
    }
    
    .distanceText {
      color: silver;
      font-family: 'open sans', arial, sans-serif;
      font-size: 1em;
      font-weight: 400;
      margin-block-start: 0.25em;
      padding-left: 18px;
      padding-right: 18px;
    }
  </style>
</head>

<body>
  <!-- The div to hold the map -->
  <div id="map"></div>

  <script src="app.js"></script>
  <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap&solution_channel=GMP_codelabs_simplestorelocator_v1_a">
  </script>
</body>

</html>

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

  1. اکنون، ویجت تکمیل خودکار را در انتهای تابع initMap در app.js ، درست قبل از بسته شدن بریس فرفری به نقشه اضافه کنید.

app.js

  // Build and add the search bar
  const card = document.createElement('div');
  const titleBar = document.createElement('div');
  const title = document.createElement('div');
  const container = document.createElement('div');
  const input = document.createElement('input');
  const options = {
    types: ['address'],
    componentRestrictions: {country: 'gb'},
  };

  card.setAttribute('id', 'pac-card');
  title.setAttribute('id', 'title');
  title.textContent = 'Find the nearest store';
  titleBar.appendChild(title);
  container.setAttribute('id', 'pac-container');
  input.setAttribute('id', 'pac-input');
  input.setAttribute('type', 'text');
  input.setAttribute('placeholder', 'Enter an address');
  container.appendChild(input);
  card.appendChild(titleBar);
  card.appendChild(container);
  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(card);

  // Make the search bar into a Places Autocomplete search bar and select
  // which detail fields should be returned about the place that
  // the user selects from the suggestions.
  const autocomplete = new google.maps.places.Autocomplete(input, options);

  autocomplete.setFields(
      ['address_components', 'geometry', 'name']);

این کد پیشنهادهای تکمیل خودکار را فقط به آدرس‌های برگشتی محدود می‌کند (زیرا تکمیل خودکار مکان می‌تواند با نام مؤسسات و مکان‌های اداری مطابقت داشته باشد) و آدرس‌های بازگردانده شده را فقط به آدرس‌هایی در بریتانیا محدود می‌کند. افزودن این مشخصات اختیاری تعداد نویسه‌هایی را که کاربر باید وارد کند کاهش می‌دهد تا پیش‌بینی‌ها را برای نشان دادن آدرس مورد نظرش محدود کند. سپس، div تکمیل خودکار را که ایجاد کرده‌اید به گوشه سمت راست بالای نقشه منتقل می‌کند و مشخص می‌کند که کدام قسمت‌ها باید در مورد هر مکان در پاسخ بازگردانده شوند.

  1. سرور خود را مجددا راه اندازی کنید و پیش نمایش خود را با اجرای دستور زیر به روز کنید:
$ python3 -m http.server 8080

اکنون باید یک ویجت تکمیل خودکار را در گوشه سمت راست بالای نقشه خود مشاهده کنید که آدرس‌های بریتانیا را با آنچه تایپ می‌کنید مطابقت دارد.

5163f34a03910187.png

اکنون، باید زمانی که کاربر یک پیش‌بینی را از ویجت تکمیل خودکار انتخاب می‌کند، رسیدگی کنید و از آن مکان به عنوان مبنایی برای محاسبه فاصله تا فروشگاه‌های خود استفاده کنید.

  1. کد زیر را به انتهای initMap در app.js بعد از کدی که به تازگی چسبانده اید اضافه کنید.

app.js

 // Set the origin point when the user selects an address
  const originMarker = new google.maps.Marker({map: map});
  originMarker.setVisible(false);
  let originLocation = map.getCenter();

  autocomplete.addListener('place_changed', async () => {
    originMarker.setVisible(false);
    originLocation = map.getCenter();
    const place = autocomplete.getPlace();

    if (!place.geometry) {
      // User entered the name of a Place that was not suggested and
      // pressed the Enter key, or the Place Details request failed.
      window.alert('No address available for input: \'' + place.name + '\'');
      return;
    }

    // Recenter the map to the selected address
    originLocation = place.geometry.location;
    map.setCenter(originLocation);
    map.setZoom(9);
    console.log(place);

    originMarker.setPosition(originLocation);
    originMarker.setVisible(true);

    // Use the selected address as the origin to calculate distances
    // to each of the store locations
    const rankedStores = await calculateDistances(map.data, originLocation);
    showStoresList(map.data, rankedStores);

    return;
  });

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

7. نزدیک ترین فروشگاه ها را فهرست کنید

Directions API بسیار شبیه تجربه درخواست مسیرها در برنامه Google Maps عمل می کند - وارد کردن یک مبدا و یک مقصد واحد برای دریافت مسیری بین این دو. Distance Matrix API این مفهوم را برای شناسایی جفت‌های بهینه بین مبداهای متعدد و چندین مقصد ممکن بر اساس زمان و مسافت‌های سفر بیشتر می‌کند. در این حالت، برای کمک به کاربر برای یافتن نزدیک‌ترین فروشگاه به آدرس انتخاب شده، یک مبدا و مجموعه‌ای از مکان‌های فروشگاه را به عنوان مقصد ارائه می‌کنید.

  1. یک تابع جدید به app.js اضافه کنید که calculateDistances نام دارد.

app.js

async function calculateDistances(data, origin) {
  const stores = [];
  const destinations = [];

  // Build parallel arrays for the store IDs and destinations
  data.forEach((store) => {
    const storeNum = store.getProperty('storeid');
    const storeLoc = store.getGeometry().get();

    stores.push(storeNum);
    destinations.push(storeLoc);
  });

  // Retrieve the distances of each store from the origin
  // The returned list will be in the same order as the destinations list
  const service = new google.maps.DistanceMatrixService();
  const getDistanceMatrix =
    (service, parameters) => new Promise((resolve, reject) => {
      service.getDistanceMatrix(parameters, (response, status) => {
        if (status != google.maps.DistanceMatrixStatus.OK) {
          reject(response);
        } else {
          const distances = [];
          const results = response.rows[0].elements;
          for (let j = 0; j < results.length; j++) {
            const element = results[j];
            const distanceText = element.distance.text;
            const distanceVal = element.distance.value;
            const distanceObject = {
              storeid: stores[j],
              distanceText: distanceText,
              distanceVal: distanceVal,
            };
            distances.push(distanceObject);
          }

          resolve(distances);
        }
      });
    });

  const distancesList = await getDistanceMatrix(service, {
    origins: [origin],
    destinations: destinations,
    travelMode: 'DRIVING',
    unitSystem: google.maps.UnitSystem.METRIC,
  });

  distancesList.sort((first, second) => {
    return first.distanceVal - second.distanceVal;
  });

  return distancesList;
}

این تابع با استفاده از مبدأ ارسال شده به آن به عنوان یک مبدأ واحد و مکان‌های فروشگاه به عنوان آرایه‌ای از مقصد، API ماتریس فاصله را فراخوانی می‌کند. سپس، آرایه‌ای از اشیاء را می‌سازد که شناسه فروشگاه را ذخیره می‌کند، فاصله بیان شده در یک رشته قابل خواندن توسط انسان، فاصله بر حسب متر به عنوان یک مقدار عددی، و آرایه را مرتب می‌کند.

کاربر انتظار دارد فهرستی از فروشگاه های سفارش داده شده از نزدیک ترین به دورترین را ببیند. با استفاده از فهرستی که از تابع calculateDistances فاصله‌ها برگردانده شده است، برای اطلاع از ترتیب نمایش فروشگاه‌ها، فهرستی در پانل کناری برای هر فروشگاه ایجاد کنید.

  1. یک تابع جدید به app.js به نام showStoresList کنید.

app.js

function showStoresList(data, stores) {
  if (stores.length == 0) {
    console.log('empty stores');
    return;
  }

  let panel = document.createElement('div');
  // If the panel already exists, use it. Else, create it and add to the page.
  if (document.getElementById('panel')) {
    panel = document.getElementById('panel');
    // If panel is already open, close it
    if (panel.classList.contains('open')) {
      panel.classList.remove('open');
    }
  } else {
    panel.setAttribute('id', 'panel');
    const body = document.body;
    body.insertBefore(panel, body.childNodes[0]);
  }


  // Clear the previous details
  while (panel.lastChild) {
    panel.removeChild(panel.lastChild);
  }

  stores.forEach((store) => {
    // Add store details with text formatting
    const name = document.createElement('p');
    name.classList.add('place');
    const currentStore = data.getFeatureById(store.storeid);
    name.textContent = currentStore.getProperty('name');
    panel.appendChild(name);
    const distanceText = document.createElement('p');
    distanceText.classList.add('distanceText');
    distanceText.textContent = store.distanceText;
    panel.appendChild(distanceText);
  });

  // Open the panel
  panel.classList.add('open');

  return;
}
  1. سرور خود را مجددا راه اندازی کنید و با اجرای دستور زیر پیش نمایش خود را به روز کنید.
$ python3 -m http.server 8080
  1. در نهایت، یک آدرس انگلستان را در نوار جستجوی تکمیل خودکار وارد کنید و روی یکی از پیشنهادات کلیک کنید.

نقشه باید در مرکز آن آدرس باشد و یک نوار کناری ظاهر شود که مکان‌های فروشگاه را به ترتیب فاصله از آدرس انتخاب‌شده فهرست می‌کند. یک نمونه به شرح زیر است:

489628918395c3d0.png

8. اختیاری: صفحه وب خود را میزبانی کنید

تا این مرحله، تنها زمانی نقشه خود را مشاهده می کنید که به طور فعال سرور HTTP پایتون خود را اجرا می کنید. برای مشاهده نقشه خود فراتر از جلسه Cloud Shell فعال یا برای اینکه بتوانید URL نقشه خود را با دیگران به اشتراک بگذارید، به استفاده از Cloud Storage برای میزبانی صفحه وب خود نگاه کنید. Cloud Storage یک سرویس وب ذخیره‌سازی فایل آنلاین برای ذخیره و دسترسی به داده‌ها در زیرساخت Google است. این سرویس عملکرد و مقیاس پذیری Google Cloud را با امنیت پیشرفته و قابلیت های اشتراک گذاری ترکیب می کند. همچنین یک ردیف رایگان ارائه می دهد که آن را برای میزبانی مکان یاب فروشگاه ساده شما عالی می کند.

با Cloud Storage، فایل‌ها در سطل‌هایی ذخیره می‌شوند که شبیه به فهرست‌های موجود در رایانه شما هستند. برای میزبانی صفحه وب خود، ابتدا باید یک سطل ایجاد کنید. شما باید یک نام منحصر به فرد برای سطل خود انتخاب کنید، شاید با استفاده از نام خود به عنوان بخشی از نام سطل.

  1. پس از انتخاب نام، دستور زیر را در Cloud Shell اجرا کنید:
$ gsutil mb gs://yourname-store-locator

gsutil ابزاری برای تعامل با Cloud Storage است. دستور mb به صورت خلاقانه مخفف "make bucket" است. برای اطلاعات بیشتر در مورد همه دستورات موجود، از جمله دستورهایی که استفاده می‌کنید، به ابزار gsutil مراجعه کنید.

به‌طور پیش‌فرض، سطل‌ها و فایل‌های میزبانی شده در فضای ذخیره‌سازی ابری خصوصی هستند. با این حال، برای مکان یاب فروشگاه شما، می‌خواهید همه فایل‌ها عمومی باشند تا برای همه از طریق اینترنت قابل دسترسی باشند. می توانید هر فایل را پس از آپلود عمومی کنید، اما این کار خسته کننده خواهد بود. در عوض، می‌توانید به سادگی سطح دسترسی پیش‌فرض را برای سطلی که ایجاد کرده‌اید تنظیم کنید و همه فایل‌هایی که در آن آپلود می‌کنید، این سطح دسترسی را به ارث می‌برند.

  1. دستور زیر را اجرا کنید و نامی را که برای سطل خود انتخاب کرده اید جایگزین yourname-store-locator کنید:
$ gsutil defacl ch -u AllUsers:R gs://yourname-store-locator
  1. اکنون می توانید تمام فایل های خود را در فهرست فعلی (در حال حاضر فقط فایل های index.html و app.js خود) با دستور زیر آپلود کنید:
$ gsutil -h "Cache-Control:no-cache" cp * gs://yourname-store-locator

اکنون باید یک صفحه وب با نقشه آنلاین داشته باشید. نشانی وب برای مشاهده آن http://storage.googleapis.com/yourname-store-locator/index.html خواهد بود و دوباره قسمت yourname-store-locator با نام سطلی که قبلاً انتخاب کرده اید جایگزین شده است.

پاک کردن

ساده ترین راه برای پاکسازی تمام منابع ایجاد شده در این پروژه، خاموش کردن پروژه Google Cloud است که در ابتدای این آموزش ایجاد کردید:

  • صفحه تنظیمات را در Cloud Console باز کنید
  • روی انتخاب پروژه کلیک کنید.
  • پروژه ای را که در ابتدای این آموزش ایجاد کردید انتخاب کنید و روی Open کلیک کنید
  • شناسه پروژه را وارد کرده و بر روی Shut down کلیک کنید.

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

تبریک می گویم! شما این کد را تکمیل کردید.

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

بیشتر بدانید

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

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

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

اگر می‌خواهید بیشتر به کدها بپردازید، به مخزن کد منبع در https://github.com/googlecodelabs/google-maps-simple-store-locator نگاهی بیندازید.