WhereYouAt DemoBuild 2016: Building the Front-end

In my previous post, I went over the user interface and application requirements. Let’s quickly revisit the project requirements:

  • Get coordinates of the users and identify which cloud the ASP.NET Core app is running on.
  • Populate maps with custom pushpins.
  • Display the number of containers running on each cloud.

UItoweb

Get Coordinates

In this app, I am getting the user location with a button using an onclick event handler. In order to grab the user’s coordinates, I used the Geolocation API . Let’s have a look at the code.

Get location

function getLocation() {
    var x = document.getElementById("demo");
    if (navigator.geolocation) {
        navigator.geolocation.watchPosition(showPosition);
    }
    else {
        x.innerHTML = "Geolocation is not supported by this browser.";
    }
}

getlocation() function simply shows the user longitude and latitude every time you load the page. But, in this case, I needed the user’s coordinates to put the pins on the map. To do this we created a simple a location web api that, we can PUT our users longitudes and latitude into.

Store location

function showPosition(position) {
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
    var xhr = new XMLHttpRequest();
    var params = "latitude=" + lat + "&longitude=" + lon;
    console.log("Params: " + params);
    xhr.open('PUT', '/locations', true);
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = function () {
        console.log("Response:" & this.responseText);
    };
    xhr.send(params); 
}

You might have noticed I am using XMLHttpRequest API. XMLHttpRequest API is used to transfer data between the client and Server. In this case, we are using it to PUT the users coordinates into a location API.

Since this was a public demo our team thought it might be a good idea to offset the actual coordinate we were receiving. For most people getting their actual coordinates might feel a little creepy to people . To offset the coordinates we added the toFixed( ) method ; allowing the app to have an idea of where the user is but, not the exact location.

Full Script to get geolocation and PUT it into an API

function getLocation() {
    var x = document.getElementById("demo");
    if (navigator.geolocation) {
        navigator.geolocation.watchPosition(showPosition);
    }
    else {
        x.innerHTML = "Geolocation is not supported by this browser.";
    }
}

function showPosition(position) {
    var lat = position.coords.latitude.toFixed(2);
    var lon = position.coords.longitude.toFixed(2);
    document.getElementById("demo").innerHTML = "You're around Latitude: " + lat + " and Longitude: " + lon;

    var xhr = new XMLHttpRequest();
    var params = "latitude=" + lat + "&longitude=" + lon;
    console.log("Params: " + params);
    xhr.open('PUT', '/locations', true);
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.onreadystatechange = function () {
        console.log("Response:" & this.responseText);
    };
    xhr.send(params); 
}

If you would like to explore the geolocation API , check out theses resources: Navigator.geolocation , getCurrentPosition, and WatchPosition.

Get Location Button

<a href="#" onclick="getLocation();  return false;" class="btn btn-default btn-xl wow tada">Get my Location</a>

Displaying Active Cloud Logo

Include @model directive

@model whereyouat.Settings

Display Cloud Name & Logo

  <h3 id="demo"></h3>
      @{
          var largeIcon = $"~/img/large/{Model.Cloud_Name}.png";
       }
   <h3>You're running ASP.NET on @Model.Cloud_Name!</h3>
   <img src="@largeIcon" alt="@Model.Cloud_Name" />

 

By including the @model statement at the top of my landing page (Views/Home/Index.cshtml), I am able to specify the type object that the view expects. By using @model directive gives the view access to Cloud_Name through the settings controller .

Results

 

Cloudgif (2)

 

Pushpins

Start by initializing the map.

var map;
function getLocations() {
       var mapOptions = {
           credentials: "Bing Key",
           mapTypeId: Microsoft.Maps.MapTypeId.road,
           zoom: 3
        };
        map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), mapOptions);

I used the JQuery $.get method to retrieve the user’s coordinates from the location API.

 $.ajax({
                type: "GET",
                url: "/locations",
                dataType: "json",
                success: function (json) {
                    //console.log(json);
                    $.each(json, function (i, entry) {
                        plotEntry(entry.latitude, entry.longitude, entry.cloud_name);
                    });
                },
                error: function (err, status, errortext) {
                    console.log(errortext);
                }
            });

For this demo, we wanted to add custom pushpin the showed not only the users locations but, the logos of the cloud their ASP.NET Core was running one. To do this we used the pushpin class. You can also use the pushpin class to add a default pins.

function plotEntry(latitude, longitude, cloud) {
            //console.log(latitude + ' ' + longitude);

            //Icons for each Cloud Type
            var pushpinOptions = { icon: '/img/' + cloud + '.png', width: 32, height: 32 };
            var pushpin = new Microsoft.Maps.Pushpin(
                new Microsoft.Maps.Location(latitude, longitude),
                pushpinOptions);

            map.entities.push(pushpin);
        }
        $().ready(getLocations);

Result

Maps

Number of request per container

For the demo, we had a /cloudcounts api that returns the cloud name, container, and count. The API looked something like this:

{ "cloud_name": "Azure ACS", "container": "185f65604f23"", "Count": 14 }

To obtain the number of request per container , we used a JQuery $.get method similar to what we did to retrieve the user coordinates. The only difference here is, we need to account for the whitespaces in the cloud_name values using the encodeURI function. Looking back to our demo requirements, we wanted to so split the number of request per container by cloud name. It would look something like the image below.

 

Maptemplate

To achieve the above we created three unordered lists; creating an id attribute for each cloud. As I mentioned earlier we used the encodeURI function to account for the whitespaces in cloud_name so, Azure ACS becomes Azure%20ACS. Let’s look at the code


JavaScript

var listoptions = {};
  
        function getcloud() {
           
            $.ajax({
                type: "GET",
                url: "/cloudcounts",
                dataType: "json",
                success: function (cloudinfo) {
                    console.log(cloudinfo);
                    $.each(cloudinfo, function (i, entry) {
                        //changes "foo bar" to "foo%20bar"
                        var cloudName = encodeURI(entry.cloud_name);
                        console.log(cloudName);
                        if (!listoptions[cloudName]) { listoptions[cloudName] = "" };
                        entry.container = entry.container.replace("whereyouat-web", "wya-w");
                        listoptions[cloudName] += '<li class="list-group-item">' + '<b>Container:</b> ' + entry.container + ' <br><b>' + entry.Count + '</b> PUTs received</li>';

                    });

                    for (var prop in listoptions) {
                        console.log(prop);
                        //Could use getElementByTagName, but here's how to do it in jQuery as "#foo" doens't work with late eval
                        var listElement = "ul[id='" + prop + "-listview']";
                        $(listElement).append(listoptions[prop])
                    }
                  
                },

                error: function (err, status, errortext) {
                    console.log(errortext);
                }

            })
 }
        $().ready(getcloud);

 

HTML

 

<ul id="Azure%20ACS-listview" data-role="listview" class="list-group"></ul>

 

Results

FinalCounts

Summary

In this and the previous post, I went over UI requirements, and how I constructed it. In series of post entitled “WhereYouAt DemoBuild 2016:….” my team is going to cover a variety of topics that include : Load Balancing, traffic managers, and containers. To read these post please visit the .Net Web Development and Tools Blog.