iPhone like infobubble with Sencha Touch

Swarnendu De April 19, 2013

Every time a client wants a map in his application, he wants an infowindow for sure to show the details of  map markers. And by infowindow, they assume the native iPhone like infobubble. Now, while creating a map for Sencha Touch, the default infowindow of Google doesn’t really look good in mobile device. So here is a piece of example showing how to improvise the infobubble in Sencha Touch.

 

iPhone like infobubble

 

 

[button link=”https://www.innofied.com/iphonetest/?url=https://www.innofied.com/sencha/anand/senchainfobubble” linking=”new-window” size=”medium” type=”simple” title=”iPhone like infobubble with Sencha Touch”]Demo[/button]
[button link=”https://github.com/anandasansol/senchainfobubble” linking=”new-window” size=”medium” type=”simple” title=”Download” label=”Download”]Download[/button]

 

Here is few simple steps to achieve this. Lets get started!

Step 1:

There is a InfoBubble similar to iPhone map bubble available online. You can download it from here: http://google-maps-utility-library-v3.googlecode.com/svn-history/r292/trunk/infobubble/src/infobubble.js

Step 2:

Now, lets create a Sencha application and structure the app like below, following the MVC structure. We have maintained a set of locations in a store just for the sake of the example.

Controller

  1. App.js

Views

  1. Main.js
  2. Details.js
  3. Map.js

Model

  1. Place

Store

  1. Places.js

Style

1. style.css

 

view/Map.js

Ext.define("Mapinfobubble.view.Map", {
  extend: 'Ext.Container',
  xtype: 'infomap',
  requires: ['Ext.Map', 'Ext.TitleBar'],
  config: {
    layout: 'fit',
    items: [{
        docked: 'top',
        xtype: 'titlebar',
        title: 'Map with InfoBubble'
      }, {
        xtype: 'map',
        name: 'infoMap'
      }
    ]
  }
});

 

model/Place.js

Ext.define('Mapinfobubble.model.Place', {
  extend: 'Ext.data.Model',
  config: {
    fields: ['description', 'name', 'latitude', 'longitude']
  }
});

 

store/Places.js

Ext.define('Mapinfobubble.store.Places', {
  extend: 'Ext.data.Store',
  config: {
    model: 'mapinfobuble.model.Place',
    proxy: {

      type: 'ajax',
      url: 'app/data/MapData.json',
      reader: {
        type: 'json',
        rootProperty: 'places'
      }
    }
  }
});

 

controller/App.js

Ext.define('Mapinfobubble.controller.App', {
  extend: 'Ext.app.Controller',
  config: {
    refs: {
      // Containers
      map: 'map[name="infoMap"]',
      infoMap: 'infomap',
      details: 'details',
      main: 'main',

      // Button
      backToMap: 'button[name="backBtnToMap"]'
    },

    control: {
      map: {
        maprender: function (thisOb, map, eOpts) {
          var me = this;
          me.map = map;
          Ext.Function.defer(me.loadMarker, 2000, me);
        }
      },

      backToMap: {
        tap: function () {
          this.getMain().animateActiveItem(this.getInfoMap(), {
            type: 'slide',
            direction: 'right'
          });
        }
      }
    }
  },

  launch: function () {
    Ext.getStore('Places').load();
  },

  /*
   * Function responsible for all the marker and infobubble handling
   **/

  loadMarker: function () {
    var me = this,
      latlngbounds = new google.maps.LatLngBounds(),
      position, marker,
      map = me.map,
      store = Ext.getStore('Places'),
      ib = new InfoBubble({
        hideCloseButton: true,
        disableAutoPan: true,
        maxHeight: 110
      });

    store.each(function (rec) {
      position = new google.maps.LatLng(rec.get('latitude'),
        rec.get('longitude'));

      marker = new google.maps.Marker({
        position: position,
        map: map,
        data: rec
      });

      /*
       * Showing InfoBubble   
       **/ (function (data, selfMarker) {
        google.maps.event.addListener(selfMarker, 'mousedown', function (event) {
          ib.record = {
            places: data
          };

          ib.setContent([
              '<div class="infobox">',
              '<div class="content">',
              data.get('description'),
              '</div>',
              '<img src="resources/images/arrow.png">',
              '</div>'
          ].join(''));

          /*
           * center the map on the marker position
           **/
          map.setCenter(selfMarker.position);

          ib.open(map, this);

          google.maps.event.addListener(map, 'mousedown', function () {
            ib.close();
          });

          /*
           * Tap on InfoBubble handled here
           **/
          google.maps.event.addDomListener(ib.bubble_, 'click', function (e) {
            if (!me.getDetails()) {
              me.getMain().add({
                xtype: 'details'
              });
            }
            me.getMain().animateActiveItem(me.getDetails(), {
              type: 'slide'
            });

            me.getDetails().setData(ib.record.places.data);
          });
        });
      }(rec, marker));

      latlngbounds.extend(position);

      map.fitBounds(latlngbounds);
    }, me);
  }
});

 

css/style.css

/******************************* Map ****************************************/

.infobox{
    height: 50px;
    width: 200px;
    margin-left: -100px;
    background-image: url("../images/infobox.png");
    background-size: 100% 100%;
    opacity: 0.8;
    display: -webkit-box;
    cursor: pointer !important;
}

.infobox .content{
    margin: 15px 0px 0px 12px;
    color: white;
    font-size: 12px;
    width: 75%;
}

.infobox img{
    margin-top:11px;
}
/***************************** Map ENDS ************************************/

 

 

[button link=”https://www.innofied.com/iphonetest/?url=https://www.innofied.com/sencha/anand/senchainfobubble” linking=”new-window” size=”medium” type=”simple” title=”iPhone like infobubble with Sencha Touch”]Demo[/button]
[button link=”https://github.com/anandasansol/senchainfobubble” linking=”new-window” size=”medium” type=”simple” title=”Download” label=”Download”]Download[/button]