1. ข้อควรทราบก่อนที่จะเริ่มต้น
หนึ่งในฟีเจอร์ที่พบบ่อยที่สุดของเว็บไซต์คือการแสดงแผนที่ Google ที่ไฮไลต์สถานที่อย่างน้อย 1 แห่งสําหรับธุรกิจ สถานประกอบการ หรือเอนทิตีอื่นๆ ที่มีตัวตนจริง วิธีนําแผนที่เหล่านี้ไปใช้อาจแตกต่างกันอย่างมาก โดยขึ้นอยู่กับข้อกําหนด เช่น จํานวนสถานที่และความถี่ของการเปลี่ยนแปลง
ใน Codelab นี้คุณจะเห็นกรณีการใช้งานที่เรียบง่ายที่สุด ซึ่งเป็นสถานที่ตั้งจํานวนหนึ่งที่แทบจะไม่มีการเปลี่ยนแปลงเลย เช่น เครื่องระบุตําแหน่งร้านสําหรับธุรกิจที่มีเครือร้านค้า ในกรณีนี้ คุณอาจใช้แนวทางเทคโนโลยีที่ค่อนข้างต่ําโดยไม่ต้องมีการเขียนโปรแกรมฝั่งเซิร์ฟเวอร์ได้ แต่นั่นก็ไม่ได้หมายความว่าคุณจะสร้างสรรค์ไม่ได้ และคุณทําได้โดยใช้ประโยชน์จากรูปแบบข้อมูล GeoJSON เพื่อจัดเก็บและแสดงข้อมูลที่กําหนดเองเกี่ยวกับร้านค้าแต่ละร้านบนแผนที่ของคุณ ตลอดจนปรับแต่งเครื่องหมายและสไตล์โดยรวมของแผนที่ด้วย
สุดท้ายคือ โบนัสของ Cloud Shell ในการพัฒนาและโฮสต์ตัวระบุร้านค้าของคุณ แม้ว่าการใช้เครื่องมือนี้จะไม่จําเป็นก็ตาม แต่การทําเช่นนั้นจะช่วยให้คุณพัฒนาเครื่องระบุตําแหน่งร้านได้จากอุปกรณ์ทุกเครื่องที่ใช้เว็บเบราว์เซอร์ และทําให้พร้อมใช้งานแบบออนไลน์แก่สาธารณะ
ข้อกำหนดเบื้องต้น
- ความรู้พื้นฐานเกี่ยวกับ 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 เพื่อทําตามขั้นตอนต่อไปนี้
- สร้างบัญชีสําหรับการเรียกเก็บเงิน
- สร้างโปรเจ็กต์
- เปิดใช้ Google Maps Platform API และ SDK (แสดงอยู่ในส่วนก่อนหน้า)
- สร้างคีย์ API
เปิดใช้งาน Cloud Shell
ใน Codelab นี้ คุณจะใช้ Cloud Shell ซึ่งเป็นสภาพแวดล้อมบรรทัดคําสั่งที่ทํางานใน Google Cloud ที่ให้สิทธิ์เข้าถึงผลิตภัณฑ์และทรัพยากรที่ทํางานใน Google Cloud เพื่อโฮสต์และเรียกใช้โปรเจ็กต์โดยสมบูรณ์จากเว็บเบราว์เซอร์ได้
หากต้องการเปิดใช้งาน Cloud Shell จาก Cloud Console ให้คลิกเปิดใช้งาน Cloud Shell (การจัดสรรและเชื่อมต่อกับสภาพแวดล้อมในอีกสักครู่)
ซึ่งจะเป็นการเปิด Shell ใหม่ในส่วนล่างของเบราว์เซอร์หลังจากอาจแสดงคั่นระหว่างหน้าคั่นระหว่างหน้า
เมื่อเชื่อมต่อกับ 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 ส่วนที่เหลือ
- ในแถบเครื่องมือของ Cloud Shell ให้คลิกเปิดเครื่องมือแก้ไข เพื่อเปิดตัวแก้ไขโค้ดในแท็บใหม่
ตัวแก้ไขโค้ดบนเว็บนี้ช่วยให้คุณแก้ไขไฟล์ใน Cloud Shell ได้อย่างง่ายดาย
- สร้างไดเรกทอรี
store-locator
ใหม่สําหรับแอปในเครื่องมือแก้ไขโค้ดโดยคลิกไฟล์ > โฟลเดอร์ใหม่
- ตั้งชื่อโฟลเดอร์ใหม่
store-locator
ต่อไป คุณสร้างหน้าเว็บด้วยแผนที่
- สร้างไฟล์ในไดเรกทอรี
store-locator
ที่ชื่อindex.html
- ใส่เนื้อหาต่อไปนี้ในไฟล์
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
- แทนที่ข้อความ
YOUR_API_KEY
ในข้อมูลโค้ดด้วยคีย์ API ที่คุณสร้างก่อนหน้านี้ใน Codelab นี้ - สุดท้าย สร้างไฟล์อื่นชื่อ
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
- ไปที่ Cloud Shell และพิมพ์ข้อมูลต่อไปนี้
$ cd store-locator $ python3 -m http.server 8080
คุณจะเห็นบรรทัดของบันทึกบางส่วนที่แสดงให้เห็นว่าคุณกําลังเรียกใช้เซิร์ฟเวอร์ HTTP แบบง่ายใน Cloud Shell พร้อมเว็บแอปซึ่งกําลังฟังบนพอร์ต localhost 8080
- เปิดแท็บเว็บเบราว์เซอร์ในแอปนี้โดยคลิกแสดงตัวอย่างเว็บในแถบเครื่องมือ Cloud Console และเลือกแสดงตัวอย่างบนพอร์ต 8080
การคลิกรายการในเมนูจะเป็นการเปิดแท็บใหม่ในเว็บเบราว์เซอร์ที่มีเนื้อหาของ HTML ที่แสดงจากเซิร์ฟเวอร์ Python HTTP แบบง่าย หากทุกอย่างเรียบร้อยดี คุณจะเห็นแผนที่ที่มีศูนย์กลางอยู่ในลอนดอน ประเทศอังกฤษ
หากต้องการหยุดเซิร์ฟเวอร์ HTTP แบบง่าย ให้กด Control+C
ใน Cloud Shell
4. ป้อนข้อมูลในแผนที่ด้วย GeoJSON
ตอนนี้เราจะมาดูข้อมูลสําหรับร้านค้ากัน GeoJSON เป็นรูปแบบข้อมูลที่แสดงถึงคุณลักษณะทางภูมิศาสตร์ง่ายๆ เช่น จุด เส้น หรือรูปหลายเหลี่ยมบนแผนที่ ฟีเจอร์อาจมีข้อมูลที่กําหนดเอง ทําให้ GeoJSON เป็นตัวเลือกที่ดีสําหรับการแสดงร้านค้า ซึ่งส่วนใหญ่จะเป็นจุดบนแผนที่ที่มีข้อมูลเพิ่มเติมเล็กน้อย เช่น ชื่อร้านค้า เวลาทําการ และหมายเลขโทรศัพท์ สิ่งสําคัญที่สุดคือ GeoJSON สนับสนุนระดับหนึ่งใน Google Maps ซึ่งหมายความว่าคุณสามารถส่งเอกสาร GeoJSON ไปยัง Google Maps ซึ่งจะแสดงผลบนแผนที่อย่างเหมาะสม
- สร้างไฟล์ใหม่ชื่อ
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
- ต่อไปให้แก้ไข
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 แบบง่ายโดยใช้คําสั่งเดิมได้
- กลับไปที่ Cloud Shell และพิมพ์ข้อมูลต่อไปนี้
$ python3 -m http.server 8080
- คลิกแสดงตัวอย่างเว็บ > ดูตัวอย่างบนพอร์ต 8080 อีกครั้ง และคุณจะเห็นแผนที่ที่เต็มไปด้วยเครื่องหมาย ซึ่งคุณสามารถคลิกเพื่อดูรายละเอียดของแต่ละร้านค้า เช่น ตัวอย่างต่อไปนี้ ความคืบหน้า
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 ข้อต่อไปนี้ก่อนติดตั้งใช้งาน
- กําหนดค่าที่ถูกต้องสําหรับตัวแปร
apiKey
โดยแทนที่สตริง'YOUR_API_KEY'
ในapp.js
ด้วยคีย์ API ของคุณเองก่อนหน้านี้ (คีย์เดียวกับที่คุณวางไว้ในindex.html
โดยไม่ใส่เครื่องหมายคําพูด) - เรียกใช้คําสั่งต่อไปนี้ใน 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
- แสดงตัวอย่างเครื่องระบุตําแหน่งร้านที่เสร็จสิ้นโดยเรียกใช้คําสั่งต่อไปนี้
$ python3 -m http.server 8080
เมื่อคุณโหลดตัวอย่างซ้ํา คุณจะเห็นตัวอย่างแผนที่นี้พร้อมการจัดรูปแบบที่กําหนดเอง รูปภาพตัวทําเครื่องหมายที่กําหนดเอง การจัดรูปแบบหน้าต่างข้อมูลที่ปรับปรุงแล้ว และรูปภาพของ Street View สําหรับแต่ละตําแหน่ง ดังนี้
6. รับข้อมูลจากผู้ใช้
ผู้ใช้เครื่องระบุตําแหน่งร้านมักจะต้องการทราบว่าร้านใดอยู่ใกล้มากที่สุดหรือที่อยู่ที่วางแผนจะเริ่มออกเดินทาง เพิ่มแถบค้นหาการเติมข้อความสถานที่อัตโนมัติเพื่อให้ผู้ใช้ป้อนที่อยู่เริ่มต้นได้อย่างง่ายดาย การเติมข้อความอัตโนมัติภายในสถานที่จะทําให้ฟังก์ชัน typeahead คล้ายกับการทํางานการเติมข้อความอัตโนมัติในแถบค้นหาอื่นๆ ของ Google แต่การคาดคะเนคือสถานที่ทั้งหมดใน Places ใน Google Maps Platform
- กลับไปแก้ไข
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>
ทั้งแถบค้นหาการเติมข้อความอัตโนมัติและแผงแบบภาพสไลด์จะถูกซ่อนไว้ในตอนแรกจนกว่าจะจําเป็นต้องใช้
- ในตอนนี้ ให้เพิ่มวิดเจ็ต 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
ที่คุณสร้างที่มุมบนขวาของแผนที่และระบุช่องที่ควรจะแสดงเกี่ยวกับสถานที่แต่ละแห่งในการตอบกลับ
- รีสตาร์ทเซิร์ฟเวอร์และรีเฟรชการแสดงตัวอย่างโดยเรียกใช้คําสั่งต่อไปนี้
$ python3 -m http.server 8080
คุณควรเห็นวิดเจ็ตการเติมข้อความอัตโนมัติที่มุมขวาบนของแผนที่ ซึ่งจะแสดงที่อยู่ในสหราชอาณาจักรที่ตรงกับชื่อที่คุณพิมพ์
ในขั้นตอนถัดไป คุณต้องจัดการเมื่อผู้ใช้เลือกการคาดคะเนจากวิดเจ็ตการเติมข้อความอัตโนมัติ และใช้ตําแหน่งนั้นเป็นพื้นฐานสําหรับการคํานวณระยะทางไปยังร้านค้าของคุณ
- เพิ่มโค้ดต่อไปนี้ไว้ที่ส่วนท้ายของ
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 แห่งและอาร์เรย์ของตําแหน่งร้านค้าเป็นปลายทาง
- เพิ่มฟังก์ชันใหม่ลงใน
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
เพื่อให้ข้อมูลลําดับการแสดงของร้านค้า
- เพิ่มฟังก์ชันใหม่ลงใน
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;
}
- รีสตาร์ทเซิร์ฟเวอร์และรีเฟรชการแสดงตัวอย่างโดยเรียกใช้คําสั่งต่อไปนี้
$ python3 -m http.server 8080
- สุดท้าย ป้อนที่อยู่ในสหราชอาณาจักรลงในแถบค้นหาของการเติมข้อความอัตโนมัติ แล้วคลิกคําแนะนํารายการใดรายการหนึ่ง
แผนที่ควรตั้งอยู่กึ่งกลางของที่อยู่นั้น และแถบด้านข้างควรจะแสดงตําแหน่งของร้านค้าตามลําดับระยะห่างจากที่อยู่ที่เลือก ดังตัวอย่างต่อไปนี้
8. ไม่บังคับ: โฮสต์หน้าเว็บ
เมื่อถึงจุดนี้ คุณจะสามารถดูแผนที่ได้เมื่อคุณเรียกใช้เซิร์ฟเวอร์ Python HTTP อยู่เท่านั้น หากต้องการดูแผนที่ของคุณนอกเหนือจากเซสชัน Cloud Shell ที่ใช้งานอยู่ หรือแชร์ URL ของแผนที่กับผู้อื่น ให้ดูที่ Cloud Storage เพื่อโฮสต์หน้าเว็บ Cloud Storage เป็นบริการเว็บสําหรับเก็บไฟล์ออนไลน์สําหรับจัดเก็บและเข้าถึงข้อมูลบนโครงสร้างพื้นฐานของ Google บริการนี้รวมประสิทธิภาพและความสามารถในการปรับขนาดของ Google Cloud เข้ากับความสามารถในการรักษาความปลอดภัยและการแชร์ขั้นสูง นอกจากนี้ เรายังมีรุ่นฟรี ซึ่งจะช่วยให้คุณโฮสต์ตัวระบุตําแหน่งร้านค้าได้สะดวกขึ้น
เมื่อใช้ Cloud Storage ไฟล์จะจัดเก็บอยู่ในที่เก็บข้อมูล ซึ่งคล้ายกับไดเรกทอรีในคอมพิวเตอร์ของคุณ หากต้องการโฮสต์หน้าเว็บ คุณต้องสร้างที่เก็บข้อมูลก่อน คุณต้องเลือกชื่อที่ไม่ซ้ําสําหรับที่เก็บข้อมูล โดยอาจใช้ชื่อของคุณเป็นส่วนหนึ่งของชื่อที่เก็บข้อมูล
- เมื่อตั้งชื่อแล้ว ให้เรียกใช้คําสั่งต่อไปนี้ใน Cloud Shell
$ gsutil mb gs://yourname-store-locator
gsutil คือเครื่องมือสําหรับการโต้ตอบกับ Cloud Storage คําสั่ง mb
ย่อมาจาก "makebucket." ดูข้อมูลเพิ่มเติมเกี่ยวกับคําสั่งทั้งหมดรวมถึงคําสั่งที่คุณใช้ได้ในเครื่องมือ gsutil
โดยค่าเริ่มต้น ที่เก็บข้อมูลและไฟล์ที่โฮสต์บน Cloud Storage จะเป็นแบบส่วนตัว อย่างไรก็ตาม สําหรับเครื่องระบุตําแหน่งร้านของคุณ คุณต้องกําหนดให้ไฟล์ทั้งหมดเป็นแบบสาธารณะ เพื่อให้ทุกคนเข้าถึงอินเทอร์เน็ตได้ คุณทําให้แต่ละไฟล์เป็นแบบสาธารณะหลังจากอัปโหลดได้ แต่น่าเบื่อ แต่คุณสามารถตั้งค่าระดับการเข้าถึงเริ่มต้นสําหรับที่เก็บข้อมูลที่คุณสร้างขึ้นได้ และไฟล์ทั้งหมดที่คุณอัปโหลดไปยังที่เก็บข้อมูลจะรับช่วงระดับการเข้าถึงนั้นแทน
- เรียกใช้คําสั่งต่อไปนี้ แทนที่
yourname-store-locator
ด้วยชื่อที่คุณเลือกสําหรับที่เก็บข้อมูล
$ gsutil defacl ch -u AllUsers:R gs://yourname-store-locator
- ตอนนี้คุณสามารถอัปโหลดไฟล์ทั้งหมดในไดเรกทอรีปัจจุบัน (เฉพาะไฟล์
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 นี้แล้ว
สิ่งที่คุณได้เรียนรู้
- การเพิ่มแผนที่สไตล์ที่กําหนดเองด้วย Maps JavaScript API
- กําลังโหลดชั้นข้อมูลลงในแผนที่ในรูปแบบ GeoJSON
- ใช้ Street View Static API เพื่อแสดงรูปภาพ Street View ในหน้าเว็บ
- การใช้ไลบรารี Places เพื่อเพิ่มแถบค้นหาที่ใช้การเติมข้อความอัตโนมัติของสถานที่ลงในหน้า
- ใช้บริการเมทริกซ์ระยะทางเพื่อคํานวณระยะทางหลายเส้นด้วยการเรียก API ครั้งเดียว
- การจัดการและทดสอบโครงการพัฒนาเว็บใน Google Cloud Platform โดยใช้อินเทอร์เฟซบรรทัดคําสั่ง Cloud Shell บนเบราว์เซอร์
- การโฮสต์เว็บไซต์ด้วย Cloud Storage
ดูข้อมูลเพิ่มเติม
- ดูวิธีโฮสต์โฮสต์เว็บโดยใช้ Google App Engine ใน Codelab ในหัวข้อการจับคู่รถไฟใต้ดิน NYC
- สํารวจ Codelab ของ Google Maps Platform เช่น การสร้างบริการการค้นหาธุรกิจใกล้เคียง
- ช่วยเราสร้างเนื้อหาที่คุณคิดว่าเป็นประโยชน์ที่สุดโดยตอบคําถามต่อไปนี้
คุณต้องการเห็น Codelab อื่นใดบ้าง
Codelab ที่คุณต้องการไม่อยู่ในรายการข้างต้นใช่ไหม ส่งคําขอเกี่ยวกับปัญหาใหม่ที่นี่
หากต้องการเจาะลึกโค้ดอีกเล็กน้อย โปรดดูที่เก็บซอร์สโค้ดที่ https://github.com/googlecodelabs/google-maps-simple-store-locator