如何使用AngularJS和PHP为任何位置生成短而独特的数字地址

在本教程中,您将学习如何开发一个使用Google Maps API为世界上任何地址生成地图代码的网络应用。此应用程序还可以从给定的地图代码中检索原始物理地址。

介绍

邮政地址通常很长,有时很难记住。 在许多情况下,需要较短的地址。 例如,能够发送仅由几个字符组成的短地址可以确保更快地提供紧急救护车服务。 Pieter Geelen和Harold Goddijn于2001年开发了Mapcode系统 ,以便为世界上任何物理地址创建简短地址。

在本教程中,您将开发一个Web应用程序,该应用程序使用Google Maps API为您选择的任何地址生成一个简短的数字地址。 您将通过从GitHub克隆此应用程序的基本代码,然后向其中添加使其完全正常运行的代码来实现此目的。 此应用程序还可以从给定的地图代码中检索原始物理地址。

先决条件

要完成本教程,您需要具备以下条件:

第1步 - 获取Google API密钥

在本教程中,您将使用JavaScript创建Google Maps的界面。 Google会分配API密钥,以便开发人员可以在Google地图上使用JavaScript API,您需要获取该API并将其添加到您的网络应用程序代码中。

要获取自己的API密钥,请访问Google的“获取API密钥”页面 单击第1步中的GET STARTED按钮,将打开一个弹出窗口,如下图所示:

单击复选框选择“ 地图” ,然后单击“ 继续” 如果您尚未登录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`)
);

此表有八列: digitaladdressstatezipstreettownhouselatitudelongitude 第一列digitaladdress使用KEY命令编制索引 MySQL中的索引功能与它们在百科全书或其他参考工作中的工作方式类似。 每当您或您的应用程序发出包含WHERE语句的查询时,MySQL就会逐行读取每列中的每个条目,这可能会成为资源密集型过程,因为您的表会累积越来越多的条目。 索引像这样的列从列中获取数据并按字母顺序存储在一个单独的位置,这意味着MySQL不必查看表中的每一行。 它只需要在索引中找到您要查找的数据,然后跳转到表中的相应行。

添加此表后,退出MySQL提示符:

exit

通过设置数据库和表格以及Google Maps API密钥,您就可以自行创建项目了。

第3步 - 创建项目

如介绍中所述,我们将从GitHub克隆此项目的基本代码,然后添加一些额外的代码以使应用程序正常运行。 这样做的原因是为了加快启动应用程序运行的过程,而不是引导您完成创建每个文件并自行添加所有代码的过程。 它还允许我们专注于添加和理解允许应用程序与Google Maps和Mapcode API进行通信的代码。

注意:要从GitHub克隆基本代码,您可能需要先在计算机上安装git 通过更新包索引然后使用apt安装git来做到这一点:

sudo apt update
sudo apt install git

您可以在此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/
digiaddress/
├── 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以获取给定位置的地图代码,由其纬度和经度指定。 然后,生成的mapcode以及纬度,经度和物理地址将存储在您在第2步中创建的数据库中db.php充当此操作的帮助程序。 createDigitalAddressApp.js文件执行许多操作来控制应用程序中看到的UX元素,包括在Google Maps界面上设置标记和边界矩形。

其余三个文件启用应用程序的第二个功能 - 即从给定的mapcode中检索物理地址:

  • findaddress.php
  • fetchaddress.php
  • findAddressApp.js

findaddress.php文件定义应用程序UI,它与index.php定义的UI不同。 应用程序接受先前生成的映射代码作为输入,并显示存储在数据库中的相应物理地址。 每当用户提交此表单时, findaddress.php就会发送一个对fetchaddress.php的调用,然后从数据库中检索相应的mapcode。 findAddressApp.js文件包含用于在Google Maps界面上设置标记和边界矩形的帮助程序代码。

通过在浏览器中访问http:// your_server_ip /digiaddress来测试安装,确保更改your_server_ip以反映服务器的IP地址。

注意:如果您不知道服务器的IP地址,可以运行以下curl命令。 此命令将打印icanhazip.com的页面内容, 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>替换为<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

您将看到新添加的表单字段和生成按钮,应用程序应如下所示:

此时,如果您在表单中输入地址信息并尝试单击“ 生成”按钮,则不会发生任何事情。 我们稍后将添加地图代码生成功能,但我们首先关注通过添加用户可以与之交互的地图来使该页面更具视觉吸引力。

第5步 - 添加Google地图控件

当地图通过Google Maps JavaScript API显示在网站上时,它们包含用户界面功能,允许访问者与他们看到的地图进行互动。 这些功能称为控件 我们将继续编辑index.php文件,将谷歌地图控件添加到此应用程序,完成后,用户将能够查看输入表单旁边的地图,拖动它以查看不同的位置,放大和缩小,以及在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

在此步骤中,我们将添加一个事件监听器,它有助于在用户提交表单时将用户输入的信息处理到mapcode中。 我们还将添加几个事件监听器,使应用程序更具交互性。 具体来说,我们将使用这些监听器更改应用程序映射中显示的位置,放置标记,并在用户在表单中输入信息时在该位置周围绘制一个矩形。 我们将这些事件监听器添加到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函数。 processFormcreateDigitalAddressApp.js文件中定义,并用作帮助函数,将用户提交的信息发送到相应的文件,然后将其处理为mapcode。 我们将在第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=""/> - 转换为“当用户的焦点从'state'字段geocodeAddress ,调用geocodeAddress函数。” 其他新行也调用geocodeAddress ,尽管用户的焦点偏离其各自的字段。

processForm函数一样, geocodeAddresscreateDigitalAddressApp.js文件中声明,但该文件中还没有任何代码定义它。 我们将完成此功能,以便在发生这些blur事件后在应用程序地图上放置标记并绘制矩形,以反映输入到表单中的信息。 我们还将添加一些代码来获取地址信息并将其处理为mapcode。

保存并关闭index.php文件(按CTRL+XY ,然后按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不为null,则此代码使用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);
                    });
                }
                . . .

保存文件,但暂时保持打开状态。 如果您再次在浏览器中访问该应用程序,则不会看到其外观或行为的任何新变化。 同样,如果您要输入地址并单击“ 生成”按钮,则应用程序仍然不会生成或显示地图代码。 这是因为我们必须在mapcode功能运行之前编辑一些文件。 让我们继续进行这些更改,并仔细研究这些地图代码是如何生成的。

第7步 - 了解地图代码生成

在查看createDigitalAddressApp.js文件的同时,滚动浏览您在上一步中添加的代码部分,以查找获取通过表单提交的信息并将其处理为唯一映射代码的代码。 每当用户单击Generate按钮时, index.php文件中的代码都会提交表单并调用processForm函数, processForm函数在createDigitalAddressApp.js定义:

/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . .
$scope.processForm = function () {
. . .

然后, processFormgenerateDigitalAddress.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) {
. . .

The Stichting Mapcode Foundation provides the API that generates mapcodes from physical addresses as a free web service. To understand how this call to the Mapcode web service works, close createDigitalAddressApp.js and open the generateDigitialAddress.php file:

nano /var/www/html/digiaddress/generateDigitalAddress.php

At the top of the file, you'll see the following:

/var/www/html/digiaddress/generateDigitalAddress.php
<?php
include("db.php");
. . .

The line reading include("db.php"); tells PHP to include all the text, code, and markup from the db.php file within the generateDigitalAddress.php file. db.php holds the login credentials for the MySQL database you created in Step 2, and by including it within generateDigitalAddress.php , we can add any address information submitted through the form to the database.

Below this include statement are a few more lines that obtain the latitude and longitude information based on the request submitted by createDigitalAddressApp.js :

/var/www/html/digiaddress/generateDigitalAddress.php
. . .
$data = json_decode(file_get_contents("php://input"));
$lat = $data->lat;
$long = $data->lng;
. . .

Look for the following comment in generateDigitalAddress.php file.

/var/www/html/digiaddress/generateDigitalAddress.php
. . .
// call to mapcode web service
. . .

Add the following line of code below this comment. This code makes a call the Mapcode API, sending lat and long as parameters.

/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");
. . .

The web service returns the JSON data which was assigned to digitaldata , and the following statement decodes that JSON:

/var/www/html/digiaddress/generateDigitalAddress.php
. . .
$digitalAddress["status"] = json_decode($digitaldata, TRUE)['local']['territory']." ".json_decode($digitaldata, TRUE)['local']['mapcode'];
. . .

This returns a mapcode for the user-specified location. The following lines then store this information in the database:

/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);
. . .

Then, the final line echoes the mapcode back to the caller function:

/var/www/html/digiaddress/generateDigitalAddress.php
. . .
echo json_encode($digitalAddress);

Save and close this file, then reopen createDigitalAddressApp.js again:

nano /var/www/html/digiaddress/js/createDigitalAddressApp.js

When a mapcode has been retrieved successfully, the following lines in the createDigitalAddressApp.js file displays it to the user in a dialog box:

/var/www/html/digiaddress/js/createDigitalAddressApp.js
. . .
digiAddress = response.data.status;
. . .
$('#digitalAddressDialog').modal('show');
. . .

Although you did add a new line of code to generateDigitalAddress.php , you still won't see any functional changes when you visit and interact with the app in your browser. This is because you've not yet added your Google API key to the geoimplement.php file, which makes the actual call to the Google Maps API.

Step 8 — Enabling Calls to the Google Maps API

This application depends on the Google Maps API to translate a physical address into the appropriate latitude and longitude coordinates. These are then passed on to the Mapcode API which uses them to generate a mapcode. Consequently, if the application is unable to communicate with the Google Maps API to generate the location's latitude and longitude, any attempt to generate a mapcode will fail.

Recall from Step 6 where, after constructing the address data, we passed the result along via an HTTP POST request in the createDigitalAddressApp.js file:

/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) {

This code block sends the address data entered by a user to the geoimplement.php file which contains the code that calls the Google Maps API. Go ahead and open this file:

nano /var/www/html/digiaddress/geoimplement.php

You'll see that it first decodes the address that was received through the POST request:

/var/www/html/digiaddress/geoimplement.php
. . .
$data=json_decode(file_get_contents("php://input"));
. . .

It then passes the address field of the input data to a geocode function which returns the geographic information on the address:

/var/www/html/digiaddress/geoimplement.php
. . .
$result = geocode($data->address);
. . .

The result is then echoed back to the caller:

/var/www/html/digiaddress/geoimplement.php
. . .
echo json_encode($result);
. . .

The geocode function encodes the address and passes it on to the Google Maps API, along with your application key:

/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>";
. . .

Before scrolling on, go ahead and add your API key to the line under the // google map geocode api url comment:

/var/www/html/digiaddress/geoimplement.php
. . .
// google map geocode api url
$url = "https://maps.googleapis.com/maps/api/geocode/json?address={$address}&key=ExampleAPIKeyH2vITfv1eIHbfka9ym634Esw7u";
. . .

After sending the call to the Google Maps API, the response is decoded and its value is returned by the function:

/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;
}
. . .

Save this file, and visit your application once again. Input US-NY in the state field and then hit TAB to change the input focus to the next field. 您将看到以下输出:

Notice that the geocoordinates and physical address that you entered in the form appear underneath the map. This makes the application feel much more engaging and interactive.

Note: When it comes to abbreviations for place names, Mapcode uses the ISO 3166 standard. This means that it may not interpret some commonly-used abbreviations as expected. For example, if you'd like to generate a Mapcode for an address in Louisiana and you enter LA , the map will jump to Los Angeles, California (rather than the state of Louisiana).

You can avoid confusion with US postal abbreviations by preceding them with US- . In the context of this Louisiana example, you would enter US-LA .

To learn more about how Mapcode uses this standard, check out the Territories and standard codes reference page .

Despite this improvement to how the application displays locations on the map, the app still isn't fully functional. The last step you need to take before you can generate a mapcode is to edit the db.php file to allow the application to access your database.

Step 9 — Adding Database Credentials and Testing Mapcode Generation

Recall that this application stores every address entered into the form — along with its latitude, longitude, and mapcode — in the database you created in Step 2. This is made possible by the code within the db.php file, which stores your database credentials and allows the application to access the locations table within it.

As a final step to enable the mapcode generation functionality, open the db.php file for editing:

nano /var/www/html/digiaddress/db.php

Near the top of this file, find the line that begins with $pass . This line submits your MySQL login credentials in order to allow the application to access your database. Replace your_password with your root MySQL user's password:

/var/www/html/digiaddress/db.php
. . .
        $username = "root";
        $pass = "your_password";
. . .

That is the last change you need to make in order to generate a mapcode from a physical address. Save and close the file, then go ahead and refresh the application in your browser once again. Enter in an address of your choice and click the Generate button. The output will look similar to this:

At this stage, you have completed your application and you can now generate a short digital address for any physical location in the world. Feel free to experiment with different addresses, and note that the address you enter does not necessarily need to be within the United States.

Your final task is to enable this app's second functionality: retrieving an address from the database using its respective mapcode.

Step 10 — Retrieving a Physical Address

Now that you're able to generate a mapcode from a given physical address, your final step is to retrieve the original physical address, as derived from the mapcode. To accomplish this, we will develop a PHP user interface, shown here:

The code for this UI is available in the findaddress.php file. As the UI defined within this file is fairly similar to the UI we covered earlier in Step 4, we will not look too closely at all the details of how it works. We will, however, go through these three files to explain generally how they function.

In order to enable the address retrieval functionality, you'll need to add your Google API key to the findaddress.php file, so open it up with your preferred editor:

nano /var/www/html/digiaddress/findaddress.php

Near the bottom of the file, find the line that begins with <script async defer src= . It will look like this:

/var/www/html/digiaddress/findaddress.php
<script async defer src="https://maps.googleapis.com/maps/api/js?key=<YOUR KEY>"></script>

Replace <YOUR KEY> with your Google API key as you've done in the previous steps, then save the file. Before closing it, though, let's take a quick look to see how these files work together.

When a user submits the form it triggers a submit event, and an event listener calls the fetchadd function:

/var/www/html/digiaddress/findaddress.php
. . .
<form ng-submit="fetchadd()" class="custom-form">
. . .

The fetchadd function sends the digital address to fetchaddress.php with a POST request:

/var/www/html/digiaddress/js/findAddressApp.js
. . .
$http({
    method : 'POST',
    url : 'fetchaddress.php',
    data : {digiaddress: $scope.digiaddress}
}).then(function(response){
. . .

If the POST is successful, the function returns a JSON response. The following line parses this response:

/var/www/html/digiaddress/js/findAddressApp.js
. . .
var jsonlatlng = JSON.parse(response.data.latlng);
. . .

The next lines set the marker on the map:

/var/www/html/digiaddress/js/findAddressApp.js
. . .
marker = new google.maps.Marker({
    position: new google.maps.LatLng(jsonlatlng.latitude, jsonlatlng.longitude),
        map: locationMap
});
. . .

And the following prints the geocoordinates and the physical address:

/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 );
. . .

Visit this application in your browser by going to the following link:

http://your_server_ip/digiaddress/findaddress.php

Test it out by entering in the mapcode you obtained earlier. The following figure shows a typical output:

With that, your application is finished. You can now create a unique mapcode for any location in the world, and then use that mapcode to retrieve the location's physical address.

结论

In this tutorial you used the Google Maps API to pin a location and gets its longitude, latitude information. This information is used to generate a unique and short digital address using Mapcode API. There are a number of practical use cases for mapcodes, ranging from emergency services to archaeological surveying. The Stichting Mapcode Foundation lists several such use cases.

致谢

Many thanks to Dinesh Karpe and Sayli Patil for developing the entire project code.