Tutorials / Learn How to Geocode and Display Japanese Addresses on a Map Using HERE Geocoding and Search API
Last Updated: November 25, 2020

Introduction

Searching for an address in Japan is often complicated as there are often no street names. Also, the Japanese address is mixed because there are three different types of native character sets (Kanji, Hiragana, and Katakana). The HERE Geocoding and Search API make this complex system easy for your applications to find the right location.

In this tutorial, you will learn how to develop a sample geocoding application using the HERE Geocoding and Search API, conduct an address lookup using HERE’s Autosuggestion feature and then plot the location on a JavaScript map.

For more information about Geocoding in Japan and the Search API, check out the documentation.

What You’ll Need

  • An account with here-tech.skawa.fun.

  • Access to the Japanese data layer. Please see the HERE JavaScript API Documentation to learn how to enable access for your developer account.

What are You Going to Build

After going through this tutorial, you will have a working geocoding application for Japan. By using this you can search for a location in Japan by providing an address as an input.

Road Map

  • Create a HERE Map
  • Implement Geocoding for Japan

Create a HERE Map

The basis of this project is a JavaScript map. Creating a Japanese focused map is very similar to creating a non-Japanese map. You will need to follow the steps below to get started.

Generate Map

To create a basic HERE JavaScript map, follow the steps below:

  • Open your favorite editor.
  • Create an index.html file.
  • Copy the following boilerplate code into the index.html.
    • If you do not have an API Key, you can follow this video to learn how to create your API key.
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Geocoding Application for Japan</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body>   
    </body>
</html>

Load the HERE JavaScript Libraries

You need to include the below libraries in the

section.

<link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
Now, you will need to add a map container inside the

section. You will render the map with 100% of the screen width and height.

<div style="width: 100%; height: 100%;" id="mapContainer"></div>

Initialize Communication with Back-End Services

Initialize the Platform object normally by passing the API key. Replace the YOUR_API_KEY with your HERE API key.

var platform = new H.service.Platform({
  'apikey': '{YOUR_API_KEY}'
});

Render the HERE Map

You will need a dedicated map style for the Japanese market in order to render the map. The following map style is optimized for the display of the Japan data.

https://js.api.here.com/v3/3.1/styles/omv/oslo/japan/normal.day.yaml

To get the Japan specific data, you need to add the below code:

var omvService = platform.getOMVService({ path: "v2/vectortiles/core/mc" });

Now, you will setup the HERE map by adding the following code.

// configure an OMV service to use the `core` endpoint
var omvService = platform.getOMVService({ path: "v2/vectortiles/core/mc" });
var baseUrl = "https://js.api.here.com/v3/3.1/styles/omv/oslo/japan/";
// create a Japan specific style
var style = new H.map.Style(`${baseUrl}normal.day.yaml`, baseUrl);
// instantiate provider and layer for the base map
var omvProvider = new H.service.omv.Provider(omvService, style);
var omvlayer = new H.map.layer.TileLayer(omvProvider, { max: 22 ,dark:true});
// instantiate (and display) a map:
var map = new H.Map(document.getElementById("mapContainer"), omvlayer, {
zoom: 17,
center: { lat: 35.68026, lng: 139.76744 },
});

To make the map interactive, add the below code:

// add a resize listener to make sure that the map occupies the whole container
window.addEventListener("resize", () => map.getViewPort().resize());

// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));

Final Code to Render the HERE Map

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- libraries -->
<link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
<!-- end -->
</head>
<body>
<!-- Display the map -->
<div class="main">
  <div style="width: 100%; height: 100%; overflow: hidden; position: fixed; top: 0; z-index: 2;" id="mapContainer"></div>
</div> 
<!-- end -->
</body>
<script>
    // to connect to HERE Services using API Key
    var platform = new H.service.Platform({
      apikey: "HERE-API-KEY",
    });
  
    // configure an OMV service to use the `core` endpoint
    var omvService = platform.getOMVService({ path: "v2/vectortiles/core/mc" }); // to get japan data
    var baseUrl = "https://js.api.here.com/v3/3.1/styles/omv/oslo/japan/";
    
    // create a Japan specific style
    var style = new H.map.Style(`${baseUrl}normal.day.yaml`, baseUrl);

    // instantiate provider and layer for the basemap
    var omvProvider = new H.service.omv.Provider(omvService, style);
    var omvlayer = new H.map.layer.TileLayer(omvProvider, { max: 22 ,dark:true});

    // instantiate (and display) a map:
    var map = new H.Map(document.getElementById("mapContainer"), omvlayer, {
      zoom: 17,
      center: { lat: 35.68026, lng: 139.76744 },
    });
    
    // add a resize listener to make sure that the map occupies the whole container
    window.addEventListener("resize", () => map.getViewPort().resize());

    // MapEvents enables the event system
    // Behavior implements default interactions for pan/zoom (also on mobile touch environments)
    var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
</script>
</html>

Open the index.html page with a browser to see the map.

map

To learn more about the Japan map. Check out the tutorial.

Implement Geocoding for Japan

Autosuggest API

To search for an address or place, you need to use the Autosuggest API to render the results. The Autosuggest API will fetch the results as you type in the input field. It will provide an autosuggestion when you start typing. Below is the endpoint:

https://autosuggest.search.hereapi.com/v1/autosuggest?at=35.6990575,139.7623009&q=${q}&limit=3&apikey=your_api_key

In the above endpoint, you will use three input parameters to fetch the results. These are the mandatory parameters to fetch the results.

  • at – specify the coordinates(lat, long) of the address.
  • q – specify any name of the street or place.
  • apikey – use your API key to authenticate with backend services.

And the response is the following:

{
    "items": [
        {
          "title": "Q",
          "id": "here:xs1:place:fac_56914387",
          "resultType": "place",
          "address": {
              "label": "東京都新宿区Q"
          },
          "position": {
              "lat": 35.69179,
              "lng": 139.70143
          },
          "access": [
              {
                  "lat": 35.69179,
                  "lng": 139.70143
              }
          ],
          "distance": 5556,
          "highlights": {
              "title": [
                  {
                      "start": 0,
                      "end": 1
                  }
              ],
              "address": {
                  "label": [
                      {
                          "start": 6,
                          "end": 7
                      }
                  ]
              }
          }
        },
        {
            "title": "QTSコントラクト",
            "id": "here:xs1:place:gp_70088175",
            "resultType": "place",
            "address": {
                "label": "東京都新宿区西五軒町8-17QTSコントラクト"
            },
            "position": {
                "lat": 35.707,
                "lng": 139.73742
            },
            "access": [
                {
                    "lat": 35.707,
                    "lng": 139.73742
                }
            ],
            "distance": 2414,
            "categories": [
                {
                    "id": "700-7250-0136",
                    "name": "事業所",
                    "primary": true
                }
            ],
            "highlights": {
                "title": [],
                "address": {
                    "label": []
                }
            }
        },
        {
            "title": "キューサイ東京営業所",
            "id": "here:xs1:place:gp_69967985",
            "resultType": "place",
            "address": {
                "label": "東京都千代田区岩本町3丁目1-9キューサイ東京営業所"
            },
            "position": {
                "lat": 35.69464,
                "lng": 139.77595
            },
            "access": [
                {
                    "lat": 35.69464,
                    "lng": 139.77595
                }
            ],
            "distance": 1327,
            "categories": [
                {
                    "id": "600-6300-0064",
                    "name": "高級食品&飲み物専門店",
                    "primary": true
                }
            ],
            "highlights": {
                "title": [],
                "address": {
                    "label": []
                }
            }
        }
    ],
    "queryTerms": []
}

Add a Search Box to the Map

Once the HTML map is added, you need to add the code for the search box to the map. Copy the following HTML snippet inside the mapContainer div tag in the index.html after the script tag.

<div class="wrapper">
  <!-- Sidebar  -->
  <nav id="sidebar">
      <div class="sidebar-header">
          <h3>Geocode Autosuggest demo for Japan</h3>
      </div>
      <div class="px-3">
          <input type="search" class="form-control" name="search" id="search-box" onkeyup="GeoCodeAutoSuggest(this.value)" autocomplete="off">
      </div>
      <div class="autocomplete-dropdown">
          <ul id="autosuggest-items"></ul>
      </div>
  </nav>
  <!-- Page Content  -->
  <div id="content" style="position: relative;">
      <nav class="navbar navbar-expand-lg navbar-light bg-light mb-0" style="z-index: 3;">
          <div class="container-fluid">
              <button type="button" id="sidebarCollapse" class="btn btn-info">
                  <i class="fas fa-align-left"></i>
                  <span></span>
              </button>
          </div>
      </nav>
      <div style="width: 100%;height: 100%;overflow: hidden;position: fixed;top: 0;z-index: 2;" id="mapContainer"></div>
  </div>
</div>
We are using Bootstrap to design our application. Copy the below code in the

section.

<!-- Bootstrap CSS CDN -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" crossorigin="anonymous">
<!-- jQuery CDN - Slim version (=without AJAX) -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" crossorigin="anonymous"></script>
<!-- Popper.JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js" crossorigin="anonymous"></script>
<!-- Bootstrap JS -->
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" crossorigin="anonymous"></script>
<!-- Font Awesome JS -->
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/solid.js" crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/fontawesome.js" crossorigin="anonymous"></script>

Once you add the above code, you will see the output similar to the below image.

search

When the user starts typing in the search box, you will use the Autosuggest API to return address suggestions and you will get the results. You can select the place from the list to show the marker on the map. Click on the marker to see the selected address.

Add the below code in the index.html file anywhere in the <script> tag:

 const GeoCodeAutoSuggest = (q) => {
    if (!q || q == null) {
      alert("Invalid search key word..");
      return;
    }
    let url = `https://autosuggest.search.hereapi.com/v1/autosuggest?at=35.6990575,139.7623009&q=${q}&limit=3&apikey=${HERE-API-KEY}`;
    fetch(url)
      .then((res) => res.json())
      .then((data) => showAutoSuggestList(data));
    };

    /* Create a Marker on the map */
    const AddDefaultMakerToMap = (cordinates = null, textContent) => {
            if (cordinates == null) {
                return;
            }
            isMapAnimated = true
            var Marker = new H.map.Marker({ lat: cordinates.lat, lng: cordinates.lng });
            Marker.setData(textContent);
            var group = new H.map.Group();

            map.addObject(group);

            // add 'tap' event listener, that opens info bubble, to the group
            Marker.addEventListener('tap', function (evt) {
                // event target is the marker itself, group is a parent event target
                // for all objects that it contains
                var bubble = new H.ui.InfoBubble(evt.target.getGeometry(), {
                    // read custom data
                    content: evt.target.getData()
                });
                // show info bubble
                ui.addBubble(bubble);
            }, false);
            map.addObject(Marker);
            map.setCenter({ lat: cordinates.lat, lng: cordinates.lng }, isMapAnimated);

        };
    /* To render the results when users search for a place */
    const showAutoSuggestList = (data) => {
      map.removeObjects(map.getObjects()) // to remove the marker
      document.getElementById("autosuggest-items").innerHTML = "";
      data.items.map((item) => {
        let li = document.createElement("li");
        li.textContent = item.title;
        li.dataPosition = item.position;
        li.addEventListener("click", (e) => {
          document.getElementById("autosuggest-items").innerHTML = "";
          document.getElementById("search-box").value = e.target.innerHTML;
          AddDefaultMakerToMap(e.target.dataPosition);
        });
        document.getElementById("autosuggest-items").appendChild(li);
      });
    };

You are done with adding the JavaScript code to search for an address or place.

Style the HERE Map

To style the map, you need to add some CSS.

@import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700";
body {
    font-family: 'Poppins', sans-serif;
    background: #fafafa;
}

p {
    font-family: 'Poppins', sans-serif;
    font-size: 1.1em;
    font-weight: 300;
    line-height: 1.7em;
    color: #999;
}

.wrapper {
    display: flex;
    width: 100%;
    align-items: stretch;
}

#sidebar {
    min-width: 300px;
    max-width: 400px;
    background: #000;
    color: #fff;
    transition: all 0.3s;
}

#sidebar.active {
    margin-left: -400px;
}

#sidebar .sidebar-header {
    padding: 20px;
    background: #000;
}

#sidebar ul.components {
    padding: 20px 0;
    border-bottom: 1px solid #47748b;
}

#content {
    width: 100%; 
    min-height: 100vh;
    transition: all 0.3s;
}

@media (max-width: 768px) {
  #sidebar {
      margin-left: -400px;
  }
  #sidebar.active {
      margin-left: 0;
  }
  #sidebarCollapse span {
      display: none;
  }
}

#sidebar ul {
    background: #fff;
    margin: 0 1rem;
    border-radius: .25rem;
    list-style:none;
}

#sidebar ul li{
   color:#000;
   padding: 5px 10px;
}

#autosuggest-items li:focus,
#autosuggest-items li:hover {
  background-color: #148496;
  cursor: pointer;
}
ul {
    list-style: none;
    background-color: white;
    padding: 0px;
    margin-left: 29px;
    width: 368px;
}

Final Code

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Geocoding Application for Japan</title>
    <!-- Bootstrap CSS CDN -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" crossorigin="anonymous">
         <!-- jQuery CDN - Slim version (=without AJAX) -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" crossorigin="anonymous"></script>
    <!-- Popper.JS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js" crossorigin="anonymous"></script>
    <!-- Bootstrap JS -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" crossorigin="anonymous"></script>
    <!-- Our Custom CSS -->
    <link rel="stylesheet" type="text/css" href="https://js.api.here.com/v3/3.1/mapsjs-ui.css" />
    <script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
    <script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
    <script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
    <script type="text/javascript" src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>
    <!-- Font Awesome JS -->
    <script defer src="https://use.fontawesome.com/releases/v5.0.13/js/solid.js" crossorigin="anonymous"></script>
    <script defer src="https://use.fontawesome.com/releases/v5.0.13/js/fontawesome.js" crossorigin="anonymous"></script>
    <style>
      @import "https://fonts.googleapis.com/css?family=Poppins:300,400,500,600,700";
      body {
          font-family: 'Poppins', sans-serif;
          background: #fafafa;
      }

      p {
          font-family: 'Poppins', sans-serif;
          font-size: 1.1em;
          font-weight: 300;
          line-height: 1.7em;
          color: #999;
      }

      .wrapper {
          display: flex;
          width: 100%;
          align-items: stretch;
      }

      #sidebar {
          min-width: 300px;
          max-width: 400px;
          background: #000;
          color: #fff;
          transition: all 0.3s;
      }

      #sidebar.active {
          margin-left: -400px;
      }

      #sidebar .sidebar-header {
          padding: 20px;
          background: #000;
      }

      #sidebar ul.components {
          padding: 20px 0;
          border-bottom: 1px solid #47748b;
      }

      #content {
          width: 100%; 
          min-height: 100vh;
          transition: all 0.3s;
      }

      @media (max-width: 768px) {
        #sidebar {
            margin-left: -400px;
        }
        #sidebar.active {
            margin-left: 0;
        }
        #sidebarCollapse span {
            display: none;
        }
      }

      #sidebar ul {
          background: #fff;
          margin: 0 1rem;
          border-radius: .25rem;
          list-style:none;
      }

      #sidebar ul li{
        color:#000;
        padding: 5px 10px;
      }

      #autosuggest-items li:focus,
      #autosuggest-items li:hover {
        background-color: #148496;
        cursor: pointer;
      }
      ul {
          list-style: none;
          background-color: white;
          padding: 0px;
          margin-left: 29px;
          width: 368px;
      }
    </style>
</head>

<body onclick="clearSearchResults()">
    <div class="wrapper">
        <!-- Sidebar  -->
        <nav id="sidebar">
            <div class="sidebar-header">
                <h3>Geocode Autosuggest demo for Japan</h3>
            </div>
            <div class="px-3">
                <input type="search" class="form-control" name="search" id="search-box" onkeyup="GeoCodeAutoSuggest(this.value)" autocomplete="off">
            </div>
            <div class="autocomplete-dropdown">
                <ul id="autosuggest-items"></ul>
            </div>
        </nav>

        <!-- Page Content  -->
        <div id="content" style="position: relative;">

            <nav class="navbar navbar-expand-lg navbar-light bg-light mb-0" style="z-index: 3;">
                <div class="container-fluid">

                    <button type="button" id="sidebarCollapse" class="btn btn-info">
                        <i class="fas fa-align-left"></i>
                        <span></span>
                    </button>
                </div>
            </nav>

            <div style="width: 100%;height: 100%;overflow: hidden;position: fixed;top: 0;z-index: 2;" id="mapContainer"></div>

        </div>
    </div>

    <script type="text/javascript">
        $(document).ready(function () {
            $('#sidebarCollapse').on('click', function () {
                $('#sidebar').toggleClass('active');
            });
        });
    </script>
    <script>
        var platform = new H.service.Platform({
            apikey: "cF1MCUW-j-ThP4xHja2a7Y_x_Bq6tg6Nz_2CFSR4IwI",
        });
        var defaultLayers = platform.createDefaultLayers();
        // configure an OMV service to use the `core` endpoint
        var omvService = platform.getOMVService({ path: "v2/vectortiles/core/mc" });
        var baseUrl = "https://js.api.here.com/v3/3.1/styles/omv/oslo/japan/";

        // create a Japan specific style
        var style = new H.map.Style(`${baseUrl}normal.day.yaml`, baseUrl);

        // instantiate provider and layer for the basemap
        var omvProvider = new H.service.omv.Provider(omvService, style);
        var omvlayer = new H.map.layer.TileLayer(omvProvider, { max: 22, dark: true });

        // instantiate (and display) a map:
        var map = new H.Map(document.getElementById("mapContainer"), omvlayer, {
            zoom: 17,
            center: { lat: 35.68026, lng: 139.76744 },
        });

        // add a resize listener to make sure that the map occupies the whole container
        window.addEventListener("resize", () => map.getViewPort().resize());

        // MapEvents enables the event system
        // Behavior implements default interactions for pan/zoom (also on mobile touch environments)
        var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
        var ui = H.ui.UI.createDefault(map, defaultLayers);
        //AddDefaultMakerToMap();
        const GeoCodeAutoSuggest = (q) => {
            if (!q || q == null) {
                return;
            }
            let url = `https://autosuggest.search.hereapi.com/v1/autosuggest?at=35.6990575,139.7623009&q=${q}&limit=3&apikey=your_api_key&lang=ja-JP`;
            fetch(url)
                .then((res) => res.json())
                .then((data) => showAutoSuggestList(data));
        };

        const AddDefaultMakerToMap = (cordinates = null, textContent) => {
            if (cordinates == null) {
                return;
            }
            isMapAnimated = true
            var Marker = new H.map.Marker({ lat: cordinates.lat, lng: cordinates.lng });
            Marker.setData(textContent);
            var group = new H.map.Group();

            map.addObject(group);

            // add 'tap' event listener, that opens info bubble, to the group
            Marker.addEventListener('tap', function (evt) {
                // event target is the marker itself, group is a parent event target
                // for all objects that it contains
                var bubble = new H.ui.InfoBubble(evt.target.getGeometry(), {
                    // read custom data
                    content: evt.target.getData()
                });
                // show info bubble
                ui.addBubble(bubble);
            }, false);
            map.addObject(Marker);
            map.setCenter({ lat: cordinates.lat, lng: cordinates.lng }, isMapAnimated);

        };

        const showAutoSuggestList = (data) => {
            map.removeObjects(map.getObjects())
            document.getElementById("autosuggest-items").innerHTML = "";
            data.items.map((item) => {
                let li = document.createElement("li");
                li.textContent = item.title;
                li.dataPosition = item.position;
                li.addEventListener("click", (e) => {
                    document.getElementById("autosuggest-items").innerHTML = "";
                    document.getElementById("search-box").value = e.target.innerHTML;
                    AddDefaultMakerToMap(e.target.dataPosition, e.target.textContent);
                });
                document.getElementById("autosuggest-items").appendChild(li);
            });
        };

        const clearSearchResults = () => {
            document.getElementById("autosuggest-items").innerHTML = "";
        }
    </script>
</body>
</html>
final-output

Conclusion

After going through this tutorial:

  • You should have learned how to use Geocoding and Search API in an application to search for an address.

Next Steps

Are you a Google Maps User? Then, the following tutorials will help you to transition to HERE Maps: