Tuesday, September 2, 2014

Showing Multiple Routes on Map with Google Direction Services

Recently in one of our project we have to show routes between two points on map. Those two points can be on same way or can be on different ways. So there were multiple routes. There are ways to do that with Google direction service. One way is that you set way points while plotting routes on the map. But in our case points were random so that would be possible. So in this blog I am going to mention trick I have used.

For showing multiple paths we have to create separate DirectionsRenderer for each route. So first we get latitude and longitude each points in an array. For example I have 4 lat longs in an array that means there will be three paths. From point 0 to point 1, point 1 to point 2 and point 2 to point 3. So we have to create three separate requests and three separate DirectionsRenderer. You can not simply use for loop here as route API has callback functions when it receives routes. So here I have used recursion function. For example you have all the points in an array called markers.  First we will generate Google Map LatLong.

for (i = 0; i < markers.length; i++) {
      var data = markers[i];
      var myLatlng = new google.maps.LatLng(data.lat, data.lng);
      lat_lng.push(myLatlng);
}

Now we will create request for each path separately.

var requestArray = [], renderArray = [];
var cur = 0;
var service = new google.maps.DirectionsService();
for (var i = 0; i < lat_lng.length  -1; i++) {
     var request = {
  origin: lat_lng[i],
           destination: lat_lng[i+1],
   travelMode: google.maps.DirectionsTravelMode.DRIVING
     };
     requestArray.push(request);
 }

So now we have all the requests created we will start with first request.

if(requestArray.length > 0){
     service.route(requestArray[cur], directionResults);
}
   
function directionResults(result, status) {
   if (status == google.maps.DirectionsStatus.OK) {
          renderArray[cur] = new google.maps.DirectionsRenderer();
          renderArray[cur].setMap(map);
          renderArray[cur].setDirections(result);
   }
   cur++;
   if(cur < requestArray.length){
    service.route(requestArray[cur], directionResults);
   }
}

As you see in above code we have variable named cur which is initialized with zero. We start with first request. directionResults is our callback function. Inside direction function we are creating a DirectionsRenderer and setting map and result to it. After that we increase the count and go to next request. Once all the requests are completed you stop the recursion. Using this you can achieve following result.


Hope this helps you.

Monday, September 1, 2014

Sencha Touch - One Way to Implement Autosuggest Textbox

Hello,

Recently in one of our Sencha Touch project there was a requirement to add autosuggest textbox. As user starts typing there should be some suggestions and user should be able to either select one of the option or type in the value. In this blog I am going to explain the approach I used for that. Please note that there could be other ways to implement this.

First lets create a store that has the options for auto suggestions. For that here is the model definition.

Ext.define('MyApp.model.Option', {
    extend:'Ext.data.Model',
    config:{
        fields:[
            { name:'id', type:'int' },
            { name:'text', type:'string' },
        ],
        idProperty: 'id'
    }
});

Now lets create a store which holds the data.

Ext.define('MyApp.store.Option', {
  extend: 'Ext.data.Store',
  config: {
    model: 'MyApp.model.Option',
    autoLoad: true,
    proxy: {
      type: 'memory'
    },
    data : [
        {id: 1,    text: "Option 1"},
        {id: 2, text: "Option 2"},
        {id: 3, text: "Option 3"},
        {id: 4, text: "Option 4"}
    ]
  }
});

Now our approach is quite simple we will create a floating panel with list and assign this store to it and as soon as user starts typing in textbox, we will show this panel near to textbox and filter store with what is typed in textbox. So lets create a floating panel.

Ext.define('MyApp.view.Traffic.AutoSuggestPanel', {
extend: 'Ext.Panel',
xtype: 'autosuggestpanel',
config: {
modal: true,
hideOnMaskTap: true,
hidden: true,
height: '180px',
width: '94%',
layout: 'fit',
margin: '-9px 0 0 0',
items: [
{
xtype: 'list',
id: 'autoSuggestList',
itemId: 'autoSuggestList',
itemHeight: 30,
itemTpl: '<div style="font-size: 13px">{name}</div>',
store: 'Option'
}
]
}
});

We will add this panel to viewport when app launches, as you see it's hidden initially so it will not be visible.

Ext.Viewport.add(Ext.create('MyApp.view.Traffic.AutoSuggestPanel'));

Now lets add keyup event to textfield on which we want to show this suggestions. Also we will add our floating panel as reference to controller.

 config: {
        refs: {
              autoSuggestPanel: 'autosuggestpanel'
              autoSuggestList: '#autoSuggestList',
              autoSuggestTextField: '#autoSuggestTextField'
       }
}

autoSuggestTextField: {
            keyup: 'onAutoSuggestTextFieldKeyUp'
            },
autoSuggestList: {
            itemtap: 'onAutoSuggestListItemTap'
            },

And define it's handler in controller.

onAutoSuggestTextFieldKeyUp: function(text){
        if( this.getAutoSuggestPanel().isHidden( ) ) {
            this. getAutoSuggestPanel().showBy(text,'bc-tc' );
        }

        Ext.getStore('Option').clearFilter();
        Ext.getStore('Option').filter('text',text.getValue());
}


Above code will show auto suggest list next to textfield. Now we have to add itemtap event for the list and set it's value in textbox. Here is handler for it.

onAutoSuggestListItemTap: function(list, index, target, record){
        var name = record.get('text');
this. getAutoSuggestPanel().hide();

       this.getAutoSuggestTextField().setValue(name);
}

That's it and you have autosuggest textbox ready.