Tạo bản đồ do người dùng đóng góp bằng Bảng tính PHP và Google

Pamela Fox, Nhóm API Google Maps
Tháng 11 năm 2007

Mục tiêu

Web là nơi có rất nhiều cộng đồng tập trung vào các khu vực địa lý và mối quan tâm: những người yêu thích bảo tàng, nhà thờ Châu Âu, công viên tiểu bang, v.v. Vì vậy, luôn cần một nhà phát triển (như bạn!) tạo ra một hệ thống mà người dùng có thể đóng góp các địa điểm được gắn thẻ địa lý cho một bản đồ, và đó chính xác là những gì chúng tôi sẽ làm ở đây. Ở cuối bài viết này, bạn sẽ có một hệ thống để người dùng có thể đăng ký, đăng nhập và thêm các địa điểm được gắn thẻ địa lý. Hệ thống sẽ sử dụng AJAX cho giao diện người dùng, PHP cho tập lệnh phía máy chủ và Bảng tính Google để lưu trữ. Nếu đã quen với việc sử dụng cơ sở dữ liệu MySQL để lưu trữ, bạn có thể dễ dàng sửa đổi mã ở đây để sử dụng phần phụ trợ của cơ sở dữ liệu MySQL.

Bài viết này được chia thành các bước sau:


Thiết lập bảng tính

Chúng tôi sẽ sử dụng Google Bảng tính để lưu trữ tất cả dữ liệu cho hệ thống này. Có hai loại dữ liệu chúng ta cần lưu trữ: thông tin tài khoản người dùng và địa điểm do người dùng thêm, vì vậy, chúng ta sẽ tạo một trang tính cho từng loại dữ liệu. Chúng ta sẽ tương tác với các trang tính bằng nguồn cấp dữ liệu danh sách của nó. Hàng này dựa vào hàng đầu tiên trong trang tính chứa nhãn cột và mỗi hàng tiếp theo chứa dữ liệu.

Truy cập vào docs.google.com và tạo bảng tính mới. Đổi tên trang tính mặc định thành "Người dùng" rồi tạo cột có tên "người dùng", "mật khẩu" và "phiên hoạt động". Sau đó, thêm một trang tính khác, đổi tên thành "Vị trí" và tạo các cột có tên là "người dùng", "trạng thái", "vĩ độ", "lng" và "ngày". Hoặc nếu bạn không cảm thấy giống như tất cả công việc thủ công đó, hãy tải mẫu này xuống và nhập vào Bảng tính Google thông qua lệnh File->Import.

Thông tin tài khoản người dùng cần được giữ bí mật (chỉ hiển thị cho chủ sở hữu bảng tính), trong khi những địa điểm do người dùng thêm sẽ được hiển thị trên bản đồ hiển thị công khai. May mắn thay, Bảng tính Google cho phép bạn quyết định chọn trang tính nào trong bảng tính có thể công khai và trang tính nào vẫn ở chế độ riêng tư (mặc định). Để xuất bản trang tính "Vị trí", hãy nhấp vào thẻ "Xuất bản", nhấp vào "Xuất bản ngay", chọn hộp kiểm "Tự động xuất bản lại", sau đó trong hộp thả xuống "Thành phần nào?", hãy chọn "Chỉ "Vị trí". Bạn sẽ thấy các tuỳ chọn chính xác trong ảnh chụp màn hình dưới đây:

Sử dụng khung Zend GData

API bảng tính Google cung cấp giao diện HTTP cho các thao tác CRUD như truy xuất hàng, chèn hàng, cập nhật hàng và xóa hàng. Khung Zend cung cấp một trình bao bọc PHP ngoài API (và các API GData khác) để bạn không phải lo lắng về việc triển khai các hoạt động HTTP thô. Khung Zend yêu cầu PHP 5.

Hãy tải khung Zend xuống rồi tải lên máy chủ của bạn nếu bạn chưa có. Khung này có tại: http://framework.zend.com/download/gdata.

Bạn nên sửa đổi PHP include_path để đưa vào thư viện Zend. Có một số cách để thực hiện việc này, tùy thuộc vào cấp độ quyền quản trị của bạn trên máy chủ. Có một cách để thêm dòng này lên trên câu lệnh yêu cầu trong mọi tệp PHP bằng cách sử dụng thư viện:

ini_set("include_path", ".:/usr/lib/php:/usr/local/lib/php:../../../library/");

Để thử nghiệm, hãy chạy bản minh hoạ Bảng tính bằng cách nhập nội dung này vào dòng lệnh trong thư mục minh hoạ/Zend/Gdata:

php Spreadsheet-ClientLogin.php --user=YourGMailUsername --pass=YourPassword

Nếu cách này có tác dụng, bạn sẽ thấy danh sách các bảng tính xuất hiện. Nếu bạn gặp lỗi, hãy kiểm tra để chắc chắn rằng đường dẫn bao gồm đã được đặt chính xác và bạn đã cài đặt PHP 5.

Tạo hàm toàn cục

Tất cả các tập lệnh PHP mà chúng tôi sẽ viết cho Bản đồ cộng đồng sẽ sử dụng phổ biến bao gồm các biến, hàm và hàm mà chúng ta sẽ đưa vào một tệp.

Ở đầu tệp, chúng ta sẽ có các câu lệnh cần thiết để bao gồm và tải thư viện Zend, được lấy từ ví dụ về Layouts-ClientLogin.php.

Sau đó, chúng ta sẽ xác định hằng số sẽ được dùng trong toàn bộ tệp: khoá bảng tính và hai mã trang tính. Để tìm thông tin cho bảng tính của bạn, hãy mở bảng tính, nhấp vào "thẻ Xuất bản" rồi nhấp vào "Tùy chọn xuất bản khác". Chọn "ATOM" từ danh sách thả xuống Định dạng tệp và nhấp vào "Tạo URL". Bạn sẽ thấy nội dung như sau:

http://spreadsheets.google.com/feeds/list/o16162288751915453340.4016005092390554215/od6/public/basic

Khoá bảng tính là chuỗi dài gồm chữ và số, sau "/list/" và mã trang tính là chuỗi dài 3 ký tự sau chuỗi đó. Để tìm mã trang tính khác, hãy chọn trang tính khác trong trình đơn thả xuống "Trang tính nào?".

Sau đó, chúng ta sẽ tạo 3 hàm: setupClient, getWkshtListFeed và printFeed. Trong setupClient, chúng tôi sẽ đặt tên người dùng và mật khẩu Gmail, xác thực bằng ClientLogin và trả về đối tượng Zend_Gdata_Tables. Trong getWkshtListFeed, chúng tôi sẽ trả về một nguồn cấp dữ liệu danh sách bảng tính cho một khoá bảng tính và mã trang tính cụ thể kèm theo một truy vấn bảng tính (không bắt buộc). Hàm printFeed được lấy từ ví dụ về Layouts-ClientLogin.php và có thể hữu ích cho bạn khi gỡ lỗi. Phương thức này sẽ lấy một đối tượng nguồn cấp dữ liệu và in ra màn hình.

Mã PHP thực hiện việc này được hiển thị bên dưới (communitymap_globals.php):

<?php
ini_set("include_path", ".:/usr/lib/php:/usr/local/lib/php:../../../library/");
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata');
Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
Zend_Loader::loadClass('Zend_Gdata_Spreadsheets');
Zend_Loader::loadClass('Zend_Http_Client');

define("SPREADSHEET_KEY", "o16162288751915453340.4016005092390554215");
define("USER_WORKSHEET_ID", "od6");
define("LOC_WORKSHEET_ID", "od7");
 
function setupClient() {
  $email = "your.name@gmail.com";
  $password = "yourPassword";
  $client = Zend_Gdata_ClientLogin::getHttpClient($email, $password,
          Zend_Gdata_Spreadsheets::AUTH_SERVICE_NAME);
  $gdClient = new Zend_Gdata_Spreadsheets($client);
  return $gdClient;
}
 
function getWkshtListFeed($gdClient, $ssKey, $wkshtId, $queryString=null) {
  $query = new Zend_Gdata_Spreadsheets_ListQuery();
  $query->setSpreadsheetKey($ssKey);
  $query->setWorksheetId($wkshtId);
  if ($queryString !== null) {
    $query->setSpreadsheetQuery($queryString);
  }
  $listFeed = $gdClient->getListFeed($query);
  return $listFeed;
}
 
function printFeed($feed)
{
  print "printing feed";
  $i = 0;
  foreach($feed->entries as $entry) {
      if ($entry instanceof Zend_Gdata_Spreadsheets_CellEntry) {
         print $entry->title->text .' '. $entry->content->text . "\n";
      } else if ($entry instanceof Zend_Gdata_Spreadsheets_ListEntry) {
         print $i .' '. $entry->title->text .' '. $entry->content->text . "\n";
      } else {
         print $i .' '. $entry->title->text . "\n";
      }
      $i++;
  }
}
 
?>

Đăng ký người dùng mới

Để đăng ký người dùng mới, chúng tôi muốn trang HTML giao diện người dùng có các trường văn bản, nút gửi và tập lệnh phụ trợ PHP để thêm người dùng vào bảng tính.

Trong tập lệnh PHP, trước tiên chúng ta sẽ bao gồm tập lệnh toàn cục, sau đó nhận giá trị tên người dùng và mật khẩu từ biến GET. Sau đó, chúng tôi sẽ thiết lập một ứng dụng Bảng tính và yêu cầu trang tính danh sách cho người dùng có một chuỗi truy vấn để chỉ cho phép kết quả ở các hàng mà cột tên người dùng bằng tên người dùng được truyền vào tập lệnh. Nếu chúng tôi không nhận được hàng nào trong kết quả nguồn cấp dữ liệu danh sách, chúng tôi có thể tiến hành an toàn khi biết rằng tên người dùng được chuyển vào là duy nhất. Trước khi chèn một hàng vào nguồn cấp dữ liệu danh sách, chúng ta sẽ tạo một mảng liên kết gồm các giá trị cột: tên người dùng, mã hoá mật khẩu bằng hàm sha1 của PHP và ký tự tô màu cho phiên. Sau đó, chúng ta gọi insertRow trên ứng dụng bảng tính, truyền mảng liên kết, khoá bảng tính và mã trang tính. Nếu đối tượng được trả về là ListFeedEntry, thì chúng ta sẽ tạo ra một thông báo thành công!

Mã PHP thực hiện việc này được hiển thị bên dưới (communitymap_newuser.php):

<?php
 
require_once 'communitymap_globals.php';
 
$username = $_GET['username'];
$password = $_GET['password'];
 
$gdClient = setupClient();
 
$listFeed = getWkshtListFeed($gdClient, SPREADSHEET_KEY, USER_WORKSHEET_ID, ('user='.$username));
$totalResults = $listFeed->totalResults;
if ( $totalResults != "0") {
  // Username already exists
  exit;
}
 
$rowArray["user"] = $username;
$rowArray["password"] = sha1($password);
$rowArray["session"] = "a";
 
$entry = $gdClient->insertRow($rowArray, SPREADSHEET_KEY, USER_WORKSHEET_ID);
if ($entry instanceof Zend_Gdata_Spreadsheets_ListEntry) {
  echo "Success!";
}
?>

Trên trang đăng ký, chúng ta có thể bao gồm API Maps để có thể sử dụng hàm trình bao bọc XMLHttpRequest có tên là GDownloadUrl. Khi người dùng nhấp vào nút gửi, chúng tôi sẽ lấy tên người dùng và mật khẩu từ các trường văn bản, tạo chuỗi thông số từ giá trị của họ và gọi GDownloadUrl trên URL tập lệnh và thông số. Vì chúng tôi đang gửi thông tin nhạy cảm, chúng tôi sẽ sử dụng phiên bản POST HTTP của GDownloadUrl (bằng cách gửi các tham số làm đối số thứ ba thay vì thêm các tham số đó vào URL). Trong hàm callback, chúng ta sẽ kiểm tra phản hồi thành công và gửi thông báo thích hợp cho người dùng.

Dưới đây là ảnh chụp màn hình và mã cho trang đăng ký mẫu (communitymap_register.htm):


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
  <title> Community Map - Register/Login </title>

  <script src="http://maps.google.com/maps?file=api&v=2&key=abcdef"
      type="text/javascript"></script>
  <script type="text/javascript">

  function register() {
    var username = document.getElementById("username").value;
    var password = document.getElementById("password").value;
    var url = "communitymap_newuser.php?";
    var params = "username=" + username + "&password=" + password;
    GDownloadUrl(url, function(data, responseCode) {
      if (data.length > 1) {
        document.getElementById("message").innerHTML = "Successfully registered." + 
          "<a href='communitymap_login.htm'>Proceed to Login</a>.";
      } else {
        document.getElementById("message").innerHTML = "Username already exists. Try again.";
      }
    }, params);
  }

  </script>

  </head>
  <body>
  <h1>Register for Community Map</h1>
  <input type="text" id="username">
  <input type="password" id="password">

  <input type="button" onclick="register()" value="Register">
  <div id="message"></div>
  </body>
</html>

Đăng nhập với tư cách người dùng

Để cho phép người dùng đăng nhập vào hệ thống, chúng tôi sẽ muốn trang HTML mà người dùng nhìn thấy để nhắc họ cung cấp tên người dùng và mật khẩu và một tập lệnh PHP để xác minh thông tin đăng nhập, tạo mã phiên và chuyển trở lại trang đăng nhập để đặt cookie. Người dùng sẽ tiếp tục được đăng nhập thông qua cookie phiên trên các trang tiếp theo.

Trong tập lệnh PHP, trước tiên chúng ta sẽ bao gồm tập lệnh toàn cục, sau đó nhận giá trị tên người dùng và mật khẩu từ biến GET. Sau đó, chúng tôi sẽ thiết lập một ứng dụng Bảng tính và yêu cầu trang tính danh sách cho người dùng có một chuỗi truy vấn để chỉ cho phép kết quả ở các hàng mà cột tên người dùng bằng tên người dùng được truyền vào tập lệnh.

Trong hàng được trả về, chúng ta sẽ kiểm tra xem giá trị băm của mật khẩu có khớp với hàm băm được lưu trữ trong bảng tính hay không. Nếu có, chúng ta sẽ tạo một mã phiên bằng cách sử dụng các hàm md5, uniqid và rand. Sau đó, chúng ta sẽ cập nhật hàng trong bảng tính với phiên hoạt động và xuất ra màn hình nếu cập nhật hàng thành công.

Phần mềm PHP thực hiện việc đó được hiển thị bên dưới (communitymap_loginuser.php):

<?php
 
require_once 'communitymap_globals.php';
 
$username = $_POST['username'];
$password = $_POST['password'];
 
$gdClient = setupClient();
 
$listFeed = getWkshtListFeed($gdClient, SPREADSHEET_KEY, USER_WORKSHEET_ID, ('user='.$username));
 
$password_hash = sha1($password);
$row = $listFeed->entries[0];
$rowData = $row->getCustom();
foreach($rowData as $customEntry) {
  if ($customEntry->getColumnName()=="password" && $customEntry->getText()==$password_hash) {
    $updatedRowArray["user"] = $username;
    $updatedRowArray["password"] = sha1($password);
    $updatedRowArray["session"] = md5(uniqid(rand(), true));
    $updatedRow = $gdClient->updateRow($row, $updatedRowArray); 
    if ($updatedRow instanceof Zend_Gdata_Spreadsheets_ListEntry) {
      echo $updatedRowArray["session"];
    }
  }
}
?>

Trên trang đăng nhập, chúng ta có thể bao gồm lại API Maps để có thể sử dụng hàm trình bao bọc XMLHttpRequest có tên là GDownloadUrl. Khi người dùng nhấp vào nút gửi, chúng tôi sẽ lấy tên người dùng và mật khẩu từ các trường văn bản, tạo URL tập lệnh bằng các thông số truy vấn và gọi GDownloadUrl trên url tập lệnh. Trong hàm callback, chúng ta sẽ đặt một cookie có mã phiên được tập lệnh trả về hoặc xuất ra thông báo lỗi nếu không có cookie nào được trả về. Hàm setCookie đến từ cookie.js dựa trên hướng dẫn JavaScript w3c: http://www.w3schools.com/js/js_cookies.asp.

Dưới đây là ảnh chụp màn hình và mã cho trang đăng nhập mẫu (communitymap_login.htm):


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>

  <title>Community Map - Login</title>
      <script src="http://maps.google.com/maps?file=api&v=2&key=abcdef"
      type="text/javascript"></script>
  <script src="cookies.js" type="text/javascript"></script>
  <script type="text/javascript">

  function login() {
    var username = document.getElementById("username").value;
    var password = document.getElementById("password").value;
    var url = "communitymap_loginuser.php?username=" + username + "&password=" + password;
    GDownloadUrl(url, function(data, responseCode) {
      if (data.length > 1) {
        setCookie("session", data, 5);
      } else {
        document.getElementById("nessage").innerHTML = "Error. Try again.";
      }
    });
  }

  </script>
  </head>
  <body>

  <h1>Login for Community Map</h1>

  <input type="text" id="username">
  <input type="password" id="password">
  <input type="button" onclick="login()" value="Login">
  <div id="message"></div>
  </body>
</html>

Cho phép người dùng thêm địa điểm trên bản đồ

Để cho phép người dùng thêm các địa điểm vào bản đồ của mình, chúng tôi muốn một trang HTML mà người dùng nhìn thấy để cho phép họ cung cấp thông tin về vị trí và hai tập lệnh PHP – một tập lệnh để kiểm tra xem họ đã đăng nhập thông qua cookie mà chúng tôi đặt hay chưa và một tập lệnh khác để thêm vị trí vào trang tính vị trí.

Trong tập lệnh PHP đầu tiên kiểm tra xem người dùng có đăng nhập hay không, trước tiên chúng tôi sẽ bao gồm tập lệnh toàn cục và sau đó nhận giá trị phiên từ biến GET. Sau đó, chúng tôi sẽ thiết lập một ứng dụng Bảng tính và yêu cầu trang tính danh sách cho người dùng có một chuỗi truy vấn để chỉ cho phép kết quả ở những hàng có cột phiên hoạt động bằng với giá trị phiên được truyền vào tập lệnh. Sau đó, chúng tôi lặp lại các mục nhập tùy chỉnh của nguồn cấp dữ liệu đó (những mục tương ứng với tiêu đề cột của chúng tôi) và in tên người dùng tương ứng cho phiên đó nếu có.

Phần mềm PHP thực hiện việc đó được hiển thị bên dưới (communitymap_checksession.php):

<?php

require_once 'communitymap_globals.php';

$session = $_GET['session'];

$gdClient = setupClient();

$listFeed = getWkshtListFeed($gdClient, SPREADSHEET_KEY, USER_WORKSHEET_ID, ('session='.$session));

if ( count($listFeed->entries) > 0) {
  $row = $listFeed->entries[0];
  $rowData = $row->getCustom();
  foreach($rowData as $customEntry) {
    if ($customEntry->getColumnName()=="user") {
      echo $customEntry->getText();
    }
  }
}
?>

Trong tập lệnh PHP thứ hai cho phép người dùng thêm vị trí, trước tiên, chúng tôi sao chép mã từcommunitymap_checksession.php để đảm bảo người dùng vẫn đang đăng nhập và hợp lệ. Sau đó, khi chúng tôi nhận lại được tên người dùng hợp lệ từ trang tính người dùng, chúng tôi sẽ nhận được các giá trị địa điểm, kinh độ và kinh độ từ biến GET. Chúng tôi đặt tất cả các giá trị đó vào một mảng kết hợp và chúng tôi cũng thêm giá trị "ngày" bằng cách sử dụng hàm date() của PHP, để chúng tôi biết được khi nào người dùng thêm địa điểm. Chúng ta truyền mảng kết hợp đó, hằng số khoá của bảng tính và hằng số mã nhận dạng trang tính vị trí vào hàm insertRow. Sau đó, chúng ta sẽ tạo ra "Thành công" nếu một hàng cho vị trí mới được thêm vào bảng tính. Nếu bạn gặp lỗi ở bước này, thì có thể là do tên tiêu đề cột không khớp. Các khóa trong mảng kết hợp phải khớp với tiêu đề cột trong trang tính được xác định theo khoá bảng tính và mã trang tính.

Phần mềm PHP thực hiện việc đó được hiển thị bên dưới (communitymap_addlocation.php):

<?php

require_once 'communitymap_globals.php';

$session = $_GET['session'];

$gdClient = setupClient();

$listFeed = getWkshtListFeed($gdClient, SPREADSHEET_KEY, USER_WORKSHEET_ID, ('session='.$session));

if ( count($listFeed->entries) > 0) {
  $row = $listFeed->entries[0];
  $rowData = $row->getCustom();
  foreach($rowData as $customEntry) {
    if ($customEntry->getColumnName()=="user") {
      $user = $customEntry->getText();
    }
  }

  $place = $_GET['place'];
  $lat = $_GET['lat'];
  $lng = $_GET['lng'];
  $rowArray["user"] = $user;
  $rowArray["place"] = $place;
  $rowArray["lat"] = $lat;
  $rowArray["lng"] = $lng;
  $rowArray["date"] = date("F j, Y, g:i a");
  $entry = $gdClient->insertRow($rowArray, SPREADSHEET_KEY, LOC_WORKSHEET_ID);
  if ($entry instanceof Zend_Gdata_Spreadsheets_ListEntry) {
    echo "Success!\n";
  }
}

?>

Trên trang thêm vị trí, chúng ta có thể thêm API Maps để chúng ta có thể sử dụng GDownloadUrl và tạo bản đồ. Sau khi trang tải, chúng tôi sử dụng hàm getCookie từ cookie.js để truy xuất giá trị phiên. Nếu chuỗi phiên hoạt động rỗng hoặc trống, chúng tôi sẽ đưa ra thông báo lỗi. Nếu không có, chúng tôi sẽ gọi GDownloadUrl trên map.checksession.php, gửi trong phiên này. Nếu tên người dùng đó được trả về thành công, chúng tôi sẽ hiển thị thông báo chào mừng cho người dùng, tiết lộ biểu mẫu thêm địa điểm và tải bản đồ vào. Biểu mẫu bao gồm trường văn bản địa chỉ, bản đồ và trường văn bản cho tên địa điểm, vĩ độ và kinh độ. Nếu người dùng chưa biết vĩ độ/kinh độ của vị trí, họ có thể mã hoá địa lý bằng cách nhập địa chỉ của họ vào biểu mẫu và nhấn vào "gửi". Thao tác đó sẽ gửi lệnh gọi đến GClientGeocoder của API Map, trình này sẽ đặt một điểm đánh dấu trên bản đồ nếu tìm thấy địa chỉ và tự động điền vào các trường văn bản vĩ độ/lng.

Khi người dùng đã hài lòng, họ có thể nhấn vào nút "thêm vị trí". Sau đó, trong JavaScript, chúng ta sẽ nhận các giá trị cho người dùng, địa điểm, kinh độ và kinh độ, và gửi các giá trị đó đến tập lệnh Communitymap_addlocation.php với GDownloadUrl.

Nếu tập lệnh đó trả về thành công, chúng ta sẽ hiển thị thông báo thành công trên màn hình.

Dưới đây là ảnh chụp màn hình và mã cho trang thêm vị trí mẫu (communitymap_addlocation.htm):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <title>Community Map - Add a Place!</title>

    <script src="http://maps.google.com/maps?file=api&v=2.x&key=abcdef" type="text/javascript"></script>
    <script src="cookies.js" type="text/javascript"></script>
    <script type="text/javascript">
    //<![CDATA[

    var map = null;
    var geocoder = null; 
    var session = null;

    function load() {
      session = getCookie('session');
      if (session != null && session != "") {
        url = "communitymap_checksession.php?session=" + session;
        GDownloadUrl(url, function(data, responseCode) {
          if (data.length > 0) {
            document.getElementById("message").innerHTML = "Welcome " + data;
            document.getElementById("content").style.display = "block";
            map = new GMap2(document.getElementById("map"));
            map.setCenter(new GLatLng(37.4419, -122.1419), 13);
            geocoder = new GClientGeocoder();
          }
        });
      } else {
        document.getElementById("message").innerHTML = "Error: Not logged in.";
      }
    }

    function addLocation() {
      var place = document.getElementById("place").value;
      var lat = document.getElementById("lat").value;
      var lng = document.getElementById("lng").value;

      var url = "communitymap_addlocation.php?session=" + session + "&place=" + place +
                "&lat=" + lat + "&lng=" + lng;
      GDownloadUrl(url, function(data, responseCode) {
        GLog.write(data);
        if (data.length > 0) {
          document.getElementById("message").innerHTML = "Location added.";
        }
      });
    }

    function showAddress(address) {
      if (geocoder) {
        geocoder.getLatLng(
          address,
          function(point) {
            if (!point) {
              alert(address + " not found");
            } else {
              map.setCenter(point, 13);
              var marker = new GMarker(point, {draggable:true});
              document.getElementById("lat").value = marker.getPoint().lat().toFixed(6);
              document.getElementById("lng").value = marker.getPoint().lng().toFixed(6);

              map.addOverlay(marker);
              GEvent.addListener(marker, "dragend", function() {
                document.getElementById("lat").value = marker.getPoint().lat().toFixed(6);
                document.getElementById("lng").value = marker.getPoint().lng().toFixed(6);
	      });
            }
          }
        );
      }
    }
    //]]>

    </script>

  </head>

  <body onload="load()" onunload="GUnload()">
   <div id="message"></div>
   <div id="content" style="display:none">

   <form action="#" onsubmit="showAddress(this.address.value); return false">
        <p>
        <input type="text" size="60" name="address" value="1600 Amphitheatre Pky, Mountain View, CA" />
        <input type="submit" value="Geocode!" />

    </form>
      </p>

      <div id="map" style="width: 500px; height: 300px"></div>
 
 	Place name: <input type="text" size="20" id="place" value="" />
	<br/>
 	Lat: <input type="text" size="20" id="lat" value="" />
	<br/>

 	Lng: <input type="text" size="20" id="lng" value="" />

        <br/>
	<input type="button" onclick="addLocation()" value="Add a location" />
    </form>
    </div>

  </body>
</html>

Tạo bản đồ

Vì bạn đã đặt trang tính vị trí ở chế độ công khai trong bước đầu tiên, nên bạn không cần phải lập trình phía máy chủ để tạo bản đồ cho các trang tính đó. Thực tế, bạn không cần phải lập trình. Bạn có thể sử dụng Bảng tính -> Trình hướng dẫn bản đồ và trình tạo này sẽ tạo tất cả mã cần thiết cho bản đồ. Trình hướng dẫn tải các mục nhập trang tính xuống trang bằng cách thêm thẻ tập lệnh trỏ đến đầu ra JSON cho nguồn cấp dữ liệu và chỉ định hàm gọi lại được gọi sau khi JSON được tải xuống. Bạn có thể xem thêm thông tin tại đây.

Mã HTML mẫu để làm việc đó có sẵn tại đây: mainmap.htm. Ảnh chụp màn hình được hiển thị dưới đây:

Kết luận

Hy vọng bây giờ bạn đã có hệ thống bản đồ do người dùng đóng góp rất tốt của riêng bạn đang chạy trên máy chủ của bạn. Bài viết này cung cấp mã rất cơ bản cần thiết cho các khía cạnh thiết yếu của hệ thống này. Tuy nhiên, giờ đây khi bạn đã quen với thư viện Bảng tính Zend, bạn có thể mở rộng hệ thống này để đáp ứng các nhu cầu cụ thể của mình. Nếu bạn gặp lỗi trong quá trình thực hiện, hãy nhớ sử dụng lệnh echo trong PHP hoặc GLog.write() của API bản đồ trong JavaScript để gỡ lỗi và bạn luôn có thể đăng trong diễn đàn dành cho nhà phát triển hoặc API bảng tính để được trợ giúp thêm.