如何使用AngularJS和PHP为任何位置生成一个简短且唯一的数字地址
介绍
邮政地址通常很长,有时很难记住。 在许多情况下,需要较短的地址。 例如,能够发送仅包含几个字符的短地址可以确保更快地提供紧急救护车服务。 Pieter Geelen 和 Harold Goddijn 在 2001 年开发了 地图代码系统 ,以便为世界上任何物理地址创建短格式地址。
在本教程中,您将开发一个 Web 应用程序,该应用程序使用 Google Maps API 为您选择的任何地址生成一个简短的数字地址。 为此,您将通过从 GitHub 克隆此应用程序的基本代码,然后向其中添加代码以使其完全正常运行。 此应用程序还可以从给定的地图代码中检索原始物理地址。
先决条件
为了完成本教程,您将需要以下内容:
- 访问 Ubuntu 18.04 服务器。 此服务器应该有一个具有
sudo
权限的非 root 用户并配置了防火墙。 要进行设置,您可以按照我们的 Ubuntu 18.04 初始服务器设置指南进行操作。 - 安装在您的机器上的 LAMP 堆栈。 这是必要的,因为您将在本教程中开发的应用程序使用 AngularJS 和 PHP,并且应用程序生成的数字地址将存储在 MySQL 数据库中。 按照我们关于 如何在 Ubuntu 18.04 上安装 Linux、Apache、MySQL、PHP (LAMP) 堆栈的指南进行设置。
- Git 安装在您的服务器上。 你可以按照教程贡献开源:Git入门来安装和设置Git。
第 1 步 — 获取 Google API 密钥
在本教程中,您将使用 JavaScript 创建 Google 地图的界面。 Google 分配 API 密钥以使开发人员能够在 Google 地图上使用 JavaScript API,您需要获取这些密钥并将其添加到您的网络应用程序的代码中。
要获取您自己的 API 密钥,请前往 Google 的 “获取 API 密钥”页面 。 单击步骤 1 中的 GET STARTED 按钮,将打开一个弹出窗口,如下图所示:
通过单击复选框选择 Maps 并点击 CONTINUE。 如果您尚未登录 Google 帐户,系统会要求您登录。 然后,窗口将要求您提供项目的名称,可以是您想要的任何名称:
在此之后,它会要求您输入您的帐单信息。 请注意,Google 提供 API 密钥作为免费试用的一部分,但它需要您设置并启用计费才能检索它们。
输入此信息后,您的 API 密钥将出现在屏幕上。 将其复制并存储在您可以轻松检索它的位置,因为您稍后需要将其添加到您的项目代码中。
获得 API 密钥后,您可以通过创建 MySQL 数据库开始构建应用程序的基础。
第 2 步 — 创建数据库
本教程中描述的 Web 应用程序接受来自用户的地址并为其生成地图代码以及指定位置的纬度和经度。 您将把这些数据存储在 MySQL 数据库中,以便以后只需输入相应的数字地址即可检索它。
首先打开 MySQL shell 并使用您的密码进行身份验证:
mysql -u root -p
在提示符下,使用以下命令创建一个名为 digitaladdress
的数据库:
CREATE DATABASE IF NOT EXISTS `digitaladdress`;
接下来,选择这个新数据库,以便您可以在其中创建一个表:
USE `digitaladdress`;
选择 digitaladdress
数据库后,在其中创建一个名为 locations
的表来存储物理地址、其经度、纬度以及应用程序将从该数据创建的地图代码。 运行以下 CREATE TABLE
语句在数据库中创建 locations
表:
CREATE TABLE `locations` ( `digitaladdress` varchar(50) DEFAULT NULL, `state` varchar(30) DEFAULT NULL, `zip` varchar(30) DEFAULT NULL, `street` varchar(30) DEFAULT NULL, `town` varchar(30) DEFAULT NULL, `house` varchar(30) DEFAULT NULL, `latitude` varchar(30) DEFAULT NULL, `longitude` varchar(30) DEFAULT NULL, KEY `digitaladdress` (`digitaladdress`) );
该表有八列:digitaladdress
、state
、zip
、street
、town
、house
、[X96X ] 和 longitude
。 第一列 digitaladdress
使用 KEY
命令进行 索引 。 MySQL 中的索引的功能类似于它们在百科全书或其他参考作品中的工作方式。 每当您或您的应用程序发出包含 WHERE
语句的查询时,MySQL 会逐行读取每列中的每个条目,随着您的表累积越来越多的条目,这可能会成为一个非常耗费资源的过程. 像这样对列进行索引从列中获取数据并按字母顺序将其存储在单独的位置,这意味着 MySQL 不必查看表中的每一行。 它只需要在索引中找到您要查找的数据,然后跳转到表中的相应行。
添加此表后,退出 MySQL 提示符:
exit
设置好数据库和表并准备好 Google Maps API 密钥后,您就可以自己创建项目了。
第三步——创建项目
如介绍中所述,我们将从 GitHub 克隆该项目的基本代码,然后添加一些额外的代码以使应用程序正常运行。 这样做的原因不是引导您完成创建每个文件并自己添加所有代码的过程,而是加快应用程序运行的过程。 它还将使我们能够专注于添加和理解允许应用程序与 Google 地图和 Mapcode API 通信的代码。
您可以在 这个 GitHub 项目页面 上找到完整项目的骨架代码。 使用以下 git
命令将项目克隆到您的服务器:
git clone https://github.com/do-community/digiaddress.git
这将在您的主目录中创建一个名为 digiaddress
的新文件夹。 将此目录移动到服务器的 Web 根目录。 如果您按照先决条件中链接的 LAMP 堆栈教程进行操作,这将是 /var/www/html
目录:
sudo mv digiaddress/ /var/www/html/
该项目包含几个 PHP 和 JS 文件,稍后您将在本教程中添加一些代码。 要查看目录结构,首先使用 apt
安装 tree
包:
sudo apt install tree
然后使用 digiaddress
目录作为参数运行 tree
命令:
tree /var/www/html/digiaddress/
Outputdigiaddress/ ├── README.md ├── db.php ├── fetchaddress.php ├── findaddress.php ├── generateDigitalAddress.php ├── geoimplement.php ├── index.php └── js ├── createDigitialAddressApp.js └── findAddressApp.js
您可以从此输出中看到该项目由六个 PHP 文件和两个 JavaScript 文件组成。 这些文件共同创建了应用程序的两个主要功能:从物理地址创建地图代码,以及解码地图代码以检索原始物理地址。 以下文件启用第一个功能:
index.php
geoimplement.php
generateDigitialAddress.php
db.php
createDigitialAddressApp.js
index.php
文件包含应用程序用户界面 (UI) 的代码,它由用户可以输入物理地址的表单组成。 每当用户提交表单时,index.php
文件都会调用 geoimplement.php
文件。 geoimplement.php
调用 Google Maps API 并将地址传递给它。 然后,Google 服务器会使用包含指定地址信息(包括其纬度和经度)的 JSON 进行响应。 然后将此信息传递到 generateDigitalAddress.php
文件,该文件调用 Mapcode API 以获取给定位置的地图代码,由其纬度和经度指定。 然后,生成的地图代码以及纬度、经度和物理地址将存储在您在步骤 2 中创建的数据库中。 db.php
充当此操作的助手。 createDigitalAddressApp.js
文件执行许多控制应用程序中看到的 UX 元素的操作,包括在 Google 地图界面上设置标记和边界矩形。
剩下的三个文件启用了应用程序的第二个功能——即从给定的地图代码中检索物理地址:
findaddress.php
fetchaddress.php
findAddressApp.js
findaddress.php
文件定义了应用程序 UI,这与 index.php
中定义的不同。 该应用程序接受先前生成的地图代码作为输入,并显示存储在数据库中的相应物理地址。 每当用户提交此表单时,findaddress.php
都会向 fetchaddress.php
发送调用,然后从数据库中检索相应的地图代码。 findAddressApp.js
文件包含用于在 Google 地图界面上设置标记和边界矩形的帮助代码。
通过在浏览器中访问 http://your_server_ip/digiaddress
来测试安装,确保更改 your_server_ip
以反映您服务器的 IP 地址。
注意:如果你不知道你的服务器的IP地址,你可以运行下面的curl
命令。 此命令将打印 icanhazip.com
的页面内容,该网站显示访问它的机器的 IP 地址:
curl http://icanhazip.com
在那里,您将在浏览器窗口的顶部看到此标题:
Generate Digital Address
这确认您已正确下载项目文件。 有了这个,让我们继续开发应用程序的主要功能:生成地图代码。
第 4 步 — 开发应用程序的 UI
虽然应用程序接口的样板代码包含在您在上一步下载的文件中,但您仍需要对其中一些文件进行一些更改和添加,以使应用程序正常运行并吸引用户。 我们将开始更新代码以开发应用程序的 UI。
使用您喜欢的编辑器打开 index.php
文件。 在这里,我们将使用 nano
:
nano /var/www/html/digiaddress/index.php
查找以下代码行:
/var/www/html/digiaddress/index.php
. . . <script async defer src="https://maps.googleapis.com/maps/api/js?key=<YOUR KEY>"></script> . . .
将 <YOUR KEY>
替换为您在步骤 1 中获得的 Google API 密钥。 添加 API 密钥后,该行应类似于以下内容:
/var/www/html/digiaddress/index.php
. . . <script async defer src="https://maps.googleapis.com/maps/api/js?key=ExampleAPIKeyH2vITfv1eIHbfka9ym634Esw7u"></script> . . .
接下来,在index.php
文件中找到如下注释:
/var/www/html/digiaddress/index.php
. . . <!-- add form code here --> . . .
我们将在此注释下方添加几十行代码,这将创建一个表单,用户可以在其中输入应用程序将用来生成地图代码的物理位置的地址。 在此注释下,添加以下突出显示的代码,该代码在表单顶部创建一个名为 Enter Address 的标题:
/var/www/html/digiaddress/index.php
. . . <!-- add form code here --> <div class="form-border spacing-top"> <div class="card-header" style="background:#cc0001; color:#ffff"> <h5>Enter Address</h5> </div> <div class="extra-padding"> . . .
在此下方,添加以下 HTML 代码。 这将创建一个包含五个文本字段(以及相应的标签)的表单,用户将在其中输入他们的信息:
/var/www/html/digiaddress/index.php
. . . <form> <div class="form-group input-group-sm"> <label for="state">State</label> <input type="text" class="form-control rounded-0 textbox-border" id="state" placeholder="" ng-model="address.state"/> </div> <div class="form-group input-group-sm"> <label for="zip" class="animated-label">Zip</label> <input type="text" class="form-control rounded-0 textbox-depth textbox-border" id="zip" ng-model="address.zip" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="town">Town</label> <input type="text" class="form-control rounded-0 textbox-border" id="town" ng-model="address.town" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="street">Street</label> <input type="text" class="form-control rounded-0 textbox-border" id="street" placeholder="" ng-model="address.street" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="house">House</label> <input type="text" class="form-control rounded-0 textbox-border" id="house" placeholder="" ng-model="address.house" disabled="disabled"/> </div> . . .
在表单代码下方,添加以下行。 这些创建了两个隐藏控件,它们传递从通过表单提交的任何地址派生的纬度和经度信息:
/var/www/html/digiaddress/index.php
. . . <div class="form-group input-group-sm"> <input type="hidden" ng-model="address.lat"/> </div> <div class="form-group input-group-sm"> <input type="hidden" ng-model="address.long"/> </div> . . .
最后,通过添加以下代码结束本节。 这将创建一个 Generate 按钮,允许用户提交表单:
/var/www/html/digiaddress/index.php
. . . <button type="submit" disabled="disabled" class="btn btn-color btn-block rounded-0" id="generate" style="color:#ffff;background-color: #cc0001;">Generate </button> </form> </div> </div> . . .
添加这些元素后,文件的这一部分应与以下内容匹配:
/var/www/html/digiaddress/index.php
. . . <!-- add form code here --> <div class="form-border spacing-top"> <div class="card-header" style="background:#cc0001; color:#ffff"> <h5>Enter Address</h5> </div> <div class="extra-padding"> <form> <div class="form-group input-group-sm"> <label for="state">State</label> <input type="text" class="form-control rounded-0 textbox-border" id="state" placeholder="" ng-model="address.state"/> </div> <div class="form-group input-group-sm"> <label for="zip" class="animated-label">Zip</label> <input type="text" class="form-control rounded-0 textbox-depth textbox-border" id="zip" ng-model="address.zip" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="town">Town</label> <input type="text" class="form-control rounded-0 textbox-border " id="town" ng-model="address.town" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="street">Street</label> <input type="text" class="form-control rounded-0 textbox-border" id="street" placeholder="" ng-model="address.street" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="house">House</label> <input type="text" class="form-control rounded-0 textbox-border" id="house" placeholder="" ng-model="address.house" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <input type="hidden" ng-model="address.lat"/> </div> <div class="form-group input-group-sm"> <input type="hidden" ng-model="address.long"/> </div> <button type="submit" disabled="disabled" class="btn btn-color btn-block rounded-0" id="generate" style="color:#ffff;background-color: #cc0001;">Generate </button> </form> </div> </div> <br> </div> <!-- add google map control --> . . .
按 CTRL+O
然后按 ENTER
保存文件,然后再次在浏览器中访问应用程序:
http://your_server_ip/digiaddress
您将看到新添加的表单字段和 Generate 按钮,应用程序应如下所示:
此时,如果您在表单中输入地址信息并尝试单击Generate按钮,则不会发生任何事情。 稍后我们将添加地图代码生成功能,但让我们首先关注通过添加用户可以与之交互的地图来使该页面更具视觉吸引力。
第 5 步 — 添加 Google 地图控件
当地图通过 Google Maps JavaScript API 显示在网站上时,它们包含允许访问者与他们看到的地图进行交互的用户界面功能。 这些功能被称为 控件 。 我们将继续编辑 index.php
文件以将 Google 地图控件添加到此应用程序,完成后,用户将能够查看输入表单旁边的地图,拖动它以查看不同的位置,放大和并在 Google 的地图、卫星和街景之间切换。
在 index.php
文件中找到以下注释:
/var/www/html/digiaddress/index.php
. . . <!-- add google map control --> . . .
在此注释下方添加以下突出显示的代码:
/var/www/html/digiaddress/index.php
. . . <!-- add google map control --> <div class="col-sm-8 map-align" ng-init="initMap()"> <div id="map" class="extra-padding" style="height: 100%; margin-bottom: 15px;"></div> <label id="geocoordinates" ng-show="latlng" ng-model="lt"></label><br/> <label id="geoaddress" ng-show="address" ng-model="padd"></label> </div> </div> . . .
保存文件,然后再次在浏览器中访问该应用程序。 您将看到以下内容:
如您所见,我们已成功将地图添加到应用程序中。 您可以拖动地图以聚焦不同的位置、放大和缩小,以及在地图、卫星和街景之间切换。 回顾您刚刚添加的代码,请注意我们还添加了两个标签控件,它们将显示在表单中输入的地理坐标和物理地址:
/var/www/html/digiaddress/index.php
. . . <label id="geocoordinates" ng-show="latlng" ng-model="lt"></label><br/> <label id="geoaddress" ng-show="address" ng-model="padd"></label> . . .
在浏览器中再次访问该应用程序并在第一个字段中输入一个州的名称。 当您将文本光标移动到下一个字段时,不会出现纬度和经度标签,地图上显示的位置也不会更改以反映您输入的信息。 让我们启用这些行为。
第 6 步 — 添加事件监听器
向应用程序添加交互式元素有助于保持其用户的参与度。 我们将通过使用事件监听器在这个应用程序中实现一些交互行为。
事件 是在网页上发生的任何动作。 事件可以是用户或浏览器本身完成的事情。 常见事件示例如下:
- 单击 HTML 按钮
- 更改输入字段的内容
- 将焦点从一个页面元素更改为另一个页面元素
事件监听器 是一个指令,它告诉程序在特定事件发生时采取特定操作。 在 AngularJS 中,事件侦听器是使用通常遵循以下格式的指令定义的:
ng-event_type=expression
在这一步中,我们将添加一个事件侦听器,帮助处理用户在提交表单时输入到地图代码中的信息。 我们还将添加更多事件侦听器,使应用程序更具交互性。 具体来说,我们将使用这些侦听器来更改应用程序地图中显示的位置,放置一个标记,并在用户将信息输入表单时在该位置周围绘制一个矩形。 我们会将这些事件侦听器添加到 index.php
,因此如果您关闭了该文件,请再次打开它:
nano /var/www/html/digiaddress/index.php
向下滚动到我们添加的第一批代码,找到以 <form>
开头的块。 它看起来像这样:
/var/www/html/digiaddress/index.php
. . . <form> <div class="form-group input-group-sm"> <label for="state">State</label> <input type="text" class="form-control rounded-0 textbox-border" id="state" placeholder="" ng-model="address.state"/> </div> <div class="form-group input-group-sm"> <label for="zip" class="animated-label">Zip</label> <input type="text" class="form-control rounded-0 textbox-depth textbox-border" id="zip" ng-model="address.zip" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="town">Town</label> <input type="text" class="form-control rounded-0 textbox-border" id="town" ng-model="address.town" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="street">Street</label> <input type="text" class="form-control rounded-0 textbox-border" id="street" placeholder="" ng-model="address.street" disabled="disabled"/> </div> <div class="form-group input-group-sm"> <label for="house">House</label> <input type="text" class="form-control rounded-0 textbox-border" id="house" placeholder="" ng-model="address.house" disabled="disabled"/> </div> </form> . . .
首先,将以下突出显示的事件侦听器添加到开始的 <form>
标记中。 此代码告诉应用程序在用户通过表单提交信息时调用 processForm
函数。 processForm
定义在 createDigitalAddressApp.js
文件中,用作辅助函数,将用户提交的信息发送到适当的文件,然后将其处理成地图代码。 我们将在第 7 步中仔细研究此函数:
/var/www/html/digiaddress/index.php
. . . <form ng-submit="processForm()" class="custom-form"> <div class="form-group input-group-sm"> <label for="state">State</label> <input type="text" class="form-control rounded-0 textbox-border" id="state" placeholder="" ng-model="address.state" </div> . . .
接下来,通过添加几个 blur
事件侦听器继续编辑此块。 当给定的页面元素失去焦点时,会发生 blur
事件。 将以下突出显示的行添加到 form
块的 input
标记。 这些行告诉应用程序在用户的焦点从我们在步骤 4 中创建的相应表单字段转移时调用 geocodeAddress
函数。 请注意,您还必须删除关闭每个 input
标记的斜线和大于号 (/>
)。 否则将阻止应用程序正确注册 blur
事件:
/var/www/html/digiaddress/index.php
. . . <form ng-submit="processForm()" class="custom-form"> <div class="form-group input-group-sm"> <label for="state">State</label> <input type="text" class="form-control rounded-0 textbox-border" id="state" placeholder="" ng-model="address.state" ng-blur="geocodeAddress(address,'state')" required=""/> </div> <div class="form-group input-group-sm"> <label for="zip" class="animated-label">Zip</label> <input type="text" class="form-control rounded-0 textbox-depth textbox-border" id="zip" ng-model="address.zip" disabled="disabled" ng-blur="geocodeAddress(address,'zip')" required=""/> </div> <div class="form-group input-group-sm"> <label for="town">Town</label> <input type="text" class="form-control rounded-0 textbox-border" id="town" ng-model="address.town" disabled="disabled" ng-blur="geocodeAddress(address,'town')" required=""/> </div> <div class="form-group input-group-sm"> <label for="street">Street</label> <input type="text" class="form-control rounded-0 textbox-border" id="street" placeholder="" ng-model="address.street" disabled="disabled" ng-blur="geocodeAddress(address,'street')" required=""/> </div> <div class="form-group input-group-sm"> <label for="house">House</label> <input type="text" class="form-control rounded-0 textbox-border" id="house" placeholder="" ng-model="address.house" disabled="disabled" ng-blur="geocodeAddress(address,'house')" required=""/> </div> . . .
这些新行中的第一行 - ng-blur="geocodeAddress(address,'state')" required=""/>
- 转换为“当用户的焦点从‘状态’字段转移时,调用 geocodeAddress
函数。” 其他新行也调用 geocodeAddress
,尽管当用户的焦点从各自的字段移开时。
与 processForm
函数一样,geocodeAddress
在 createDigitalAddressApp.js
文件中声明,但该文件中还没有任何代码定义它。 我们将完成此功能,以便在这些 blur
事件发生后在应用程序地图上放置一个标记并绘制一个矩形,以反映输入到表单中的信息。 我们还将添加一些获取地址信息并将其处理为地图代码的代码。
保存并关闭 index.php
文件(按 CTRL+X
、Y
,然后按 ENTER
)然后打开 createDigitalAddressApp.js
文件:
nano /var/www/html/digiaddress/js/createDigitalAddressApp.js
在此文件中,找到以下行:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . $scope.geocodeAddress = function (address, field) { . . .
这一行是我们声明 geocodeAddress
函数的地方。 在这下面几行,我们声明了一个名为 fullAddress
的变量,它根据用户在应用程序的表单字段中输入的信息构造一个人类可读的邮寄地址。 这是通过一系列 if
语句完成的:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . var fullAddress = ""; if (address ['house']) { angular.element(document.getElementById('generate'))[0].disabled = false; fullAddress = address ['house'] + ","; } if (address ['town']) { angular.element(document.getElementById('street'))[0].disabled = false; fullAddress = fullAddress + address ['town'] + ","; } if (address ['street']) { angular.element(document.getElementById('house'))[0].disabled = false; fullAddress = fullAddress + address ['street'] + ","; } if (address ['state']) { angular.element(document.getElementById('zip'))[0].disabled = false; fullAddress = fullAddress + address ['state'] + " "; } if (address ['zip']) { angular.element(document.getElementById('town'))[0].disabled = false; fullAddress = fullAddress + address ['zip']; } . . .
在这些行之后是以下注释:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . // add code for locating the address on Google maps . . .
在此注释下方,添加以下行来检查 fullAddress
是否为 null 以外的任何值:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . if (fullAddress !== "") { . . .
在此行下方添加以下代码。 如果 fullAddress
不为空,此代码使用 HTTP POST 方法 将输入到表单中的信息提交到 geoimplement.php
文件:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . $http({ method: 'POST', url: 'geoimplement.php', data: {address: fullAddress}, headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).then(function successCallback(results) { . . .
接下来,添加以下行来检查 PHP 调用是否成功返回:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . if (results.data !== "false") { . . .
如果 PHP 调用成功返回,我们将能够处理结果。 添加以下行,通过调用 removeRectangle
函数(定义在 createDigitalAddressApp.js
文件的顶部)来删除之前可能已在地图上绘制的任何边界矩形:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . removeRectangle(); . . .
在 removeRectangle();
行下,添加以下四行,这将创建一个指向地图控件上新位置的标记:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . new google.maps.Marker({ map: locationMap, position: results.data.geometry.location }); . . .
然后添加以下代码,从结果中获取经纬度信息,并与我们在第 5 步的 index.php
文件中创建的两个 HTML 标签一起显示:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . lat = results.data.geometry.location.lat; lng = results.data.geometry.location.lng; $scope.address.lat = lat; $scope.address.lng = lng; geoCoordLabel = angular.element(document.querySelector('#geocoordinates')); geoCoordLabel.html("Geo Coordinate: " + lat + "," + lng); geoAddressLabel = angular.element(document.querySelector('#geoaddress')); geoAddressLabel.html("Geo Address: " + fullAddress); $scope.latlng = true; . . .
最后,在这些行下方,添加以下内容。 此代码创建一个视口,在地图上标记一个新的边界矩形:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . if (results.data.geometry.viewport) { rectangle = new google.maps.Rectangle({ strokeColor: '#FF0000', strokeOpacity: 0.8, strokeWeight: 0.5, fillColor: '#FF0000', fillOpacity: 0.35, map: locationMap, bounds: { north: results.data.geometry.viewport.northeast.lat, south: results.data.geometry.viewport.southwest.lat, east: results.data.geometry.viewport.northeast.lng, west: results.data.geometry.viewport.southwest.lng } }); var googleBounds = new google.maps.LatLngBounds(results.data.geometry.viewport.southwest, results.data.geometry.viewport.northeast); locationMap.setCenter(new google.maps.LatLng(lat, lng)); locationMap.fitBounds(googleBounds); } } else { errorLabel = angular.element(document.querySelector('#lt')); errorLabel.html("Place not found."); $scope.latlng = true; removeRectangle(); } }, function errorCallback(results) { console.log(results); }); } . . .
添加此内容后,文件的这一部分将如下所示:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . // add code for locating the address on Google maps if (fullAddress !== "") { $http({ method: 'POST', url: 'geoimplement.php', data: {address: fullAddress}, headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).then(function successCallback(results) { if (results.data !== "false") { removeRectangle(); new google.maps.Marker({ map: locationMap, position: results.data.geometry.location }); lat = results.data.geometry.location.lat; lng = results.data.geometry.location.lng; $scope.address.lat = lat; $scope.address.lng = lng; geoCoordLabel = angular.element(document.querySelector('#geocoordinates')); geoCoordLabel.html("Geo Coordinate: " + lat + "," + lng); geoAddressLabel = angular.element(document.querySelector('#geoaddress')); geoAddressLabel.html("Geo Address: " + fullAddress); $scope.latlng = true; if (results.data.geometry.viewport) { rectangle = new google.maps.Rectangle({ strokeColor: '#FF0000', strokeOpacity: 0.8, strokeWeight: 0.5, fillColor: '#FF0000', fillOpacity: 0.35, map: locationMap, bounds: { north: results.data.geometry.viewport.northeast.lat, south: results.data.geometry.viewport.southwest.lat, east: results.data.geometry.viewport.northeast.lng, west: results.data.geometry.viewport.southwest.lng } }); var googleBounds = new google.maps.LatLngBounds(results.data.geometry.viewport.southwest, results.data.geometry.viewport.northeast); locationMap.setCenter(new google.maps.LatLng(lat, lng)); locationMap.fitBounds(googleBounds); } } else { errorLabel = angular.element(document.querySelector('#lt')); errorLabel.html("Place not found."); $scope.latlng = true; removeRectangle(); } }, function errorCallback(results) { console.log(results); }); } . . .
保存文件,但暂时保持打开状态。 如果您再次在浏览器中访问该应用程序,您将不会看到它的外观或行为有任何新的变化。 同样,如果您要输入地址并单击 Generate 按钮,应用程序仍然不会生成或显示地图代码。 这是因为我们仍然必须编辑一些文件才能使地图代码功能起作用。 让我们继续进行这些更改,并仔细看看这些地图代码是如何生成的。
第 7 步 - 了解地图代码生成
在查看 createDigitalAddressApp.js
文件的同时,滚动查看您在上一步中添加的代码部分,以找到获取通过表单提交的信息并将其处理为唯一地图代码的代码。 每当用户单击 Generate 按钮时,index.php
文件中的代码都会提交表单并调用 processForm
函数,该函数在 createDigitalAddressApp.js
中定义:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . $scope.processForm = function () { . . .
processForm
然后对 generateDigitalAddress.php
文件进行 HTTP POST:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . $http({ method: 'POST', url: 'generateDigitalAddress.php', data: $scope.address, headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).then(function (response) { . . .
Stichting Mapcode Foundation 提供从物理地址生成地图代码的 API,作为免费的 Web 服务。 要了解此对 Mapcode Web 服务的调用如何工作,请关闭 createDigitalAddressApp.js
并打开 generateDigitialAddress.php
文件:
nano /var/www/html/digiaddress/generateDigitalAddress.php
在文件的顶部,您将看到以下内容:
/var/www/html/digiaddress/generateDigitalAddress.php
<?php include("db.php"); . . .
读取 include("db.php");
的行告诉 PHP include generateDigitalAddress.php
文件中 db.php
文件中的所有文本、代码和标记。 db.php
保存您在步骤 2 中创建的 MySQL 数据库的登录凭据,通过将其包含在 generateDigitalAddress.php
中,我们可以将通过表单提交的任何地址信息添加到数据库中。
在这个include
语句下面还有几行根据createDigitalAddressApp.js
提交的请求获取经纬度信息:
/var/www/html/digiaddress/generateDigitalAddress.php
. . . $data = json_decode(file_get_contents("php://input")); $lat = $data->lat; $long = $data->lng; . . .
在 generateDigitalAddress.php
文件中查找以下注释。
/var/www/html/digiaddress/generateDigitalAddress.php
. . . // call to mapcode web service . . .
在此注释下方添加以下代码行。 此代码调用 Mapcode API,发送 lat
和 long
作为参数。
/var/www/html/digiaddress/generateDigitalAddress.php
. . . // call to mapcode web service $digitaldata = file_get_contents("https://api.mapcode.com/mapcode/codes/".$lat.",".$long."?include=territory,alphabet&allowLog=true&client=web"); . . .
Web 服务返回分配给 digitaldata
的 JSON 数据,以下语句对该 JSON 进行解码:
/var/www/html/digiaddress/generateDigitalAddress.php
. . . $digitalAddress["status"] = json_decode($digitaldata, TRUE)['local']['territory']." ".json_decode($digitaldata, TRUE)['local']['mapcode']; . . .
这将返回用户指定位置的地图代码。 然后以下行将此信息存储在数据库中:
/var/www/html/digiaddress/generateDigitalAddress.php
. . . $obj = new databaseConnection(); $conn = $obj->dbConnect(); $obj->insertLocation($conn, $digitalAddress["status"],$data->state,$data->zip,$data->street,$data->town,$data->house,$lat,$long); . . .
然后,最后一行将映射代码回显给调用者函数:
/var/www/html/digiaddress/generateDigitalAddress.php
. . . echo json_encode($digitalAddress);
保存并关闭此文件,然后再次重新打开 createDigitalAddressApp.js
:
nano /var/www/html/digiaddress/js/createDigitalAddressApp.js
成功检索地图代码后,createDigitalAddressApp.js
文件中的以下行将在对话框中将其显示给用户:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . . digiAddress = response.data.status; . . . $('#digitalAddressDialog').modal('show'); . . .
尽管您确实在 generateDigitalAddress.php
中添加了一行新代码,但当您在浏览器中访问并与应用程序交互时,您仍然不会看到任何功能更改。 这是因为您尚未将 Google API 密钥添加到 geoimplement.php
文件中,该文件会实际调用 Google Maps API。
第 8 步 — 启用对 Google Maps API 的调用
此应用程序依靠 Google Maps API 将物理地址转换为适当的纬度和经度坐标。 然后将它们传递给 Mapcode API,后者使用它们生成地图代码。 因此,如果应用程序无法与 Google Maps API 通信以生成位置的纬度和经度,则任何生成地图代码的尝试都将失败。
回想第 6 步,在构建 address
数据后,我们通过 createDigitalAddressApp.js
文件中的 HTTP POST 请求传递结果:
/var/www/html/digiaddress/js/createDigitalAddressApp.js
$http({ method: 'POST', url: 'geoimplement.php', data: {address: fullAddress}, headers: {'Content-Type': 'application/x-www-form-urlencoded'} }).then(function successCallback(results) {
此代码块将用户输入的地址数据发送到 geoimplement.php
文件,该文件包含调用 Google Maps API 的代码。 继续打开这个文件:
nano /var/www/html/digiaddress/geoimplement.php
您会看到它首先对通过 POST 请求接收到的 address
进行解码:
/var/www/html/digiaddress/geoimplement.php
. . . $data=json_decode(file_get_contents("php://input")); . . .
然后它将输入数据的 address
字段传递给 geocode
函数,该函数返回地址的地理信息:
/var/www/html/digiaddress/geoimplement.php
. . . $result = geocode($data->address); . . .
然后将结果回显给调用者:
/var/www/html/digiaddress/geoimplement.php
. . . echo json_encode($result); . . .
geocode
函数对 address
进行编码,并将其与您的应用程序密钥一起传递给 Google Maps API:
/var/www/html/digiaddress/geoimplement.php
. . . // url encode the address $address = urlencode($address); // google map geocode api url $url = "https://maps.googleapis.com/maps/api/geocode/json?address={$address}&key=<YOUR KEY>"; . . .
在继续滚动之前,将您的 API 密钥添加到 // google map geocode api url
注释下的行中:
/var/www/html/digiaddress/geoimplement.php
. . . // google map geocode api url $url = "https://maps.googleapis.com/maps/api/geocode/json?address={$address}&key=ExampleAPIKeyH2vITfv1eIHbfka9ym634Esw7u"; . . .
将调用发送到 Google Maps API 后,响应被解码并由函数返回其值:
/var/www/html/digiaddress/geoimplement.php
. . . // get the json response $resp_json = file_get_contents($url); // decode the json $resp = json_decode($resp_json, true); if ($resp['status'] == 'OK') { return $resp['results'][0]; } else { return false; } . . .
保存此文件,然后再次访问您的应用程序。 在状态字段中输入 US-NY
,然后点击 TAB
将输入焦点更改为下一个字段。 您将看到以下输出:
请注意,您在表单中输入的地理坐标和实际地址显示在地图下方。 这使应用程序感觉更具吸引力和交互性。
注意: 地名缩写时,Mapcode 使用 ISO 3166 标准。 这意味着它可能无法按预期解释一些常用的缩写。 例如,如果您想为路易斯安那州的地址生成地图代码并输入 LA
,则地图将跳转到加利福尼亚州洛杉矶(而不是路易斯安那州)。
您可以通过在它们前面加上 US-
来避免与美国邮政缩写混淆。 在此路易斯安那州示例的上下文中,您将输入 US-LA
。
要了解有关 Mapcode 如何使用此标准的更多信息,请查看 领土和标准代码参考页 。
尽管对应用程序在地图上显示位置的方式进行了改进,但该应用程序仍不能完全发挥作用。 在生成地图代码之前需要执行的最后一步是编辑 db.php
文件以允许应用程序访问您的数据库。
第 9 步 — 添加数据库凭证并测试 Mapcode 生成
回想一下,此应用程序将输入到表单中的每个地址连同其纬度、经度和地图代码一起存储在您在步骤 2 中创建的数据库中。 这可以通过 db.php
文件中的代码实现,该文件存储您的数据库凭据并允许应用程序访问其中的 locations
表。
作为启用地图代码生成功能的最后一步,打开 db.php
文件进行编辑:
nano /var/www/html/digiaddress/db.php
在该文件的顶部附近,找到以 $pass
开头的行。 此行提交您的 MySQL 登录凭据,以允许应用程序访问您的数据库。 将 your_password
替换为您的 root MySQL 用户密码:
/var/www/html/digiaddress/db.php
. . . $username = "root"; $pass = "your_password"; . . .
这是从物理地址生成地图代码所需的最后更改。 保存并关闭文件,然后再次在浏览器中刷新应用程序。 输入您选择的地址,然后单击 Generate 按钮。 输出将类似于以下内容:
在这个阶段,您已经完成了您的申请,您现在可以为世界上的任何物理位置生成一个简短的数字地址。 随意尝试不同的地址,并注意您输入的地址不一定必须在美国境内。
您的最后一项任务是启用此应用程序的第二个功能:使用相应的地图代码从数据库中检索地址。
第 10 步 — 检索物理地址
现在您可以从给定的物理地址生成地图代码,最后一步是检索从地图代码派生的原始物理地址。 为此,我们将开发一个 PHP 用户界面,如下所示:
此 UI 的代码可在 findaddress.php
文件中找到。 由于此文件中定义的 UI 与我们之前在第 4 步中介绍的 UI 非常相似,因此我们不会仔细研究其工作原理的所有细节。 但是,我们将通过这三个文件来大致解释它们的功能。
为了启用地址检索功能,您需要将您的 Google API 密钥添加到 findaddress.php
文件中,因此请使用您喜欢的编辑器打开它:
nano /var/www/html/digiaddress/findaddress.php
在文件底部附近,找到以 <script async defer src=
开头的行。 它看起来像这样:
/var/www/html/digiaddress/findaddress.php
<script async defer src="https://maps.googleapis.com/maps/api/js?key=<YOUR KEY>"></script>
将 <YOUR KEY>
替换为您在前面步骤中所做的 Google API 密钥,然后保存文件。 不过,在关闭它之前,让我们快速浏览一下这些文件是如何协同工作的。
当用户提交表单时,它会触发 submit
事件,并且事件监听器会调用 fetchadd
函数:
/var/www/html/digiaddress/findaddress.php
. . . <form ng-submit="fetchadd()" class="custom-form"> . . .
fetchadd
函数通过 POST 请求将数字地址发送到 fetchaddress.php
:
/var/www/html/digiaddress/js/findAddressApp.js
. . . $http({ method : 'POST', url : 'fetchaddress.php', data : {digiaddress: $scope.digiaddress} }).then(function(response){ . . .
如果 POST 成功,该函数将返回 JSON 响应。 以下行解析此响应:
/var/www/html/digiaddress/js/findAddressApp.js
. . . var jsonlatlng = JSON.parse(response.data.latlng); . . .
接下来的几行在地图上设置了标记:
/var/www/html/digiaddress/js/findAddressApp.js
. . . marker = new google.maps.Marker({ position: new google.maps.LatLng(jsonlatlng.latitude, jsonlatlng.longitude), map: locationMap }); . . .
以下打印地理坐标和物理地址:
/var/www/html/digiaddress/js/findAddressApp.js
. . . geoCoordLabel = angular.element(document.querySelector('#geocoordinates')); geoCoordLabel.html("Geo Coordinate: "+ jsonlatlng.latitude +","+ jsonlatlng.longitude); geoAddressLabel = angular.element(document.querySelector('#geoaddress')); geoAddressLabel.html("Geo Address: " + jsonlatlng.house +","+ jsonlatlng.town +","+ jsonlatlng.street +","+ jsonlatlng.state + " " + jsonlatlng.zip ); . . .
通过转到以下链接在浏览器中访问此应用程序:
http://your_server_ip/digiaddress/findaddress.php
通过输入您之前获得的地图代码进行测试。 下图显示了一个典型的输出:
这样,您的应用程序就完成了。 您现在可以为世界上的任何位置创建一个唯一的地图代码,然后使用该地图代码来检索该位置的物理地址。
结论
在本教程中,您使用 Google Maps API 固定位置并获取其经度、纬度信息。 此信息用于使用 Mapcode API 生成唯一且简短的数字地址。 地图代码有许多实际用例,从紧急服务到考古调查。 [Stichting Mapcode Foundation] (http://www.mapcode.com/aboutus.html) 列出了几个这样的用例。
致谢
非常感谢 Dinesh Karpe 和 Sayli Patil 开发了整个项目代码。