22 Sep 2011

What’s New in iOS5

iOS posted by Rajat Bhalla

iOS5

This is the first major upgrade to iOS ever since it was rechristened from iPhone OS.

Apple’s iOS 5 page says that they are “taking iOS to a whole new level”.

Scott Forstall, SVP iOS Software, says that this is the “widest and most extensive update for iOS, ever”.

The update boasts of 200 new updates.

Let’s look at the new features to see if that is really true or is it just old wine in a new bottle.

I am able to review some of these on an iPad running iOS 5 Beta 7.

1. Notifications

This is not a new feature. iOS users are already familiar with notification pop-ups and badged icons. What is new is the way these notifications are lending themselves to the user.

With the device in an unlocked state, you can drag down the notification bar on top and see a list of notifications from various apps. Tapping any would take you straight to that app.

While iOS users may drop their jaw on this, Android users are only yawning as this was already on Android since version 1 !!! (do I hear someone shouting “copy-cats”)

Additionally, the iOS notification drop-down also shows weather and a stock ticker.

Even in a locked state when the device shows a list of notifications, you can swipe a notification directly and open its app instead of having to unlock the device first. Now that is something that would make Android users jealous.

2. Newsstand

Apple had caused a lot of heartburn to publishers earlier this year over its seemingly atrocious terms of engagement.

However, after the two parties agreed to mutually respectable terms, it was the end user who emerged as a winner.

Newsstand is a single repository of all your newspaper and magazine subscriptions purchased from App Store.

The magazines and dailies are downloaded in the background and are available for offline reading.

Simulating your book shelf, the exploded view of the newsstand shows you the cover of each magazine and daily that you have subscribed to.

3. Twitter

Twitter app for Apple was already available since but what is new is the OS wide support for it.

Integrating Twitter into iOS and offering it as a single sign-on is a smart move by Apple and great news for the Twitterati.

Now you can sign-on with Twitter and login to any other application permitting a Twitter login without having to specify your credentials again.

Not to mention, that the OS wide integration allows you to Tweet from a lot of native applications like Photos, YouTube, Safari, Maps, etc.

Additionally, you can complement your contacts information with their Twitter information like photo, @username, etc.

4. Safari

Mozilla’s Firefox has always been my personal favourite (at least on a PC*) but the additions iOS has done to Safari really tempt me to switch.

When you are reading an article (blog post, news article, etc.) on Safari and switch on the Reader mode from the address bar, you see the article freed of all the clutter (like side bars, ads, related stories, all the junk that web developers like us put in a page). The article is displayed in a neat (I am tempted to say “sexy”) fashion with Serif fonts, a la hardcopy publication. Just focus on the article without any distractions.

Reading list is another interesting addition. It allows you to save articles for later viewing. And more importantly, this list is accessible across devices by using iCloud. So you can view articles on your iPhone while commuting home that you had saved earlier on iPad while in office.

And to top the Safari cake is the cherry of tabbed browsing. Switch among multiple tabs the same way you would on your PC*.

5. Reminders

I have always had trouble managing my to-do lists, at least on a PC. Simple text document, Excel sheet, Ta-da lists, I have tried it all.

But this simple application can be a solution to all your woes about managing to-do lists, at least on iOS.

You can create new lists and quickly add list items. Check them off as you complete them.

View all completed list items in a separate list and in the list you created.

You can mark a date and time to be reminded about an individual list item (without which it would not make sense to call the feature as “Reminders”).

Here comes the best part about reminders: in addition to specifying time and date, you can also specify place. That is, be reminded of a chore when you arrive at a place (pick up groceries from supermarket) or when you leave a place (call your wife when you leave from office so that she can be prepared with a new set of chores when you reach home).

And you can sync these reminder with your other Apple devices using CalDAV or iCloud or with your Outlook using Microsoft Exchange.

6. Camera

Now Apple claims to have the most popular camera among mobile phones and as popular has regular cameras using Flickr as a reference for this statistic.

Even if that were to be true, the new features would only serve to bolster iPhone’s camera’s position.

The chances of missing a moment worth capturing are even less with the quick access to camera even from the lock screen.

Just double click the home button to reveal the camera button and dive straight into the camera app.

And click like a regular camera with your iPhone held in landscape mode and using the volume-up button. :)

Also you can view grid lines on your screen so that you can align the picture even before taking it.

Want to zoom in, just pinch to zoom!

Another great feature which I doubt if any other mobile camera has is an AE/AF Lock.

Now I am not a photography expert but as I understand, on iPhone, if you select an area and lock the AE/AF (auto exposure, auto focus) and even pan a little, the exposure and focus of the selected area would not change despite the change in background light.

I would have to check this on an iPhone running iOS 5 but as I gather from Scott’s# demo, it seems to work.

7. Photos

All that beautiful pictures can me made too look even better by some handy tools now offered by the Photos app.

I hate it when my eyes in the photo appear red as if I am a Sith lord. You need not make your loved ones look like that if you use the red-eye reduction tool.

Then you can also crop, rotate, organise into albums the photos you took on your iPhone on the phone itself.

8. Mail

While the mail app on iOS devices used to appear like makeshift mail, it is going to become lot better and would come close to appearing like the mail on Mac (well, almost).

With the addition of rich text editing (bold, italics, underlines, etc.) and indentation, mails sent from iOS devices would look lot more like their Mac cousins.

Besides, you wont have to type again if you mentioned a contact name by mistake in CC instead of To or BCC. Just drag them to the other field.

Messages can be flagged / unflagged on the device itself, searching would include the mail body in addition to the to, from, and subject fields, swipe to view/hide the inbox, yada yada yada.

But one feature really made me skip a beat (I actually said “Whoa” when I saw the demo) is the split keyboard on iPad

You can split the keyboard and drag it upwards so as to type by just using your thumbs while holding the iPad. Awesome!

9. PC Free

This is actually a goood one (that wasn’t a typo, I use the ooo sound when I really like something, like “hey, that girl is goood”)

The pre-requisite of having a PC to sync your device with has been done away with.

The iOS device can be the only computing device in your home for all you care.

Activate, update it over-the-air. Not to mention that updates are now delta-updates so you just download what has changed, not everything including the kitchen sink.

10. iMessage

Well, I am not saying that Apple is trying to emulate the success that BlackBerry achieved through its BlackBerry Messenger, but…umm…yes, I think I am saying that.

But its a great feature to have anyhow.

iMessage allows you to exchange messages over 3G/Wi-fi with your friend if he/she also has an iOS device.

iMessage is built into the existing messages and allows you to exchange photos, videos, group messages, and of course simple texts.

You can receive delivery receipts (no more excuses like “I never received your message”), read receipts (or “I didnt read your message”) and even get to know when the other party is typing a message.

Besides, these messages are synced across all your iOD devices so you can resume the conversation from your iPad if, for example, your iPhone got run over by  a truck.

11. Wifi-Sync

This is another feature that aims at making your iOS device truly wireless.

No need to plug in your device to your PC to sync with iTunes. A shared wi-fi connection between your device and the PC would handle the syncing.

But, I am wondering what would be left of the poor battery if you are syncing a lot of audio and video.

These were some of the new features that iOS offers to the end users.

But even iOS developers have a lot to cheer about.

With more than 1500 new APIs, developers can unleash their creativity and develop really useful apps (and some weird ones too).

Apple claims to have done significant enhancements to Xcode, Instruments, and Simulator.

Then they have incorporated the CoreImage framework from Mac OSX to iOS that allows the developer to weave some real magic in their apps that handle images (red-eye reduction for example).

Hope you enjoyed reading the post.

Stay tuned for more (especially my soon to come blog post on Android).

Feel free to comment on this post or you can reach me at rajat(at)vinsol(dot)com.

* The term PC has been used to differentiate desktop computers, laptops from mobile iOS devices.
# iOS5 introduced and demoed by Scott Forstall, SVP iOS Software

References

1. Keynote Video: http://www.apple.com/apple-events/wwdc-2011/
2. iOS Video: http://www.apple.com/ios/ios5/gallery.html#video-ios
3. Features: http://www.apple.com/ios/ios5/features.html
4. Title Image Source: http://images.apple.com/ios/ios5/images/overview_hero.png

Did you like this? Share it:
02 Sep 2011

Sencha and Ruby on Rails

about this site posted by vipin

Sencha touch is a Javascript framework based on the most popular MVC pattern. It lets you build cross platform mobile web application using Javascript, HTML5 and CSS that amazingly look like native mobile applications. I think it can be described and understood better with the help of a demo application. If you can’t wait to see a few of the Sencha’s stuff till we build our demo application you should click here.

Note: If you don’t have a smart phone with a webkit browser in it, you can view Sencha demo in any webkit browser preferably Safari.

This is a simple application backed by Rails where you can ask questions and those can be answered. For no specific reason I name it ‘Tarot’. With Tarot we want to be able to ask a question, answer to it, show a list of question for a given tag and show a question with its answers.

Before we go further I would suggest you to clone the code from my github account. As a matter of fact we like short and sweet blogs and I won’t be giving full application code in the blog. After you have cloned in the application directory, don’t forget to run:

bundle install
rake db:setup

Without doing much of the the talk lets dive in to building the Rails part first.

Use of Rails in this application is minimal. It simply serves a few ajax requests and sends back json response. Everything else you expect from a mobile application could be achieved with Sencha Touch.

AR Models

On the server side we are going to have two models Question and Answer.

As it is expected our question has_many answers. There is one thing to mention, I have used acts_as_taggable gem to tag the questions. Simple run all the migrations and run server.

Controllers on Server:

As we just want to do the minimal with our rails part of the application.

Keeping things simple I have setup the index and tags action to respond with the array of all tagged questions and list of all tags to create the tag cloud respectively in the JSON format, which we would finally be parsing at the client end with the help of Sencha.

The client expects JSON data in the following format:

{
	data: {
		   question: {
				 title: 'Title'
				 description: 'Description'
				 answer_count: 4
                                           }
	         }
}

By writing “render :json => {:sucess => true, :data => [question]}” we have made create action to respond accordingly.

def create
    question = Question.new(params[:questions].first.except(:answer_count))
    respond_to do |format|
      question.save
        format.json {
          render :json => {:sucess => true, :data => [question]}
        }
    end
 end 

It seems to be enough of rails and the time when we start giving our Tarot some touches of Sencha.
First thing first, you must have sencha library somewhere in your application where views have access to it and the most appropriate place I find is the public directory where all your .js and .css files go.
Fortunately you don’t have to download the library separately if you have already cloned the application from github. If not I would suggest you do it now.

Note: Sencha Touch comes with lot of other things bundled with it which we can always get rid of. The files of our interest are sencha-touch-debug.js and sencha-touch.css in the development mode and sencha-touch.js and sencha-touch.css in the production mode.

As mentioned earlier Sencha Touch is an MVC framework, its directory structure can be made to look somewhat like a rails application, though it is not mandatory. As it turns out I am a rails guy and love the rails way. Let’s check the public directory where all our Sencha code is placed. Sencha directory structure look like:

public/app    #main application folder
app/app.js    #Tarot boots up from here
app/util.js    # Extra utility function go inside this

#Try to get the significance of following from their names, its easy
app/models
models/questionModel.js
models/answerModel.js
models/tagModel.js

app/conrollers
controller/questionController.js

app/views
views/home.js
views/list.js
views/tarotViewport.js
views/new.js
app/resources
resources/terot.css

If you check application.html.erb, all the the .js files are included in it.

Tip: You should compress all your Javascript files when you run your application in production.

Sencha Digging Deeper:

The first step for most of the Sencha Application is to create a namespace by registering the application. Simply open up app.js file(the starting point of the application) and the check the code in there:

Ext.regApplication({
    name: 'tarot',
    launch: function() {
        this.views.viewport = new this.views.Viewport();
    }
});

The above represents a Sencha Application. Most Applications consist of at least the application’s name and a launch function.

Instantiating a new application automatically creates a global variable using the configured name property and sets up namespaces for views, stores, models and controllers within the app:

//this code is run internally automatically when creating the app (Senncha way of creating namespace)
Ext.ns('MyApp', 'MyApp.views', 'MyApp.stores', 'MyApp.models', 'MyApp.controllers');

The launch function usually creates the Application’s Viewport and runs any actions the Application needs to perform when it boots up. The launch function is only expected to be run once.

A few snapshots of the application viewport:

Home Image

Fig 1: Home

Fig 2: Create Question

Before we create our viewport or any other viewable component, lets create our models and avail the data to play by creating a store(remember sencha touch is MVC framework). A store simply fetches data from the remote server via proxies and keeps it stored in the local storage of the browser. You can get whole lot of information about the store object from the sencha documentation.

We have three model on the client part of Tarot and their corresponding stores. The minimum requirement for a model is its field object. It can also be stuffed with validations, associations, proxy( can be moved to the store).….

Our models/tagModel.js file look like:

tarot.models.Tag = new Ext.regModel('Tag', {
    fields: [
    {
        name: 'name',
        type: 'string'
    },

    {
        name: 'id',
        type: 'int'
    }],
    proxy: {
        type: 'ajax',
        url: 'tags',
        id  : 'taggings',
        reader: {
            type  : 'json',
            record: 'tag',
            root: 'data'
        }
    }
});

tarot.stores.Tags = new Ext.data.Store({
    autoLoad: true,
    model: "Tag",
    sorter: [{
        property : 'name',
        direction: 'ASC'
    }],
    getGroupString: function(instance) {
        return instance.get('name')[0];
    }
});

The official documentation of proxy says:

Proxies are used by Stores to handle the loading and saving of Model data. Usually developers will not need to create or interact with proxies directly.

proxy: {
        type: 'ajax',
        url: 'tags',
        id  : 'taggings',
        reader: {
            type  : 'json',
            record: 'tag',
            root: 'data'
        }
    }

tarot.stores.Tags uses the proxy which has been defined in the model to fetch the initial set of tags from the server. We have made our store to fetch the tags when the application first boots up by specifying

autoload: true

It sends a get(ajax) request to the pathname ‘tags’ wich inturn invokes the tags action within QuestionController and response with the requested data.

The ‘reader’ object specify the format of the record data it should expect from the server. By default it takes ‘records’ as the root value.

The store:

tarot.stores.Tags = new Ext.data.Store({
    autoLoad: true,
    model: "Tag",
    sorter: [{
        property : 'name',
        direction: 'ASC'
    }],
    getGroupString: function(instance) {
        return instance.get('name')[0];
    }
});

Having autoLoad set to true loads our store with the initial set of tags when the application boots up.
The similar can be achieved by calling tarot.stores.Tags.load() in the Application launch function.

‘getGroupString’ takes the instance of the model and should return the string by which the data is grouped in the store. We’d be using formed groups later in the application.

The other two models are written similarly, if you still get stuck, refer to the Sencha Touch documentation.

Finally we have reached the point where we can watch things moving on the screen. Back in the application launch function we create and object of Viewport. But what actually is a Viewport?

Note: Before going further you should keep the app/tarotViewport.js file open.

The basic building block(viewport) of a sencha app is a panel which contains subpanel and other components. Our viewport panel has a toolbar with back(initially hidden) and ‘askme’ buttons and the list of tags docked on the left. This consists of the navigation part of our application and makes it nicer and easier to navigate.

this.tagList = new Ext.List({
            id: 'tagindexlist',
            title: 'Tags',
            store: tarot.stores.Tags,
            itemTpl: '<div>{name}</div>',
            grouped: true,
            indexBar: true,
            emptyText: 'Tags Empty',
            ui: 'round',
            style: {
                minWidth: '250px',
                borderRight: '5px solid #4D80BC'
            },
            onItemDisclosure: function(record){
                Ext.dispatch({
                    controller: tarot.controllers.questions,
                    action: 'index',
                    animation: {
                        type: 'slide',
                        direction: 'left'
                    },
                    extras: record.data.name
                })
            }

        });

The store attribute above instructs list the load the data from. For every record in the store the itemTpl is rendered. Back in the tag store definition we grouped our store with the first character of every instance. Grouped: true takes the advantage of the same and shows the list items grouped together. ‘onItemDisclosure’ adds a disclosure icon to the list item and a listener to it which is fired when the icon is tapped and invokes the index function of our ‘tarot.controllers.questions’.

this.backButton = new Ext.Button({
            text: 'Back',
            ui: 'back',
            hidden: true,
            handler: this.onBackTap,
            scope: this
        });

The handler of a button specifies the function to call when the button is tapped. The button in our viewport is hidden for the first card. Once any other card is set as an activeItem the back button is shown. For the same purpose we have added a listener to the viewport:

listeners: {
        beforecardswitch : function( viewprt,newCard,oldCard,index){
            if(index == 0)
                viewprt.backButton.hide();
            else
                viewprt.backButton.show();
        }
    }

Our viewport has the tarot.views.home as its first item which would be set as active item(card) of the panel by default. The code can be in app/views/home.js.

tpl: new Ext.XTemplate('<div><div class="question-blk"><div class="ques-title">{title}</div><span class="answerCount">Answer<p>{answers_count}</p></span></div>'),

Our home defines a Data View view which renders the list of all question autoloaded by the the tarot.stores.questions store. A dataview if capable of displaying data with custom templates. Just like a list in our viewport it can also be bound to the store. Tpl Represents an HTML fragment template. The html inside is rendered for every record inside the store by looping through it.

It also adds a listener to the items rendered which on being tapped invokes the show function of the controller. The similar code has been written in the app/views/list.js which can be refered in our application by tarot.views.questionList (the magic of the namespaces).

tarot.views.answerList in the app/views/show.js file does extra efforts to render two more components. It docks the current question on the top and a form to give answers to that question at the bottom. tarot.views.questionNew simply has almost code and it is self explanatory.

Its time when we move to the ‘C’ part of our Sencha MVC.

Our controllers/questionController.js has defined a few function which can be invoked from our application using Ext.dispatch as we have previously been doing. The index function is called when the tag disclosure from the tag list is tapped and is responsible for loading tarot.stores.taggedQuestions and setting tarot.views.questionList to be the current activeItem which inturn renders the template for each question.

It merges options with some more attributes and calls the loader function from util.js file.

loader: function(options){
        var mask = tarot.util.actions.createLoadingMask();
        mask.show();
        options.store.data.clear();
        options.model.proxy.extraParams = {
            filter_param: options.extras
        }
        options.store.load(
        {
            scope   : this,
            callback: function(records, operation, success) {
                mask.hide();
                if(success){
                     tarot.views.viewport.setActiveItem(options.activeItem, options.animation);
                }
                else{
                    alert('Error while loading the questions');
                }
            }
        });
    }

The loader function does a number of things. The previous data from the store in cleared and sends a fresh request to the server by options.store.load() with an extra parameter to filter the records. In this case it is going to be the tag name. The load() function accepts a parameter as an object which should define the callback function, that gets invoked when the response is received from the server. This function is passed the records that are fetched from the server, the operation object which avails more information about the current operation and a boolean success specifying whether the operation was a successful. If the operation was a success we hide the mask which was shown at the very first. At last it sets the activeItem of the viewport to be the tarot.views.questionList.

In the similar fashion tarot.views.answerList is loaded. One thing is to mention here is, every time the store is updated the corresponding views(DataView) are automatically updated to render the current state of the store. No extra work is to be done, isn’t it nice! Just in case you have not associated any store with the data view check out the update() function.

Creating a new question:

On tapping the save button from tarot.views.QuestionNew the create function is called from the tarot.controller.question. The create function takes the from values and creates a model object filling in the parameters pulled from the form. As we like to keep our code DRY, we use our saveRecord() function to create both the question and answers. We merges options in the create action with the required properties and pass it onto saveRecord().

create: function(options) {
        options.form = tarot.views.questionNew;
        options.activeitem = tarot.views.home;
        var params = options.form.getValues();
        options.record = Ext.ModelMgr.create(params, tarot.models.Question);
        options.store = tarot.stores.questions;
        this.saveRecord(options)
    },

if (errors.isValid()) {
            record.save({
                success: function(){
                    options.form.reset();
                    if(options.activeitem){
                        Ext.Msg.show({
                            title: 'Saved',
                            msg: 'Record has been saved',
                            buttons: Ext.MessageBox.OK,
                            fn: function() {
                                tarot.views.viewport.setActiveItem(options.activeitem, options.animation);
                            }
                        });
                    }
                    options.store.load();

                }
            });
            return true;
        } else{}

Our saveRecord() takes validations into and proceeds only if the record is valid else it shows up a message box with the validations errors. Again the magic of the proxy spreads here, which is hidden from the developer. When the save function is called the it sends the POST(Ajax) request to the ‘questions’ path with record fields in the parameters and extra parameters(if any). On success the success callback is called. Few other callbacks are ‘failure’ and ‘callback’ (get called whether success or failure) .

Our answers to the questions are created the same way but no card of the viewport is switched and being on the same card tarot.views.DataView object is updated automatically.

I hope this gives you a nice overview of building mobile web application with Sencha Touch. But this is not it! There is lot more and can be used to build amazing cross platform application efficiently.

Did you like this? Share it:
30 Aug 2011

Geo/Proximity Search with MySQL

Search posted by waseem

In location based web applications we come across a problem that requires us to fetch some information from our database that is at some certain distance from a particular location. Generally this problem can be defined as following.

Give me all the things near location

Queries like “Fetch all the nearest friends”, “Fetch all the nearest restaurants” or “Fetch all the closest software developers” are essentially same as above.

If we analyze above problem, we see that we have three keywords in it viz. things, near and location. things is the data-set in which we are looking for information. It is usually a table in our database. It could be a users or restaurants table. The keyword near is the amount of distance within which we need to look into our data-set for information. It is given by a user using our application or already defined by us. Normally it is a few kilometers or miles. The third keyword, location is the place from which we need to measure the nearness of records in our data-set. This is also given by users using our application. It is identified by latitude and longitude on earth’s surface.

If we analyze above problem from engineering point of view, we can define it as following.

Give me all the things
order by distance from location
where distance < kilometers

We are actually looking for records sorted by their distance from location. And we are considering only those records that have distance less than specified by user in kilometers or miles. Out of four keywords in the problem, we know three already viz. things — a table in our database, location and kilometers — provided by user. The only thing that we do not know is the distance between location and records in our data-set. Lets find a way to calculate the distance.

We have latitude and longitude of all the records in our data-set. For now lets assume that we have a hotels table in our database that has following structure.

id name latitude longitude
1 Le Meridien 6.4420085 3.415344
2

We also have location of the user in the form of latitude and longitude.

The distance between two points on the surface of a sphere is given by Haversine Formula. Distance is given by following formula.

In above formula,

d = Distance between two points.
R = Radius of the sphere on which the points are. In our case it is earth with 3959 Miles or 6371 Kilometers.
lat1 and long1 are co-ordinates of the first point and lat2 and long2 are co-ordinates of second point in radians.

The corresponding MySQL statement to calculate distance between locations orig and dest:

  6371 * 2 * ASIN(SQRT(POWER(SIN(RADIANS(orig.lat - ABS(dest.lat))), 2) + COS(RADIANS(orig.lat)) * COS(RADIANS(ABS(dest.lat))) * POWER(SIN(RADIANS(orig.long - dest.long)), 2)))

And our complete MySQL query to get all the hotels that are within 10 kilometers from location identified by orig.

SELECT id, name,
6371 * 2 * ASIN(SQRT(POWER(SIN(RADIANS(orig.lat - ABS(hotels.latitude))), 2) + COS(RADIANS(orig.lat)) * COS(RADIANS(ABS(hotels.latitude))) * POWER(SIN(RADIANS(orig.long - hotels.longitude)), 2))) AS distance
FROM hotels
HAVING distance < 10
ORDER BY distance LIMIT 10;

Benchmark

If we run EXPLAIN on the previous query we do not get very pleasant results.

mysql> EXPLAIN query \G
           id: 1
  select_type: SIMPLE
        table: hotels
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10574
        Extra: Using filesort
1 row in set (0.00 sec)

This query scanned the whole table! It went through all the 10574 records in the table one by one and found the distance of that record from the location and then sorted all the records by its distance from it. This is not scalable for large data-sets.

Optimization

If we analyze our original problem once again.

Give me all the things
order by distance from location
where distance < kilometers

Earlier we scanned whole table to find out the distance between each record and location specified by the user. But we are looking for records that are within the kilometers as specified by the user. If somehow we can find a relationship that describes how co-ordinates change with change in distance, we can get the co-ordinates of hotels that may be farthest from the location specified by the user. These farthest co-ordinates will form a boundary within which all other records will reside. Then we need to look only for the records that are within this boundary. It turns out to be that we do have relationship between co-ordinates and distance.

1˚ of latitude ~= 111.04 Kms
1˚ of longitude ~= cos(latitude) * 111.04 Kms

We calculate the co-ordinates of the bounding box using above relationship between distance and co-ordinate change. We do this for location from orig and allowed distance given by dist

long1 = orig.long – dist / ABS(COS(RADIANS(orig.lat)) * 111.04)
long2 = orig.long + dist / ABS(COS(RADIANS(orig.lat)) * 111.04)

lat1 = orig.lat – dist / (111.04)
lat2 = orig.lat + dist / (111.04)

The bounding box will encompass the circle whose center and radius is given by user. Following figure gives us an idea how it will look like.

The black dot is center of the circle it is also the location of the user. Radius of the circle is allowed kilometers withing which we need to look. Since the box is larger than the circle, it will encompass some records that do not fall within the circle. This may give use some false hits. The red dots denote false hits. The green dots denote correct hits.

For faster lookups, we define indexes on latitude and longitude columns in our table.

CREATE INDEX `index_hotels_on_latitude_and_longitude` ON `hotels` (`latitude`, `longitude`)

We also change our original query to find the records within above box whose boundaries are defined by lat1, long1 and lat2, long2.

SELECT id, name,
6371 * 2 * ASIN(SQRT(POWER(SIN(RADIANS(orig.lat - ABS(hotels.latitude))), 2) + COS(RADIANS(orig.lat)) * COS(RADIANS(ABS(hotels.latitude))) * POWER(SIN(RADIANS(orig.long - hotels.longitude)), 2))) AS distance
FROM hotels
WHERE hotels.latitude BETWEEN lat1 AND lat2 AND hotels.longitude BETWEEN long1 AND long2
HAVING distance < 10
ORDER BY distance LIMIT 10;

If we run EXPLAIN on above query.

mysql> EXPLAIN query \G
           id: 1
  select_type: SIMPLE
        table: listings
         type: range
possible_keys: index_hotels_on_latitude_and_longitude
          key: index_hotels_on_latitude_and_longitude
      key_len: 10
          ref: NULL
         rows: 825
        Extra: Using where, Using filesort
1 row in set (0.00 sec)

We see that number of rows now scanned are far more less than earlier. This time it scanned only 825 rows. In fact these are the number of records that are within the bounding box. So the number of rows that are to be scanned depend upon the number of records falling within the box. If our application has records that are concentrated around a place, number of scanned rows will be higher for query executed around that place.

Using MySQL Spatial Data types

MySQL natively supports Spatial Data Types. Lets use these data types to solve our problem.

ALTER TABLE hotels ADD location POINT NOT NULL;

UPDATE hotels SET location = POINT(hotels.latitude, hotels.longitude);

ALTER TABLE hotels ADD SPATIAL KEY (location);

First we add a location column in our hotels table of POINT type. We also update the location column to have existing co-ordinates of our records. Finally we add a spatial key on the location column.

As of now MySQL does not have any standard GIS function that calculates distance between two points on the surface of a sphere. Lets define our own.

DELIMITER $$
 CREATE FUNCTION distance (a POINT, b POINT) RETURNS double DETERMINISTIC
   BEGIN
     RETURN 6371 * 2 * ASIN(SQRT(POWER(SIN(RADIANS(ABS(X(a)) - ABS(X(b)))), 2) + COS(RADIANS(ABS(X(a)))) * COS(RADIANS(ABS(X(b)))) * POWER(SIN(RADIANS(Y(a) - Y(b))), 2)));
   END  $$
DELIMITER ;

We use the same haversine formula to calculate distance between point a and point b.

Since we are now using Point data type to store locations of hotels in our database, we will use MySQL’s GIS functions to specify bounding box.

SET @bbox = 'POLYGON((lat1 long1, lat1 long2, lat2 long2, lat2 long1, lat1 long1))'

Above defines a polygon that has four vertices defined by (lat1 long1), (lat1 long2), (lat2 long2) and (lat2 long1). The last coordinate explicitly specifies that it is a closed polygon. The closing point is same as the first vertice of the polygon. Variables lat1, lat2, long1 and long2 are the same that we calculated earlier.

Now we update our SQL query to use POINT data types.

SELECT id, name, distance(hotels.location, POINT(orig.lat, orig.long)) AS cdist
FROM hotels
WHERE INTERSECTS(hotels.location, PolygonFromText(@bbox))
HAVING cdist < 10
ORDER BY cdist LIMIT 10;

Above, we are using INTERSECTS function provided by MySQL to find out whether location of a hotel falls within the bounnding box or not. PolygonFromText simply returs a polygon defined in a string. Lets run EXPLAIN on above query.

mysql> EXPLAIN query \G
           id: 1
  select_type: SIMPLE
        table: hotels
         type: range
possible_keys: location
          key: location
      key_len: 34
          ref: NULL
         rows: 70
        Extra: Using where; Using temporary; Using filesort

The number of rows scanned is significantly decreased. We can see that storing coordinates in POINT data type has improved the performance.


Following are some pointers that might be helpful exploring MySQL and Proximity searching.



Did you like this? Share it:
21 Jun 2011

‘Launching Soon’ – Helping Startups Build Online Identity Even before the Actual Launch

Rails 3, open_source, plugin, plugins, rails, rails plugins posted by naveen

The process of brand building begins even before the actual website is launched. To have an eye-catching temporary ‘Launching Soon’ page can do a world of good for your online brand identity. It is the first step that lets you create initial buzz about your business and, therefore, it becomes imperative to have a dedicated ‘Launching Soon’ or ‘Coming Soon’ page in place. Needless to say that an aesthetic landing page embosses a long lasting and distinctive impression in the visitors’ psyche, ensuring a successful first step in climbing the long ladder.

Quick Introduction about ‘Launching Soon’

‘Launching Soon’ is a simple rails plugin that helps rails projects to manage a dedicated launching soon page before the actual launch date. The plugin also collects email from potential customers and can be integrated through an API to popular email marketing service providers like MailChimp & CampaignMonitor (to store customers email contacts). It lets you have a launch timer in place, and you can even have your company logo, about us section and much more. In a nutshell, all primary branding elements are present on your landing page (even before the launch of the official website). Exciting, isn’t it!

To hack over the excitement, ‘Launching Soon’ is an open source rails plugin which can be used by anyone & everyone to set up a fully customized and dedicated landing page in just a few minutes.

Why bother for a dedicated launch soon page?

Gone are the days when terrible yet oh so nostalgic ‘Under Construction’ animated GIF was appreciated by visitors. In its place, the use of more effective, functional and boiled down single ‘Coming Soon’ page is a cogent trend, capable of instantly satisfying the primary goals of the website owners.

For obvious reasons, there are other benefits of exerting efforts to have a great ‘Coming Soon’ page:

1.   Jumpstart your web presence – An effective landing page is the best way to ease the transition from going from naught to a full matured website launch.
2.    Engage with the visitors – Think from where you can benefit the most, a garish graphic which says coming soon or one page site that interacts with the visitors.
3.    Capture user data – This is perhaps one of the most important aspects of having a landing page. It lets you gather a database of genuinely interested users to whom you can send a newsletter notifying the release of your website. Big enough to help your site gain momentum.
4.    Search engine optimization – Getting a domain name booked is not enough. It is essential and imperative to have something substantial online immediately rather than wait for the final product.

With Launching Soon, it is possible to encompass all the above mentioned aspects without any rigorous development and design hassles. With a simple rails plug and play you would be up and running within minutes with your landing page, buzzing about your business and building an online identity. So, if you need a launching soon page then this is it…‘Launching Soon’ can be a near perfect solution.

Get the app code at:

https://github.com/vinsol/Launching-Soon

Note – Currently ‘Launching Soon’ works  with only rails 2.x. We are working on its compatibility with rails 3.x and would keep you posted with the updates.

Did you like this? Share it:
17 Jun 2011

A Rails Developer’s impression of CoffeeScript – Part 2

CofeeScript posted by Shreya Bhatia

We had a look at the basics of CoffeeScript in the previous post. In this tutorial, we’ll see how it is supported in Rails and how can we use it. Ruby CoffeeScript is a ruby bridge to the CoffeeScript compiler. The coffee-script library will automatically choose the best JavaScript engine for our platform. The available engines are V8, Node.js, and JavaScriptCore.

To use CoffeeScript with Rails 3.0.x

We can use either of the two gems available:
- Barista – gem that provides CoffeeScript support for Rails and Rack apps
- BistroCar – another gem that serves up CoffeeScript from within our Rails application

The latest versions of Barista depends on the coffee-script gem. It auto-detects the available compilers on our system as there are several ways to install CoffeeScript. We can install via node.js as the official documentation suggests or else we can use the therubyracer gem and we won’t have to install anything else! therubyracer includes V8 (the fast Javascript engine from Google).

Finally the coffee-script gem depends on the coffee-script-source gem. This gem contains the CoffeeScript source code and it is synced with official releases.

RubyInside has a good tutorial for installing necessary gems and get CoffeeScript working in Rails projects. It also describes how to use CoffeeScript with jQuery.

Here is what we need to add to our Gemfile :

gem 'therubyracer', :require => false
gem 'barista'

Next, we need to generate barista_config.rb file which is stored in config/initializers/ that contains a set of options to configure Barista options

# Generate barista configuration file
rails g barista:install

The two basic settings for barista are the root and output_root configurations. The default directory where barista looks for your coffeescript files is the coffeescripts folder in your app directory which you need to manually create. We can change this default location by making changes in barista_config.rb.

 c.root = Rails.root.join("app", "scripts")

Similarly, default location for compiled javascript files generated by Barista gem is the public/javascripts directory. Lets say, we want Barista to compile CoffeeScript files into public/javascripts/compiled, we’ll need to add this line to Barista configuration file :

c.output_root = Rails.root.join("public", "javascripts", "compiled")

CoffeeScript with JQuery

To use CoffeeScript with JQuery, the initial setup is as follows -

# Add this to Gemfile
gem "jquery-rails"

# Run bundle install. To invoke the generator, run:
rails generate jquery:install

Lets start by writing the simplest JS statement in CoffeeScript

alert("Hey")

Generated JS -

(function() {
  alert("Hey");
}).call(this);

Well, parenthesis for arguments are optional in CoffeeScript, so we can write

alert "Hey"

So far, so good.

Executing something on document.ready with Jquery

$('#form_tag').bind('blur', () ->
   alert('coffee-script')
)

Doing it this way, the .bind call would executing too soon, before the document is ready and thus it doesn’t do anything. Wrap it in a call to $(document).ready like this

$(document).ready ->
  $('#dummy_form_tag').bind 'blur', ->
    alert 'coffee-script'

Global functions

If we want to make a global function in coffeescript, we can explicitly assign it as a property of the global window object

window.dummyFunc = (dummy_arg) ->
  alert dummy_arg

Sample code to highlight(in red color) all required but empty fields, on clicking the form. Example –

<%= f.text_field :title, :class => 'required' %>

We give ‘required’ class to all the required input text fields.

$(document).ready ->
  $('#dummy_form').bind 'click', ->
    empty_fields = ($(this)).find("input.required")
    if empty_fields.length
      empty_fields.each ->
        $(this).css "background-color", "red"
      false

Generated JS –

(function() {
  $(document).ready(function() {
    return $('#new_post').bind('click', function() {
      var empty_fields;
      empty_fields = ($(this)).find("input.required");
      if (empty_fields.length) {
        empty_fields.each(function() {
          return $(this).css("background-color", "red");
        });
        return false;
      }
    });
  });
}).call(this);

CoffeeScript Demo (GitHub Repo)

This sample Rails application lets us create posts, each post can have multiple sections. It uses Ryan Bates’s Nifty Generator Plugin to generate form layouts and basic skeleton for controllers and models.

Add_More_coffeescript

Clicking the “Add more” link lets us create more sections. This JavaScript functionality has been created using CoffeeScript.

If we clone the repo and run server.. notice the log -

Started GET "/posts" for 127.0.0.1 at 2011-05-13 00:18:25 +0530
[Barista] Compiling all scripts for barista
[Barista] Compiling all coffeescripts

On every request, Barista compiles the coffee files and generates equivalent JavaScript code. Every coffee file in app/coffeescript has an auto-generated corresponding file in public/javascript directory.

Other support

rack-coffee – Serves up coffeescript from rack middleware
After we’ve required ‘rack/coffee’, we put this in the Rails initializer config block:

config.middleware.use Rack::Coffee, :root => "#{RAILS_ROOT}/public"

coffee-haml-filter Custom haml filter for rendering CoffeeScript inside our Haml templates. Sample Code -

 :coffee
    window.cl: s =>
      if typeof(console) != 'undefined' then console.log(s) else s

CoffeeScript in the wild – Is a comprehensive list of all projects that have adopted CoffeeScript.

Coffeebeans gives us inline CoffeeScript

<%= coffee_script_tag do %>
  	alert 'coffee script is awesome!'
<% end %>

Generated JavaScript -

(function() {
  	alert('coffee script is awesome!');
}).call(this);

Rails 3.1 and CoffeeScript

Rails 3.1 will have native CoffeeScript supports(via Sprockets 2). RubyInside has another good tutorial on how to start using CoffeeScript in Rails 3.1. This default can be turned off by commenting out the depedndencies in the generated Gemfile. If we want to write code in JS, we still can – just leave off the .coffee suffix from the filename. The application.js file is no longer shipping with .coffee added for the simple reason that it’ll have no code. But if coffee is available, we’ll be generating JS stubs for new controllers (like helpers) with the coffee extension on). Write .js files, like we were doing before. Be sure not to write coffeescript in .coffee files if we don’t want to use coffeescript. By doing so, we will be using coffeescript. Instead we should only write javascript in .js files.

Did you like this? Share it:
Next Page »« Previous Page