สร้างเครื่องระบุตําแหน่งร้านแบบง่ายๆ ด้วย Google Maps Platform (JavaScript)

1. ข้อควรทราบก่อนที่จะเริ่มต้น

หนึ่งในฟีเจอร์ที่พบบ่อยที่สุดของเว็บไซต์คือการแสดงแผนที่ Google ที่ไฮไลต์สถานที่อย่างน้อย 1 แห่งสําหรับธุรกิจ สถานประกอบการ หรือเอนทิตีอื่นๆ ที่มีตัวตนจริง วิธีนําแผนที่เหล่านี้ไปใช้อาจแตกต่างกันอย่างมาก โดยขึ้นอยู่กับข้อกําหนด เช่น จํานวนสถานที่และความถี่ของการเปลี่ยนแปลง

ใน Codelab นี้คุณจะเห็นกรณีการใช้งานที่เรียบง่ายที่สุด ซึ่งเป็นสถานที่ตั้งจํานวนหนึ่งที่แทบจะไม่มีการเปลี่ยนแปลงเลย เช่น เครื่องระบุตําแหน่งร้านสําหรับธุรกิจที่มีเครือร้านค้า ในกรณีนี้ คุณอาจใช้แนวทางเทคโนโลยีที่ค่อนข้างต่ําโดยไม่ต้องมีการเขียนโปรแกรมฝั่งเซิร์ฟเวอร์ได้ แต่นั่นก็ไม่ได้หมายความว่าคุณจะสร้างสรรค์ไม่ได้ และคุณทําได้โดยใช้ประโยชน์จากรูปแบบข้อมูล GeoJSON เพื่อจัดเก็บและแสดงข้อมูลที่กําหนดเองเกี่ยวกับร้านค้าแต่ละร้านบนแผนที่ของคุณ ตลอดจนปรับแต่งเครื่องหมายและสไตล์โดยรวมของแผนที่ด้วย

สุดท้ายคือ โบนัสของ Cloud Shell ในการพัฒนาและโฮสต์ตัวระบุร้านค้าของคุณ แม้ว่าการใช้เครื่องมือนี้จะไม่จําเป็นก็ตาม แต่การทําเช่นนั้นจะช่วยให้คุณพัฒนาเครื่องระบุตําแหน่งร้านได้จากอุปกรณ์ทุกเครื่องที่ใช้เว็บเบราว์เซอร์ และทําให้พร้อมใช้งานแบบออนไลน์แก่สาธารณะ

489628918395c3d0.png

ข้อกำหนดเบื้องต้น

  • ความรู้พื้นฐานเกี่ยวกับ HTML และ JavaScript

สิ่งที่คุณจะทํา

  • แสดงแผนที่พร้อมด้วยชุดตําแหน่งร้านค้าและข้อมูลที่จัดเก็บไว้ในรูปแบบ GeoJSON
  • ปรับแต่งเครื่องหมายและตัวแผนที่เอง
  • แสดงข้อมูลเพิ่มเติมเกี่ยวกับร้านค้าเมื่อมีการคลิกเครื่องหมาย
  • เพิ่มแถบค้นหาการเติมข้อความสถานที่อัตโนมัติลงในหน้าเว็บ
  • ระบุตําแหน่งร้านค้าที่ใกล้กับจุดเริ่มต้นที่ผู้ใช้ระบุมากที่สุด

2. ตั้งค่า

ในขั้นตอนที่ 3 ของส่วนต่อไปนี้ ให้เปิดใช้ API 3 รายการต่อไปนี้สําหรับ Codelab นี้

  • Maps JavaScript API
  • Places API
  • Distance Matrix API

เริ่มต้นใช้งาน Google Maps Platform

หากคุณไม่เคยใช้ Google Maps Platform มาก่อน ให้ทําตามคู่มือเริ่มต้นใช้งาน Google Maps Platform หรือดูเพลย์ลิสต์การเริ่มต้นใช้งาน Google Maps Platform เพื่อทําตามขั้นตอนต่อไปนี้

  1. สร้างบัญชีสําหรับการเรียกเก็บเงิน
  2. สร้างโปรเจ็กต์
  3. เปิดใช้ Google Maps Platform API และ SDK (แสดงอยู่ในส่วนก่อนหน้า)
  4. สร้างคีย์ API

เปิดใช้งาน Cloud Shell

ใน Codelab นี้ คุณจะใช้ Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคําสั่งที่ทํางานใน Google Cloud ที่ให้สิทธิ์เข้าถึงผลิตภัณฑ์และทรัพยากรที่ทํางานใน Google Cloud เพื่อโฮสต์และเรียกใช้โปรเจ็กต์โดยสมบูรณ์จากเว็บเบราว์เซอร์ได้

หากต้องการเปิดใช้งาน Cloud Shell จาก Cloud Console ให้คลิกเปิดใช้งาน Cloud Shell 89665d8d348105cd.png (การจัดสรรและเชื่อมต่อกับสภาพแวดล้อมในอีกสักครู่)

5f504766b9b3be17.png

ซึ่งจะเป็นการเปิด Shell ใหม่ในส่วนล่างของเบราว์เซอร์หลังจากอาจแสดงคั่นระหว่างหน้าคั่นระหว่างหน้า

d3bb67d514893d1f.png

เมื่อเชื่อมต่อกับ Cloud Shell แล้ว ระบบจะตรวจสอบว่าคุณตรวจสอบสิทธิ์แล้ว และมีการตั้งค่าโปรเจ็กต์เป็นรหัสโปรเจ็กต์ที่คุณเลือกแล้วในระหว่างการตั้งค่า

$ 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 ให้คลิกเปิดเครื่องมือแก้ไข 996514928389de40.png เพื่อเปิดตัวแก้ไขโค้ดในแท็บใหม่

ตัวแก้ไขโค้ดบนเว็บนี้ช่วยให้คุณแก้ไขไฟล์ใน Cloud Shell ได้อย่างง่ายดาย

Screen Shot 2017-04-19 เวลา 10.22.48 AM.png

  1. สร้างไดเรกทอรี 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> คู่ แท็กสคริปต์แรกจะโหลดไฟล์ JavaScript ที่ชื่อ app.js ซึ่งมีโค้ด JavaScript ทั้งหมด แท็กสคริปต์ที่ 2 จะโหลดคีย์ API รวมไปถึงการใช้ไลบรารี Places สําหรับฟังก์ชันการเติมข้อความอัตโนมัติที่คุณจะเพิ่มภายหลัง และระบุชื่อฟังก์ชัน JavaScript ที่ทํางานเมื่อโหลด Maps JavaScript API เช่น initMap

  1. แทนที่ข้อความ YOUR_API_KEY ในข้อมูลโค้ดด้วยคีย์ API ที่คุณสร้างก่อนหน้านี้ใน Codelab นี้
  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 พร้อมเว็บแอปซึ่งกําลังฟังบนพอร์ต localhost 8080

  1. เปิดแท็บเว็บเบราว์เซอร์ในแอปนี้โดยคลิกแสดงตัวอย่างเว็บ95e419ae763a1d48.pngในแถบเครื่องมือ Cloud Console และเลือกแสดงตัวอย่างบนพอร์ต 8080

ไฟล์ 47b06e5169eb5add.png

bdab1f021a3b91d5.png

การคลิกรายการในเมนูจะเป็นการเปิดแท็บใหม่ในเว็บเบราว์เซอร์ที่มีเนื้อหาของ HTML ที่แสดงจากเซิร์ฟเวอร์ Python HTTP แบบง่าย หากทุกอย่างเรียบร้อยดี คุณจะเห็นแผนที่ที่มีศูนย์กลางอยู่ในลอนดอน ประเทศอังกฤษ

หากต้องการหยุดเซิร์ฟเวอร์ HTTP แบบง่าย ให้กด Control+C ใน Cloud Shell

4. ป้อนข้อมูลในแผนที่ด้วย GeoJSON

ตอนนี้เราจะมาดูข้อมูลสําหรับร้านค้ากัน GeoJSON เป็นรูปแบบข้อมูลที่แสดงถึงคุณลักษณะทางภูมิศาสตร์ง่ายๆ เช่น จุด เส้น หรือรูปหลายเหลี่ยมบนแผนที่ ฟีเจอร์อาจมีข้อมูลที่กําหนดเอง ทําให้ GeoJSON เป็นตัวเลือกที่ดีสําหรับการแสดงร้านค้า ซึ่งส่วนใหญ่จะเป็นจุดบนแผนที่ที่มีข้อมูลเพิ่มเติมเล็กน้อย เช่น ชื่อร้านค้า เวลาทําการ และหมายเลขโทรศัพท์ สิ่งสําคัญที่สุดคือ GeoJSON สนับสนุนระดับหนึ่งใน Google Maps ซึ่งหมายความว่าคุณสามารถส่งเอกสาร GeoJSON ไปยัง Google Maps ซึ่งจะแสดงผลบนแผนที่อย่างเหมาะสม

  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"
            }
        }
    ]
}

มีข้อมูลจํานวนมหาศาล แต่เมื่อคุณใช้แล้ว คุณจะเห็นโครงสร้างของร้านแต่ละแห่งที่ซ้ําเหมือนกัน ร้านค้าแต่ละร้านจะแสดงเป็น GeoJSON Point พร้อมกับพิกัดและข้อมูลเพิ่มเติมที่อยู่ในคีย์ properties เป็นที่น่าสนใจว่า GeoJSON สามารถรวมคีย์ที่มีชื่อที่กําหนดเองไว้ใต้คีย์ properties ใน Codelab คีย์เหล่านี้คือ 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 นอกจากนี้คุณยังได้กําหนดฟังก์ชันให้ทํางานทุกครั้งที่มีการคลิกเครื่องหมายอีกด้วย จากนั้นฟังก์ชันสามารถเข้าถึงข้อมูลเพิ่มเติมสําหรับร้านค้าที่มีคลิกเครื่องหมาย และใช้ข้อมูลในหน้าต่างข้อมูลที่แสดง หากต้องการทดสอบแอปนี้ คุณสามารถเรียกใช้เซิร์ฟเวอร์ Python HTTP แบบง่ายโดยใช้คําสั่งเดิมได้

  1. กลับไปที่ Cloud Shell และพิมพ์ข้อมูลต่อไปนี้
$ python3 -m http.server 8080
  1. คลิกแสดงตัวอย่างเว็บ 95e419ae763a1d48.png > ดูตัวอย่างบนพอร์ต 8080 อีกครั้ง และคุณจะเห็นแผนที่ที่เต็มไปด้วยเครื่องหมาย ซึ่งคุณสามารถคลิกเพื่อดูรายละเอียดของแต่ละร้านค้า เช่น ตัวอย่างต่อไปนี้ ความคืบหน้า

c4507f7d3ea18439.png

5. ปรับแต่งแผนที่

เกือบเสร็จแล้ว คุณมีแผนที่พร้อมเครื่องหมายร้านค้าทั้งหมดและข้อมูลเพิ่มเติมที่จะแสดงเมื่อคลิก แต่ดูเหมือนว่าแผนที่อื่นๆ ของ Google จะออกไปข้างนอก แย่จัง! เพิ่มความจัดจ้านด้วยสไตล์แผนที่ที่กําหนดเอง เครื่องหมาย โลโก้ และรูปภาพ Street View

นี่คือ 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 อีกครั้ง) และรูปภาพ Street View ของตําแหน่งร้านค้า

คุณต้องทําตามขั้นตอน 2-3 ข้อต่อไปนี้ก่อนติดตั้งใช้งาน

  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

เมื่อคุณโหลดตัวอย่างซ้ํา คุณจะเห็นตัวอย่างแผนที่นี้พร้อมการจัดรูปแบบที่กําหนดเอง รูปภาพตัวทําเครื่องหมายที่กําหนดเอง การจัดรูปแบบหน้าต่างข้อมูลที่ปรับปรุงแล้ว และรูปภาพของ Street View สําหรับแต่ละตําแหน่ง ดังนี้

3d8d13da126021dd.png

6. รับข้อมูลจากผู้ใช้

ผู้ใช้เครื่องระบุตําแหน่งร้านมักจะต้องการทราบว่าร้านใดอยู่ใกล้มากที่สุดหรือที่อยู่ที่วางแผนจะเริ่มออกเดินทาง เพิ่มแถบค้นหาการเติมข้อความสถานที่อัตโนมัติเพื่อให้ผู้ใช้ป้อนที่อยู่เริ่มต้นได้อย่างง่ายดาย การเติมข้อความอัตโนมัติภายในสถานที่จะทําให้ฟังก์ชัน typeahead คล้ายกับการทํางานการเติมข้อความอัตโนมัติในแถบค้นหาอื่นๆ ของ Google แต่การคาดคะเนคือสถานที่ทั้งหมดใน Places ใน Google Maps Platform

  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. ในตอนนี้ ให้เพิ่มวิดเจ็ต Autocomplete ลงในแผนที่ที่ส่วนท้ายของฟังก์ชัน 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;
  });

โค้ดจะเพิ่ม Listener ให้เมื่อผู้ใช้คลิกที่คําแนะนําอันใดอันหนึ่ง ศูนย์กลางของแผนที่จะปรากฏในที่อยู่ที่เลือกไว้และกําหนดต้นทางเป็นพื้นฐานสําหรับการคํานวณระยะทางของคุณ คุณใช้การคํานวณระยะทางในขั้นตอนถัดไป

7. แสดงรายชื่อร้านค้าที่ใกล้ที่สุด

Directions API ทํางานคล้ายกับประสบการณ์การขอเส้นทางในแอป Google Maps โดยป้อนต้นทาง 1 แห่งและจุดหมายเดียวเพื่อรับเส้นทางระหว่างทั้ง 2 แห่ง DISTANCE Matrix API นี้ใช้แนวคิดนี้ในการระบุการจับคู่ข้อมูลที่เหมาะสมที่สุดระหว่างต้นทางที่เป็นไปได้หลายแห่งและปลายทางหลายแห่งที่เป็นไปได้โดยอิงตามเวลาเดินทางและระยะทาง ในกรณีนี้ เพื่อช่วยให้ผู้ใช้ค้นหาร้านค้าที่ใกล้ที่สุดโดยใช้ที่อยู่ที่เลือกไว้ คุณต้องระบุต้นทาง 1 แห่งและอาร์เรย์ของตําแหน่งร้านค้าเป็นปลายทาง

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

ฟังก์ชันนี้จะเรียกใช้ DISTANCE Matrix 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. ไม่บังคับ: โฮสต์หน้าเว็บ

เมื่อถึงจุดนี้ คุณจะสามารถดูแผนที่ได้เมื่อคุณเรียกใช้เซิร์ฟเวอร์ Python 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 ย่อมาจาก "makebucket." ดูข้อมูลเพิ่มเติมเกี่ยวกับคําสั่งทั้งหมดรวมถึงคําสั่งที่คุณใช้ได้ในเครื่องมือ gsutil

โดยค่าเริ่มต้น ที่เก็บข้อมูลและไฟล์ที่โฮสต์บน Cloud Storage จะเป็นแบบส่วนตัว อย่างไรก็ตาม สําหรับเครื่องระบุตําแหน่งร้านของคุณ คุณต้องกําหนดให้ไฟล์ทั้งหมดเป็นแบบสาธารณะ เพื่อให้ทุกคนเข้าถึงอินเทอร์เน็ตได้ คุณทําให้แต่ละไฟล์เป็นแบบสาธารณะหลังจากอัปโหลดได้ แต่น่าเบื่อ แต่คุณสามารถตั้งค่าระดับการเข้าถึงเริ่มต้นสําหรับที่เก็บข้อมูลที่คุณสร้างขึ้นได้ และไฟล์ทั้งหมดที่คุณอัปโหลดไปยังที่เก็บข้อมูลจะรับช่วงระดับการเข้าถึงนั้นแทน

  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

ตอนนี้คุณควรมีหน้าเว็บที่มีแผนที่ออนไลน์ URL ที่ดูจะเป็น http://storage.googleapis.com/yourname-store-locator/index.html อีกครั้งโดยแทนที่ส่วน yourname-store-locator ด้วยชื่อที่เก็บข้อมูลที่คุณเลือกไว้ก่อนหน้านี้

การทําความสะอาด

วิธีที่ง่ายที่สุดในการล้างทรัพยากรทั้งหมดที่สร้างขึ้นในโปรเจ็กต์นี้คือปิดโปรเจ็กต์ Google Cloud ที่คุณสร้างไว้ตอนเริ่มต้นบทแนะนํานี้

  • เปิดหน้าการตั้งค่าใน Cloud Console
  • คลิกเลือกโปรเจ็กต์
  • เลือกโปรเจ็กต์ที่คุณสร้างที่จุดเริ่มต้นของบทแนะนํานี้ แล้วคลิกเปิด
  • ป้อนรหัสโปรเจ็กต์ แล้วคลิกปิด

9. ยินดีด้วย

ยินดีด้วย คุณสิ้นสุด Codelab นี้แล้ว

สิ่งที่คุณได้เรียนรู้

ดูข้อมูลเพิ่มเติม

คุณต้องการเห็น Codelab อื่นใดบ้าง

การแสดงภาพข้อมูลบนแผนที่ ข้อมูลเพิ่มเติมเกี่ยวกับการปรับแต่งรูปแบบของแผนที่ การสร้างการโต้ตอบแบบ 3 มิติในแผนที่

Codelab ที่คุณต้องการไม่อยู่ในรายการข้างต้นใช่ไหม ส่งคําขอเกี่ยวกับปัญหาใหม่ที่นี่

หากต้องการเจาะลึกโค้ดอีกเล็กน้อย โปรดดูที่เก็บซอร์สโค้ดที่ https://github.com/googlecodelabs/google-maps-simple-store-locator