序章

住所は通常長く、覚えにくい場合があります。 短いアドレスが望ましいシナリオはいくつかあります。 たとえば、数文字だけで構成される短いアドレスを送信する機能があると、緊急救急車サービスのより迅速な配信が保証されます。 PieterGeelenとHaroldGoddijnは、2001年にマップコードシステムを開発し、世界中のあらゆる物理アドレスの短い形式のアドレスを簡単に作成できるようにしました。

このチュートリアルでは、Google Maps APIを使用して、選択した任意のアドレスの短いデジタルアドレスを生成するWebアプリを開発します。 これを行うには、GitHubからこのアプリのベースコードを複製し、完全に機能するようにするコードを追加します。 このアプリは、特定のマップコードから元の物理アドレスを取得することもできます。

前提条件

このチュートリアルを完了するには、次のものが必要です。

  • Ubuntu18.04サーバーへのアクセス。 このサーバーには、sudo特権とファイアウォールが構成されたroot以外のユーザーが必要です。 これを設定するには、 Ubuntu18.04の初期サーバー設定ガイドに従ってください。

  • マシンにインストールされているLAMPスタック。 このチュートリアルで開発するアプリケーションはAngularJSとPHPを使用し、アプリケーションが生成するデジタルアドレスはMySQLデータベースに保存されるため、これが必要です。 Linux、Apache、MySQL、PHP(LAMP)スタックをUbuntu 18.04 にインストールする方法に関するガイドに従って、これを設定してください。

  • サーバーにGitがインストールされています。 チュートリアルオープンソースへの貢献:Git入門に従って、Gitをインストールおよびセットアップできます。

ステップ1—GoogleAPIキーを取得する

このチュートリアルでは、JavaScriptを使用してGoogleマップへのインターフェースを作成します。 GoogleはAPIキーを割り当てて、開発者がGoogleマップでJavaScript APIを使用できるようにします。これを取得して、ウェブアプリのコードに追加する必要があります。

独自のAPIキーを取得するには、Googleの「GetAPIKey」ページにアクセスしてください。 手順1のGETSTARTED ボタンをクリックすると、次の画像に示すようなポップアップが開きます。

チェックボックスをクリックしてマップを選択し、続行をクリックします。 Googleアカウントにまだログインしていない場合は、ログインするように求められます。 次に、ウィンドウでプロジェクトの名前を指定するように求められます。名前は任意の名前にすることができます。

これに続いて、請求情報の入力を求められます。 Googleは無料トライアルの一部としてAPIキーを提供していますが、APIキーを取得するには、課金を設定して有効にする必要があることに注意してください。

この情報を入力すると、APIキーが画面に表示されます。 後でプロジェクトコードに追加する必要があるため、簡単に取得できる場所にコピーして保存します。

APIキーを取得したら、MySQLデータベースを作成してアプリケーションの基盤を構築し始めることができます。

ステップ2—データベースの作成

このチュートリアルで説明するWebアプリケーションは、ユーザーからのアドレスを受け入れ、指定された場所の緯度と経度とともにそのアドレスのマップコードを生成します。 このデータをMySQLデータベースに保存して、後でそれぞれのデジタルアドレスを入力するだけで取得できるようにします。

MySQLシェルを開き、パスワードで認証することから始めます。

  1. mysql -u root -p

プロンプトで、次のコマンドを使用してdigitaladdressというデータベースを作成します。

  1. CREATE DATABASE IF NOT EXISTS `digitaladdress`;

次に、この新しいデータベースを選択して、その中にテーブルを作成できるようにします。

  1. USE `digitaladdress`;

digitaladdressデータベースを選択したら、その中にlocationsというテーブルを作成して、このデータからアプリケーションが作成する物理アドレス、経度、緯度、およびマップコードを保存します。 次のCREATE TABLEステートメントを実行して、データベース内にlocationsテーブルを作成します。

  1. CREATE TABLE `locations` (
  2. `digitaladdress` varchar(50) DEFAULT NULL,
  3. `state` varchar(30) DEFAULT NULL,
  4. `zip` varchar(30) DEFAULT NULL,
  5. `street` varchar(30) DEFAULT NULL,
  6. `town` varchar(30) DEFAULT NULL,
  7. `house` varchar(30) DEFAULT NULL,
  8. `latitude` varchar(30) DEFAULT NULL,
  9. `longitude` varchar(30) DEFAULT NULL,
  10. KEY `digitaladdress` (`digitaladdress`)
  11. );

このテーブルには、digitaladdressstatezipstreettownhouselatitude、およびlongitude。 最初の列digitaladdressは、KEYコマンドを使用してインデックス付きになります。 MySQLのインデックスは、百科事典やその他の参考書での動作と同じように機能します。 ユーザーまたはアプリケーションがWHEREステートメントを含むクエリを発行するたびに、MySQLは各列のすべてのエントリを行ごとに読み取ります。これは、テーブルにエントリが増えるにつれて、非常にリソースを消費するプロセスになる可能性があります。 。 このように列にインデックスを付けると、列からデータが取得され、アルファベット順に別の場所に格納されます。つまり、MySQLはテーブルのすべての行を調べる必要がありません。 インデックスで探しているデータを見つけて、テーブルの対応する行にジャンプするだけです。

このテーブルを追加したら、MySQLプロンプトを終了します。

  1. exit

データベースとテーブルを設定し、Google Maps APIキーを手元に置いたら、プロジェクト自体を作成する準備が整います。

ステップ3—プロジェクトの作成

はじめに述べたように、このプロジェクトのベースコードをGitHubから複製してから、アプリケーションを機能させるためにいくつかのコードを追加します。 この理由は、各ファイルを作成してすべてのコードを自分で追加するプロセスを説明するのではなく、アプリを実行するプロセスを高速化するためです。 また、アプリがGoogleMapsとMapcodeAPIの両方と通信できるようにするコードの追加と理解に集中できるようになります。

プロジェクト全体のスケルトンコードは、このGitHubプロジェクトページにあります。 次のgitコマンドを使用して、プロジェクトをサーバーに複製します。

  1. git clone https://github.com/do-community/digiaddress.git

これにより、ホームディレクトリにdigiaddressという新しいフォルダが作成されます。 このディレクトリをサーバーのWebルートに移動します。 前提条件にリンクされているLAMPスタックチュートリアルに従った場合、これは/var/www/htmlディレクトリになります。

  1. sudo mv digiaddress/ /var/www/html/

このプロジェクトには、このチュートリアルの後半でコードを追加するPHPファイルとJSファイルがいくつか含まれています。 ディレクトリ構造を表示するには、最初にaptを使用してtreeパッケージをインストールします。

  1. sudo apt install tree

次に、digiaddressディレクトリを引数として指定してtreeコマンドを実行します。

  1. tree /var/www/html/digiaddress/
Output
digiaddress/ ├── README.md ├── db.php ├── fetchaddress.php ├── findaddress.php ├── generateDigitalAddress.php ├── geoimplement.php ├── index.php └── js ├── createDigitialAddressApp.js └── findAddressApp.js

この出力から、プロジェクトが6つのPHPファイルと2つのJavaScriptファイルで構成されていることがわかります。 これらのファイルを組み合わせることで、アプリケーションの2つの主要な機能が作成されます。物理アドレスからマップコードを作成することと、マップコードをデコードして元の物理アドレスを取得することです。 次のファイルは、最初の機能を有効にします。

  • index.php
  • geoimplement.php
  • generateDigitialAddress.php
  • db.php
  • createDigitialAddressApp.js

index.phpファイルには、アプリケーションのユーザーインターフェイス(UI)のコードが含まれています。このコードは、ユーザーが物理アドレスを入力できるフォームで構成されています。 index.phpファイルは、ユーザーがフォームを送信するたびにgeoimplement.phpファイルを呼び出します。 geoimplement.phpはGoogleMapsAPIを呼び出し、アドレスを渡します。 次に、Googleサーバーは、緯度や経度など、指定されたアドレスの情報を含むJSONで応答します。 次に、この情報はgenerateDigitalAddress.phpファイルに渡されます。このファイルは、Mapcode APIを呼び出して、緯度と経度で指定された特定の場所のマップコードを取得します。 結果のマップコードは、緯度、経度、および物理アドレスとともに、手順2で作成したデータベースに保存されます。 db.phpは、この操作のヘルパーとして機能します。 createDigitalAddressApp.jsファイルは、Googleマップインターフェースでのマーカーや境界長方形の設定など、アプリに表示されるUX要素を制御する多くの操作を実行します。

残りの3つのファイルは、アプリケーションの2番目の機能、つまり、指定されたマップコードから物理アドレスを取得できるようにします。

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

findaddress.phpファイルは、index.phpで定義されているものとは異なるアプリケーションUIを定義します。 アプリケーションは、以前に生成されたマップコードを入力として受け入れ、データベースに保存されている対応する物理アドレスを表示します。 ユーザーがこのフォームを送信するたびに、findaddress.phpfetchaddress.phpに呼び出しを送信し、データベースからそれぞれのマップコードを取得します。 findAddressApp.jsファイルには、Googleマップインターフェースでマーカーと境界長方形を設定するためのヘルパーコードが含まれています。

ブラウザでhttp://your_server_ip/digiaddressにアクセスし、サーバーのIPアドレスを反映するようにyour_server_ipを変更して、インストールをテストします。

注:サーバーのIPアドレスがわからない場合は、次のcurlコマンドを実行できます。 このコマンドは、icanhazip.comのページコンテンツを出力します。これは、アクセスしているマシンのIPアドレスを示すWebサイトです。

  1. curl http://icanhazip.com

そこに到達すると、ブラウザウィンドウの上部に次の見出しが表示されます。

Generate Digital Address

これにより、プロジェクトファイルが正しくダウンロードされたことを確認できます。 それでは、アプリの主な機能であるマップコードの生成に進みましょう。

ステップ4—アプリケーションのUIを開発する

アプリケーションインターフェイスの定型コードは前の手順でダウンロードしたファイルに含まれていますが、アプリケーションを機能させてユーザーにとって魅力的なものにするために、これらのファイルの一部にいくつかの変更と追加を行う必要があります。 アプリケーションのUIを開発するためのコードの更新から始めます。

お好みのエディタを使用してindex.phpファイルを開きます。 ここでは、nanoを使用します。

  1. 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で取得したGoogleAPIキーに置き換えます。 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 -->
. . .

このコメントの下に数十行のコードを追加します。これにより、ユーザーが、アプリケーションがマップコードを生成するために使用する物理的な場所のアドレスを入力できるフォームが作成されます。 このコメントの下に、フォームの上部に EnterAddressというタイトルを作成する次の強調表示されたコードを追加します。

/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コードを追加します。 これにより、ユーザーが情報を入力する5つのテキストフィールド(および適切なラベル)を含むフォームが作成されます。

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

フォームコードの下に、次の行を追加します。 これらは、フォームから送信された任意の住所から取得した緯度と経度の情報を渡す2つの非表示のコントロールを作成します。

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

最後に、次のコードを追加してこのセクションを閉じます。 これにより、生成ボタンが作成され、ユーザーは次のフォームを送信できるようになります。

/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+OENTERの順に押してファイルを保存し、ブラウザでアプリケーションに再度アクセスします。

http://your_server_ip/digiaddress

新しく追加されたフォームフィールドとGenerateボタンが表示され、アプリケーションは次のようになります。

この時点で、フォームにアドレス情報を入力して生成ボタンをクリックしようとしても、何も起こりません。 マップコード生成機能は後で追加しますが、最初に、ユーザーが操作できるマップを追加して、このページをより視覚的に魅力的なものにすることに焦点を当てましょう。

ステップ5—Googleマップコントロールを追加する

マップがGoogleMapsJavaScript APIを介してWebサイトに表示される場合、マップには、訪問者が表示されているマップを操作できるようにするユーザーインターフェイス機能が含まれています。 これらの機能は、コントロールとして知られています。 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>
. . .

ファイルを保存してから、ブラウザでアプリケーションに再度アクセスします。 次のように表示されます。

ご覧のとおり、アプリケーションにマップが正常に追加されました。 地図をドラッグしてさまざまな場所に焦点を合わせたり、ズームインとズームアウトしたり、地図、衛星、ストリートビューを切り替えたりすることができます。 追加したコードを振り返ると、フォームに入力された地理座標と物理アドレスを表示する2つのラベルコントロールも追加されていることに注意してください。

/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—イベントリスナーを追加する

アプリケーションにインタラクティブな要素を追加すると、ユーザーの関心を維持するのに役立ちます。 イベントリスナーを使用して、このアプリケーションにいくつかのインタラクティブな動作を実装します。

イベントは、Webページで発生するアクションです。 イベントは、ユーザーまたはブラウザー自体によって実行されるものにすることができます。 一般的なイベントの例は次のとおりです。

  • HTMLボタンをクリックする
  • 入力フィールドの内容を変更する
  • あるページ要素から別のページ要素にフォーカスを変更する

イベントリスナーは、特定のイベントが発生したときに特定のアクションを実行するようにプログラムに指示するディレクティブです。 AngularJSでは、イベントリスナーは一般的に次の形式に従うディレクティブで定義されます。

ng-event_type=expression

このステップでは、ユーザーがフォームを送信するたびに、ユーザーがマップコードに入力した情報を処理するのに役立つイベントリスナーを追加します。 また、アプリケーションをよりインタラクティブにするイベントリスナーをさらにいくつか追加します。 具体的には、これらのリスナーを使用して、アプリケーションマップに表示される場所を変更し、マーカーを配置し、ユーザーがフォームに情報を入力するときに場所の周囲に長方形を描画します。 これらのイベントリスナーをindex.phpに追加するので、ファイルを閉じた場合は、そのファイルをもう一度開きます。

  1. 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ファイルで定義され、ユーザーから送信された情報を適切なファイルに送信し、マップコードに処理するヘルパー関数として機能します。 ステップ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関数と同様に、geocodeAddresscreateDigitalAddressApp.jsファイルで宣言されていますが、それを定義するコードはまだそのファイルにありません。 フォームに入力された情報を反映するためにこれらのblurイベントが発生した後、マーカーを配置してアプリケーションマップ上に長方形を描画するように、この関数を完了します。 また、アドレス情報を取得してマップコードに処理するコードを追加します。

index.phpファイルを保存して閉じ(CTRL+XYENTERの順に押す)、createDigitalAddressApp.jsファイルを開きます。

  1. 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でない場合、HTTPPOSTメソッドを使用してフォームに入力された情報を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呼び出しが正常に返された場合、結果を処理できるようになります。 次の行を追加します。これにより、createDigitalAddressApp.jsファイルの上部に定義されているremoveRectangle関数を呼び出して、以前にマップ上に描画された可能性のある境界長方形が削除されます。

/var/www/html/digiaddress/js/createDigitalAddressApp.js
                            . . .
                            removeRectangle();
                            . . .

removeRectangle();行の下に、次の4行を追加します。これにより、マップコントロール上の新しい場所を指すマーカーが作成されます。

/var/www/html/digiaddress/js/createDigitalAddressApp.js
                            . . .
                            new google.maps.Marker({
                                map: locationMap,
                                position: results.data.geometry.location
                            });
                            . . .

次に、次のコードを追加します。このコードは、結果から緯度と経度の情報を取得し、手順5でindex.phpファイルに作成した2つの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 () {
. . .

次に、processFormgenerateDigitalAddress.phpファイルにHTTPPOSTを作成します。

/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 は、無料のWebサービスとして物理アドレスからマップコードを生成するAPIを提供します。 このMapcodeWebサービスの呼び出しがどのように機能するかを理解するには、createDigitalAddressApp.jsを閉じて、generateDigitialAddress.phpファイルを開きます。

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

ファイルの上部に、次のように表示されます。

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

include("db.php");という行は、PHPに、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
. . .

このコメントの下に次のコード行を追加します。 このコードはMapcodeAPIを呼び出し、latlongをパラメーターとして送信します。

/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を再度開きます。

  1. 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に新しいコード行を追加しましたが、ブラウザーでアプリにアクセスして操作しても、機能の変更は表示されません。 これは、GoogleAPIキーをgeoimplement.phpファイルにまだ追加していないためです。これにより、GoogleMapsAPIが実際に呼び出されます。

ステップ8— GoogleMapsAPIへの呼び出しを有効にする

このアプリケーションは、Google Maps APIに依存して、物理アドレスを適切な緯度と経度の座標に変換します。 次に、これらはMapcode APIに渡され、MapcodeAPIはそれらを使用してマップコードを生成します。 その結果、アプリケーションがGoogle Maps APIと通信して場所の緯度と経度を生成できない場合、マップコードを生成しようとしても失敗します。

ステップ6を思い出してください。ここでは、addressデータを作成した後、createDigitalAddressApp.jsファイルでHTTPPOSTリクエストを介して結果を渡しました。

/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ファイルに送信します。このファイルには、GoogleMapsAPIを呼び出すコードが含まれています。 先に進み、このファイルを開きます。

  1. 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をエンコードし、アプリケーションキーとともにGoogleMapsAPIに渡します。

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

スクロールする前に、// google map geocode api urlコメントの下の行にAPIキーを追加してください。

/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はISO3166標準を使用します。 これは、一般的に使用される一部の略語を期待どおりに解釈できない可能性があることを意味します。 たとえば、ルイジアナ州の住所のマップコードを生成する場合、LAと入力すると、マップは(ルイジアナ州ではなく)カリフォルニア州ロサンゼルスにジャンプします。

US-を前に付けることで、米国の郵便略語との混同を避けることができます。 このルイジアナの例のコンテキストでは、US-LAと入力します。

Mapcodeがこの標準をどのように使用するかについて詳しくは、地域と標準コードのリファレンスページをご覧ください。

アプリケーションが地図上に場所を表示する方法がこのように改善されたにもかかわらず、アプリはまだ完全には機能していません。 マップコードを生成する前に実行する必要がある最後の手順は、db.phpファイルを編集して、アプリケーションがデータベースにアクセスできるようにすることです。

ステップ9—データベースクレデンシャルの追加とマップコード生成のテスト

このアプリケーションは、フォームに入力されたすべてのアドレスを、緯度、経度、およびマップコードとともに、手順2で作成したデータベースに保存することを思い出してください。 これは、db.phpファイル内のコードによって可能になります。このコードは、データベースクレデンシャルを格納し、アプリケーションがその中のlocationsテーブルにアクセスできるようにします。

マップコード生成機能を有効にする最後のステップとして、db.phpファイルを開いて編集します。

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

このファイルの先頭近くで、$passで始まる行を見つけます。 この行は、アプリケーションがデータベースにアクセスできるようにするために、MySQLログイン資格情報を送信します。 your_passwordrootMySQLユーザーのパスワードに置き換えます。

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

これは、物理アドレスからマップコードを生成するために行う必要がある最後の変更です。 ファイルを保存して閉じてから、ブラウザでアプリケーションをもう一度更新してください。 ご希望のアドレスを入力し、生成ボタンをクリックしてください。 出力は次のようになります。

この段階で申請が完了し、世界中の物理的な場所の短いデジタルアドレスを生成できるようになりました。 さまざまな住所を自由に試してみてください。入力する住所は、必ずしも米国内である必要はありません。

最後のタスクは、このアプリの2番目の機能を有効にすることです。それぞれのマップコードを使用してデータベースからアドレスを取得します。

ステップ10—物理アドレスを取得する

これで、特定の物理アドレスからマップコードを生成できるようになりました。最後のステップは、マップコードから派生した元の物理アドレスを取得することです。 これを実現するために、次のようなPHPユーザーインターフェイスを開発します。

このUIのコードは、findaddress.phpファイルで入手できます。 このファイル内で定義されたUIは、前の手順4で説明したUIとかなり似ているため、その動作の詳細についてはあまり詳しく説明しません。 ただし、これら3つのファイルを調べて、それらがどのように機能するかを一般的に説明します。

アドレス取得機能を有効にするには、GoogleAPIキーをfindaddress.phpファイルに追加する必要があるため、お好みのエディターで開きます。

  1. 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>をGoogleAPIキーに置き換えてから、ファイルを保存します。 ただし、閉じる前に、これらのファイルがどのように連携するかを簡単に見てみましょう。

ユーザーがフォームを送信すると、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を使用して場所を固定し、その経度、緯度の情報を取得しました。 この情報は、MapcodeAPIを使用して一意の短いデジタルアドレスを生成するために使用されます。 マップコードには、緊急サービスから考古学的調査に至るまで、多くの実用的なユースケースがあります。 [Stichting Mapcode Foundation]( http://www.mapcode.com/aboutus.html )には、そのようなユースケースがいくつかリストされています。

謝辞

プロジェクトコード全体を開発してくれたDineshKarpeSayliPatilに感謝します。