1. Trước khi bắt đầu
Một trong những tính năng phổ biến nhất của trang web là hiển thị bản đồ của Google để làm nổi bật một hoặc nhiều vị trí cho doanh nghiệp, cơ sở hoặc một số pháp nhân khác có mặt tại đó. Cách các bản đồ này được triển khai có thể thay đổi rất nhiều tùy thuộc vào các yêu cầu, chẳng hạn như số lượng vị trí và tần suất mà các bản đồ này thay đổi.
Trong lớp học lập trình này, bạn xem xét trường hợp sử dụng đơn giản nhất – một số vị trí hiếm khi thay đổi, chẳng hạn như bộ định vị cửa hàng cho doanh nghiệp có một chuỗi cửa hàng. Trong trường hợp này, bạn có thể sử dụng phương pháp công nghệ tương đối thấp mà không cần lập trình phía máy chủ. Nhưng điều đó không có nghĩa là bạn không thể sáng tạo và bạn làm như vậy bằng cách tận dụng định dạng dữ liệu GeoJSON để lưu trữ và hiển thị thông tin tùy ý về từng cửa hàng trên bản đồ của bạn, cũng như tùy chỉnh các điểm đánh dấu và kiểu tổng thể của bản đồ.
Cuối cùng, như một lợi ích khác, bạn sử dụng Cloud Shell để phát triển và lưu trữ công cụ định vị cửa hàng của mình. Mặc dù việc sử dụng công cụ này không bắt buộc, nhưng việc này cho phép bạn phát triển bộ định vị cửa hàng từ bất kỳ thiết bị nào chạy trình duyệt web và hiển thị công khai trên mạng.
Điều kiện tiên quyết
- Kiến thức cơ bản về HTML và JavaScript
Bạn sẽ thực hiện
- Hiển thị bản đồ có một tập hợp các vị trí cửa hàng và thông tin được lưu trữ ở định dạng GeoJSON.
- Tùy chỉnh các điểm đánh dấu và bản đồ.
- Hiện thêm thông tin về cửa hàng khi người dùng nhấp vào điểm đánh dấu của cửa hàng.
- Thêm thanh tìm kiếm Tự động hoàn thành địa điểm vào trang web.
- Xác định vị trí cửa hàng gần nhất với điểm xuất phát do người dùng cung cấp.
2. Bắt đầu thiết lập
Ở bước 3 của phần sau, hãy bật 3 API sau đây cho lớp học lập trình này:
- API JavaScript cho Maps
- Places API
- Distance Matrix API
Bắt đầu sử dụng Nền tảng Google Maps
Nếu bạn chưa từng sử dụng Nền tảng Google Maps, hãy làm theo Hướng dẫn bắt đầu sử dụng Nền tảng Google Maps hoặc xem Danh sách phát Bắt đầu với Nền tảng Google Maps để hoàn thành các bước sau:
- Tạo một tài khoản thanh toán.
- Tạo một dự án.
- Bật API và SDK của nền tảng Google Maps (được liệt kê trong phần trước).
- Tạo khoá API.
Kích hoạt Cloud Shell
Trong lớp học lập trình này, bạn sử dụng Cloud Shell, một môi trường dòng lệnh chạy trong Google Cloud, cung cấp quyền truy cập vào các sản phẩm và tài nguyên chạy trên Google Cloud để bạn có thể lưu trữ và chạy hoàn toàn dự án của mình trên trình duyệt web.
Để kích hoạt Cloud Shell từ Cloud Console, hãy nhấp vào Kích hoạt Cloud Shell (chỉ mất vài phút để cấp phép và kết nối với môi trường).
Thao tác này sẽ mở một màn hình shell mới ở phần dưới của trình duyệt sau khi có thể hiển thị quảng cáo xen kẽ giới thiệu.
Sau khi kết nối với Cloud Shell, bạn sẽ thấy rằng bạn đã được xác thực và dự án này đã được đặt thành mã dự án mà bạn đã chọn trong quá trình thiết lập.
$ gcloud auth list Credentialed Accounts: ACTIVE ACCOUNT * <myaccount>@<mydomain>.com
$ gcloud config list project [core] project = <YOUR_PROJECT_ID>
Nếu vì lý do nào đó mà dự án chưa được đặt, hãy chạy lệnh sau:
$ gcloud config set project <YOUR_PROJECT_ID>
3. "Hello, World!" cùng với một bản đồ
Bắt đầu phát triển bằng một bản đồ
Trong Cloud Shell, bạn bắt đầu bằng cách tạo một trang HTML sẽ phân phát làm cơ sở cho phần còn lại của lớp học lập trình.
- Trong thanh công cụ của Cloud Shell, hãy nhấp vào Chạy trình chỉnh sửa để mở một trình soạn thảo mã trong thẻ mới.
Trình chỉnh sửa mã dựa trên web này cho phép bạn dễ dàng chỉnh sửa các tệp trong Cloud Shell.
- Tạo thư mục
store-locator
mới cho ứng dụng của bạn trong trình soạn thảo mã bằng cách nhấp vào Tệp > Thư mục mới.
- Đặt tên cho thư mục mới là
store-locator
.
Tiếp theo, bạn tạo một trang web có bản đồ.
- Tạo một tệp trong thư mục
store-locator
có tênindex.html
.
- Đặt nội dung sau đây vào tệp
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>
Đây là trang HTML hiển thị bản đồ. Tệp này chứa một số CSS để đảm bảo bản đồ sẽ chiếm toàn bộ trang, một thẻ <div>
để giữ bản đồ và một cặp thẻ <script>
. Thẻ tập lệnh đầu tiên tải một tệp JavaScript có tên là app.js
, tệp này chứa tất cả mã JavaScript. Thẻ tập lệnh thứ hai tải khóa API, bao gồm việc sử dụng Thư viện địa điểm để sử dụng chức năng tự động hoàn thành mà bạn sẽ thêm sau này và chỉ định tên hàm JavaScript chạy sau khi API JavaScript của Maps được tải, cụ thể là initMap
.
- Thay thế văn bản
YOUR_API_KEY
trong đoạn mã bằng khóa API mà bạn đã tạo trước đó trong lớp học lập trình này. - Cuối cùng, hãy tạo một tệp khác có tên
app.js
bằng mã sau:
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 },
});
}
Đó là mã bắt buộc tối thiểu để tạo bản đồ. Bạn chuyển tham chiếu đến thẻ <div>
để giữ bản đồ, đồng thời chỉ định phần giữa và mức thu phóng.
Để kiểm tra ứng dụng này, bạn có thể chạy máy chủ HTTP Python đơn giản trong Cloud Shell.
- Truy cập Cloud Shell và nhập nội dung sau:
$ cd store-locator $ python3 -m http.server 8080
Bạn thấy một số dòng kết quả nhật ký cho biết rằng bạn đang thực sự chạy máy chủ HTTP đơn giản trong Cloud Shell bằng ứng dụng web đang nghe trên cổng localhost 8080.
- Mở một thẻ trình duyệt web trên ứng dụng này bằng cách nhấp vào Xem trước trên web trong thanh công cụ Cloud Console rồi chọn Xem trước trên cổng 8080.
Nhấp vào mục trình đơn này sẽ mở ra một thẻ mới trong trình duyệt web có nội dung HTML được phân phát từ máy chủ HTTP đơn giản. Nếu mọi thứ diễn ra tốt đẹp, bạn sẽ thấy một bản đồ tập trung vào London, Anh.
Để dừng máy chủ HTTP đơn giản, nhấn Control+C
trong Cloud Shell.
4. Điền sẵn bản đồ bằng GeoJSON
Bây giờ, hãy xem dữ liệu của các cửa hàng. XMLJSON là một định dạng dữ liệu đại diện cho các đối tượng địa lý đơn giản, chẳng hạn như điểm, đường hoặc đa giác trên bản đồ. Các tính năng cũng có thể chứa dữ liệu bất kỳ. Điều này giúp GeoJSON trở thành một ứng cử viên xuất sắc khi đại diện cho cửa hàng, về cơ bản là những điểm trên bản đồ có một chút dữ liệu bổ sung, chẳng hạn như tên, giờ mở cửa và số điện thoại của cửa hàng. Điều quan trọng nhất là GeoJSON có hỗ trợ hạng nhất trong Google Maps, có nghĩa là bạn có thể gửi tài liệu GeoJSON đến một bản đồ Google và nó sẽ hiển thị nó trên bản đồ một cách thích hợp.
- Tạo một tệp mới có tên là
stores.json
và dán mã sau:
store.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"
}
}
]
}
Đó là rất nhiều dữ liệu, nhưng khi bạn kiểm tra kỹ, bạn sẽ thấy cấu trúc đó chỉ đơn giản là cấu trúc lặp lại cho mỗi cửa hàng. Mỗi cửa hàng được trình bày dưới dạng GeoJSON Point
cùng với tọa độ và dữ liệu bổ sung chứa trong khóa properties
. Điều thú vị là GeoJSON cho phép bao gồm các khóa được đặt tên tùy ý trong khóa properties
. Trong lớp học lập trình này, các khóa đó là category
, hours
, description
, name
và phone
.
- Bây giờ, hãy chỉnh sửa
app.js
để tải JSONJSON trongstores.js
lên bản đồ của bạn.
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);
});
}
Trong ví dụ về mã, bạn đã tải GeoJSON vào bản đồ bằng cách gọi loadGeoJson
và chuyển tên của tệp JSON. Bạn cũng đã xác định một hàm để chạy mỗi lần nhấp vào điểm đánh dấu. Sau đó, hàm này có thể truy cập vào dữ liệu bổ sung của cửa hàng có điểm đánh dấu đã nhấp vào và sử dụng thông tin trong cửa sổ thông tin hiển thị. Để kiểm tra ứng dụng này, bạn có thể chạy máy chủ HTTP Python đơn giản bằng cách sử dụng lệnh giống như trước đây.
- Quay lại Cloud Shell và nhập nội dung sau:
$ python3 -m http.server 8080
- Nhấp vào Xem trước trên web > Xem trước trên cổng 8080 lần nữa và bạn sẽ thấy bản đồ có đầy đủ các điểm đánh dấu mà bạn có thể nhấp vào để xem chi tiết về từng cửa hàng, như trong ví dụ sau. Tiến trình!
5. Tùy chỉnh bản đồ
Bạn sắp hoàn thành rồi. Bạn có một bản đồ với tất cả các điểm đánh dấu cửa hàng và thông tin bổ sung đang hiển thị khi được nhấp vào. Tuy nhiên, có vẻ như mọi Google khác đều lập bản đồ tại đó. Thật tuyệt! Tăng giá trị bằng cách sử dụng kiểu bản đồ, điểm đánh dấu, biểu trưng và hình ảnh Chế độ xem phố tùy chỉnh.
Đây là phiên bản mới của app.js
có thêm kiểu tùy chỉnh:
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);
});
}
Đây là thông tin bạn đã thêm:
- Biến
mapStyle
chứa tất cả thông tin để định kiểu cho bản đồ. (Ngoài ra, bạn có thể tạo kiểu quảng cáo của riêng mình nếu muốn.) - Bằng cách sử dụng phương thức
map.data.setStyle
, bạn đã áp dụng các điểm đánh dấu tùy chỉnh – một điểm đánh dấu khác nhau cho mỗicategory
từ GeoJSON. - Bạn đã sửa đổi biến
content
để bao gồm biểu trưng (một lần nữa bằng cách sử dụngcategory
từ GeoJSON) và hình ảnh Chế độ xem phố cho vị trí của cửa hàng.
Trước khi triển khai thẻ này, bạn cần hoàn thành một vài bước sau:
- Đặt giá trị chính xác cho biến
apiKey
bằng cách thay thế chuỗi'YOUR_API_KEY'
trongapp.js
bằng khóa API của riêng bạn (trước đó là khóa mà bạn đã dán trongindex.html
), để nguyên dấu ngoặc kép. - Chạy các lệnh sau trong Cloud Shell để tải đồ họa điểm đánh dấu và biểu trưng xuống. Hãy đảm bảo bạn đang ở trong thư mục
store-locator
. DùngControl+C
để dừng máy chủ HTTP đơn giản nếu máy chủ đang chạy.
$ 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
- Xem trước bộ định vị cửa hàng đã hoàn thành bằng cách chạy lệnh sau:
$ python3 -m http.server 8080
Khi tải lại bản xem trước, bạn sẽ thấy nội dung như bản đồ này với kiểu tùy chỉnh, hình ảnh điểm đánh dấu tùy chỉnh, định dạng cửa sổ thông tin được cải thiện và hình ảnh Chế độ xem phố cho mỗi vị trí:
6. Lấy thông tin do người dùng nhập
Người dùng công cụ định vị cửa hàng thường muốn biết cửa hàng nào gần họ nhất hoặc một địa chỉ mà họ dự định bắt đầu hành trình của mình. Thêm thanh tìm kiếm Tự động hoàn thành địa điểm để cho phép người dùng dễ dàng nhập địa chỉ bắt đầu. Tính năng Tự động hoàn thành địa điểm cung cấp chức năng đánh dấu tương tự như cách hoạt động của tính năng Tự động hoàn thành trong các thanh tìm kiếm khác của Google, nhưng cụm từ gợi ý đều là tất cả Địa điểm trong Nền tảng Google Maps.
- Quay lại chỉnh sửa
index.html
để thêm kiểu cho thanh tìm kiếm Tự động hoàn thành và bảng kết quả bên được liên kết. Đừng quên thay thế khóa API nếu bạn đã dán mã cũ.
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>
Cả thanh tìm kiếm của tính năng Tự động hoàn thành và bảng trượt sẽ đều bị ẩn cho đến khi cần thiết.
- Bây giờ, hãy thêm tiện ích Tự động hoàn thành vào bản đồ ở cuối hàm
initMap
trongapp.js
, ngay trước dấu ngoặc nhọn đóng.
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']);
Mã này hạn chế các nội dung đề xuất Tự động hoàn thành chỉ trả về địa chỉ (vì tính năng Tự động hoàn thành địa điểm có thể khớp với tên cơ sở và vị trí quản trị) và giới hạn địa chỉ được trả về chỉ những địa chỉ ở Vương quốc Anh. Việc thêm các thông số tùy chọn này sẽ giảm số lượng ký tự mà người dùng cần nhập để thu hẹp cụm từ gợi ý để hiển thị địa chỉ mà họ đang tìm kiếm. Sau đó, hệ thống này sẽ di chuyển div
Tự động hoàn thành mà bạn đã tạo vào góc trên cùng bên phải của bản đồ và chỉ định trường nào sẽ được trả về về mỗi Địa điểm trong nội dung phản hồi.
- Khởi động lại máy chủ và làm mới bản xem trước của bạn bằng cách chạy lệnh sau:
$ python3 -m http.server 8080
Bạn sẽ thấy tiện ích Tự động hoàn thành ở góc trên cùng bên phải của bản đồ ngay bây giờ, tiện ích này cho bạn biết địa chỉ ở Vương quốc Anh khớp với nội dung bạn nhập.
Giờ đây, bạn cần xử lý khi người dùng chọn một cụm từ gợi ý từ tiện ích Tự động hoàn thành và sử dụng vị trí đó làm cơ sở để tính khoảng cách đến các cửa hàng của bạn.
- Thêm mã sau vào cuối
initMap
trongapp.js
sau mã bạn vừa dán.
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;
});
Mã này sẽ thêm một trình xử lý để khi người dùng nhấp vào một trong các đề xuất, bản đồ sẽ được căn cứ vào địa chỉ đã chọn và đặt nguồn gốc làm cơ sở cho các phép tính khoảng cách của bạn. Bạn triển khai các phép tính khoảng cách trong bước tiếp theo.
7. Liệt kê các cửa hàng gần nhất
API Chỉ đường hoạt động giống như trải nghiệm yêu cầu chỉ đường trong ứng dụng Google Maps — nhập một nguồn gốc và một điểm đến duy nhất để nhận tuyến đường giữa hai mục tiêu. API Ma trận khoảng cách nâng cao khái niệm này để xác định những cặp ghép tối ưu giữa nhiều nguồn gốc có thể có và nhiều điểm đến có thể dựa trên thời gian di chuyển và khoảng cách. Trong trường hợp này, để giúp người dùng tìm cửa hàng gần nhất đến địa chỉ đã chọn, bạn cung cấp một nguồn gốc và một mảng vị trí cửa hàng làm điểm đến.
- Thêm một hàm mới vào
app.js
có tên là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;
}
Hàm này gọi API Ma trận khoảng cách bằng cách sử dụng nguồn gốc được chuyển đến dưới dạng một nguồn gốc và các vị trí cửa hàng dưới dạng một mảng đích. Sau đó, Analytics xây dựng một mảng đối tượng lưu trữ mã cửa hàng, khoảng cách biểu thị trong một chuỗi mà con người có thể đọc được, khoảng cách tính bằng mét dưới dạng một giá trị số và sắp xếp mảng.
Người dùng cần xem danh sách cửa hàng được sắp xếp theo thứ tự từ gần nhất đến xa nhất. Điền thông tin vào bảng điều khiển bên cho mỗi cửa hàng bằng cách sử dụng danh sách được trả về từ hàm calculateDistances
để thông báo thứ tự hiển thị của các cửa hàng.
- Thêm một hàm mới vào
app.js
có tên là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;
}
- Khởi động lại máy chủ và làm mới bản xem trước của bạn bằng cách chạy lệnh sau.
$ python3 -m http.server 8080
- Cuối cùng, hãy nhập địa chỉ ở Vương quốc Anh vào thanh tìm kiếm Tự động hoàn thành rồi nhấp vào một trong các đề xuất.
Bản đồ phải căn giữa vào địa chỉ đó và thanh bên sẽ xuất hiện liệt kê các vị trí cửa hàng theo khoảng cách từ địa chỉ đã chọn. Dưới đây là một ví dụ:
8. Không bắt buộc: Lưu trữ trang web
Cho đến thời điểm này, bạn chỉ xem bản đồ của mình khi bạn đang chạy máy chủ HTTP Python. Để xem bản đồ của bạn sau phiên Cloud Shell đang hoạt động hoặc để chia sẻ URL cho bản đồ của bạn với người khác, hãy xem cách sử dụng Cloud Storage để lưu trữ trang web của bạn. Cloud Storage là dịch vụ web lưu trữ tệp trực tuyến để lưu trữ và truy cập vào dữ liệu trên cơ sở hạ tầng của Google. Dịch vụ này kết hợp hiệu suất và khả năng mở rộng của Google Cloud với khả năng chia sẻ và bảo mật nâng cao. Dịch vụ này cũng cung cấp một Bậc miễn phí, phù hợp để lưu trữ công cụ định vị cửa hàng đơn giản của bạn.
Với Cloud Storage, các tệp được lưu trữ trong các nhóm, tương tự như các thư mục trên máy tính của bạn. Để lưu trữ trang web, trước tiên, bạn cần tạo một bộ chứa. Bạn cần chọn một tên duy nhất cho bộ chứa của mình, có thể bằng cách sử dụng tên của bạn làm tên của bộ chứa.
- Sau khi bạn quyết định tên, hãy chạy lệnh sau trong Cloud Shell:
$ gsutil mb gs://yourname-store-locator
gsutil là công cụ để tương tác với Cloud Storage. Lệnh mb
sáng tạo là viết tắt "make bundle." Để biết thêm thông tin về tất cả các lệnh có sẵn, bao gồm cả những lệnh bạn sử dụng, hãy xem công cụ gsutil.
Theo mặc định, các nhóm và tệp được lưu trữ trên Cloud Storage sẽ ở chế độ riêng tư. Tuy nhiên, đối với bộ định vị cửa hàng, bạn muốn công khai tất cả các tệp sao cho mọi người có thể truy cập được qua Internet. Bạn có thể đặt từng tệp ở chế độ công khai sau khi tải tệp đó lên, nhưng việc này sẽ rất nhàm chán. Thay vào đó, bạn chỉ cần đặt cấp truy cập mặc định cho bộ chứa mà bạn đã tạo và tất cả tệp bạn tải lên sẽ kế thừa cấp truy cập đó.
- Chạy lệnh sau, thay thế
yourname-store-locator
bằng tên mà bạn đã chọn cho bộ chứa của mình:
$ gsutil defacl ch -u AllUsers:R gs://yourname-store-locator
- Giờ đây, bạn có thể tải tất cả tệp lên thư mục hiện tại (hiện chỉ có tệp
index.html
vàapp.js
) bằng lệnh sau:
$ gsutil -h "Cache-Control:no-cache" cp * gs://yourname-store-locator
Giờ đây, bạn sẽ có một trang web với bản đồ trực tuyến. URL để xem URL đó sẽ là http://storage.googleapis.com/yourname-store-locator/index.html, một lần nữa với phần yourname-store-locator được thay thế bằng tên bộ chứa mà bạn đã chọn trước đó.
Dọn dẹp
Cách dễ dàng nhất để dọn dẹp tất cả các tài nguyên được tạo trong dự án này là tắt Dự án Google Cloud mà bạn đã tạo ở đầu hướng dẫn này:
- Mở Trang cài đặt trong Cloud Console
- Nhấp vào Chọn một dự án.
- Chọn dự án mà bạn đã tạo ở đầu hướng dẫn này rồi nhấp vào Mở
- Nhập mã dự án rồi nhấp vào Tắt.
9. Xin chúc mừng
Xin chúc mừng! Bạn đã hoàn thành lớp học lập trình này.
Những điều bạn đã học được
- Thêm bản đồ kiểu tùy chỉnh với API JavaScript của Maps
- Tải một lớp dữ liệu lên bản đồ ở định dạng GeoJSON
- Sử dụng API Chế độ xem phố để hiển thị hình ảnh Chế độ xem phố trong một trang web.
- Sử dụng Thư viện địa điểm để thêm thanh tìm kiếm Tự động hoàn thành địa điểm vào trang
- Sử dụng dịch vụ Ma trận khoảng cách để tính toán nhiều khoảng cách bằng một lệnh gọi API
- Quản lý và thử nghiệm các dự án phát triển web trong Google Cloud Platform bằng giao diện dòng lệnh Cloud Shell dựa trên trình duyệt
- Lưu trữ một trang web bằng Cloud Storage
Tìm hiểu thêm
- Tìm hiểu một cách khác để lưu trữ bản đồ web của bạn bằng cách sử dụng Google App Engine trong lớp học lập trình Liên kết tàu điện ngầm NYC.
- Khám phá thêm các lớp học lập trình về Nền tảng Google Maps, chẳng hạn như dịch vụ Xây dựng tìm kiếm doanh nghiệp lân cận.
- Hãy giúp chúng tôi tạo nội dung mà bạn thấy hữu ích nhất bằng cách trả lời câu hỏi dưới đây:
Bạn muốn xem những lớp học lập trình nào khác?
Lớp học lập trình mà bạn muốn không được liệt kê ở trên? Yêu cầu phát hành vấn đề mới tại đây.
Nếu bạn muốn tìm hiểu sâu hơn về mã này, hãy xem kho mã nguồn tại https://github.com/googlecodelabs/google-maps-simple-store-locator.