Hands On

Locate Christmas markets with JavaScript, AJAX, external data source and HERE Isoline Routing

By Shruti Kuber | 20 December 2018

'Tis the season! Time to unwind with mulled wine and munch on Christmas cookies with the best company at one of Berlin's many Christmas markets. The German capital has a database of all its pop-up seasonal markets which we wanted to play around with. We will now see how to fetch this data using AJAX, display the markets on the map using our Geocoder and find the one that can be reached the fastest, practically, using Isoline routing. To use any of the HERE JavaScript APIs you need to get your App_ID and App_code by signing up for a Freemium account. To display a map and set a marker on a location, follow our Senior Evangelist Michael Palermo's tutorial.

Screen Shot 2018-12-15 at 2.56.58 AM

Once you have a basic map and a marker, we will use XMLHttpRequest to fetch the json file from the external data source.

	var xmlhttp = new XMLHttpRequest();
	xmlhttp.open("GET", "https://www.berlin.de/sen/web/service/maerkte-feste/weihnachtsmaerkte/index.php/index/all.json?q=", true);

We need to now parse this data as a json object and extract the address of the markets. After scanning the dataset, I found that the required fields are strasse and plz_ort. These data fields are the search text for our geocoder.

function addXmasMkts(){
      var geocodingParams = {
        searchText: ' '
      };
      var xmlhttp = new XMLHttpRequest();
      xmlhttp.open("GET", "https://www.berlin.de/sen/web/service/maerkte-feste/weihnachtsmaerkte/index.php/index/all.json?q=", true);
      xmlhttp.onreadystatechange = function() 
      {
        if (this.readyState == 4 && this.status == 200) 
        {
          var myArr = JSON.parse(this.responseText);
          var XmasDataString = '';

          for(i = 0; i < myArr.results.count; i ++)
          {
            XmasDataString = myArr.index[i].strasse +','+ myArr.index[i].plz_ort
            geocodingParams = {
              searchText: XmasDataString
            };
            M.Geo.geocode(geocodingParams, onResult, function(e) {
              alert(e);
            });
          }
        }
      };
      xmlhttp.send();
    }
    
    addXmasMkts();

Screen Shot 2018-12-15 at 2.57.25 AM

The Geocoder API takes the address string as a parameter and gives the position of the searched location in terms of Latitude and Longitude. This position is marked by placing markers on the map


//  A callback function to process the geocoding response and place markers at the obtained position:
    var onResult = function(result) {
    var locations = result.Response.View[0].Result,
      position,
      marker;
    position = {
      lat: locations[0].Location.DisplayPosition.Latitude,
      lng: locations[0].Location.DisplayPosition.Longitude
    };
    marker = new H.map.Marker(position,{icon: iconXmas}) ;
    M.Map.addObject(marker);

  };

Once you have your position and the markets' positions marked, we check the markets nearest to us by drawing a circle of radius 5Km around our position. You will thus see all the markets in a 5km radius of your position. The radius here is in meters.
Screen Shot 2018-12-15 at 2.57.57 AM

var customStyle = {
      strokeColor: 'dark green',
      fillColor: 'rgba(0, 255, 100, 0.2)',
      lineWidth: 1,
    };

    function drawCircle(){
    var circle = new H.map.Circle({lat: M.Lat, lng: M.Lng},5000,{ style: customStyle });
    M.Map.addObject(circle);}

    drawCircle();

Although this gives a fair idea about which markets are nearest from you, they cannot necessarily be reached within a similar time given the time of the day, traffic and road conditions. To take these conditions into consideration and to get a realistic view of places that can be reached, we use the Isoline Routing API. The Isoline highlights an area which can be reached by car from your position in 10 minutes or less. Isoline also has a pedestrian mode. Lets take a look at the code for this one.


  // Get an instance of the routing service:
    var router = M.Platform.getRoutingService();
// save your location as a string of latitude and longitude
    var myLoc = M.Lat + ',' + M.Lng;
// set the routing parameters for Isoline routing
    var routingParams = {
      'mode': 'fastest;car;traffic:enabled',// traffic matters for our commute| you can also disable traffic
      'start': myLoc,
      'departure': '2018-12-14T17:00:00', // set the departure time
      'range': '600', //10 (10x60secs) minutes of driving
      'rangetype': 'time'
    };

    // Define a callback function to process the isoline response.
    var onRoutingResult = function(result) {
      var center = new H.geo.Point(
          result.response.center.latitude,
          result.response.center.longitude),
        isolineCoords = result.response.isoline[0].component[0].shape,
        linestring = new H.geo.LineString(),
        isolinePolygon,
        isolineCenter;
        // Add the returned isoline coordinates to a linestring:
         isolineCoords.forEach(function(coords) {
         linestring.pushLatLngAlt.apply(linestring, coords.split(','));
         });

         // Create a polygon and a marker representing the isoline:
         isolinePolygon = new H.map.Polygon(linestring);
         // isolineCenter = new H.map.Marker(center);

         // Add the polygon and marker to the map:
         M.Map.addObject(isolinePolygon);

         // Center and zoom the map so that the whole isoline polygon is
         // in the viewport:
        M.Map.setViewBounds(isolinePolygon.getBounds());
       };

       // // Call the Routing API to calculate an isoline:
       router.calculateIsoline(
         routingParams,
         onRoutingResult,
         function(error) {
         alert(error.message);
         }
       );

Screen Shot 2018-12-15 at 2.58.19 AM

You can try your hand at more routing parameters to refine your isoline area. Try swapping the 'rangetype': to 'distance' and the 'range': to '5000'//meters. You will clearly be able to see that there are still some places which were inside the circle but not reachable if you consider traffic and time using the isoline routing.
Screen Shot 2018-12-15 at 2.58.45 AM

With this tutorial, we have seen how to use external data sources, call the data using AJAX, parse the json file using JSON.parse, draw a circle on the map and calculate reachable places considering traffic and time with isoline routing. If you have any difficulties in following this tutorial, comment below and I will try to answer them. You can also ask us your doubts about any of our HERE APIs on stackoverflow with the tag 'here-api' and our team will answer your queries.

Thats all from me for this year. Happy holidays! See you on the other side of 2018.