概览
本教程介绍如何利用 Google Maps JavaScript API 将 MySQL 数据库中的信息显示在 Google 地图上,其适用对象为掌握了 MySQL、PHP 和 XML 中级知识的人士。
本教程中的地图显示两种标记来区分餐馆和酒吧的位置。MySQL 中的数据库存储有关每个标记位置的信息,例如地点类型(它是餐馆还是酒吧)及其名称、地址和地理坐标。地图通过一个充当数据库与地图之间媒介的 XML 文件从数据库检索这些信息。可以利用 PHP 语句将数据库中的标记信息导出到一个 XML 文件中。
点击下面地图上的某个标记可显示一个包含位置名称和地址的信息窗口。标记带有“R”或“B”标签,分别用于显示餐馆和酒吧的位置。
以下示例显示了创建此地图所需的完整代码。
var customLabel = {
restaurant: {
label: 'R'
},
bar: {
label: 'B'
}
};
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(-33.863276, 151.207977),
zoom: 12
});
var infoWindow = new google.maps.InfoWindow;
// Change this depending on the name of your PHP or XML file
downloadUrl('https://storage.googleapis.com/mapsdevsite/json/mapmarkers2.xml', function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName('marker');
Array.prototype.forEach.call(markers, function(markerElem) {
var name = markerElem.getAttribute('name');
var address = markerElem.getAttribute('address');
var type = markerElem.getAttribute('type');
var point = new google.maps.LatLng(
parseFloat(markerElem.getAttribute('lat')),
parseFloat(markerElem.getAttribute('lng')));
var infowincontent = document.createElement('div');
var strong = document.createElement('strong');
strong.textContent = name
infowincontent.appendChild(strong);
infowincontent.appendChild(document.createElement('br'));
var text = document.createElement('text');
text.textContent = address
infowincontent.appendChild(text);
var icon = customLabel[type] || {};
var marker = new google.maps.Marker({
map: map,
position: point,
label: icon.label
});
marker.addListener('click', function() {
infoWindow.setContent(infowincontent);
infoWindow.open(map, marker);
});
});
});
}
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('GET', url, true);
request.send(null);
}
function doNothing() {}
<div id="map"></div>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
<!-- Replace the value of the key parameter with your own API key. --> <script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap"> </script>
自己试一试
悬停在代码块右上角以复制代码或在 JSFiddle 中打开。
<!DOCTYPE html >
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Using MySQL and PHP with Google Maps</title>
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var customLabel = {
restaurant: {
label: 'R'
},
bar: {
label: 'B'
}
};
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(-33.863276, 151.207977),
zoom: 12
});
var infoWindow = new google.maps.InfoWindow;
// Change this depending on the name of your PHP or XML file
downloadUrl('https://storage.googleapis.com/mapsdevsite/json/mapmarkers2.xml', function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName('marker');
Array.prototype.forEach.call(markers, function(markerElem) {
var name = markerElem.getAttribute('name');
var address = markerElem.getAttribute('address');
var type = markerElem.getAttribute('type');
var point = new google.maps.LatLng(
parseFloat(markerElem.getAttribute('lat')),
parseFloat(markerElem.getAttribute('lng')));
var infowincontent = document.createElement('div');
var strong = document.createElement('strong');
strong.textContent = name
infowincontent.appendChild(strong);
infowincontent.appendChild(document.createElement('br'));
var text = document.createElement('text');
text.textContent = address
infowincontent.appendChild(text);
var icon = customLabel[type] || {};
var marker = new google.maps.Marker({
map: map,
position: point,
label: icon.label
});
marker.addListener('click', function() {
infoWindow.setContent(infowincontent);
infoWindow.open(map, marker);
});
});
});
}
function downloadUrl(url, callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('GET', url, true);
request.send(null);
}
function doNothing() {}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
</body>
</html>
入门指南
在计算机上安装、设置并配置一个使用 PHP 的 MySQL 服务器。
在 MySQL 中创建表
在 MySQL 中创建一个表,其中包含标记 id、name、address、lat、lng 和 type 等地图标记的属性。
id 属性充当主键,type 属性用于区分餐馆和酒吧。
要将表的存储空间保持在最低水平,可将 lat 和 lng 属性指定为尺寸是 (10,6) 的浮点值。如此一来,字段便可在小数点后存储 6 位,还可在小数点前最多存储 4 位。
可以通过 phpMyAmin 界面与 MySQL 数据库进行交互。以下屏幕截图显示了在 phpMyAdmin 中设置的表。
还可以利用 SQL 命令,通过下面这样的 SQL 语句来创建表。
CREATE TABLE `markers` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , `name` VARCHAR( 60 ) NOT NULL , `address` VARCHAR( 80 ) NOT NULL , `lat` FLOAT( 10, 6 ) NOT NULL , `lng` FLOAT( 10, 6 ) NOT NULL , `type` VARCHAR( 30 ) NOT NULL ) ENGINE = MYISAM ;
填充表
可以利用 phpMyAdmin 界面中用于导入各种格式数据的“Import”功能将标记数据导入 SQL 数据库。
以下是本教程中地图的标记数据,采用的是 .csv 格式。
Love.Fish,"580 Darling Street, Rozelle, NSW",-33.861034,151.171936,restaurant Young Henrys,"76 Wilford Street, Newtown, NSW",-33.898113,151.174469,bar Hunter Gatherer,"Greenwood Plaza, 36 Blue St, North Sydney NSW ",-33.840282,151.207474,bar The Potting Shed,"7A, 2 Huntley Street, Alexandria, NSW",-33.910751,151.194168,bar Nomad,"16 Foster Street, Surry Hills, NSW",-33.879917,151.210449,bar Three Blue Ducks,"43 Macpherson Street, Bronte, NSW",-33.906357,151.263763,restaurant Single Origin Roasters,"60-64 Reservoir Street, Surry Hills, NSW",-33.881123,151.209656,restaurant Red Lantern,"60 Riley Street, Darlinghurst, NSW",-33.874737,151.215530,restaurant
还可以利用以下 SQL 命令将标记数据导入 SQL 表。
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Love.Fish', '580 Darling Street, Rozelle, NSW', '-33.861034', '151.171936', 'restaurant');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Young Henrys', '76 Wilford Street, Newtown, NSW', '-33.898113', '151.174469', 'bar');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Hunter Gatherer', 'Greenwood Plaza, 36 Blue St, North Sydney NSW', '-33.840282', '151.207474', 'bar');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('The Potting Shed', '7A, 2 Huntley Street, Alexandria, NSW', '-33.910751', '151.194168', 'bar');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Nomad', '16 Foster Street, Surry Hills, NSW', '-33.879917', '151.210449', 'bar');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Three Blue Ducks', '43 Macpherson Street, Bronte, NSW', '-33.906357', '151.263763', 'restaurant');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Single Origin Roasters', '60-64 Reservoir Street, Surry Hills, NSW', '-33.881123', '151.209656', 'restaurant');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`, `type`) VALUES ('Red Lantern', '60 Riley Street, Darlinghurst, NSW', '-33.874737', '151.215530', 'restaurant');
利用 PHP 以 XML 格式输出数据
此时,您应该得到了一个名为 markers 的表,其中包含地图标记数据。此部分介绍如何利用 PHP 语句以 XML 格式从 SQL 数据库导出表数据。地图可以利用 XML 文件通过异步 JavaScript 调用来检索标记数据。
使用 XML 文件作为数据库与 Google 地图之间的媒介可加快初始页面加载速度,以及提高地图应用的灵活性。它可以简化调试工作,因为您可以独立验证数据库的 XML 输出,以及 XML 的 JavaScript 解析。还可以让运行的地图完全基于静态 XML 文件,不使用 MySQL 数据库。
如果您从未使用 PHP 来连接 MySQL 数据库,请访问 php.net 并研读有关 mysql_connect、mysql_select_db、my_sql_query 和 mysql_error 的内容。
可以利用 PHP 通过下列三种不同方法中的任意一种方法以 XML 格式输出 SQL 表数据。
使用公共浏览器访问使用 PHP 文件的数据库时,必须确保数据库凭证的安全。这可以通过在存放主要 PHP 代码的 PHP 文件以外单独使用一个 PHP 文件来存放数据库连接信息来实现。包含凭据的文件内容应与以下所示类似,但包含的是您自己的数据库信息。
<?php $username="username"; $password="password"; $database="username-databaseName"; ?>
利用 PHP 的 DOM XML 函数输出 XML
PHP 的 DOM XML 函数负责某些微妙处理(例如对 XML 中的特殊实体进行转义),并且可以让创建结构更复杂的 XML 变得轻松。可以利用 DOM XML 函数创建 XML 节点、追加子节点以及将 XML 文档输出到屏幕。要确定服务器的 PHP 是否启用了 DOM XML 功能,请检查配置或尝试初始化一个 domxml_new_doc()。
以下这个 PHP 文件的作用是连接 MySQL 数据库,并将 XML 转储到浏览器。
<?php
require("phpsqlajax_dbinfo.php");
// Start XML file, create parent node
$doc = domxml_new_doc("1.0");
$node = $doc->create_element("markers");
$parnode = $doc->append_child($node);
// Opens a connection to a MySQL server
$connection=mysql_connect ('localhost', $username, $password);
if (!$connection) {
die('Not connected : ' . mysql_error());
}
// Set the active MySQL database
$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ('Can\'t use db : ' . mysql_error());
}
// Select all the rows in the markers table
$query = "SELECT * FROM markers WHERE 1";
$result = mysql_query($query);
if (!$result) {
die('Invalid query: ' . mysql_error());
}
header("Content-type: text/xml");
// Iterate through the rows, adding XML nodes for each
while ($row = @mysql_fetch_assoc($result)){
// Add to XML document node
$node = $doc->create_element("marker");
$newnode = $parnode->append_child($node);
$newnode->set_attribute("name", $row['name']);
$newnode->set_attribute("address", $row['address']);
$newnode->set_attribute("lat", $row['lat']);
$newnode->set_attribute("lng", $row['lng']);
$newnode->set_attribute("type", $row['type']);
}
$xmlfile = $doc->dump_mem();
echo $xmlfile;
?>
在以上文件中,PHP 代码首先初始化了一个新的 XML 文档并创建“markers”父节点。然后连接数据库,对标记表执行 SELECT *(全选)查询,并对结果进行循环访问。对于表中的每一行(每个位置),代码都会新建一个 XML 节点(使用行属性作为 XML 属性),并将其追加到父节点。代码的最后一部分则是将 XML 转储到浏览器屏幕。
注:如果数据库包含国际字符或由于其他原因而需要强制进行 UTF-8 输出,可以对数据输出使用 utf8_encode。
利用 PHP 的 echo 输出 XML
如果无法访问 PHP 的 dom_xml 函数,则可使用 echo 函数输出 XML。在仅使用 echo 函数时使用辅助函数(例如 parseToXML)可将几种特殊实体(<、>、"、')正确编码为 XML 适用形式。
以下这个 PHP 文件的作用是连接 MySQL 数据库,并将 XML 转储到浏览器。
<?php
require("phpsqlajax_dbinfo.php");
function parseToXML($htmlStr)
{
$xmlStr=str_replace('<','<',$htmlStr);
$xmlStr=str_replace('>','>',$xmlStr);
$xmlStr=str_replace('"','"',$xmlStr);
$xmlStr=str_replace("'",''',$xmlStr);
$xmlStr=str_replace("&",'&',$xmlStr);
return $xmlStr;
}
// Opens a connection to a MySQL server
$connection=mysql_connect ('localhost', $username, $password);
if (!$connection) {
die('Not connected : ' . mysql_error());
}
// Set the active MySQL database
$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ('Can\'t use db : ' . mysql_error());
}
// Select all the rows in the markers table
$query = "SELECT * FROM markers WHERE 1";
$result = mysql_query($query);
if (!$result) {
die('Invalid query: ' . mysql_error());
}
header("Content-type: text/xml");
// Start XML file, echo parent node
echo '<markers>';
// Iterate through the rows, printing XML nodes for each
while ($row = @mysql_fetch_assoc($result)){
// Add to XML document node
echo '<marker ';
echo 'name="' . parseToXML($row['name']) . '" ';
echo 'address="' . parseToXML($row['address']) . '" ';
echo 'lat="' . $row['lat'] . '" ';
echo 'lng="' . $row['lng'] . '" ';
echo 'type="' . $row['type'] . '" ';
echo '/>';
}
// End XML file
echo '</markers>';
?>
以上代码的作用是连接数据库,对标记表执行 SELECT *(全选)查询,然后输出父 markers 节点,并循环访问查询结果,接着输出每个表行中的标记(每个位置)的 XML 节点。如果其中包含任何特殊实体,这段代码先通过 parseToXML 函数发送名称和地址字段。脚本最后以输出 markers 结束标记结束。
注:如果数据库包含国际字符或需要强制进行 UTF-8 输出,可以对 XML 数据输出使用 utf8_encode。
利用 PHP 的 DOM 函数输出 XML
以下这个 PHP 文件的作用是连接 MySQL 数据库,并将 XML 转储到浏览器。
<?php
require("phpsqlajax_dbinfo.php");
// Start XML file, create parent node
$dom = new DOMDocument("1.0");
$node = $dom->createElement("markers");
$parnode = $dom->appendChild($node);
// Opens a connection to a MySQL server
$connection=mysql_connect ('localhost', $username, $password);
if (!$connection) { die('Not connected : ' . mysql_error());}
// Set the active MySQL database
$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ('Can\'t use db : ' . mysql_error());
}
// Select all the rows in the markers table
$query = "SELECT * FROM markers WHERE 1";
$result = mysql_query($query);
if (!$result) {
die('Invalid query: ' . mysql_error());
}
header("Content-type: text/xml");
// Iterate through the rows, adding XML nodes for each
while ($row = @mysql_fetch_assoc($result)){
// Add to XML document node
$node = $dom->createElement("marker");
$newnode = $parnode->appendChild($node);
$newnode->setAttribute("name",$row['name']);
$newnode->setAttribute("address", $row['address']);
$newnode->setAttribute("lat", $row['lat']);
$newnode->setAttribute("lng", $row['lng']);
$newnode->setAttribute("type", $row['type']);
}
echo $dom->saveXML();
?>
以上代码的作用是初始化一个新的 XML 文档并创建“markers”父节点。然后连接数据库,对标记表执行 SELECT *(全选)查询,并对结果进行循环访问。代码接着为表中的每一行(每个位置)创建一个 XML 节点(使用行属性作为 XML 属性),并将其追加到父节点。然后将输出 XML 转储到浏览器屏幕。
注:如果数据库包含国际字符或需要强制进行 UTF-8 输出,可以对数据输出使用 utf8_encode。
检查确认 XML 输出工作正常
要确认 PHP 脚本产生的 XML 有效,请通过浏览器调用所创建的 PHP 脚本文件,然后便可看到如下所示的 XML 输出。
<markers> <marker name="Love.Fish" address="580 Darling Street, Rozelle, NSW" lat="-33.861034" lng="151.171936" type="restaurant"/> <marker name="Young Henrys" address="76 Wilford Street, Newtown, NSW" lat="-33.898113" lng="151.174469" type="bar"/> <marker name="Hunter Gatherer" address="Greenwood Plaza, 36 Blue St, North Sydney NSW" lat="-33.840282" lng="151.207474" type="bar"/> <marker name="The Potting Shed" address="7A, 2 Huntley Street, Alexandria, NSW" lat="-33.910751" lng="151.194168" type="bar"/> <marker name="Nomad" address="16 Foster Street, Surry Hills, NSW" lat="-33.879917" lng="151.210449" type="bar"/> <marker name="Three Blue Ducks" address="43 Macpherson Street, Bronte, NSW" lat="-33.906357" lng="151.263763" type="restaurant"/> <marker name="Single Origin Roasters" address="60-64 Reservoir Street, Surry Hills, NSW" lat="-33.881123" lng="151.209656" type="restaurant"/> <marker name="Red Lantern" address="60 Riley Street, Darlinghurst, NSW" lat="-33.874737" lng="151.215530" type="restaurant"/> </markers>
如果浏览器不是以 XML 输出形式显示数据库中的标记数据,请尝试通过从文件中删除将标头设置为 text/xml 内容类型的代码行进行调试。这行代码可能致使浏览器尝试解析 XML 并给查看调试消息造成困难。
创建地图
此部分介绍如何利用 JavaScript 以及输出 XML 文件开发本教程中的地图示例。请阅读相关文档,了解更多有关 Google 地图创建基础知识的信息。
在文本编辑器中新建一个文件,并将其另存为 index.html。阅读后续部分,以理解可向该文件添加的代码。
加载 XML 文件
要将 XML 文件加载到页面中,可以利用浏览器提供的 XMLHttpRequest 对象。这个对象是“AJAX”编程的基础,可以通过它检索与请求网页位于同一网域的文件。
定义您自己的文件加载函数,并将其命名为 downloadUrl()。该函数采用以下两个参数:
url:指定 XML 文件或生成该文件的 PHP 脚本的路径,具体取决于您是否想在数据库发生变化时动态更新 XML 文件。本教程中的这个地图调用一个静态标记数据 XML 文件。
将这个 XML 文件存放在 HTML 文件所在的同一目录通常最为方便,因为这样一来,便可直接通过文件名进行引用。-
callback表示当 XML 返回给 JavaScript 时脚本调用的函数。
以下代码展示了函数声明。
function downloadUrl(url,callback) {
var request = window.ActiveXObject ?
new ActiveXObject('Microsoft.XMLHTTP') :
new XMLHttpRequest;
request.onreadystatechange = function() {
if (request.readyState == 4) {
request.onreadystatechange = doNothing;
callback(request, request.status);
}
};
request.open('GET', url, true);
request.send(null);
}
注:由于 XMLHttpRequest 是异步的,因此 callback 函数会根据 XML 文件的大小启动 downloadURL 函数。XML 文件越大,需要的时间可能就越长。因此,最好不要在 downloadUrl 之后放置任何依赖 callback 函数内标记的代码。可以改为将此类代码置于 callback 函数内。
现在您已定义了函数,可以通过传入 PHP 文件的名称和 callback 函数使用代码调用它。本教程中的地图调用一个静态标记数据 XML 文件,如以下代码所示。
downloadUrl('https://storage.googleapis.com/mapsdevsite/json/mapmarkers2.xml', function(data) {
var xml = data.responseXML;
var markers = xml.documentElement.getElementsByTagName('marker');
Array.prototype.forEach.call(markers, function(markerElem) {
var name = markerElem.getAttribute('name');
var address = markerElem.getAttribute('address');
var type = markerElem.getAttribute('type');
var point = new google.maps.LatLng(
parseFloat(markerElem.getAttribute('lat')),
parseFloat(markerElem.getAttribute('lng')));
var infowincontent = document.createElement('div');
var strong = document.createElement('strong');
strong.textContent = name
infowincontent.appendChild(strong);
infowincontent.appendChild(document.createElement('br'));
var text = document.createElement('text');
text.textContent = address
infowincontent.appendChild(text);
var icon = customLabel[type] || {};
var marker = new google.maps.Marker({
map: map,
position: point,
label: icon.label
});
创建自定义标记
以下代码展示如何通过先创建一个关联数组来为标记添加自定义标签。这个数组会将标签与标记 type 字符串 restaurant 或 bar 关联起来。在您根据 XML 文件创建标记时,这可以方便对标签的引用。
var customLabel = {
restaurant: {
label: 'R'
},
bar: {
label: 'B'
}
};
创建标记和信息窗口
创建标记时,可以使用 type 类型作为 customLabel 关联数组的键来检索相应的标记标签。将 .label 属性以 google.maps.Marker 构造函数选项形式进行转发。
接下来,通过连接名称、地址和用来强调名称的 HTML 标记来创建您想在信息窗口中显示的 HTML。
如果在数据库中存储的是 HTML 格式的说明,可能需要处理 HTML 实体转义,并绑定至该 HTML 输出。等到已经在 JavaScript 中分别检索了每个属性时,您就可以随意在客户端对 HTML 进行各种尝试,并可快速预览新的格式设置。
构建 HTML 字符串后,可通过以下代码为标记添加在点击时显示信息窗口的事件侦听器。
marker.addListener('click', function() {
infoWindow.setContent(infowincontent);
infoWindow.open(map, marker);
});
规则汇总
在浏览器中打开 index.html 文件。页面加载时,initMap 函数会设置地图,然后调用 downloadUrl 函数。该函数循环访问所有 marker 元素,并检索每个 marker 元素的 name、address、type 和 latLng 属性。
代码随后会创建标记,向地图添加标记,并为每个标记绑定一个在点击时显示说明的信息窗口。
更多信息
如果您想使用自己的位置数据在地图上绘制标记,可以利用批量地理编码服务将地址转换成标记位置的经纬度。
