Monday 14 September 2015

Customizing the google map and populating locations from Database using WEB API2 .Net

Following is a brief tutorial of how you can customize the default google map ( I have used the JS API) and populating geo locations from a Database.

There are many good tutorials where you can dynamically plot geo locations using a database table. Most of them are PHP based. For ASP and .Net fans, following is a very naive way of accomplish the same result.

We are going to use a WEB API2 Rest service to fetch data in to our map front end. You can see how easily we can built a Code first WEB API using SQL server in this link.

Following is my model class. It is very simple and contains only geo location data.

 
public class MapIcons
    {
        [Key]
        public Guid Id { get; set; }

        public double Latitude { get; set; }

        public double Longitude { get; set; }

        [StringLength(50)]
        public string Name { get; set; }

        [StringLength(50)]
        public string Caption { get; set; }

        public int CapSize { get; set; }

        [StringLength(50)]
        public string Icon { get; set; }
    
    }

Following is the context class
 
 public partial class MapDataContext : DbContext
    {
        public MapDataContext()
            : base("name=DBContext")
        {
        }


        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
        }

        public DbSet<MapXyIcons> MapIcons { get; set; }
    }

Updated configuration class to populate some initial data.
 
internal sealed class Configuration : DbMigrationsConfiguration
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(GoogleMapService.Models.MapDataContext context)
        {


            context.MapXyIcons.AddOrUpdate(m => m.Id,
                new Models.MapXyIcons
                {
                    Id = Guid.NewGuid(),
                    Name = "TestXy1",
                    Caption = "Test Xy 1 ",
                    Icon = "light",
                    Latitude = 6.9025191,
                    Longitude = 79.8596352,
                    CapSize = 10
                },
                new Models.MapXyIcons
                {
                    Id = Guid.NewGuid(),
                    Name = "TestXy2",
                    Caption = "Test Xy 2 ",
                    Icon = "poly",
                    Latitude = 6.9023642,
                    Longitude = 79.861076,
                    CapSize = 10
                },
                new Models.MapXyIcons
                {
                    Id = Guid.NewGuid(),
                    Name = "TestXy2",
                    Caption = "Test Xy 2 ",
                    Icon = "poly",
                    Latitude = 6.9019559,
                    Longitude = 79.8612179,
                    CapSize = 10
                },
                new Models.MapXyIcons
                {
                    Id = Guid.NewGuid(),
                    Name = "TestXy3",
                    Caption = "Test Xy 3 ",
                    Icon = "light",
                    Latitude = 6.9019559,
                    Longitude = 79.8612179,
                    CapSize = 10
                },
                new Models.MapXyIcons
                {
                    Id = Guid.NewGuid(),
                    Name = "TestXy4",
                    Caption = "Test Xy 4 ",
                    Icon = "Light",
                    Latitude = 6.9021217,
                    Longitude = 79.8617325,
                    CapSize = 10
                }
                );

        }
    }

The Web API controller goes as follows.
 
 [RoutePrefix("Icons")]
    public class MapIconController : ApiController
    {
        private MapDataContext db = new MapDataContext();

        // GET api/MapIcon
        [HttpGet, Route("GetAll")]
        [HttpHeaderAttribute("Access-Control-Allow-Origin", "*")]
        public IHttpActionResult GetMapIcons()
        {
            return Ok(db.MapIcons.ToListAsync());
        }

        // GET api/MapIcon/5
        [ResponseType(typeof(MapIcons))]
        public async Task<IHttpActionResult> GetMapIcons(Guid id)
        {
            MapIcons mapicons = await db.MapIcons.FindAsync(id);
            if (mapxyicons == null)
            {
                return NotFound();
            }

            return Ok(mapicons);
        }
     }

Note that I'm returning a Json response to the client with Map data. This would make the client implementation easy and independent.
[HttpHeaderAttribute("Access-Control-Allow-Origin", "*")] : This attribute make your life easier when testing the applications in the development environment itself. Otherwise you need to install a CORS plugin in your browser and allow cross origin.
The server side code is done now and we need to concentrate on the client side implementation. I did a customization to the google default map and You can easily learn this using google tutorial itself.
You can access the service api as in following jquery code.
 

            function ajax(url) {
                return new Promise(function (resolve, reject) {
                    var xhr = new XMLHttpRequest();
                    xhr.onload = function () {
                        resolve(this.responseText);
                    };
                    xhr.onerror = reject;
                    xhr.open('GET', url);
                    xhr.send();
                });
            }

            ajax("http://localhost:1210/Icons/GetAll").then(function (result) {
                mapJson = result;

                var mapObj = JSON.parse(mapJson);
            };

Note that I have used promises to implement this in order to support Async server side calls.
Finally, we need to iterate thorough the data set and plot icons based on their locations.
 
   var features = [];

                for (var i = 0; i < mapObj.Result.length; i++) {

                    var pos = new google.maps.LatLng(mapObj.Result[i].Latitude, mapObj.Result[i].Longitude);

                    var feature = {
                        position: pos,
                        type: mapObj.Result[i].Icon
                    };

                    features.push(feature);

                    var mapLabel = new MapLabel({
                        text: mapObj.Result[i].Caption,
                        position: pos,
                        map: map,
                        minZoom: 10,
                        maxZoom: 25,
                        strokeColor: '#ffff7f',
                        strokeWeight: 20,
                        fontColor: '#ff0000',
                        fontSize: mapObj.Result[i].CapSize,
                        align: 'center'
                    });
                }

                for (var i = 0, feature; feature = features[i]; i++) {
                    addMarker(feature);
                }

                function addMarker(feature) {
                    var marker = new google.maps.Marker({
                        position: feature.position,
                        icon: icons[feature.type].icon,
                        map: map
                    });
                }


Additionally , I have added a small legend based on the icon types.
 
 var legend = document.getElementById('legend');

                for (var key in icons) {
                    var type = icons[key];
                    var name = type.name;
                    var icon = type.icon;
                    var div = document.createElement('div');
                    div.innerHTML = '<img src="' + icon + '"> ' + name;
                    legend.appendChild(div);
                }


Following is a screen of the output of this application.

You can download the full source code from this location.

No comments:

Post a Comment